Author: sewardj
Date: 2008-02-17 00:30:12 +0000 (Sun, 17 Feb 2008)
New Revision: 7416

Log:
More tidying up in Dwarf3 variable reading:

* m_debuginfo.c: more all variable-related stuff
  further down the file

* m_storage.c: deal properly with code address ranges for variables,
  in which the address ranges for which variables exist overlap.

  Also, add a new method canonicaliseVarInfo, which doesn't
  actually change the data structures, but does walk over them
  (when .debug_info reading is complete) to check representational
  invariants are being observed.



Modified:
   branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c
   branches/DATASYMS/coregrind/m_debuginfo/priv_d3basics.h
   branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h
   branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c
   branches/DATASYMS/coregrind/m_debuginfo/storage.c
   branches/DATASYMS/coregrind/m_debuginfo/tytypes.c


Modified: branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c 2008-02-17 00:25:49 UTC 
(rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c 2008-02-17 00:30:12 UTC 
(rev 7416)
@@ -194,6 +194,9 @@
 {
    Word i, j;
    struct strchunk *chunk, *next;
+   TyAdmin *admin1, *admin2;
+   GExpr *gexpr1, *gexpr2;
+
    vg_assert(di != NULL);
    if (di->filename)   ML_(dinfo_free)(di->filename);
    if (di->symtab)     ML_(dinfo_free)(di->symtab);
@@ -206,37 +209,43 @@
       ML_(dinfo_free)(chunk);
    }
 
-   { TyAdmin *admin1, *admin2;
-     GExpr *gexpr1, *gexpr2;
-     for (admin1 = di->tyadmins; admin1; admin1 = admin2) {
-        admin2 = admin1->next;
-        ML_(delete_TyAdmin_and_payload)(admin1);
-     }
-     for (gexpr1 = di->gexprs; gexpr1; gexpr1 = gexpr2) {
-        gexpr2 = gexpr1->next;
-        ML_(dinfo_free)(gexpr1);
-     }
+   /* Delete the two admin lists.  These lists exist purely so that we
+      can visit each object exactly once when we need to delete
+      them. */
+   for (admin1 = di->admin_tyadmins; admin1; admin1 = admin2) {
+      admin2 = admin1->next;
+      ML_(delete_TyAdmin_and_payload)(admin1);
    }
+   for (gexpr1 = di->admin_gexprs; gexpr1; gexpr1 = gexpr2) {
+      gexpr2 = gexpr1->next;
+      ML_(dinfo_free)(gexpr1);
+   }
 
+   /* Dump the variable info.  This is kinda complex: we must take
+      care not to free items which reside in either the admin lists
+      (as we have just freed them) or which reside in the DebugInfo's
+      string table. */
    if (di->varinfo) {
       for (i = 0; i < VG_(sizeXA)(di->varinfo); i++) {
          OSet* scope = *(OSet**)VG_(indexXA)(di->varinfo, i);
          if (!scope) continue;
-         // iterate over all entries in 'scope'
+         /* iterate over all entries in 'scope' */
          VG_(OSetGen_ResetIter)(scope);
          while (True) {
             DiAddrRange* arange = VG_(OSetGen_Next)(scope);
             if (!arange) break;
-            // for each var in 'arange'
+            /* for each var in 'arange' */
             vg_assert(arange->vars);
             for (j = 0; j < VG_(sizeXA)( arange->vars ); j++) {
                DiVariable* var = (DiVariable*)VG_(indexXA)(arange->vars,j);
                vg_assert(var);
                /* Nothing to free in var: all the pointer fields refer
-                  to stuff either on an admin list, or in .strchunks */
+                  to stuff either on an admin list, or in
+                  .strchunks */
             }
             VG_(deleteXA)(arange->vars);
-            /* Don't free arange itself, as OSetGen_Destroy does that */
+            /* Don't free arange itself, as OSetGen_Destroy does
+               that */
          }
          VG_(OSetGen_Destroy)(scope);
       }
@@ -999,454 +1008,6 @@
    return True;
 }
 
-/////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////
-/// begin Generate data description from DWARF3 debug info
-
-/* 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.  Note that
-   regs, which supplies ip,sp,fp values, will be NULL for global
-   variables, and non-NULL for local variables. */
-static Bool data_address_is_in_var ( /*OUT*/UWord* offset,
-                                     DiVariable*   var,
-                                     RegSummary*   regs,
-                                     Addr          data_addr )
-{
-   SizeT    var_szB;
-   GXResult res;
-   Bool     show = False;
-   vg_assert(var->name);
-   vg_assert(var->type);
-   vg_assert(var->gexpr);
-   var_szB = ML_(sizeOfType)(var->type);
-
-   if (show) {
-      VG_(printf)("VVVV: find loc: %s :: ", var->name );
-      ML_(pp_Type_C_ishly)( var->type );
-      VG_(printf)("\n");
-   }
-
-   res = ML_(evaluate_GX)( var->gexpr, var->fbGX, regs );
-
-   if (show) 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 = data_addr - res.res;
-      return True;
-   } else {
-      return False;
-   }
-}
-
-
-/* Format the acquired information into dname1[0 .. n_dname-1] and
-   dname2[0 .. n_dname-1] in an understandable way.  Not so easy.
-   If frameNo is -1, this is assumed to be a global variable; else
-   a local variable. */
-static void format_message ( /*OUT*/Char* dname1,
-                             /*OUT*/Char* dname2,
-                             Int      n_dname,
-                             Addr     data_addr,
-                             DiVariable* var,
-                             OffT     var_offset,
-                             OffT     residual_offset,
-                             XArray* /*UChar*/ described,
-                             Int      frameNo, 
-                             ThreadId tid )
-{
-   Bool have_descr, have_srcloc;
-   UChar* vo_plural = var_offset == 1 ? "" : "s";
-   UChar* ro_plural = residual_offset == 1 ? "" : "s";
-
-   vg_assert(frameNo >= -1);
-   vg_assert(dname1 && dname2 && n_dname > 1);
-   vg_assert(described);
-   vg_assert(var && var->name);
-   have_descr = VG_(sizeXA)(described) > 0
-                && *(UChar*)VG_(indexXA)(described,0) != '\0';
-   have_srcloc = var->fileName && var->lineNo > 0;
-
-   dname1[0] = dname2[0] = '\0';
-
-   /* ------ local cases ------ */
-
-   if ( frameNo >= 0 && (!have_srcloc) && (!have_descr) ) {
-      /* no srcloc, no description:
-         Address 0x7fefff6cf is 543 bytes inside local var "a",
-         in frame #1 of thread 1
-      */
-      VG_(snprintf)(
-         dname1, n_dname,
-         "Address 0x%lx is %lu byte%s inside local var \"%s\",",
-         data_addr, var_offset, vo_plural, var->name );
-      VG_(snprintf)(
-         dname2, n_dname,
-         "in frame #%d of thread %d", frameNo, (Int)tid);
-   } 
-   else
-   if ( frameNo >= 0 && have_srcloc && (!have_descr) ) {
-      /* no description:
-         Address 0x7fefff6cf is 543 bytes inside local var "a"
-         declared at dsyms7.c:17, in frame #1 of thread 1
-      */
-      VG_(snprintf)(
-         dname1, n_dname,
-         "Address 0x%lx is %lu byte%s inside local var \"%s\"",
-         data_addr, var_offset, vo_plural, var->name );
-      VG_(snprintf)(
-         dname2, n_dname,
-         "declared at %s:%d, in frame #%d of thread %d",
-         var->fileName, var->lineNo, frameNo, (Int)tid);
-   }
-   else
-   if ( frameNo >= 0 && (!have_srcloc) && have_descr ) {
-      /* no srcloc:
-         Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2
-         in frame #1 of thread 1
-      */
-      VG_(snprintf)(
-         dname1, n_dname,
-         "Address 0x%lx is %lu byte%s inside %s%s",
-         data_addr, residual_offset, ro_plural, var->name,
-         VG_(indexXA)(described,0) );
-      VG_(snprintf)(
-         dname2, n_dname,
-         "in frame #%d of thread %d", frameNo, (Int)tid);
-   } 
-   else
-   if ( frameNo >= 0 && have_srcloc && have_descr ) {
-     /* Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
-        declared at dsyms7.c:17, in frame #1 of thread 1 */
-      VG_(snprintf)(
-         dname1, n_dname,
-         "Address 0x%lx is %lu byte%s inside %s%s,",
-         data_addr, residual_offset, ro_plural, var->name,
-         VG_(indexXA)(described,0) );
-      VG_(snprintf)(
-         dname2, n_dname,
-         "declared at %s:%d, in frame #%d of thread %d",
-         var->fileName, var->lineNo, frameNo, (Int)tid);
-   }
-   else
-   /* ------ global cases ------ */
-   if ( frameNo >= -1 && (!have_srcloc) && (!have_descr) ) {
-      /* no srcloc, no description:
-         Address 0x7fefff6cf is 543 bytes inside global var "a"
-      */
-      VG_(snprintf)(
-         dname1, n_dname,
-         "Address 0x%lx is %lu byte%s inside global var \"%s\"",
-         data_addr, var_offset, vo_plural, var->name );
-   } 
-   else
-   if ( frameNo >= -1 && have_srcloc && (!have_descr) ) {
-      /* no description:
-         Address 0x7fefff6cf is 543 bytes inside global var "a"
-         declared at dsyms7.c:17
-      */
-      VG_(snprintf)(
-         dname1, n_dname,
-         "Address 0x%lx is %lu byte%s inside global var \"%s\"",
-         data_addr, var_offset, vo_plural, var->name );
-      VG_(snprintf)(
-         dname2, n_dname,
-         "declared at %s:%d",
-         var->fileName, var->lineNo);
-   }
-   else
-   if ( frameNo >= -1 && (!have_srcloc) && have_descr ) {
-      /* no srcloc:
-         Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
-         a global variable
-      */
-      VG_(snprintf)(
-         dname1, n_dname,
-         "Address 0x%lx is %lu byte%s inside %s%s,",
-         data_addr, residual_offset, ro_plural, var->name,
-         VG_(indexXA)(described,0) );
-      VG_(snprintf)(
-         dname2, n_dname,
-         "a global variable");
-   } 
-   else
-   if ( frameNo >= -1 && have_srcloc && have_descr ) {
-     /* Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
-        a global variable declared at dsyms7.c:17 */
-      VG_(snprintf)(
-         dname1, n_dname,
-         "Address 0x%lx is %lu byte%s inside %s%s,",
-         data_addr, residual_offset, ro_plural, var->name,
-         VG_(indexXA)(described,0) );
-      VG_(snprintf)(
-         dname2, n_dname,
-         "a global variable declared at %s:%d",
-         var->fileName, var->lineNo);
-   }
-   else 
-      vg_assert(0);
-
-   dname1[n_dname-1] = dname2[n_dname-1] = 0;
-}
-
-
-/* Determine if data_addr is a local variable in the frame
-   characterised by (ip,sp,fp), and if so write its description into
-   dname{1,2}[0..n_dname-1], and return True.  If not, return
-   False. */
-static 
-Bool consider_vars_in_frame ( /*OUT*/Char* dname1,
-                              /*OUT*/Char* dname2,
-                              Int n_dname,
-                              Addr data_addr,
-                              Addr ip, Addr sp, Addr fp,
-                              /* shown to user: */
-                              ThreadId tid, Int frameNo )
-{
-   Word       i;
-   DebugInfo* di;
-   RegSummary regs;
-
-   static UInt n_search = 0;
-   static UInt n_steps = 0;
-   n_search++;
-
-   /* first, find the DebugInfo that pertains to 'ip'. */
-   for (di = debugInfo_list; di; di = di->next) {
-      n_steps++;
-      /* 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)
-         break;
-   }
- 
-   /* Didn't find it.  Strange -- means ip is a code address outside
-      of any mapped text segment.  Unlikely but not impossible -- app
-      could be generating code to run. */
-   if (!di)
-      return False;
-
-   if (0 && ((n_search & 0x1) == 0))
-      VG_(printf)("consider_vars_in_frame: %u searches, "
-                  "%u DebugInfos looked at\n", 
-                  n_search, n_steps);
-   /* Start of performance-enhancing hack: once every ??? (chosen
-      hackily after profiling) successful searches, move the found
-      DebugInfo one step closer to the start of the list.  This makes
-      future searches cheaper. */
-   if ((n_search & 0xFFFF) == 0) {
-      /* Move si one step closer to the start of the list. */
-      move_DebugInfo_one_step_forward( di );
-   }
-   /* End of performance-enhancing hack. */
-
-   /* any var info at all? */
-   if (!di->varinfo)
-      return False;
-
-   /* 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. */
-   regs.ip = ip;
-   regs.sp = sp;
-   regs.fp = fp;
-
-   /* "for each scope, working outwards ..." */
-   for (i = VG_(sizeXA)(di->varinfo) - 1; i >= 1; i--) {
-      XArray*      vars;
-      Word         j;
-      DiAddrRange* arange;
-      OSet*        this_scope 
-         = *(OSet**)VG_(indexXA)( di->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;
-      /* stay sane */
-      vg_assert(arange->aMin <= arange->aMax);
-      /* It must bracket the ip we asked for, else
-         ML_(cmp_for_DiAddrRange_range) is somehow broken. */
-      vg_assert(arange->aMin <= ip && ip <= arange->aMax);
-      /* But it mustn't cover the entire address range.  We only
-         expect that to happen for the global scope (level 0), which
-         we're not looking at here. */
-      vg_assert(! (arange->aMin == (Addr)0
-                   && arange->aMax == ~(Addr)0) );
-      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 )) {
-            OffT residual_offset = 0;
-            XArray* described = ML_(describe_type)( &residual_offset,
-                                                    var->type, offset );
-            format_message( dname1, dname2, n_dname, 
-                            data_addr, var, offset, residual_offset,
-                            described, frameNo, tid );
-            VG_(deleteXA)( described );
-            return True;
-         }
-      }
-   }
-
-   return False;
-}
-
-/* Try to form some description of data_addr by looking at the DWARF3
-   debug info we have.  This considers all global variables, and all
-   frames in the stacks of all threads.  Result (or as much as will
-   fit) is put into into dname{1,2}[0 .. n_dname-1] and is guaranteed
-   to be zero terminated. */
-Bool VG_(get_data_description)( /*OUT*/Char* dname1,
-                                /*OUT*/Char* dname2,
-                                Int  n_dname,
-                                Addr data_addr )
-{
-#  define N_FRAMES 8
-   Addr ips[N_FRAMES], sps[N_FRAMES], fps[N_FRAMES];
-   UInt n_frames;
-
-   Addr       stack_min, stack_max;
-   ThreadId   tid;
-   Bool       found;
-   DebugInfo* di;
-   Word       j;
-
-   vg_assert(n_dname > 1);
-   dname1[n_dname-1] = dname2[n_dname-1] = 0;
-
-   if (0) VG_(printf)("GDD: dataaddr %p\n", data_addr);
-
-   /* First, see if data_addr is (or is part of) a global variable.
-      Loop over the DebugInfos we have.  Check data_addr against the
-      outermost scope of all of them, as that should be a global
-      scope. */
-   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;
-      /* 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
-                && 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);
-         /* Note we use a NULL RegSummary* here.  It can't make any
-            sense for a global variable to have a location expression
-            which depends on a SP/FP/IP value.  So don't supply any.
-            This means, if the evaluation of the location
-            expression/list requires a register, we have to let it
-            fail. */
-         if (data_address_is_in_var( &offset, var, 
-                                     NULL/* RegSummary* */, 
-                                     data_addr )) {
-            OffT residual_offset = 0;
-            XArray* described = ML_(describe_type)( &residual_offset,
-                                                    var->type, offset );
-            format_message( dname1, dname2, n_dname, 
-                            data_addr, var, offset, residual_offset,
-                            described, -1/*frameNo*/, tid );
-            VG_(deleteXA)( described );
-            dname1[n_dname-1] = dname2[n_dname-1] = 0;
-            return True;
-         }
-      }
-   }
-
-   /* Ok, well it's not a global variable.  So now let's snoop around
-      in the stacks of all the threads.  First try to figure out which
-      thread's stack data_addr is in. */
-
-   /* Perhaps it's on a thread's stack? */
-   found = False;
-   VG_(thread_stack_reset_iter)(&tid);
-   while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
-      if (stack_min >= stack_max)
-         continue; /* ignore obviously stupid cases */
-      if (stack_min - VG_STACK_REDZONE_SZB <= data_addr
-          && data_addr <= stack_max) {
-         found = True;
-         break;
-      }
-   }
-   if (!found) {
-      dname1[n_dname-1] = dname2[n_dname-1] = 0;
-      return False;
-   }
-
-   /* We conclude data_addr is in thread tid's stack.  Unwind the
-      stack to get a bunch of (ip,sp,fp) triples describing the
-      frames, and for each frame, consider the local variables. */
-
-   n_frames = VG_(get_StackTrace)( tid, ips, N_FRAMES,
-                                   sps, fps, 0/*first_ip_delta*/ );
-   vg_assert(n_frames >= 0 && n_frames <= N_FRAMES);
-   for (j = 0; j < n_frames; j++) {
-      if (consider_vars_in_frame( dname1, dname2, n_dname,
-                                  data_addr,
-                                  ips[j], sps[j], fps[j], tid, j )) {
-         dname1[n_dname-1] = dname2[n_dname-1] = 0;
-         return True;
-      }
-   }
-
-   /* We didn't find anything useful. */
-   dname1[n_dname-1] = dname2[n_dname-1] = 0;
-   return False;
-#  undef N_FRAMES
-}
-
-/// end Generate data description from DWARF3 debug info
-/////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////
-
 /* 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. */
