Author: sewardj
Date: 2008-02-07 12:02:12 +0000 (Thu, 07 Feb 2008)
New Revision: 7376

Log:

* rename VG_(get_dataname_and_offset) 
  to VG_(get_datasym_and_offset)

* new function VG_(get_data_description), which attempts to
  describe a data address based on variable type and location
  data stored in the DebugInfo type.  In particular should be
  able to describe variables on the stack.



Modified:
   branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c
   branches/DATASYMS/include/pub_tool_debuginfo.h


Modified: branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c 2008-02-07 11:58:22 UTC 
(rev 7375)
+++ branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c 2008-02-07 12:02:12 UTC 
(rev 7376)
@@ -49,11 +49,13 @@
 #include "pub_core_aspacemgr.h"
 #include "pub_core_machine.h"     // VG_PLAT_USES_PPCTOC
 #include "pub_core_xarray.h"
+#include "pub_core_oset.h"
 #include "priv_storage.h"
 #include "priv_readdwarf.h"
 #include "priv_readstabs.h"
 #if defined(VGO_linux)
 # include "priv_readelf.h"
+# include "priv_readdwarf3.h"
 #elif defined(VGO_aix5)
 # include "pub_core_debuglog.h"
 # include "pub_core_libcproc.h"
@@ -528,6 +530,14 @@
    }
 
    if (di->have_rx_map && di->have_rw_map && !di->have_dinfo) {
+
+      vg_assert(di->filename);
+      TRACE_SYMTAB("\n");
+      TRACE_SYMTAB("------ start ELF OBJECT "
+                   "------------------------------\n");
+      TRACE_SYMTAB("------ name = %s\n", di->filename);
+      TRACE_SYMTAB("\n");
+
       /* We're going to read symbols and debug info for the vma ranges
          [rx_map_avma,+rx_map_size) and [rw_map_avma,+rw_map_size).
          First get rid of any other DebugInfos which overlap either of
@@ -538,18 +548,28 @@
       ok = ML_(read_elf_debug_info)( di );
 
       if (ok) {
+         TRACE_SYMTAB("\n------ Canonicalising the "
+                      "acquired info ------\n");
          /* prepare read data for use */
          ML_(canonicaliseTables)( di );
          /* notify m_redir about it */
+         TRACE_SYMTAB("\n------ Notifying m_redir ------\n");
          VG_(redir_notify_new_DebugInfo)( di );
          /* Note that we succeeded */
          di->have_dinfo = True;
       } else {
+         TRACE_SYMTAB("\n------ ELF reading failed ------\n");
          /* Something went wrong (eg. bad ELF file).  Should we delete
             this DebugInfo?  No - it contains info on the rw/rx
             mappings, at least. */
       }
 
+      TRACE_SYMTAB("\n");
+      TRACE_SYMTAB("------ name = %s\n", di->filename);
+      TRACE_SYMTAB("------ end ELF OBJECT "
+                   "------------------------------\n");
+      TRACE_SYMTAB("\n");
+
    }
 }
 
@@ -694,7 +714,8 @@
       }
 
       /* Note this short-circuit check relies on the assumption that
-         .bss is mapped immediately after .data. */
+         .bss is mapped immediately after .data.  This is an assumption
+         that readelf.c makes anyway. */
       if (!inRange) continue;
 
       sno = ML_(search_one_symtab) ( 
@@ -870,17 +891,17 @@
 #  undef N_TMPBUF
 }
 
