Merge in the DATASYMS branch.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7540 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index 4f704a2..8c1c2c2 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -44,6 +44,7 @@
 #include "pub_tool_tooliface.h"
 #include "pub_tool_threadstate.h"
 #include "pub_tool_oset.h"
+#include "pub_tool_debuginfo.h"     // VG_(get_dataname_and_offset)
 
 #include "mc_include.h"
 #include "memcheck.h"   /* for client requests */
@@ -2625,10 +2626,13 @@
 /* The classification of a faulting address. */
 typedef 
    enum { 
-      Addr_Undescribed,   // as-yet unclassified
-      Addr_Unknown,       // classification yielded nothing useful
-      Addr_Stack,          
-      Addr_Block,
+      Addr_Undescribed, // as-yet unclassified
+      Addr_Unknown,     // classification yielded nothing useful
+      Addr_Block,       // in malloc'd/free'd block
+      Addr_Stack,       // on a thread's stack       
+      Addr_DataSym,     // in a global data sym
+      Addr_Variable,    // variable described by the debug info
+      Addr_SectKind     // last-ditch classification attempt
    }
    AddrTag;
 
@@ -2657,6 +2661,27 @@
          ExeContext* lastchange;
       } Block;
 
+      // In a global .data symbol.  This holds the first 63 chars of
+      // the variable's (zero terminated), plus an offset.
+      struct {
+         Char name[128];
+         OffT offset;
+      } DataSym;
+
+      // Is described by Dwarf debug info.  Arbitrary strings.  Must
+      // be the same length.
+      struct {
+         Char descr1[96];
+         Char descr2[96];
+      } Variable;
+
+      // Could only narrow it down to be the PLT/GOT/etc of a given
+      // object.  Better than nothing, perhaps.
+      struct {
+         Char       objname[128];
+         VgSectKind kind;
+      } SectKind;
+
       // Classification yielded nothing useful.
       struct { } Unknown;
 
@@ -2833,6 +2858,36 @@
          break;
       }
 
+      case Addr_DataSym:
+         VG_(message)(Vg_UserMsg, 
+                      "%sAddress 0x%llx is %llu bytes "
+                        "inside data symbol \"%t\"%s", 
+                      xpre, 
+                      (ULong)a, 
+                      (ULong)ai->Addr.DataSym.offset,
+                      ai->Addr.DataSym.name, 
+                      xpost);
+         break;
+
+      case Addr_Variable:
+         if (ai->Addr.Variable.descr1[0] != '\0')
+            VG_(message)(Vg_UserMsg, "%s%s%s",
+                         xpre, ai->Addr.Variable.descr1, xpost);
+         if (ai->Addr.Variable.descr2[0] != '\0')
+            VG_(message)(Vg_UserMsg, "%s%s%s",
+                         xpre, ai->Addr.Variable.descr2, xpost);
+         break;
+
+      case Addr_SectKind:
+         VG_(message)(Vg_UserMsg, 
+                      "%sAddress 0x%llx is in the %t segment of %t%s",
+                      xpre, 
+                      (ULong)a, 
+                      VG_(pp_SectKind)(ai->Addr.SectKind.kind),
+                      ai->Addr.SectKind.objname, 
+                      xpost);
+         break;
+
       default:
          VG_(tool_panic)("mc_pp_AddrInfo");
    }
@@ -3321,26 +3376,18 @@
 
 /* Describe an address as best you can, for error messages,
    putting the result in ai. */
-static void describe_addr ( Addr a, AddrInfo* ai )
+static void describe_addr ( Addr a, /*OUT*/AddrInfo* ai )
 {
-   MC_Chunk* mc;
-   ThreadId  tid;
-   Addr      stack_min, stack_max;
+   MC_Chunk*  mc;
+   ThreadId   tid;
+   Addr       stack_min, stack_max;
+   VgSectKind sect;
 
    tl_assert(Addr_Undescribed == ai->tag);
 
    /* Perhaps it's a user-def'd block? */
-   if (client_perm_maybe_describe( a, ai ))
+   if (client_perm_maybe_describe( a, ai )) {
       return;
-
-   /* Perhaps it's on a thread's stack? */
-   VG_(thread_stack_reset_iter)();
-   while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
-      if (stack_min <= a && a <= stack_max) {
-         ai->tag            = Addr_Stack;
-         ai->Addr.Stack.tid = tid;
-         return;
-      }
    }
    /* Search for a recently freed block which might bracket it. */
    mc = MC_(get_freed_list_head)();
@@ -3369,6 +3416,61 @@
          return;
       }
    }
