Fixes for the DWARF2 reader, from Josef Weidendorfer:

Attached patch is for the Dwarf2 source line info reader;
For reading, a state machine is used reconstructing source line
info while running and reading (see DWARF2 specification, ch. 6.2).
The state machine was correct, but the calls to addLineInfo()
were wrong: It reported most of the times too small ranges
for source code statements, because it used only the diff of the last
state machine command instead of the diff to the last statement
boundary. Effect: Around 1/3 of all addresses with source line info got
unknown location.
The patch adds a "last_address" to the state machine to remember the last
statement boundary. On reset, it#s initialised to the "invalid" address 0. I
hope this is OK (or should we use "(Addr)-1" instead?).
The patch now uses the "is_stmt" boolean correctly to only call addLineInfo()
if there's a statement boundary (on x86, is_stmt most probably is
always true...).

MERGE TO STABLE


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1209 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_symtab2.c b/coregrind/vg_symtab2.c
index ac5b195..1c0d41a 100644
--- a/coregrind/vg_symtab2.c
+++ b/coregrind/vg_symtab2.c
@@ -324,6 +324,11 @@
    loc.size      = (UShort)size;
    loc.lineno    = lineno;
    loc.fnmoff    = fnmoff;
+
+   if (0) VG_(message)(Vg_DebugMsg, 
+		       "addLoc: addr %p, size %d, line %d, file %s",
+		       this,size,lineno,&si->strtab[fnmoff]);
+
    addLoc ( si, &loc );
 }
 
@@ -913,6 +918,11 @@
 typedef struct State_Machine_Registers
 {
   Addr  address;
+  /* Holds the address of the last statement boundary.
+   * We use it to calculate statement lengths. Without it,
+   * we would need to search backwards for last statement begin
+   * each time we are emitting a statement with addLineInfo */
+  Addr  last_address;
   UInt  file;
   UInt  line;
   UInt  column;
@@ -962,6 +972,7 @@
 {
   if (0) VG_(printf)("smr.a := %p (reset)\n", 0 );
   state_machine_regs.address = 0;
+  state_machine_regs.last_address = 0;
   state_machine_regs.file = 1;
   state_machine_regs.line = 1;
   state_machine_regs.column = 0;
@@ -996,6 +1007,7 @@
   len += bytes_read;
   op_code = * data ++;
 
+  if (0) VG_(printf)("dwarf2: ext OPC: %d\n", op_code);
 
   switch (op_code)
     {
@@ -1005,10 +1017,13 @@
       state_machine_regs.end_sequence = 1; /* JRS: added for compliance
          with spec; is pointless due to reset_state_machine below 
       */
-      addLineInfo (si, (*fnames)[state_machine_regs.file], 
-                       si->offset + (state_machine_regs.address - 1), 
-                       si->offset + (state_machine_regs.address), 
-                       0, 0);
+      if (state_machine_regs.is_stmt) {
+	  if (state_machine_regs.last_address)
+	      addLineInfo (si, (*fnames)[state_machine_regs.file], 
+                       si->offset + state_machine_regs.last_address, 
+                       si->offset + state_machine_regs.address, 
+                       state_machine_regs.line, 0);
+      }
       reset_state_machine (is_stmt);
       break;
 
@@ -1102,6 +1117,9 @@
       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;
@@ -1188,6 +1206,8 @@
 
          op_code = * data ++;
 
+	 if (0) VG_(printf)("dwarf2: OPC: %d\n", op_code);
+
          if (op_code >= info.li_opcode_base)
            {
              Int advAddr;
@@ -1200,11 +1220,15 @@
              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 );
-             addLineInfo (si, fnames[state_machine_regs.file], 
-                              si->offset + (state_machine_regs.address 
-                                            - advAddr), 
-                              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) 
+		     addLineInfo (si, fnames[state_machine_regs.file], 
+			      si->offset + state_machine_regs.last_address, 
+                              si->offset + state_machine_regs.address, 
                               state_machine_regs.line, 0);
+		 state_machine_regs.last_address = state_machine_regs.address;
+	     }
              state_machine_regs.line += adv;
            }
          else switch (op_code)
@@ -1218,10 +1242,15 @@
            case DW_LNS_copy:
              if (0) VG_(printf)("1002: si->o %p, smr.a %p\n", 
                                 si->offset, state_machine_regs.address );
-             addLineInfo (si, fnames[state_machine_regs.file], 
-                              si->offset + state_machine_regs.address, 
-                              si->offset + (state_machine_regs.address + 1),
+	     if (state_machine_regs.is_stmt) {
+		 /* only add a statement if there was a previous boundary */
+		 if (state_machine_regs.last_address) 
+		     addLineInfo (si, fnames[state_machine_regs.file], 
+                              si->offset + state_machine_regs.last_address, 
+                              si->offset + state_machine_regs.address,
                               state_machine_regs.line , 0);
+		 state_machine_regs.last_address = state_machine_regs.address;
+	     }
              state_machine_regs.basic_block = 0; /* JRS added */
              break;