@@ -1773,10 +1334,12 @@
 }
 
 
-/*------------------------------------------------------------*/
-/*--- For unwinding the stack using                       --- */
-/*--- pre-summarised DWARF3 .eh_frame info                 ---*/
-/*------------------------------------------------------------*/
+/*--------------------------------------------------------------*/
+/*---                                                        ---*/
+/*--- TOP LEVEL: FOR UNWINDING THE STACK USING               ---*/
+/*---            DWARF3 .eh_frame INFO                       ---*/
+/*---                                                        ---*/
+/*--------------------------------------------------------------*/
 
 /* Gather up all the constant pieces of info needed to evaluate
    a CfiExpr into one convenient struct. */
@@ -2002,6 +1565,459 @@
 }
 
 
+/*--------------------------------------------------------------*/
+/*---                                                        ---*/
+/*--- TOP LEVEL: GENERATE DESCRIPTION OF DATA ADDRESSES      ---*/
+/*---            FROM DWARF3 DEBUG INFO                      ---*/
+/*---                                                        ---*/
+/*--------------------------------------------------------------*/
+
+/* 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.  Note that
+   regs, which supplies ip,sp,fp values, will be NULL for global
+   variables, and non-NULL for local variables. */
+static Bool data_address_is_in_var ( /*OUT*/UWord* offset,
+                                     DiVariable*   var,
+                                     RegSummary*   regs,
+                                     Addr          data_addr )
+{
+   SizeT    var_szB;
+   GXResult res;
+   Bool     show = False;
+   vg_assert(var->name);
+   vg_assert(var->type);
+   vg_assert(var->gexpr);
+   var_szB = ML_(sizeOfType)(var->type);
+
+   if (show) {
+      VG_(printf)("VVVV: find loc: %s :: ", var->name );
+      ML_(pp_Type_C_ishly)( var->type );
+      VG_(printf)("\n");
+   }
+
+   res = ML_(evaluate_GX)( var->gexpr, var->fbGX, regs );
+
+   if (show) 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 = data_addr - res.res;
+      return True;
+   } else {
+      return False;
+   }
+}
+
+
+/* Format the acquired information into dname1[0 .. n_dname-1] and
+   dname2[0 .. n_dname-1] in an understandable way.  Not so easy.
+   If frameNo is -1, this is assumed to be a global variable; else
+   a local variable. */
+static void format_message ( /*OUT*/Char* dname1,
+                             /*OUT*/Char* dname2,
+                             Int      n_dname,
+                             Addr     data_addr,
+                             DiVariable* var,
+                             OffT     var_offset,
+                             OffT     residual_offset,
+                             XArray* /*UChar*/ described,
+                             Int      frameNo, 
+                             ThreadId tid )
+{
+   Bool have_descr, have_srcloc;
+   UChar* vo_plural = var_offset == 1 ? "" : "s";
+   UChar* ro_plural = residual_offset == 1 ? "" : "s";
+
+   vg_assert(frameNo >= -1);
+   vg_assert(dname1 && dname2 && n_dname > 1);
+   vg_assert(described);
+   vg_assert(var && var->name);
+   have_descr = VG_(sizeXA)(described) > 0
+                && *(UChar*)VG_(indexXA)(described,0) != '\0';
+   have_srcloc = var->fileName && var->lineNo > 0;
+
+   dname1[0] = dname2[0] = '\0';
+
+   /* ------ local cases ------ */
+
+   if ( frameNo >= 0 && (!have_srcloc) && (!have_descr) ) {
+      /* no srcloc, no description:
+         Address 0x7fefff6cf is 543 bytes inside local var "a",
+         in frame #1 of thread 1
+      */
+      VG_(snprintf)(
+         dname1, n_dname,
+         "Address 0x%lx is %lu byte%s inside local var \"%s\",",
+         data_addr, var_offset, vo_plural, var->name );
+      VG_(snprintf)(
+         dname2, n_dname,
+         "in frame #%d of thread %d", frameNo, (Int)tid);
+   } 
+   else
+   if ( frameNo >= 0 && have_srcloc && (!have_descr) ) {
+      /* no description:
+         Address 0x7fefff6cf is 543 bytes inside local var "a"
+         declared at dsyms7.c:17, in frame #1 of thread 1
+      */
+      VG_(snprintf)(
+         dname1, n_dname,
+         "Address 0x%lx is %lu byte%s inside local var \"%s\"",
+         data_addr, var_offset, vo_plural, var->name );
+      VG_(snprintf)(
+         dname2, n_dname,
+         "declared at %s:%d, in frame #%d of thread %d",
+         var->fileName, var->lineNo, frameNo, (Int)tid);
+   }
+   else
+   if ( frameNo >= 0 && (!have_srcloc) && have_descr ) {
+      /* no srcloc:
+         Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2
+         in frame #1 of thread 1
+      */
+      VG_(snprintf)(
+         dname1, n_dname,
+         "Address 0x%lx is %lu byte%s inside %s%s",
+         data_addr, residual_offset, ro_plural, var->name,
+         VG_(indexXA)(described,0) );
+      VG_(snprintf)(
+         dname2, n_dname,
+         "in frame #%d of thread %d", frameNo, (Int)tid);
+   } 
+   else
+   if ( frameNo >= 0 && have_srcloc && have_descr ) {
+     /* Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
+        declared at dsyms7.c:17, in frame #1 of thread 1 */
+      VG_(snprintf)(
+         dname1, n_dname,
+         "Address 0x%lx is %lu byte%s inside %s%s,",
+         data_addr, residual_offset, ro_plural, var->name,
+         VG_(indexXA)(described,0) );
+      VG_(snprintf)(
+         dname2, n_dname,
+         "declared at %s:%d, in frame #%d of thread %d",
+         var->fileName, var->lineNo, frameNo, (Int)tid);
+   }
+   else
+   /* ------ global cases ------ */
+   if ( frameNo >= -1 && (!have_srcloc) && (!have_descr) ) {
+      /* no srcloc, no description:
+         Address 0x7fefff6cf is 543 bytes inside global var "a"
+      */
+      VG_(snprintf)(
+         dname1, n_dname,
+         "Address 0x%lx is %lu byte%s inside global var \"%s\"",
+         data_addr, var_offset, vo_plural, var->name );
+   } 
+   else
+   if ( frameNo >= -1 && have_srcloc && (!have_descr) ) {
+      /* no description:
+         Address 0x7fefff6cf is 543 bytes inside global var "a"
+         declared at dsyms7.c:17
+      */
+      VG_(snprintf)(
+         dname1, n_dname,
+         "Address 0x%lx is %lu byte%s inside global var \"%s\"",
+         data_addr, var_offset, vo_plural, var->name );
+      VG_(snprintf)(
+         dname2, n_dname,
+         "declared at %s:%d",
+         var->fileName, var->lineNo);
+   }
+   else
+   if ( frameNo >= -1 && (!have_srcloc) && have_descr ) {
+      /* no srcloc:
+         Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
+         a global variable
+      */
+      VG_(snprintf)(
+         dname1, n_dname,
+         "Address 0x%lx is %lu byte%s inside %s%s,",
+         data_addr, residual_offset, ro_plural, var->name,
+         VG_(indexXA)(described,0) );
+      VG_(snprintf)(
+         dname2, n_dname,
+         "a global variable");
+   } 
+   else
+   if ( frameNo >= -1 && have_srcloc && have_descr ) {
+     /* Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
+        a global variable declared at dsyms7.c:17 */
+      VG_(snprintf)(
+         dname1, n_dname,
+         "Address 0x%lx is %lu byte%s inside %s%s,",
+         data_addr, residual_offset, ro_plural, var->name,
+         VG_(indexXA)(described,0) );
+      VG_(snprintf)(
+         dname2, n_dname,
+         "a global variable declared at %s:%d",
+         var->fileName, var->lineNo);
+   }
+   else 
+      vg_assert(0);
+
+   dname1[n_dname-1] = dname2[n_dname-1] = 0;
+}
+
+
+/* Determine if data_addr is a local variable in the frame
+   characterised by (ip,sp,fp), and if so write its description into
+   dname{1,2}[0..n_dname-1], and return True.  If not, return
+   False. */
+static 
+Bool consider_vars_in_frame ( /*OUT*/Char* dname1,
+                              /*OUT*/Char* dname2,
+                              Int n_dname,
+                              Addr data_addr,
+                              Addr ip, Addr sp, Addr fp,
+                              /* shown to user: */
+                              ThreadId tid, Int frameNo )
+{
+   Word       i;
+   DebugInfo* di;
+   RegSummary regs;
+
+   static UInt n_search = 0;
+   static UInt n_steps = 0;
+   n_search++;
+
+   /* first, find the DebugInfo that pertains to 'ip'. */
+   for (di = debugInfo_list; di; di = di->next) {
+      n_steps++;
+      /* 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)
+         break;
+   }
+ 
+   /* Didn't find it.  Strange -- means ip is a code address outside
+      of any mapped text segment.  Unlikely but not impossible -- app
+      could be generating code to run. */
+   if (!di)
+      return False;
+
+   if (0 && ((n_search & 0x1) == 0))
+      VG_(printf)("consider_vars_in_frame: %u searches, "
+                  "%u DebugInfos looked at\n", 
+                  n_search, n_steps);
+   /* Start of performance-enhancing hack: once every ??? (chosen
+      hackily after profiling) successful searches, move the found
+      DebugInfo one step closer to the start of the list.  This makes
+      future searches cheaper. */
+   if ((n_search & 0xFFFF) == 0) {
+      /* Move si one step closer to the start of the list. */
+      move_DebugInfo_one_step_forward( di );
+   }
+   /* End of performance-enhancing hack. */
+
+   /* any var info at all? */
+   if (!di->varinfo)
+      return False;
+
+   /* 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. */
+   regs.ip = ip;
+   regs.sp = sp;
+   regs.fp = fp;
+
+   /* "for each scope, working outwards ..." */
+   for (i = VG_(sizeXA)(di->varinfo) - 1; i >= 1; i--) {
+      XArray*      vars;
+      Word         j;
+      DiAddrRange* arange;
+      OSet*        this_scope 
+         = *(OSet**)VG_(indexXA)( di->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;
+      /* stay sane */
+      vg_assert(arange->aMin <= arange->aMax);
+      /* It must bracket the ip we asked for, else
+         ML_(cmp_for_DiAddrRange_range) is somehow broken. */
+      vg_assert(arange->aMin <= ip && ip <= arange->aMax);
+      /* It must have an attached XArray of DiVariables. */
+      vars = arange->vars;
+      vg_assert(vars);
+      /* But it mustn't cover the entire address range.  We only
+         expect that to happen for the global scope (level 0), which
+         we're not looking at here.  Except, it may cover the entire
+         address range, but in that case the vars array must be
+         empty. */
+      vg_assert(! (arange->aMin == (Addr)0
+                   && arange->aMax == ~(Addr)0
+                   && VG_(sizeXA)(vars) > 0) );
+      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 )) {
+            OffT residual_offset = 0;
+            XArray* described = ML_(describe_type)( &residual_offset,
+                                                    var->type, offset );
+            format_message( dname1, dname2, n_dname, 
+                            data_addr, var, offset, residual_offset,
+                            described, frameNo, tid );
+            VG_(deleteXA)( described );
+            return True;
+         }
+      }
+   }
+
+   return False;
+}
+
+/* Try to form some description of data_addr by looking at the DWARF3
+   debug info we have.  This considers all global variables, and all
+   frames in the stacks of all threads.  Result (or as much as will
+   fit) is put into into dname{1,2}[0 .. n_dname-1] and is guaranteed
+   to be zero terminated. */
+Bool VG_(get_data_description)( /*OUT*/Char* dname1,
+                                /*OUT*/Char* dname2,
+                                Int  n_dname,
+                                Addr data_addr )
+{
+#  define N_FRAMES 8
+   Addr ips[N_FRAMES], sps[N_FRAMES], fps[N_FRAMES];
+   UInt n_frames;
+
+   Addr       stack_min, stack_max;
+   ThreadId   tid;
+   Bool       found;
+   DebugInfo* di;
+   Word       j;
+
+   vg_assert(n_dname > 1);
+   dname1[n_dname-1] = dname2[n_dname-1] = 0;
+
+   if (0) VG_(printf)("GDD: dataaddr %p\n", data_addr);
+
+   /* First, see if data_addr is (or is part of) a global variable.
+      Loop over the DebugInfos we have.  Check data_addr against the
+      outermost scope of all of them, as that should be a global
+      scope. */
+   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;
+      /* 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
+                && 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);
+         /* Note we use a NULL RegSummary* here.  It can't make any
+            sense for a global variable to have a location expression
+            which depends on a SP/FP/IP value.  So don't supply any.
+            This means, if the evaluation of the location
+            expression/list requires a register, we have to let it
+            fail. */
+         if (data_address_is_in_var( &offset, var, 
+                                     NULL/* RegSummary* */, 
+                                     data_addr )) {
+            OffT residual_offset = 0;
+            XArray* described = ML_(describe_type)( &residual_offset,
+                                                    var->type, offset );
+            format_message( dname1, dname2, n_dname, 
+                            data_addr, var, offset, residual_offset,
+                            described, -1/*frameNo*/, tid );
+            VG_(deleteXA)( described );
+            dname1[n_dname-1] = dname2[n_dname-1] = 0;
+            return True;
+         }
+      }
+   }
+
+   /* Ok, well it's not a global variable.  So now let's snoop around
+      in the stacks of all the threads.  First try to figure out which
+      thread's stack data_addr is in. */
+
+   /* Perhaps it's on a thread's stack? */
+   found = False;
+   VG_(thread_stack_reset_iter)(&tid);
+   while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
+      if (stack_min >= stack_max)
+         continue; /* ignore obviously stupid cases */
+      if (stack_min - VG_STACK_REDZONE_SZB <= data_addr
+          && data_addr <= stack_max) {
+         found = True;
+         break;
+      }
+   }
+   if (!found) {
+      dname1[n_dname-1] = dname2[n_dname-1] = 0;
+      return False;
+   }
+
+   /* We conclude data_addr is in thread tid's stack.  Unwind the
+      stack to get a bunch of (ip,sp,fp) triples describing the
+      frames, and for each frame, consider the local variables. */
+
+   n_frames = VG_(get_StackTrace)( tid, ips, N_FRAMES,
+                                   sps, fps, 0/*first_ip_delta*/ );
+   vg_assert(n_frames >= 0 && n_frames <= N_FRAMES);
+   for (j = 0; j < n_frames; j++) {
+      if (consider_vars_in_frame( dname1, dname2, n_dname,
+                                  data_addr,
+                                  ips[j], sps[j], fps[j], tid, j )) {
+         dname1[n_dname-1] = dname2[n_dname-1] = 0;
+         return True;
+      }
+   }
+
+   /* We didn't find anything useful. */
+   dname1[n_dname-1] = dname2[n_dname-1] = 0;
+   return False;
+#  undef N_FRAMES
+}
+
+
 /*------------------------------------------------------------*/
 /*--- DebugInfo accessor functions                         ---*/
 /*------------------------------------------------------------*/

