|
From: <sv...@va...> - 2008-02-17 00:30:18
|
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, ®s, 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, ®s, 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);
|