+   /* Perhaps the variable type/location data describes it? */
+   tl_assert(sizeof(ai->Addr.Variable.descr1) 
+             == sizeof(ai->Addr.Variable.descr2));
+   VG_(memset)( &ai->Addr.Variable.descr1, 
+                0, sizeof(ai->Addr.Variable.descr1));
+   VG_(memset)( &ai->Addr.Variable.descr2, 
+                0, sizeof(ai->Addr.Variable.descr2));
+   if (VG_(get_data_description)(
+             &ai->Addr.Variable.descr1[0],
+             &ai->Addr.Variable.descr2[0],
+             sizeof(ai->Addr.Variable.descr1)-1, 
+             a )) {
+      ai->tag = Addr_Variable;
+      tl_assert( ai->Addr.Variable.descr1
+                    [ sizeof(ai->Addr.Variable.descr1)-1 ] == 0);
+      tl_assert( ai->Addr.Variable.descr2
+                    [ sizeof(ai->Addr.Variable.descr2)-1 ] == 0);
+      return;
+   }
+   /* Have a look at the low level data symbols - perhaps it's in
+      there. */
+   VG_(memset)( &ai->Addr.DataSym.name,
+                0, sizeof(ai->Addr.DataSym.name));
+   if (VG_(get_datasym_and_offset)(
+             a, &ai->Addr.DataSym.name[0],
+             sizeof(ai->Addr.DataSym.name)-1,
+             &ai->Addr.DataSym.offset )) {
+      ai->tag = Addr_DataSym;
+      tl_assert( ai->Addr.DataSym.name
+                    [ sizeof(ai->Addr.DataSym.name)-1 ] == 0);
+      return;
+   }
+   /* Perhaps it's on a thread's stack? */
+   VG_(thread_stack_reset_iter)(&tid);
+   while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
+      if (stack_min - VG_STACK_REDZONE_SZB <= a && a <= stack_max) {
+         ai->tag            = Addr_Stack;
+         ai->Addr.Stack.tid = tid;
+         return;
+      }
+   }
+   /* last ditch attempt at classification */
+   tl_assert( sizeof(ai->Addr.SectKind.objname) > 4 );
+   VG_(memset)( &ai->Addr.SectKind.objname, 
+                0, sizeof(ai->Addr.SectKind.objname));
+   VG_(strcpy)( ai->Addr.SectKind.objname, "???" );
+   sect = VG_(seginfo_sect_kind)( &ai->Addr.SectKind.objname[0],
+                                  sizeof(ai->Addr.SectKind.objname)-1, a);
+   if (sect != Vg_SectUnknown) {
+      ai->tag = Addr_SectKind;
+      ai->Addr.SectKind.kind = sect;
+      tl_assert( ai->Addr.SectKind.objname
+                    [ sizeof(ai->Addr.SectKind.objname)-1 ] == 0);
+      return;
+   }
    /* Clueless ... */
    ai->tag = Addr_Unknown;
    return;
@@ -3388,26 +3490,31 @@
    case Err_Overlap:
    case Err_RegParam:
    // For Err_Leaks the returned size does not matter -- they are always
-   // shown with VG_(unique_error)() so they 'extra' not copied.  But we make it
-   // consistent with the others.
+   // shown with VG_(unique_error)() so they 'extra' not copied.  But
+   // we make it consistent with the others.
    case Err_Leak:
       return sizeof(MC_Error);
 
    // These ones always involve a memory address.
    case Err_Addr:
-      describe_addr ( VG_(get_error_address)(err), &extra->Err.Addr.ai );
+      describe_addr ( VG_(get_error_address)(err),
+                      &extra->Err.Addr.ai );
       return sizeof(MC_Error);
    case Err_MemParam:
-      describe_addr ( VG_(get_error_address)(err), &extra->Err.MemParam.ai );
+      describe_addr ( VG_(get_error_address)(err),
+                      &extra->Err.MemParam.ai );
       return sizeof(MC_Error);
    case Err_Jump:
-      describe_addr ( VG_(get_error_address)(err), &extra->Err.Jump.ai );
+      describe_addr ( VG_(get_error_address)(err),
+                      &extra->Err.Jump.ai );
       return sizeof(MC_Error);
    case Err_User:
-      describe_addr ( VG_(get_error_address)(err), &extra->Err.User.ai );
+      describe_addr ( VG_(get_error_address)(err),
+                      &extra->Err.User.ai );
       return sizeof(MC_Error);
    case Err_Free:
-      describe_addr ( VG_(get_error_address)(err), &extra->Err.Free.ai );
+      describe_addr ( VG_(get_error_address)(err),
+                      &extra->Err.Free.ai );
       return sizeof(MC_Error);
    case Err_IllegalMempool:
       describe_addr ( VG_(get_error_address)(err),