Modified: branches/DATASYMS/coregrind/m_debuginfo/priv_d3basics.h
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/priv_d3basics.h     2008-02-17 
00:25:49 UTC (rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/priv_d3basics.h     2008-02-17 
00:30:12 UTC (rev 7416)
@@ -587,7 +587,7 @@
 
 /* Evaluation of a DWARF3 expression (and hence of a GExpr) may
    require knowing a suitably contextualising set of values for the
-   instruction, frame and stack pointer (and, in general, all
+   instruction, frame and stack pointers (and, in general, all
    registers, though we punt on such generality here).  Here's a
    struct to carry the bare essentials. */
 typedef
@@ -603,10 +603,10 @@
    GXResult;
 
 /* Evaluate a guarded expression.  If regs is NULL, then gx is assumed
-   (and checked) to contain just a single guarded expression, which a
+   (and checked) to contain just a single guarded expression, with a
    guard which covers the entire address space and so always evaluates
    to True (iow, gx is a single unconditional expression).  If regs is
-   non-NULL then its 'ip' value is used to select which of the
+   non-NULL then its .ip value is used to select which of the
    embedded DWARF3 location expressions to use, and that is duly
    evaluated.
 

Modified: branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h      2008-02-17 
00:25:49 UTC (rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h      2008-02-17 
00:30:12 UTC (rev 7416)
@@ -385,9 +385,16 @@
    */
    XArray* /* of OSet of DiAddrRange */varinfo;
 
-   /* For the purposes of deletion: */
-   TyAdmin* tyadmins;
-   GExpr*   gexprs;
+   /* These are lists of the relevant typed objects, held here
+      expressly for the purposes of visiting each object exactly once
+      when we need to delete them. */
+
+   /* A list of TyAdmin structs, and the payloads that they refer
+      to. */
+   TyAdmin* admin_tyadmins;
+
+   /* A list of guarded DWARF3 expressions. */
+   GExpr*   admin_gexprs;
 };
 
 /* --------------------- functions --------------------- */

