static void read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr) { var->index = read_leb128 (ptr, &ptr); var->offset = read_sleb128 (ptr, &ptr); var->size = read_leb128 (ptr, &ptr); var->begin_scope = read_leb128 (ptr, &ptr); var->end_scope = read_leb128 (ptr, &ptr); READ_UNALIGNED (gpointer, ptr, var->type); ptr += sizeof (gpointer); *rptr = ptr; }
static MonoDebugMethodJitInfo * mono_debug_read_method (MonoDebugMethodAddress *address) { MonoDebugMethodJitInfo *jit; guint32 i; guint8 *ptr; jit = g_new0 (MonoDebugMethodJitInfo, 1); jit->code_start = address->code_start; jit->code_size = address->code_size; jit->wrapper_addr = address->wrapper_addr; ptr = (guint8 *) &address->data; jit->prologue_end = read_leb128 (ptr, &ptr); jit->epilogue_begin = read_leb128 (ptr, &ptr); jit->num_line_numbers = read_leb128 (ptr, &ptr); jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers); for (i = 0; i < jit->num_line_numbers; i++) { MonoDebugLineNumberEntry *lne = &jit->line_numbers [i]; lne->il_offset = read_sleb128 (ptr, &ptr); lne->native_offset = read_sleb128 (ptr, &ptr); } if (*ptr++) { jit->this_var = g_new0 (MonoDebugVarInfo, 1); read_variable (jit->this_var, ptr, &ptr); } jit->num_params = read_leb128 (ptr, &ptr); jit->params = g_new0 (MonoDebugVarInfo, jit->num_params); for (i = 0; i < jit->num_params; i++) read_variable (&jit->params [i], ptr, &ptr); jit->num_locals = read_leb128 (ptr, &ptr); jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals); for (i = 0; i < jit->num_locals; i++) read_variable (&jit->locals [i], ptr, &ptr); if (*ptr++) { jit->gsharedvt_info_var = g_new0 (MonoDebugVarInfo, 1); jit->gsharedvt_locals_var = g_new0 (MonoDebugVarInfo, 1); read_variable (jit->gsharedvt_info_var, ptr, &ptr); read_variable (jit->gsharedvt_locals_var, ptr, &ptr); } return jit; }
static LineNumberTableFlags method_get_lnt_flags (MonoDebugMethodInfo *minfo) { MonoSymbolFile *symfile; const unsigned char *ptr; guint32 flags; if ((symfile = minfo->handle->symfile) == NULL) return (LineNumberTableFlags)0; ptr = symfile->raw_contents + minfo->data_offset; /* Has to read 'flags' which is preceeded by a bunch of other data */ /* compile_unit_index */ read_leb128 (ptr, &ptr); /* local variable table offset */ read_leb128 (ptr, &ptr); /* namespace id */ read_leb128 (ptr, &ptr); /* code block table offset */ read_leb128 (ptr, &ptr); /* scope variable table offset */ read_leb128 (ptr, &ptr); /* real name offset */ read_leb128 (ptr, &ptr); flags = read_leb128 (ptr, &ptr); return (LineNumberTableFlags)flags; }
static gboolean method_has_column_info (MonoDebugMethodInfo *minfo) { MonoSymbolFile *symfile; const unsigned char *ptr; guint32 flags; if ((symfile = minfo->handle->symfile) == NULL) return FALSE; ptr = symfile->raw_contents + minfo->data_offset; /* Has to read 'flags' which is preceeded by a bunch of other data */ /* compile_unit_index */ read_leb128 (ptr, &ptr); /* local variable table offset */ read_leb128 (ptr, &ptr); /* namespace id */ read_leb128 (ptr, &ptr); /* code block table offset */ read_leb128 (ptr, &ptr); /* scope variable table offset */ read_leb128 (ptr, &ptr); /* real name offset */ read_leb128 (ptr, &ptr); flags = read_leb128 (ptr, &ptr); return (flags & 2) > 0; }
static gchar * read_string (const uint8_t *ptr, const uint8_t **endp) { gchar *s; int len = read_leb128 (ptr, &ptr); s = g_filename_from_utf8 ((const char *) ptr, len, NULL, NULL, NULL); ptr += len; if (endp) *endp = ptr; return s; }
/* * mono_debug_symfile_lookup_locals: * * Return information about the local variables of MINFO from the symbol file. * Return NULL if no information can be found. * The result should be freed using mono_debug_symfile_free_locals (). */ MonoDebugLocalsInfo* mono_debug_symfile_lookup_locals (MonoDebugMethodInfo *minfo) { MonoSymbolFile *symfile = minfo->handle->symfile; const uint8_t *p; int i, len, compile_unit_index, locals_offset, num_locals, block_index; int namespace_id, code_block_table_offset; MonoDebugLocalsInfo *res; if (!symfile) return NULL; p = symfile->raw_contents + minfo->data_offset; compile_unit_index = read_leb128 (p, &p); locals_offset = read_leb128 (p, &p); namespace_id = read_leb128 (p, &p); code_block_table_offset = read_leb128 (p, &p); res = g_new0 (MonoDebugLocalsInfo, 1); p = symfile->raw_contents + code_block_table_offset; res->num_blocks = read_leb128 (p, &p); res->code_blocks = g_new0 (MonoDebugCodeBlock, res->num_blocks); for (i = 0; i < res->num_blocks; ++i) { res->code_blocks [i].type = read_leb128 (p, &p); res->code_blocks [i].parent = read_leb128 (p, &p); res->code_blocks [i].start_offset = read_leb128 (p, &p); res->code_blocks [i].end_offset = read_leb128 (p, &p); } p = symfile->raw_contents + locals_offset; num_locals = read_leb128 (p, &p); res->num_locals = num_locals; res->locals = g_new0 (MonoDebugLocalVar, num_locals); for (i = 0; i < num_locals; ++i) { res->locals [i].index = read_leb128 (p, &p); len = read_leb128 (p, &p); res->locals [i].name = g_malloc (len + 1); memcpy (res->locals [i].name, p, len); res->locals [i].name [len] = '\0'; p += len; block_index = read_leb128 (p, &p); if (block_index >= 1 && block_index <= res->num_blocks) res->locals [i].block = &res->code_blocks [block_index - 1]; } return res; }
/* * mono_debug_symfile_get_line_numbers_full: * * On return, SOURCE_FILE_LIST will point to a GPtrArray of MonoDebugSourceFile * structures, and SOURCE_FILES will contain indexes into this array. * The MonoDebugSourceFile structures are owned by this module. */ void mono_debug_symfile_get_line_numbers_full (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int *n_il_offsets, int **il_offsets, int **line_numbers, int **source_files) { // FIXME: Unify this with mono_debug_symfile_lookup_location MonoSymbolFile *symfile; const unsigned char *ptr; StatementMachine stm; uint32_t i; GPtrArray *il_offset_array, *line_number_array, *source_file_array; if (source_file_list) *source_file_list = NULL; if (n_il_offsets) *n_il_offsets = 0; if (source_files) *source_files = NULL; if (source_file) *source_file = NULL; if ((symfile = minfo->handle->symfile) == NULL) return; il_offset_array = g_ptr_array_new (); line_number_array = g_ptr_array_new (); source_file_array = g_ptr_array_new (); stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base); stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range); stm.opcode_base = (uint8_t) read32 (&symfile->offset_table->_line_number_table_opcode_base); stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range; mono_debugger_lock (); ptr = symfile->raw_contents + minfo->lnt_offset; stm.symfile = symfile; stm.offset = stm.last_offset = 0; stm.last_file = 0; stm.last_line = 0; stm.first_file = 0; stm.file = 1; stm.line = 1; stm.is_hidden = FALSE; while (TRUE) { uint8_t opcode = *ptr++; if (opcode == 0) { uint8_t size = *ptr++; const unsigned char *end_ptr = ptr + size; opcode = *ptr++; if (opcode == DW_LNE_end_sequence) { if (il_offset_array->len == 0) /* Empty table */ break; add_line (&stm, il_offset_array, line_number_array, source_file_array); break; } else if (opcode == DW_LNE_MONO_negate_is_hidden) { stm.is_hidden = !stm.is_hidden; } else if ((opcode >= DW_LNE_MONO__extensions_start) && (opcode <= DW_LNE_MONO__extensions_end)) { ; // reserved for future extensions } else { g_warning ("Unknown extended opcode %x in LNT", opcode); } ptr = end_ptr; continue; } else if (opcode < stm.opcode_base) { switch (opcode) { case DW_LNS_copy: add_line (&stm, il_offset_array, line_number_array, source_file_array); break; case DW_LNS_advance_pc: stm.offset += read_leb128 (ptr, &ptr); break; case DW_LNS_advance_line: stm.line += read_leb128 (ptr, &ptr); break; case DW_LNS_set_file: stm.file = read_leb128 (ptr, &ptr); break; case DW_LNS_const_add_pc: stm.offset += stm.max_address_incr; break; default: g_warning ("Unknown standard opcode %x in LNT", opcode); g_assert_not_reached (); } } else { opcode -= stm.opcode_base; stm.offset += opcode / stm.line_range; stm.line += stm.line_base + (opcode % stm.line_range); add_line (&stm, il_offset_array, line_number_array, source_file_array); } } if (!stm.file && stm.first_file) stm.file = stm.first_file; if (stm.file && source_file) { int offset = read32(&(stm.symfile->offset_table->_source_table_offset)) + (stm.file - 1) * sizeof (MonoSymbolFileSourceEntry); MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *) (stm.symfile->raw_contents + offset); if (source_file) *source_file = read_string (stm.symfile->raw_contents + read32(&(se->_data_offset)), NULL); } if (source_file_list) { int file, last_file = 0; *source_file_list = g_ptr_array_new (); if (source_files) *source_files = g_malloc (il_offset_array->len * sizeof (int)); for (i = 0; i < il_offset_array->len; ++i) { file = GPOINTER_TO_UINT (g_ptr_array_index (source_file_array, i)); if (file && file != last_file) { MonoDebugSourceInfo *info = get_source_info (symfile, file); g_ptr_array_add (*source_file_list, info); } last_file = file; if (source_files) (*source_files) [i] = (*source_file_list)->len - 1; } if ((*source_file_list)->len == 0 && stm.file) { MonoDebugSourceInfo *info = get_source_info (symfile, stm.file); g_ptr_array_add (*source_file_list, info); } } if (n_il_offsets) *n_il_offsets = il_offset_array->len; if (il_offsets && line_numbers) { *il_offsets = g_malloc (il_offset_array->len * sizeof (int)); *line_numbers = g_malloc (il_offset_array->len * sizeof (int)); for (i = 0; i < il_offset_array->len; ++i) { (*il_offsets) [i] = GPOINTER_TO_UINT (g_ptr_array_index (il_offset_array, i)); (*line_numbers) [i] = GPOINTER_TO_UINT (g_ptr_array_index (line_number_array, i)); } } g_ptr_array_free (il_offset_array, TRUE); g_ptr_array_free (line_number_array, TRUE); mono_debugger_unlock (); return; }
/** * mono_debug_symfile_lookup_location: * @minfo: A `MonoDebugMethodInfo' which can be retrieved by * mono_debug_lookup_method(). * @offset: IL offset within the corresponding method's CIL code. * * This function is similar to mono_debug_lookup_location(), but we * already looked up the method and also already did the * `native address -> IL offset' mapping. */ MonoDebugSourceLocation * mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset) { MonoDebugSourceLocation *location = NULL; MonoSymbolFile *symfile; const unsigned char *ptr; StatementMachine stm; #define DW_LNS_copy 1 #define DW_LNS_advance_pc 2 #define DW_LNS_advance_line 3 #define DW_LNS_set_file 4 #define DW_LNS_const_add_pc 8 #define DW_LNE_end_sequence 1 #define DW_LNE_MONO_negate_is_hidden 0x40 #define DW_LNE_MONO__extensions_start 0x40 #define DW_LNE_MONO__extensions_end 0x7f if ((symfile = minfo->handle->symfile) == NULL) return NULL; stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base); stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range); stm.opcode_base = (uint8_t) read32 (&symfile->offset_table->_line_number_table_opcode_base); stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range; mono_debugger_lock (); ptr = symfile->raw_contents + minfo->lnt_offset; stm.symfile = symfile; stm.offset = stm.last_offset = 0; stm.last_file = 0; stm.last_line = 0; stm.first_file = 0; stm.file = 1; stm.line = 1; stm.is_hidden = FALSE; while (TRUE) { uint8_t opcode = *ptr++; if (opcode == 0) { uint8_t size = *ptr++; const unsigned char *end_ptr = ptr + size; opcode = *ptr++; if (opcode == DW_LNE_end_sequence) { if (check_line (&stm, -1, &location)) goto out_success; break; } else if (opcode == DW_LNE_MONO_negate_is_hidden) { stm.is_hidden = !stm.is_hidden; } else if ((opcode >= DW_LNE_MONO__extensions_start) && (opcode <= DW_LNE_MONO__extensions_end)) { ; // reserved for future extensions } else { g_warning ("Unknown extended opcode %x in LNT", opcode); } ptr = end_ptr; continue; } else if (opcode < stm.opcode_base) { switch (opcode) { case DW_LNS_copy: if (check_line (&stm, offset, &location)) goto out_success; break; case DW_LNS_advance_pc: stm.offset += read_leb128 (ptr, &ptr); break; case DW_LNS_advance_line: stm.line += read_leb128 (ptr, &ptr); break; case DW_LNS_set_file: stm.file = read_leb128 (ptr, &ptr); break; case DW_LNS_const_add_pc: stm.offset += stm.max_address_incr; break; default: g_warning ("Unknown standard opcode %x in LNT", opcode); goto error_out; } } else { opcode -= stm.opcode_base; stm.offset += opcode / stm.line_range; stm.line += stm.line_base + (opcode % stm.line_range); if (check_line (&stm, offset, &location)) goto out_success; } } error_out: mono_debugger_unlock (); return NULL; out_success: mono_debugger_unlock (); return location; }
static bool read_uleb128(struct dwbuf *d, uint64_t *v) { return (read_leb128(d, v, false)); }
static bool read_sleb128(struct dwbuf *d, int64_t *v) { return (read_leb128(d, (uint64_t *)v, true)); }
/* * mono_debug_symfile_get_seq_points: * * On return, SOURCE_FILE_LIST will point to a GPtrArray of MonoDebugSourceFile * structures, and SOURCE_FILES will contain indexes into this array. * The MonoDebugSourceFile structures are owned by this module. */ void mono_debug_symfile_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points) { // FIXME: Unify this with mono_debug_symfile_lookup_location MonoSymbolFile *symfile; const unsigned char *ptr; StatementMachine stm; uint32_t i, j, n; LineNumberTableFlags flags; GPtrArray *il_offset_array, *line_number_array, *source_file_array, *hidden_array; gboolean has_column_info, has_end_info; MonoSymSeqPoint *sps; if (source_file_list) *source_file_list = NULL; if (seq_points) *seq_points = NULL; if (n_seq_points) *n_seq_points = 0; if (source_files) *source_files = NULL; if (source_file) *source_file = NULL; if ((symfile = minfo->handle->symfile) == NULL) return; flags = method_get_lnt_flags (minfo); has_column_info = (flags & LNT_FLAG_HAS_COLUMN_INFO) > 0; has_end_info = (flags & LNT_FLAG_HAS_END_INFO) > 0; il_offset_array = g_ptr_array_new (); line_number_array = g_ptr_array_new (); source_file_array = g_ptr_array_new (); hidden_array = g_ptr_array_new(); stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base); stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range); stm.opcode_base = (uint8_t) read32 (&symfile->offset_table->_line_number_table_opcode_base); stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range; mono_debugger_lock (); ptr = symfile->raw_contents + minfo->lnt_offset; stm.symfile = symfile; stm.offset = stm.last_offset = 0; stm.last_file = 0; stm.last_line = 0; stm.first_file = 0; stm.file = 1; stm.line = 1; stm.is_hidden = FALSE; while (TRUE) { uint8_t opcode = *ptr++; if (opcode == 0) { uint8_t size = *ptr++; const unsigned char *end_ptr = ptr + size; opcode = *ptr++; if (opcode == DW_LNE_end_sequence) { if (il_offset_array->len == 0) /* Empty table */ break; break; } else if (opcode == DW_LNE_MONO_negate_is_hidden) { stm.is_hidden = !stm.is_hidden; } else if ((opcode >= DW_LNE_MONO__extensions_start) && (opcode <= DW_LNE_MONO__extensions_end)) { ; // reserved for future extensions } else { g_warning ("Unknown extended opcode %x in LNT", opcode); } ptr = end_ptr; continue; } else if (opcode < stm.opcode_base) { switch (opcode) { case DW_LNS_copy: add_line (&stm, il_offset_array, line_number_array, source_file_array, hidden_array); break; case DW_LNS_advance_pc: stm.offset += read_leb128 (ptr, &ptr); break; case DW_LNS_advance_line: stm.line += read_leb128 (ptr, &ptr); break; case DW_LNS_set_file: stm.file = read_leb128 (ptr, &ptr); break; case DW_LNS_const_add_pc: stm.offset += stm.max_address_incr; break; default: g_warning ("Unknown standard opcode %x in LNT", opcode); g_assert_not_reached (); } } else { opcode -= stm.opcode_base; stm.offset += opcode / stm.line_range; stm.line += stm.line_base + (opcode % stm.line_range); add_line (&stm, il_offset_array, line_number_array, source_file_array, hidden_array); } } if (!stm.file && stm.first_file) stm.file = stm.first_file; if (stm.file && source_file) { int offset = read32(&(stm.symfile->offset_table->_source_table_offset)) + (stm.file - 1) * sizeof (MonoSymbolFileSourceEntry); MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *) (stm.symfile->raw_contents + offset); if (source_file) *source_file = read_string (stm.symfile->raw_contents + read32(&(se->_data_offset)), NULL); } if (source_file_list) { int file, last_file = 0; *source_file_list = g_ptr_array_new (); if (source_files) *source_files = (int *)g_malloc (il_offset_array->len * sizeof (int)); for (i = 0; i < il_offset_array->len; ++i) { file = GPOINTER_TO_UINT (g_ptr_array_index (source_file_array, i)); if (file && file != last_file) { MonoDebugSourceInfo *info = get_source_info (symfile, file); g_ptr_array_add (*source_file_list, info); } last_file = file; if (source_files) (*source_files) [i] = (*source_file_list)->len - 1; } if ((*source_file_list)->len == 0 && stm.file) { MonoDebugSourceInfo *info = get_source_info (symfile, stm.file); g_ptr_array_add (*source_file_list, info); } } if (n_seq_points) { g_assert (seq_points); n = il_offset_array->len; for (i = 0; i < il_offset_array->len; i++) { if (GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) { n --; } } *n_seq_points = n; *seq_points = sps = g_new0 (MonoSymSeqPoint, n); j = 0; for (i = 0; i < il_offset_array->len; ++i) { MonoSymSeqPoint *sp = &(sps [j]); if (!GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) { sp->il_offset = GPOINTER_TO_UINT (g_ptr_array_index (il_offset_array, i)); sp->line = GPOINTER_TO_UINT (g_ptr_array_index (line_number_array, i)); sp->column = -1; sp->end_line = -1; sp->end_column = -1; j ++; } } if (has_column_info) { j = 0; for (i = 0; i < il_offset_array->len; ++i) { MonoSymSeqPoint *sp = &(sps [j]); int column = read_leb128 (ptr, &ptr); if (!GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) { sp->column = column; j++; } } } if (has_end_info) { j = 0; for (i = 0; i < il_offset_array->len; ++i) { MonoSymSeqPoint *sp = &(sps [j]); int end_row, end_column = -1; end_row = read_leb128 (ptr, &ptr); if (end_row != 0xffffff) { end_row += GPOINTER_TO_UINT (g_ptr_array_index (line_number_array, i)); end_column = read_leb128 (ptr, &ptr); if (!GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) { sp->end_line = end_row; sp->end_column = end_column; j++; } } } } } g_ptr_array_free (il_offset_array, TRUE); g_ptr_array_free (line_number_array, TRUE); g_ptr_array_free (hidden_array, TRUE); mono_debugger_unlock (); return; }
void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz ) { DWARF2_External_LineInfo * external; DWARF2_Internal_LineInfo info; UChar * standard_opcodes; UChar * data = dwarf2; UChar * end = dwarf2 + dwarf2_sz; UChar * end_of_sequence; Char ** fnames = NULL; /* Fails due to gcc padding ... vg_assert(sizeof(DWARF2_External_LineInfo) == sizeof(DWARF2_Internal_LineInfo)); */ while (data < end) { external = (DWARF2_External_LineInfo *) data; /* Check the length of the block. */ info.li_length = * ((UInt *)(external->li_length)); if (info.li_length == 0xffffffff) { VG_(symerr)("64-bit DWARF line info is not supported yet."); break; } if (info.li_length + sizeof (external->li_length) > dwarf2_sz) { VG_(symerr)("DWARF line info appears to be corrupt " "- the section is too small"); return; } /* Check its version number. */ info.li_version = * ((UShort *) (external->li_version)); if (info.li_version != 2) { VG_(symerr)("Only DWARF version 2 line info " "is currently supported."); return; } info.li_prologue_length = * ((UInt *) (external->li_prologue_length)); info.li_min_insn_length = * ((UChar *)(external->li_min_insn_length)); info.li_default_is_stmt = True; /* WAS: = * ((UChar *)(external->li_default_is_stmt)); */ /* Josef Weidendorfer (20021021) writes: It seems to me that the Intel Fortran compiler generates bad DWARF2 line info code: It sets "is_stmt" of the state machine in the the line info reader to be always false. Thus, there is never a statement boundary generated and therefore never a instruction range/line number mapping generated for valgrind. Please have a look at the DWARF2 specification, Ch. 6.2 (x86.ddj.com/ftp/manuals/tools/dwarf.pdf). Perhaps I understand this wrong, but I don't think so. I just had a look at the GDB DWARF2 reader... They completely ignore "is_stmt" when recording line info ;-) That's the reason "objdump -S" works on files from the the intel fortran compiler. */ /* JRS: changed (UInt*) to (UChar*) */ info.li_line_base = * ((UChar *)(external->li_line_base)); info.li_line_range = * ((UChar *)(external->li_line_range)); info.li_opcode_base = * ((UChar *)(external->li_opcode_base)); if (0) VG_(printf)("dwarf2: line base: %d, range %d, opc base: %d\n", info.li_line_base, info.li_line_range, info.li_opcode_base); /* Sign extend the line base field. */ info.li_line_base <<= 24; info.li_line_base >>= 24; end_of_sequence = data + info.li_length + sizeof (external->li_length); reset_state_machine (info.li_default_is_stmt); /* Read the contents of the Opcodes table. */ standard_opcodes = data + sizeof (* external); /* Read the contents of the Directory table. */ data = standard_opcodes + info.li_opcode_base - 1; if (* data == 0) { } else { /* We ignore the directory table, since gcc gives the entire path as part of the filename */ while (* data != 0) { data += VG_(strlen) ((char *) data) + 1; } } /* Skip the NUL at the end of the table. */ if (*data != 0) { VG_(symerr)("can't find NUL at end of DWARF2 directory table"); return; } data ++; /* Read the contents of the File Name table. */ if (* data == 0) { } else { while (* data != 0) { UChar * name; Int bytes_read; ++ state_machine_regs.last_file_entry; name = data; /* Since we don't have realloc (0, ....) == malloc (...) semantics, we need to malloc the first time. */ if (fnames == NULL) fnames = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof (UInt) * 2); else fnames = VG_(arena_realloc)(VG_AR_SYMTAB, fnames, VG_MIN_MALLOC_SZB, sizeof(UInt) * (state_machine_regs.last_file_entry + 1)); data += VG_(strlen) ((Char *) data) + 1; fnames[state_machine_regs.last_file_entry] = VG_(addStr) (si,name, -1); read_leb128 (data, & bytes_read, 0); data += bytes_read; read_leb128 (data, & bytes_read, 0); data += bytes_read; read_leb128 (data, & bytes_read, 0); data += bytes_read; } } /* Skip the NUL at the end of the table. */ if (*data != 0) { VG_(symerr)("can't find NUL at end of DWARF2 file name table"); return; } data ++; /* Now display the statements. */ while (data < end_of_sequence) { UChar op_code; Int adv; Int bytes_read; op_code = * data ++; if (0) VG_(printf)("dwarf2: OPC: %d\n", op_code); if (op_code >= info.li_opcode_base) { Int advAddr; op_code -= info.li_opcode_base; adv = (op_code / info.li_line_range) * info.li_min_insn_length; advAddr = adv; state_machine_regs.address += adv; if (0) VG_(printf)("smr.a += %p\n", adv ); adv = (op_code % info.li_line_range) + info.li_line_base; if (0) VG_(printf)("1002: si->o %p, smr.a %p\n", si->offset, state_machine_regs.address ); state_machine_regs.line += adv; if (state_machine_regs.is_stmt) { /* only add a statement if there was a previous boundary */ if (state_machine_regs.last_address) VG_(addLineInfo) (si, fnames[state_machine_regs.last_file], si->offset + state_machine_regs.last_address, si->offset + state_machine_regs.address, state_machine_regs.last_line, 0); state_machine_regs.last_address = state_machine_regs.address; state_machine_regs.last_file = state_machine_regs.file; state_machine_regs.last_line = state_machine_regs.line; } } else switch (op_code) { case DW_LNS_extended_op: data += process_extended_line_op ( si, &fnames, data, info.li_default_is_stmt, sizeof (Addr)); break; case DW_LNS_copy: if (0) VG_(printf)("1002: si->o %p, smr.a %p\n", si->offset, state_machine_regs.address ); if (state_machine_regs.is_stmt) { /* only add a statement if there was a previous boundary */ if (state_machine_regs.last_address) VG_(addLineInfo) (si, fnames[state_machine_regs.last_file], si->offset + state_machine_regs.last_address, si->offset + state_machine_regs.address, state_machine_regs.last_line, 0); state_machine_regs.last_address = state_machine_regs.address; state_machine_regs.last_file = state_machine_regs.file; state_machine_regs.last_line = state_machine_regs.line; } state_machine_regs.basic_block = 0; /* JRS added */ break; case DW_LNS_advance_pc: adv = info.li_min_insn_length * read_leb128 (data, & bytes_read, 0); data += bytes_read; state_machine_regs.address += adv; if (0) VG_(printf)("smr.a += %p\n", adv ); break; case DW_LNS_advance_line: adv = read_leb128 (data, & bytes_read, 1); data += bytes_read; state_machine_regs.line += adv; break; case DW_LNS_set_file: adv = read_leb128 (data, & bytes_read, 0); data += bytes_read; state_machine_regs.file = adv; break; case DW_LNS_set_column: adv = read_leb128 (data, & bytes_read, 0); data += bytes_read; state_machine_regs.column = adv; break; case DW_LNS_negate_stmt: adv = state_machine_regs.is_stmt; adv = ! adv; state_machine_regs.is_stmt = adv; break; case DW_LNS_set_basic_block: state_machine_regs.basic_block = 1; break; case DW_LNS_const_add_pc: adv = (((255 - info.li_opcode_base) / info.li_line_range) * info.li_min_insn_length); state_machine_regs.address += adv; if (0) VG_(printf)("smr.a += %p\n", adv ); break; case DW_LNS_fixed_advance_pc: /* XXX: Need something to get 2 bytes */ adv = *((UShort *)data); data += 2; state_machine_regs.address += adv; if (0) VG_(printf)("smr.a += %p\n", adv ); break; case DW_LNS_set_prologue_end: break; case DW_LNS_set_epilogue_begin: break; case DW_LNS_set_isa: adv = read_leb128 (data, & bytes_read, 0); data += bytes_read; break; default: { int j; for (j = standard_opcodes[op_code - 1]; j > 0 ; --j) { read_leb128 (data, &bytes_read, 0); data += bytes_read; } } break; } } VG_(arena_free)(VG_AR_SYMTAB, fnames); fnames = NULL; } }
/* Handled an extend line op. Returns true if this is the end of sequence. */ static int process_extended_line_op( SegInfo *si, Char*** fnames, UChar* data, Int is_stmt, Int pointer_size) { UChar op_code; Int bytes_read; UInt len; UChar * name; Addr adr; len = read_leb128 (data, & bytes_read, 0); data += bytes_read; if (len == 0) { VG_(message)(Vg_UserMsg, "badly formed extended line op encountered!\n"); return bytes_read; } len += bytes_read; op_code = * data ++; if (0) VG_(printf)("dwarf2: ext OPC: %d\n", op_code); switch (op_code) { case DW_LNE_end_sequence: if (0) VG_(printf)("1001: si->o %p, smr.a %p\n", si->offset, state_machine_regs.address ); state_machine_regs.end_sequence = 1; /* JRS: added for compliance with spec; is pointless due to reset_state_machine below */ if (state_machine_regs.is_stmt) { if (state_machine_regs.last_address) VG_(addLineInfo) (si, (*fnames)[state_machine_regs.last_file], si->offset + state_machine_regs.last_address, si->offset + state_machine_regs.address, state_machine_regs.last_line, 0); } reset_state_machine (is_stmt); break; case DW_LNE_set_address: /* XXX: Pointer size could be 8 */ vg_assert(pointer_size == 4); adr = *((Addr *)data); if (0) VG_(printf)("smr.a := %p\n", adr ); state_machine_regs.address = adr; break; case DW_LNE_define_file: ++ state_machine_regs.last_file_entry; name = data; if (*fnames == NULL) *fnames = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof (UInt) * 2); else *fnames = VG_(arena_realloc)( VG_AR_SYMTAB, *fnames, VG_MIN_MALLOC_SZB, sizeof(UInt) * (state_machine_regs.last_file_entry + 1)); (*fnames)[state_machine_regs.last_file_entry] = VG_(addStr) (si,name, -1); data += VG_(strlen) ((char *) data) + 1; read_leb128 (data, & bytes_read, 0); data += bytes_read; read_leb128 (data, & bytes_read, 0); data += bytes_read; read_leb128 (data, & bytes_read, 0); break; default: break; } return len; }