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 */