Modified: branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c        2008-02-17 
00:25:49 UTC (rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c        2008-02-17 
00:30:12 UTC (rev 7416)
@@ -2974,10 +2974,10 @@
 
    /* record the TyAdmins and the GExprs in di so they can be freed
       later */
-   vg_assert(!di->tyadmins);
-   di->tyadmins = admin;
-   vg_assert(!di->gexprs);
-   di->gexprs = gexprs;
+   vg_assert(!di->admin_tyadmins);
+   di->admin_tyadmins = admin;
+   vg_assert(!di->admin_gexprs);
+   di->admin_gexprs = gexprs;
 }
 
 

Modified: branches/DATASYMS/coregrind/m_debuginfo/storage.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/storage.c   2008-02-17 00:25:49 UTC 
(rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/storage.c   2008-02-17 00:30:12 UTC 
(rev 7416)
@@ -522,67 +522,168 @@
 }
 
 
-static Word cmp_for_DiAddrRange ( const void* keyV, const void* elemV ) {
+Word ML_(cmp_for_DiAddrRange_range) ( const void* keyV,
+                                      const void* elemV ) {
    const Addr* key = (const Addr*)keyV;
    const DiAddrRange* elem = (const DiAddrRange*)elemV;
    if (0)
-      VG_(printf)("cmp_for_DiAddrRange: %p vs %p\n", *key, elem->aMin);
+      VG_(printf)("cmp_for_DiAddrRange_range: %p vs %p\n",
+                  *key, elem->aMin);
    if ((*key) < elem->aMin) return -1;
-   if ((*key) > elem->aMin) return 1;
-   return 0;
-}
-Word ML_(cmp_for_DiAddrRange_range) ( const void* keyV, const void* elemV ) {
-   const Addr* key = (const Addr*)keyV;
-   const DiAddrRange* elem = (const DiAddrRange*)elemV;
-   if (0)
-      VG_(printf)("cmp_for_DiAddrRange_range: %p vs %p\n", *key, elem->aMin);
-   if ((*key) < elem->aMin) return -1;
    if ((*key) > elem->aMax) return 1;
    return 0;
 }
 
+static
+void show_scope ( OSet* /* of DiAddrRange */ scope, HChar* who )
+{
+   DiAddrRange* range;
+   VG_(printf)("Scope \"%s\" = {\n", who);
+   VG_(OSetGen_ResetIter)( scope );
+   while (True) {
+      range = VG_(OSetGen_Next)( scope );
+      if (!range) break;
+      VG_(printf)("   %p .. %p: %lu vars\n", range->aMin, range->aMax,
+                  range->vars ? VG_(sizeXA)(range->vars) : 0);
+   }
+   VG_(printf)("}\n");
+}
+
 /* 'inner' is an XArray of DiAddrRange.  Find the entry corresponding
     to [aMin,aMax].  If that doesn't exist, create one.  Take care to
-    preserve the invariant that none of the address ranges overlap.
-    That's unlikely to be the case unless the DWARF3 from which these
-    calls results contains bogus range info; however in the interests
-    of robustness, do handle the case. */
-static DiAddrRange* find_or_create_arange ( 
-                       OSet* /* of DiAddrRange */ inner,
-                       Addr aMin, 
-                       Addr aMax
-                    )
+    preserve the invariant that none of the address ranges have the
+    same starting value (aMin).  That's unlikely to be the case unless
+    the DWARF3 from which these calls results contains bogus range
+    info; however in the interests of robustness, do handle the
+    case. */
+static void add_var_to_arange ( 
+               /*MOD*/OSet* /* of DiAddrRange */ scope,
+               Addr aMin, 
+               Addr aMax,
+               DiVariable* var
+            )
 {
-   DiAddrRange* old = VG_(OSetGen_Lookup)( inner, &aMin );
-   if (!old) {
-      DiAddrRange tmp;
-      tmp.aMin = aMin;
-      tmp.aMax = aMax;
-      tmp.vars = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free),
-                             sizeof(DiVariable) );
-      old = VG_(OSetGen_AllocNode)( inner, sizeof(DiAddrRange) );
-      vg_assert(old);
-      *old = tmp;
-      VG_(OSetGen_Insert)( inner, old );
+   DiAddrRange *first, *last;
+   DiAddrRange *range, *rangep;
+   vg_assert(aMin <= aMax);
+
+   if (0) VG_(printf)("add_var_to_arange: %p .. %p\n", aMin, aMax);
+   if (0) show_scope( scope, "add_var_to_arange(1)" );
+
+   /* See if the lower end of the range (aMin) falls exactly on an
+      existing range boundary.  If not, find the range it does fall
+      into, and split it (copying the variables in the process), so
+      that aMin does exactly fall on a range boundary. */
+   first = VG_(OSetGen_Lookup)( scope, &aMin );
+   /* It must be present, since the presented OSet must cover
+      the entire address range. */
+   vg_assert(first);
+   vg_assert(first->aMin <= first->aMax);
+   vg_assert(first->aMin <= aMin && aMin <= first->aMax);
+
+   if (first->aMin < aMin) {
+      DiAddrRange* nyu;
+      /* Ok.  We'll have to split 'first'. */
+      /* truncate the upper end of 'first' */
+      Addr tmp = first->aMax;
+      first->aMax = aMin-1;
+      vg_assert(first->aMin <= first->aMax);
+      /* create a new range */
+      nyu = VG_(OSetGen_AllocNode)( scope, sizeof(DiAddrRange) );
+      vg_assert(nyu);
+      nyu->aMin = aMin;
+      nyu->aMax = tmp;
+      vg_assert(nyu->aMin <= nyu->aMax);
+      /* copy vars into it */
+      vg_assert(first->vars);
+      nyu->vars = VG_(cloneXA)( first->vars );
+      vg_assert(nyu->vars);
+      VG_(OSetGen_Insert)( scope, nyu );
+      first = nyu;
    }
-   return old;
+
+   vg_assert(first->aMin == aMin);
+
+   /* Now do exactly the same for the upper end (aMax): if it doesn't
+      fall on a boundary, cause it to do so by splitting the range it
+      does currently fall into. */
+   last = VG_(OSetGen_Lookup)( scope, &aMax );
+   vg_assert(last->aMin <= last->aMax);
+   vg_assert(last->aMin <= aMax && aMax <= last->aMax);
+
+   if (aMax < last->aMax) {
+      DiAddrRange* nyu;
+      /* We have to split 'last'. */
+      /* truncate the lower end of 'last' */
+      Addr tmp = last->aMin;
+      last->aMin = aMax+1;
+      vg_assert(last->aMin <= last->aMax);
+      /* create a new range */
+      nyu = VG_(OSetGen_AllocNode)( scope, sizeof(DiAddrRange) );
+      vg_assert(nyu);
+      nyu->aMin = tmp;
+      nyu->aMax = aMax;
+      vg_assert(nyu->aMin <= nyu->aMax);
+      /* copy vars into it */
+      vg_assert(last->vars);
+      nyu->vars = VG_(cloneXA)( last->vars );
+      vg_assert(nyu->vars);
+      VG_(OSetGen_Insert)( scope, nyu );
+      last = nyu;
+   }
+
+   vg_assert(aMax == last->aMax);
+
+   /* Great.  Now we merely need to iterate over the segments from
+      'first' to 'last' inclusive, and add 'var' to the variable set
+      of each of them. */
+   if (0) show_scope( scope, "add_var_to_arange(2)" );
+
+   range = rangep = NULL;
+   VG_(OSetGen_ResetIterAt)( scope, &aMin );
+   while (True) {
+      range = VG_(OSetGen_Next)( scope );
+      if (!range) break;
+      if (range->aMin >= aMax) break;
+      if (0) VG_(printf)("have range %p %p\n", 
+                         range->aMin, range->aMax);
+
+      /* Sanity checks */
+      if (!rangep) {
+         /* This is the first in the range */
+         vg_assert(range->aMin == aMin);
+      } else {
+         vg_assert(rangep->aMax + 1 == range->aMin);
+      }
+
+      vg_assert(range->vars);
+      VG_(addToXA)( range->vars, var );
+
+      rangep = range;
+   }
+   /* Done.  We should have seen at least one range. */
+   vg_assert(rangep);
+   vg_assert(rangep->aMax == aMax);
 }
 