-/* Looks up 'a' in the collection of data symbols, and if found puts
-   its name (or as much as will fit) into dname[0 .. n_dname-1]
-   including zero terminator.  Also the 'a's offset from the symbol
-   start is put into *offset. */
-Bool VG_(get_dataname_and_offset)( Addr a,
-                                   /*OUT*/Char* dname, Int n_dname,
-                                   /*OUT*/OffT* offset )
+/* Looks up data_addr in the collection of data symbols, and if found
+   puts its name (or as much as will fit) into dname[0 .. n_dname-1],
+   which is guaranteed to be zero terminated.  Also data_addr's offset
+   from the symbol start is put into *offset. */
+Bool VG_(get_datasym_and_offset)( Addr data_addr,
+                                  /*OUT*/Char* dname, Int n_dname,
+                                  /*OUT*/OffT* offset )
 {
    Bool ok;
    vg_assert(n_dname > 1);
-   ok = get_sym_name ( /*demangle*/False, a, dname, n_dname,
+   ok = get_sym_name ( /*demangle*/False, data_addr, dname, n_dname,
                        /*match_anywhere_in_sym*/True, 
                        /*show offset?*/False,
                        /*data syms only please*/False,
@@ -891,7 +912,184 @@
    return True;
 }
 
+/* Try to form some description of data_addr by looking at the DWARF3
+   debug info we have.  This only looks at stack locations (for the
+   top frame of the thread from which ip/sp/fp are taken) and at
+   global variables.  Result (or as much as will fit) is put into into
+   dname[0 .. n_dname-1] and is guaranteed to be zero terminated. */
 
+/* Evaluate the location expression/list for var, to see whether or
+   not data_addr falls within the variable.  If so also return the
+   offset of data_addr from the start of the variable.*/
+static Bool data_address_is_in_var ( /*OUT*/UWord* offset,
+                                     DiVariable*   var,
+                                     RegSummary*   regs,
+                                     Addr          data_addr )
+{
+   SizeT    var_szB;
+   GXResult res;
+   vg_assert(var->name);
+   vg_assert(var->typeV);
+   vg_assert(var->gexprV);
+   var_szB = ML_(sizeOfD3Type)(var->typeV);
+
+   if (1) {
+      VG_(printf)("VVVV: find loc: %s :: ", var->name );
+      ML_(pp_D3Type_C_ishly)( var->typeV );
+      VG_(printf)("\n");
+   }
+
+   res = ML_(evaluate_GX)( var->gexprV, var->fbGXv, regs );
+
+   if (1) VG_(printf)("VVVV: -> 0x%lx %s\n", res.res, 
+                      res.failure ? res.failure : "(success)");
+   if (!res.failure && res.res <= data_addr
+                    && data_addr < res.res + var_szB) {
+      *offset = res.res - data_addr;
+      return True;
+   } else {
+      return False;
+   }
+}
+Bool VG_(get_data_description)( Addr data_addr,
+                                Addr ip, Addr sp, Addr fp,
+                                /*OUT*/Char* dname, Int n_dname )
+{
+   DebugInfo* di;
+   RegSummary regs;
+   DebugInfo* di_for_ip;
+
+   vg_assert(n_dname > 1);
+   dname[n_dname-1] = 0;
+
+   if (0) VG_(printf)("GDnO: dataaddr %p, ip at error %p\n",
+                      data_addr, ip );
+
+   /* Loop over the DebugInfos we have.  Check data_addr against the
+      outermost scope of all of them (as that should be a global
+      scope).  Also, identify the di which contains the PC address.
+      That will be the one in which we need to look to find info on
+      nested scopes. */
+
+   regs.ip = ip;
+   regs.sp = sp;
+   regs.fp = fp;
+
+   di_for_ip = NULL;
+   for (di = debugInfo_list; di != NULL; di = di->next) {
+      OSet*        global_scope;
+      Int          gs_size;
+      Addr         zero;
+      DiAddrRange* global_arange;
+      Word         i;
+      XArray*      vars;
+
+      /* text segment missing? unlikely, but handle it .. */
+      if (di->text_size == 0)
+         continue;
+      /* Ok.  So does this text mapping bracket the ip? */
+      if (di->text_avma <= ip && ip < di->text_avma + di->text_size)
+         di_for_ip = di;
+      /* any var info at all? */
+      if (!di->varinfo)
+         continue;
+      /* perhaps this object didn't contribute any vars at all? */
+      if (VG_(sizeXA)( di->varinfo ) == 0)
+         continue;
+      global_scope = *(OSet**)VG_(indexXA)( di->varinfo, 0 );
+      vg_assert(global_scope);
+      gs_size = VG_(OSetGen_Size)( global_scope );
+      /* The global scope might be completely empty if this
+         compilation unit declared locals but nothing global. */
+      if (gs_size == 0)
+          continue;
+      /* But if it isn't empty, then it must contain exactly one
+         element, which covers the entire address range. */
+      vg_assert(gs_size == 1);
+      /* Fish out the global scope and check it is as expected. */
+      zero = 0;
+      global_arange 
+         = VG_(OSetGen_Lookup)( global_scope, &zero );
+      /* The global range from (Addr)0 to ~(Addr)0 must exist */
+      vg_assert(global_arange);
+      vg_assert(global_arange->aMin ==  (Addr)0);
+      vg_assert(global_arange->aMax == ~(Addr)0);
+      /* Any vars in this range? */
+      if (!global_arange->vars)
+         continue;
+      /* Ok, there are some vars in the global scope of this
+         DebugInfo.  Wade through them and see if the data addresses
+         of any of them bracket data_addr. */
+      vars = global_arange->vars;
+      for (i = 0; i < VG_(sizeXA)( vars ); i++) {
+         SizeT offset;
+         DiVariable* var = (DiVariable*)VG_(indexXA)( vars, i );
+         vg_assert(var->name);
+         if (data_address_is_in_var( &offset, var, &regs, data_addr )) {
+            VG_(snprintf)(
+               dname, (SizeT)n_dname,
+               "Address 0x%lx is %lu bytes inside global var \"%s\"",
+               data_addr, offset, var->name);
+            dname[n_dname-1] = 0;
+            return True;
+         }
+      }
+   }
+
+   if (0) {
+      VG_(printf)("di_for_ip %p\n", di_for_ip);
+      VG_(printf)("vi %p\n", di_for_ip->varinfo);
+      VG_(printf)("vi size %d\n", (Int)VG_(sizeXA)(di_for_ip->varinfo));
+   }
+
+   /* Now that we've considered all the globals in scope, consider the
+      locals. */
+   if (di_for_ip && di_for_ip->varinfo) {
+      Word i;
+      /* Work through the scopes from most deeply nested outwards,
+         looking for code address ranges that bracket 'ip'.  The
+         variables on each such address range found are in scope right
+         now.  Don't descend to level zero as that is the global
+         scope. */
+      /* "for each scope, working outwards ..." */
+      for (i = VG_(sizeXA)(di_for_ip->varinfo) - 1; i >= 1; i--) {
+         XArray*      vars;
+         Word         j;
+         DiAddrRange* arange;
+         OSet*        this_scope 
+            = *(OSet**)VG_(indexXA)( di_for_ip->varinfo, i );
+         if (!this_scope)
+            continue;
+         /* Find the set of variables in this scope that
+            bracket the program counter. */
+         arange = VG_(OSetGen_LookupWithCmp)(
+                     this_scope, &ip, 
+                     ML_(cmp_for_DiAddrRange_range)
+                  );
+         if (!arange)
+            continue;
+         vg_assert(arange->aMin <= ip && ip <= arange->aMax);
+         vars = arange->vars;
+         for (j = 0; j < VG_(sizeXA)( vars ); j++) {
+            DiVariable* var = (DiVariable*)VG_(indexXA)( vars, j );
+            SizeT       offset;
+            if (data_address_is_in_var( &offset, var, &regs, data_addr )) {
+               VG_(snprintf)(
+                  dname, (SizeT)n_dname,
+                  "Address 0x%lx is %lu bytes inside local var \"%s\"",
+                  data_addr, offset, var->name);
+               dname[n_dname-1] = 0;
+               return True;
+            }
+         }
+      }
+   }
+
+   /* We didn't find anything useful. */
+   return False;
+}
+
+
 /* Map a code address to the name of a shared object file or the
    executable.  Returns False if no idea; otherwise True.  Doesn't
    require debug info.  Caller supplies buf and nbuf. */
@@ -1322,7 +1520,7 @@
       n_steps++;
 
       /* Use the per-DebugInfo summary address ranges to skip
-        inapplicable DebugInfos quickly. */
+         inapplicable DebugInfos quickly. */
       if (si->cfsi_used == 0)
          continue;
       if (*ipP < si->cfsi_minaddr || *ipP > si->cfsi_maxaddr)

Modified: branches/DATASYMS/include/pub_tool_debuginfo.h
===================================================================
--- branches/DATASYMS/include/pub_tool_debuginfo.h      2008-02-07 11:58:22 UTC 
(rev 7375)
+++ branches/DATASYMS/include/pub_tool_debuginfo.h      2008-02-07 12:02:12 UTC 
(rev 7376)
@@ -74,17 +74,26 @@
    entry points within it. */
 extern Bool VG_(get_fnname_if_entry) ( Addr a, Char* fnname, Int n_fnname );
 
-/* Looks up 'a' in the collection of data symbols, and if found puts
-   its name (or as much as will fit) into dname[0 .. n_dname-1]
-   including zero terminator.  Also the 'a's offset from the symbol
-   start is put into *offset. */
-extern Bool VG_(get_dataname_and_offset)( Addr a,
-                                          /*OUT*/Char* dname, Int n_dname,
-                                          /*OUT*/OffT* offset );
+/* Looks up data_addr in the collection of data symbols, and if found
+   puts its name (or as much as will fit) into dname[0 .. n_dname-1],
+   which is guaranteed to be zero terminated.  Also data_addr's offset
+   from the symbol start is put into *offset. */
+extern Bool VG_(get_datasym_and_offset)( Addr data_addr,
+                                         /*OUT*/Char* dname, Int n_dname,
+                                         /*OUT*/OffT* offset );
 
+/* Try to form some description of data_addr by looking at the DWARF3
+   debug info we have.  This only looks at stack locations (for the
+   top frame of the thread from which ip/sp/fp are taken) and at
+   global variables.  Result (or as much as will fit) is put into into
+   dname[0 .. n_dname-1] and is guaranteed to be zero terminated. */
+extern Bool VG_(get_data_description)( Addr data_addr,
+                                       Addr ip, Addr sp, Addr fp,
+                                       /*OUT*/Char* dname, Int n_dname );
+
 /* Succeeds if the address is within a shared object or the main executable.
    It doesn't matter if debug info is present or not. */
-extern Bool VG_(get_objname)  ( Addr a, Char* objname,  Int n_objname );
+extern Bool VG_(get_objname)  ( Addr a, Char* objname, Int n_objname );
 
 /* Puts into 'buf' info about the code address %eip:  the address, function
    name (if known) and filename/line number (if known), like this:


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Valgrind-developers mailing list
Valgrind-developers@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/valgrind-developers

Reply via email to