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