+/* Top-level place to call to add a variable description (as extracted
+   from a DWARF3 .debug_info section. */
 void ML_(addVar)( struct _DebugInfo* di,
                   Int    level,
                   Addr   aMin,
                   Addr   aMax,
-                  UChar* name,
+                  UChar* name, /* in di's .strchunks */
                   Type*  type,
                   GExpr* gexpr,
                   GExpr* fbGX,
-                  UChar* fileName, /* where decl'd - may be NULL */
+                  UChar* fileName, /* where decl'd - may be NULL.
+                                      in di's .strchunks */
                   Int    lineNo, /* where decl'd - may be zero */
                   Bool   show )
 {
-   OSet* /* of DiAddrRange */ inner;
-   DiAddrRange* range;
-   DiVariable   var;
+   OSet* /* of DiAddrRange */ scope;
+   DiVariable var;
+   Bool       all;
 
    if (0) {
       VG_(printf)("  ML_(addVar): level %d  %p-%p  %s :: ",
@@ -615,35 +716,120 @@
    vg_assert(level < 256); /* arbitrary; stay sane */
    /* Expand the top level array enough to map this level */
    while ( VG_(sizeXA)(di->varinfo) <= level ) {
-      inner = VG_(OSetGen_Create)( offsetof(DiAddrRange,aMin), 
-                                   cmp_for_DiAddrRange,
+      DiAddrRange* nyu;
+      scope = VG_(OSetGen_Create)( offsetof(DiAddrRange,aMin), 
+                                   ML_(cmp_for_DiAddrRange_range),
                                    ML_(dinfo_zalloc), ML_(dinfo_free) );
-      if (0) VG_(printf)("create: inner = %p, adding at %ld\n",
-                         inner, VG_(sizeXA)(di->varinfo));
-      VG_(addToXA)( di->varinfo, &inner );
+      vg_assert(scope);
+      if (0) VG_(printf)("create: scope = %p, adding at %ld\n",
+                         scope, VG_(sizeXA)(di->varinfo));
+      VG_(addToXA)( di->varinfo, &scope );
+      /* Add a single range covering the entire address space.  At
+         level 0 we require this doesn't get split.  At levels above 0
+         we require that any additions to it cause it to get split. */
+      nyu = VG_(OSetGen_AllocNode)( scope, sizeof(DiAddrRange) );
+      vg_assert(nyu);
+      nyu->aMin = (Addr)0;
+      nyu->aMax = ~(Addr)0;
+      nyu->vars = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free),
+                              sizeof(DiVariable) );
+      vg_assert(nyu->vars);
+      VG_(OSetGen_Insert)( scope, nyu );
    }
 
    vg_assert( VG_(sizeXA)(di->varinfo) > level );
-   inner = *(OSet**)VG_(indexXA)( di->varinfo, level );
-   vg_assert(inner);
+   scope = *(OSet**)VG_(indexXA)( di->varinfo, level );
+   vg_assert(scope);
 
-   /* Now we need to find the relevant DiAddrRange within 'inner',
-      or create one if not present. */
-   /* DiAddrRange* */ range = find_or_create_arange( inner, aMin, aMax );
-   /* DiVariable var; */
    var.name     = name;
    var.type     = type;
    var.gexpr    = gexpr;
    var.fbGX     = fbGX;
    var.fileName = fileName;
    var.lineNo   = lineNo;
-   vg_assert(range);
-   vg_assert(range->vars);
-   vg_assert(range->aMin == aMin);
-   VG_(addToXA)( range->vars, &var );
+
+   all = aMin == (Addr)0 && aMax == ~(Addr)0;
+   vg_assert(level == 0 ? all : !all);
+
+   add_var_to_arange( /*MOD*/scope, aMin, aMax, &var );
 }
 
 
+/* This really just checks the constructed data structure, as there is
+   no canonicalisation to do. */
+static void canonicaliseVarInfo ( struct _DebugInfo* di )
+{
+   Word i, nInThisScope;
+
+   if (!di->varinfo)
+      return;
+
+   for (i = 0; i < VG_(sizeXA)(di->varinfo); i++) {
+
+      DiAddrRange *range, *rangep;
+      OSet* scope = *(OSet**)VG_(indexXA)(di->varinfo, i);
+      if (!scope) continue;
+
+      /* Deal with the global-scope case. */
+      if (i == 0) {
+         Addr zero = 0;
+         vg_assert(VG_(OSetGen_Size)( scope ) == 1);
+         range = VG_(OSetGen_Lookup)( scope, &zero );
+         vg_assert(range);
+         vg_assert(range->aMin == (Addr)0);
+         vg_assert(range->aMax == ~(Addr)0);
+         continue;
+      }
+
+      /* All the rest of this is for the local-scope case. */
+      /* iterate over all entries in 'scope' */
+      nInThisScope = 0;
+      range = rangep = NULL;
+      VG_(OSetGen_ResetIter)(scope);
+      while (True) {
+         range = VG_(OSetGen_Next)(scope);
+         if (!range) {
+           /* We just saw the last one.  There must have been at
+              least one entry in the range. */
+           vg_assert(rangep);
+           vg_assert(rangep->aMax == ~(Addr)0);
+           break;
+         }
+
+         vg_assert(range->aMin <= range->aMax);
+         vg_assert(range->vars);
+
+         if (!rangep) {
+           /* This is the first entry in the range. */
+           vg_assert(range->aMin == 0);
+         } else {
+           vg_assert(rangep->aMax + 1 == range->aMin);
+         }
+
+         rangep = range;
+         nInThisScope++;
+      } /* iterating over ranges in a given scope */
+
+      /* If there's only one entry in this (local) scope, it must
+         cover the entire address space (obviously), but it must not
+         contain any vars. */
+
+      vg_assert(nInThisScope > 0);
+      if (nInThisScope == 1) {
+         Addr zero = 0;
+         vg_assert(VG_(OSetGen_Size)( scope ) == 1);
+         range = VG_(OSetGen_Lookup)( scope, &zero );
+         vg_assert(range);
+         vg_assert(range->aMin == (Addr)0);
+         vg_assert(range->aMax == ~(Addr)0);
+         vg_assert(range->vars);
+         vg_assert(VG_(sizeXA)(range->vars) == 0);
+      }
+
+   } /* iterate over scopes */
+}
+
+
 /*------------------------------------------------------------*/
 /*--- Canonicalisers                                       ---*/
 /*------------------------------------------------------------*/
@@ -1060,13 +1246,14 @@
 }
 
 
