Patch in a DWARF1 (obsolete) line number reader, from the stable (2.0)
branch. Apparently the Lahey Fortran compiler emits DWARF1 line
number info.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2105 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_dwarf.c b/coregrind/vg_dwarf.c
index b444f2d..dca025c 100644
--- a/coregrind/vg_dwarf.c
+++ b/coregrind/vg_dwarf.c
@@ -1,5 +1,5 @@
/*--------------------------------------------------------------------*/
-/*--- Read DWARF2 debug info. vg_symtab_dwarf.c ---*/
+/*--- Read DWARF2 debug info. vg_dwarf.c ---*/
/*--------------------------------------------------------------------*/
/*
@@ -531,6 +531,303 @@
}
}
+
+/*------------------------------------------------------------*/
+/*--- Read DWARF1 format line number info. ---*/
+/*------------------------------------------------------------*/
+
+/* DWARF1 appears to be redundant, but nevertheless the Lahey Fortran
+ compiler generates it.
+*/
+
+/* The following three enums (dwarf_tag, dwarf_form, dwarf_attribute)
+ are taken from the file include/elf/dwarf.h in the GNU gdb-6.0
+ sources, which are Copyright 1992, 1993, 1995, 1999 Free Software
+ Foundation, Inc and naturally licensed under the GNU General Public
+ License version 2 or later.
+*/
+
+/* Tag names and codes. */
+
+enum dwarf_tag {
+ TAG_padding = 0x0000,
+ TAG_array_type = 0x0001,
+ TAG_class_type = 0x0002,
+ TAG_entry_point = 0x0003,
+ TAG_enumeration_type = 0x0004,
+ TAG_formal_parameter = 0x0005,
+ TAG_global_subroutine = 0x0006,
+ TAG_global_variable = 0x0007,
+ /* 0x0008 -- reserved */
+ /* 0x0009 -- reserved */
+ TAG_label = 0x000a,
+ TAG_lexical_block = 0x000b,
+ TAG_local_variable = 0x000c,
+ TAG_member = 0x000d,
+ /* 0x000e -- reserved */
+ TAG_pointer_type = 0x000f,
+ TAG_reference_type = 0x0010,
+ TAG_compile_unit = 0x0011,
+ TAG_string_type = 0x0012,
+ TAG_structure_type = 0x0013,
+ TAG_subroutine = 0x0014,
+ TAG_subroutine_type = 0x0015,
+ TAG_typedef = 0x0016,
+ TAG_union_type = 0x0017,
+ TAG_unspecified_parameters = 0x0018,
+ TAG_variant = 0x0019,
+ TAG_common_block = 0x001a,
+ TAG_common_inclusion = 0x001b,
+ TAG_inheritance = 0x001c,
+ TAG_inlined_subroutine = 0x001d,
+ TAG_module = 0x001e,
+ TAG_ptr_to_member_type = 0x001f,
+ TAG_set_type = 0x0020,
+ TAG_subrange_type = 0x0021,
+ TAG_with_stmt = 0x0022,
+
+ /* GNU extensions */
+
+ TAG_format_label = 0x8000, /* for FORTRAN 77 and Fortran 90 */
+ TAG_namelist = 0x8001, /* For Fortran 90 */
+ TAG_function_template = 0x8002, /* for C++ */
+ TAG_class_template = 0x8003 /* for C++ */
+};
+
+/* Form names and codes. */
+
+enum dwarf_form {
+ FORM_ADDR = 0x1,
+ FORM_REF = 0x2,
+ FORM_BLOCK2 = 0x3,
+ FORM_BLOCK4 = 0x4,
+ FORM_DATA2 = 0x5,
+ FORM_DATA4 = 0x6,
+ FORM_DATA8 = 0x7,
+ FORM_STRING = 0x8
+};
+
+/* Attribute names and codes. */
+
+enum dwarf_attribute {
+ AT_sibling = (0x0010|FORM_REF),
+ AT_location = (0x0020|FORM_BLOCK2),
+ AT_name = (0x0030|FORM_STRING),
+ AT_fund_type = (0x0050|FORM_DATA2),
+ AT_mod_fund_type = (0x0060|FORM_BLOCK2),
+ AT_user_def_type = (0x0070|FORM_REF),
+ AT_mod_u_d_type = (0x0080|FORM_BLOCK2),
+ AT_ordering = (0x0090|FORM_DATA2),
+ AT_subscr_data = (0x00a0|FORM_BLOCK2),
+ AT_byte_size = (0x00b0|FORM_DATA4),
+ AT_bit_offset = (0x00c0|FORM_DATA2),
+ AT_bit_size = (0x00d0|FORM_DATA4),
+ /* (0x00e0|FORM_xxxx) -- reserved */
+ AT_element_list = (0x00f0|FORM_BLOCK4),
+ AT_stmt_list = (0x0100|FORM_DATA4),
+ AT_low_pc = (0x0110|FORM_ADDR),
+ AT_high_pc = (0x0120|FORM_ADDR),
+ AT_language = (0x0130|FORM_DATA4),
+ AT_member = (0x0140|FORM_REF),
+ AT_discr = (0x0150|FORM_REF),
+ AT_discr_value = (0x0160|FORM_BLOCK2),
+ /* (0x0170|FORM_xxxx) -- reserved */
+ /* (0x0180|FORM_xxxx) -- reserved */
+ AT_string_length = (0x0190|FORM_BLOCK2),
+ AT_common_reference = (0x01a0|FORM_REF),
+ AT_comp_dir = (0x01b0|FORM_STRING),
+ AT_const_value_string = (0x01c0|FORM_STRING),
+ AT_const_value_data2 = (0x01c0|FORM_DATA2),
+ AT_const_value_data4 = (0x01c0|FORM_DATA4),
+ AT_const_value_data8 = (0x01c0|FORM_DATA8),
+ AT_const_value_block2 = (0x01c0|FORM_BLOCK2),
+ AT_const_value_block4 = (0x01c0|FORM_BLOCK4),
+ AT_containing_type = (0x01d0|FORM_REF),
+ AT_default_value_addr = (0x01e0|FORM_ADDR),
+ AT_default_value_data2 = (0x01e0|FORM_DATA2),
+ AT_default_value_data4 = (0x01e0|FORM_DATA4),
+ AT_default_value_data8 = (0x01e0|FORM_DATA8),
+ AT_default_value_string = (0x01e0|FORM_STRING),
+ AT_friends = (0x01f0|FORM_BLOCK2),
+ AT_inline = (0x0200|FORM_STRING),
+ AT_is_optional = (0x0210|FORM_STRING),
+ AT_lower_bound_ref = (0x0220|FORM_REF),
+ AT_lower_bound_data2 = (0x0220|FORM_DATA2),
+ AT_lower_bound_data4 = (0x0220|FORM_DATA4),
+ AT_lower_bound_data8 = (0x0220|FORM_DATA8),
+ AT_private = (0x0240|FORM_STRING),
+ AT_producer = (0x0250|FORM_STRING),
+ AT_program = (0x0230|FORM_STRING),
+ AT_protected = (0x0260|FORM_STRING),
+ AT_prototyped = (0x0270|FORM_STRING),
+ AT_public = (0x0280|FORM_STRING),
+ AT_pure_virtual = (0x0290|FORM_STRING),
+ AT_return_addr = (0x02a0|FORM_BLOCK2),
+ AT_abstract_origin = (0x02b0|FORM_REF),
+ AT_start_scope = (0x02c0|FORM_DATA4),
+ AT_stride_size = (0x02e0|FORM_DATA4),
+ AT_upper_bound_ref = (0x02f0|FORM_REF),
+ AT_upper_bound_data2 = (0x02f0|FORM_DATA2),
+ AT_upper_bound_data4 = (0x02f0|FORM_DATA4),
+ AT_upper_bound_data8 = (0x02f0|FORM_DATA8),
+ AT_virtual = (0x0300|FORM_STRING),
+
+ /* GNU extensions. */
+
+ AT_sf_names = (0x8000|FORM_DATA4),
+ AT_src_info = (0x8010|FORM_DATA4),
+ AT_mac_info = (0x8020|FORM_DATA4),
+ AT_src_coords = (0x8030|FORM_DATA4),
+ AT_body_begin = (0x8040|FORM_ADDR),
+ AT_body_end = (0x8050|FORM_ADDR)
+};
+
+/* end of enums taken from gdb-6.0 sources */
+
+void VG_(read_debuginfo_dwarf1) (
+ SegInfo* si,
+ UChar* dwarf1d, Int dwarf1d_sz,
+ UChar* dwarf1l, Int dwarf1l_sz )
+{
+ UInt stmt_list;
+ Bool stmt_list_found;
+ Int die_offset, die_szb, at_offset;
+ UShort die_kind, at_kind;
+ UChar* at_base;
+ UChar* src_filename;
+
+ if (0)
+ VG_(printf)("read_debuginfo_dwarf1 ( %p, %d, %p, %d )\n",
+ dwarf1d, dwarf1d_sz, dwarf1l, dwarf1l_sz );
+
+ /* This loop scans the DIEs. */
+ die_offset = 0;
+ while (True) {
+ if (die_offset >= dwarf1d_sz) break;
+
+ die_szb = *(Int*)(dwarf1d + die_offset);
+ die_kind = *(UShort*)(dwarf1d + die_offset + 4);
+
+ /* We're only interested in compile_unit DIEs; ignore others. */
+ if (die_kind != TAG_compile_unit) {
+ die_offset += die_szb;
+ continue;
+ }
+
+ if (0)
+ VG_(printf)("compile-unit DIE: offset %d, tag 0x%x, size %d\n",
+ die_offset, (Int)die_kind, die_szb );
+
+ /* We've got a compile_unit DIE starting at (dwarf1d +
+ die_offset+6). Try and find the AT_name and AT_stmt_list
+ attributes. Then, finally, we can read the line number info
+ for this source file. */
+
+ /* The next 3 are set as we find the relevant attrs. */
+ src_filename = NULL;
+ stmt_list_found = False;
+ stmt_list = 0;
+
+ /* This loop scans the Attrs inside compile_unit DIEs. */
+ at_base = dwarf1d + die_offset + 6;
+ at_offset = 0;
+ while (True) {
+ if (at_offset >= die_szb-6) break;
+
+ at_kind = *(UShort*)(at_base + at_offset);
+ if (0) VG_(printf)("atoffset %d, attag 0x%x\n",
+ at_offset, (Int)at_kind );
+ at_offset += 2; /* step over the attribute itself */
+ /* We have to examine the attribute to figure out its
+ length. */
+ switch (at_kind) {
+ case AT_stmt_list:
+ case AT_language:
+ case AT_sibling:
+ if (at_kind == AT_stmt_list) {
+ stmt_list_found = True;
+ stmt_list = *(Int*)(at_base+at_offset);
+ }
+ at_offset += 4; break;
+ case AT_high_pc:
+ case AT_low_pc:
+ at_offset += sizeof(void*); break;
+ case AT_name:
+ case AT_producer:
+ case AT_comp_dir:
+ /* Zero terminated string, step over it. */
+ if (at_kind == AT_name)
+ src_filename = at_base + at_offset;
+ while (at_offset < die_szb-6 && at_base[at_offset] != 0)
+ at_offset++;
+ at_offset++;
+ break;
+ default:
+ VG_(printf)("Unhandled DWARF-1 attribute 0x%x\n",
+ (Int)at_kind );
+ VG_(core_panic)("Unhandled DWARF-1 attribute");
+ } /* switch (at_kind) */
+ } /* looping over attributes */
+
+ /* So, did we find the required stuff for a line number table in
+ this DIE? If yes, read it. */
+ if (stmt_list_found /* there is a line number table */
+ && src_filename != NULL /* we know the source filename */
+ ) {
+ /* Table starts:
+ Length:
+ 4 bytes, includes the entire table
+ Base address:
+ unclear (4? 8?), assuming native pointer size here.
+ Then a sequence of triples
+ (source line number -- 32 bits
+ source line column -- 16 bits
+ address delta -- 32 bits)
+ */
+ Addr base;
+ Int len;
+ Char* curr_filenm;
+ UChar* ptr;
+ UInt prev_line, prev_delta;
+
+ curr_filenm = VG_(addStr) ( si, src_filename, -1 );
+ prev_line = prev_delta = 0;
+
+ ptr = dwarf1l + stmt_list;
+ len = *(Int*)ptr; ptr += sizeof(Int);
+ base = (Addr)(*(void**)ptr); ptr += sizeof(void*);
+ len -= (sizeof(Int) + sizeof(void*));
+ while (len > 0) {
+ UInt line;
+ UShort col;
+ UInt delta;
+ line = *(UInt*)ptr; ptr += sizeof(UInt);
+ col = *(UShort*)ptr; ptr += sizeof(UShort);
+ delta = *(UShort*)ptr; ptr += sizeof(UInt);
+ if (0) VG_(printf)("line %d, col %d, delta %d\n",
+ line, (Int)col, delta );
+ len -= (sizeof(UInt) + sizeof(UShort) + sizeof(UInt));
+
+ if (delta > 0 && prev_line > 0) {
+ if (0) VG_(printf) (" %d %d-%d\n",
+ prev_line, prev_delta, delta-1);
+ VG_(addLineInfo) ( si, curr_filenm,
+ base + prev_delta, base + delta,
+ prev_line, 0 );
+ }
+ prev_line = line;
+ prev_delta = delta;
+ }
+ }
+
+ /* Move on the the next DIE. */
+ die_offset += die_szb;
+
+ } /* Looping over DIEs */
+
+}
+
+
/*--------------------------------------------------------------------*/
-/*--- end vg_symtab_dwarf.c ---*/
+/*--- end vg_dwarf.c ---*/
/*--------------------------------------------------------------------*/
diff --git a/coregrind/vg_symtab2.c b/coregrind/vg_symtab2.c
index 6195784..de7ee53 100644
--- a/coregrind/vg_symtab2.c
+++ b/coregrind/vg_symtab2.c
@@ -968,6 +968,8 @@
UChar* stab = NULL; /* .stab (stabs) */
UChar* stabstr = NULL; /* .stabstr (stabs) */
UChar* debug_line = NULL; /* .debug_line (dwarf2) */
+ UChar* dwarf1d = NULL; /* .debug (dwarf1) */
+ UChar* dwarf1l = NULL; /* .line (dwarf1) */
/* Section sizes, in bytes */
UInt o_strtab_sz = 0;
@@ -977,10 +979,14 @@
UInt stab_sz = 0;
UInt stabstr_sz = 0;
UInt debug_line_sz = 0;
+ UInt dwarf1d_sz = 0;
+ UInt dwarf1l_sz = 0;
+
+ Bool has_debuginfo = False;
/* Find all interesting sections */
for (i = 0; i < ehdr->e_shnum; i++) {
- #define FIND(sec_name, sec_data, sec_size, in_exec, type) \
+# define FIND(sec_name, sec_data, sec_size, in_exec, type) \
if (0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \
if (0 != sec_data) \
VG_(core_panic)("repeated section!\n"); \
@@ -1007,11 +1013,13 @@
else FIND(".stab", stab, stab_sz, 0, UChar*)
else FIND(".stabstr", stabstr, stabstr_sz, 0, UChar*)
else FIND(".debug_line", debug_line, debug_line_sz, 0, UChar*)
+ else FIND(".debug", dwarf1d, dwarf1d_sz, 0, UChar*)
+ else FIND(".line", dwarf1l, dwarf1l_sz, 0, UChar*)
else FIND(".got", si->got_start, si->got_size, 1, Addr)
else FIND(".plt", si->plt_start, si->plt_size, 1, Addr)
- #undef FIND
+# undef FIND
/* Check some sizes */
vg_assert((o_dynsym_sz % sizeof(Elf32_Sym)) == 0);
@@ -1028,12 +1036,20 @@
/* Read the stabs and/or dwarf2 debug information, if any. */
if (stab != NULL && stabstr != NULL) {
- VG_(read_debuginfo_stabs) ( si, stab, stab_sz, stabstr, stabstr_sz );
-
- } else if (debug_line) {
+ has_debuginfo = True;
+ VG_(read_debuginfo_stabs) ( si, stab, stab_sz,
+ stabstr, stabstr_sz );
+ }
+ if (debug_line) {
+ has_debuginfo = True;
VG_(read_debuginfo_dwarf2) ( si, debug_line, debug_line_sz );
-
- } else {
+ }
+ if (dwarf1d && dwarf1l) {
+ has_debuginfo = True;
+ VG_(read_debuginfo_dwarf1) ( si, dwarf1d, dwarf1d_sz,
+ dwarf1l, dwarf1l_sz );
+ }
+ if (!has_debuginfo) {
VG_(symerr)(" object doesn't have any debug info");
goto out;
}
diff --git a/coregrind/vg_symtab2.h b/coregrind/vg_symtab2.h
index 3c378b7..36f2c57 100644
--- a/coregrind/vg_symtab2.h
+++ b/coregrind/vg_symtab2.h
@@ -185,7 +185,16 @@
/* --------------------
DWARF2 reader
-------------------- */
-void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz );
+void VG_(read_debuginfo_dwarf2) ( SegInfo* si,
+ UChar* dwarf2, Int dwarf2_sz );
+
+/* --------------------
+ DWARF1 reader
+ -------------------- */
+void VG_(read_debuginfo_dwarf1) ( SegInfo* si,
+ UChar* dwarf1d, Int dwarf1d_sz,
+ UChar* dwarf1l, Int dwarf1l_sz );
+
#endif /* _VG_SYMTYPE_H */