-/* Canonicalise the tables held by 'si', in preparation for use.  Call
+/* Canonicalise the tables held by 'di', in preparation for use.  Call
    this after finishing adding entries to these tables. */
 void ML_(canonicaliseTables) ( struct _DebugInfo* di )
 {
    canonicaliseSymtab ( di );
    canonicaliseLoctab ( di );
    canonicaliseCFI ( di );
+   canonicaliseVarInfo ( di );
 }
 
 

Modified: branches/DATASYMS/coregrind/m_debuginfo/tytypes.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/tytypes.c   2008-02-17 00:25:49 UTC 
(rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/tytypes.c   2008-02-17 00:30:12 UTC 
(rev 7416)
@@ -80,24 +80,23 @@
    return type;
 }
 
-void ML_(delete_TyAtom)( TyAtom* atom ) {
+static void delete_TyAtom ( TyAtom* atom ) {
    /* .name is in DebugInfo.strchunks */
    ML_(dinfo_free)(atom);
 }
-void ML_(delete_TyField)( TyField* field ) {
+static void delete_TyField ( TyField* field ) {
    /* .name is in DebugInfo.strchunks */
    /* typeR and loc will be on the admin list; no need to free */
    ML_(dinfo_free)(field);
 }
-void ML_(delete_TyBounds)( TyBounds* bounds ) {
+static void delete_TyBounds ( TyBounds* bounds ) {
    ML_(dinfo_free)(bounds);
 }
-void ML_(delete_D3Expr)( D3Expr* expr ) {
+static void delete_D3Expr ( D3Expr* expr ) {
    /* .bytes is in DebugInfo.strchunks */
    ML_(dinfo_free)(expr);
 }
-__attribute__((noinline))
-void ML_(delete_Type)( Type* ty ) {
+static void delete_Type ( Type* ty ) {
    switch (ty->tag) {
       case Ty_Base:
          /* .name is in DebugInfo.strchunks */
@@ -144,11 +143,11 @@
 void ML_(delete_TyAdmin_and_payload) ( TyAdmin* ad ) {
    vg_assert(ad->payload);
    switch (ad->tag) {
-      case TyA_Type:   ML_(delete_Type)(ad->payload);     break;
-      case TyA_Atom:   ML_(delete_TyAtom)(ad->payload);   break;
-      case TyA_Expr:   ML_(delete_D3Expr)(ad->payload);   break;
-      case TyA_Field:  ML_(delete_TyField)(ad->payload);  break;
-      case TyA_Bounds: ML_(delete_TyBounds)(ad->payload); break;
+      case TyA_Type:   delete_Type(ad->payload);     break;
+      case TyA_Atom:   delete_TyAtom(ad->payload);   break;
+      case TyA_Expr:   delete_D3Expr(ad->payload);   break;
+      case TyA_Field:  delete_TyField(ad->payload);  break;
+      case TyA_Bounds: delete_TyBounds(ad->payload); break;
       default:         vg_assert(0);
    }
    ML_(dinfo_free)(ad);


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