|
From: <sv...@va...> - 2008-09-09 08:49:26
|
Author: sewardj Date: 2008-09-09 09:49:35 +0100 (Tue, 09 Sep 2008) New Revision: 8591 Log: Merge, from svn://svn.valgrind.org/branches/SGCHECK, core changes needed to support the sg_ part of this tool, mostly: * query functions for finding out the stack and global blocks visible at any given program counter value * add a ULong abstract handle to the DebugInfo structure, and use it to provide a mechanism whereby tools can reliably know when the debuginfo has been updated (and so query the new debuginfo if they want) This is believed to comprise essentially r8529, r8531, r8557, r8559. Modified: branches/PTRCHECK/coregrind/m_debuginfo/d3basics.c branches/PTRCHECK/coregrind/m_debuginfo/debuginfo.c branches/PTRCHECK/coregrind/m_debuginfo/priv_d3basics.h branches/PTRCHECK/coregrind/m_debuginfo/priv_misc.h branches/PTRCHECK/coregrind/m_debuginfo/priv_storage.h branches/PTRCHECK/coregrind/m_debuginfo/priv_tytypes.h branches/PTRCHECK/coregrind/m_main.c branches/PTRCHECK/coregrind/m_syswrap/syswrap-generic.c branches/PTRCHECK/coregrind/m_tooliface.c branches/PTRCHECK/coregrind/m_wordfm.c branches/PTRCHECK/coregrind/pub_core_debuginfo.h branches/PTRCHECK/coregrind/pub_core_tooliface.h branches/PTRCHECK/drd/drd_main.c branches/PTRCHECK/helgrind/hg_main.c branches/PTRCHECK/include/pub_tool_debuginfo.h branches/PTRCHECK/include/pub_tool_tooliface.h branches/PTRCHECK/include/pub_tool_wordfm.h branches/PTRCHECK/memcheck/mc_main.c Modified: branches/PTRCHECK/coregrind/m_debuginfo/d3basics.c =================================================================== --- branches/PTRCHECK/coregrind/m_debuginfo/d3basics.c 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/m_debuginfo/d3basics.c 2008-09-09 08:49:35 UTC (rev 8591) @@ -38,10 +38,12 @@ #include "pub_core_libcassert.h" #include "pub_core_libcprint.h" #include "pub_core_options.h" +#include "pub_core_xarray.h" #include "pub_core_vki.h" /* VKI_PROT_READ */ #include "pub_core_aspacemgr.h" /* VG_(is_valid_for_client) */ +#include "priv_misc.h" #include "priv_d3basics.h" /* self */ HChar* ML_(pp_DW_children) ( DW_children hashch ) @@ -673,6 +675,147 @@ } +/* Evaluate a very simple Guarded (DWARF3) expression. The expression + is expected to denote a constant, with no reference to any + registers nor to any frame base expression. The expression is + expected to have at least one guard. If there is more than one + guard, all the sub-expressions are evaluated and compared. The + address ranges on the guards are ignored. GXR_Failure is returned + in the following circumstances: + * no guards + * any of the subexpressions require a frame base expression + * any of the subexpressions denote a register location + * any of the subexpressions do not produce a manifest constant + * there's more than one subexpression, all of which successfully + evaluate to a constant, but they don't all produce the same constant. + */ +GXResult ML_(evaluate_trivial_GX)( GExpr* gx, Addr data_bias ) +{ + GXResult res; + Addr aMin, aMax; + UChar uc; + UShort nbytes; + Word i, nGuards; + MaybeUWord *muw, *muw2; + + HChar* badness = NULL; + UChar* p = &gx->payload[0]; + XArray* results = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free), + sizeof(MaybeUWord) ); + + uc = *p++; /*biasMe*/ + vg_assert(uc == 0 || uc == 1); + /* in fact it's senseless to evaluate if the guards need biasing. + So don't. */ + vg_assert(uc == 0); + + nGuards = 0; + while (True) { + MaybeUWord thisResult; + uc = *p++; + if (uc == 1) /*isEnd*/ + break; + vg_assert(uc == 0); + aMin = * (Addr*)p; p += sizeof(Addr); + aMax = * (Addr*)p; p += sizeof(Addr); + nbytes = * (UShort*)p; p += sizeof(UShort); + nGuards++; + if (0) VG_(printf)(" guard %ld: %#lx %#lx\n", + nGuards, aMin,aMax); + + thisResult.b = False; + thisResult.w = 0; + + /* Peer at this particular subexpression, to see if it's + obviously a constant. */ + if (nbytes == 1 + sizeof(Addr) && *p == DW_OP_addr) { + thisResult.b = True; + thisResult.w = *(Addr*)(p+1) + data_bias; + } + else if (nbytes == 2 + sizeof(Addr) + && *p == DW_OP_addr + && *(p + 1 + sizeof(Addr)) == DW_OP_GNU_push_tls_address) { + if (!badness) + badness = "trivial GExpr is DW_OP_addr plus trailing junk"; + } + else if (nbytes >= 1 && *p >= DW_OP_reg0 && *p <= DW_OP_reg31) { + if (!badness) + badness = "trivial GExpr denotes register (1)"; + } + else if (nbytes >= 1 && *p == DW_OP_fbreg) { + if (!badness) + badness = "trivial GExpr requires fbGX"; + } + else if (nbytes >= 1 && *p >= DW_OP_breg0 && *p <= DW_OP_breg31) { + if (!badness) + badness = "trivial GExpr requires register value"; + } + else if (nbytes >= 1 && *p == DW_OP_regx) { + if (!badness) + badness = "trivial GExpr denotes register (2)"; + } + else { + VG_(printf)(" ML_(evaluate_trivial_GX): unhandled:\n "); + ML_(pp_GX)( gx ); + VG_(printf)("\n"); + tl_assert(0); + } + + VG_(addToXA)( results, &thisResult ); + + p += (UWord)nbytes; + } + + res.kind = GXR_Failure; + + tl_assert(nGuards == VG_(sizeXA)( results )); + tl_assert(nGuards >= 0); + if (nGuards == 0) { + tl_assert(!badness); + res.word = (UWord)"trivial GExpr has no guards (!)"; + VG_(deleteXA)( results ); + return res; + } + + for (i = 0; i < nGuards; i++) { + muw = VG_(indexXA)( results, i ); + if (muw->b == False) + break; + } + + vg_assert(i >= 0 && i <= nGuards); + if (i < nGuards) { + /* at least one subexpression failed to produce a manifest constant. */ + vg_assert(badness); + res.word = (UWord)badness; + VG_(deleteXA)( results ); + return res; + } + + /* All the subexpressions produced a constant, but did they all produce + the same one? */ + muw = VG_(indexXA)( results, 0 ); + tl_assert(muw->b == True); /* we just established that all exprs are ok */ + + for (i = 1; i < nGuards; i++) { + muw2 = VG_(indexXA)( results, i ); + tl_assert(muw2->b == True); + if (muw2->w != muw->w) { + res.word = (UWord)"trivial GExpr: subexpressions disagree"; + VG_(deleteXA)( results ); + return res; + } + } + + /* Well, we have success. All subexpressions evaluated, and + they all agree. Hurrah. */ + res.kind = GXR_Value; + res.word = muw->w; + VG_(deleteXA)( results ); + return res; +} + + void ML_(pp_GXResult) ( GXResult res ) { switch (res.kind) { Modified: branches/PTRCHECK/coregrind/m_debuginfo/debuginfo.c =================================================================== --- branches/PTRCHECK/coregrind/m_debuginfo/debuginfo.c 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/m_debuginfo/debuginfo.c 2008-09-09 08:49:35 UTC (rev 8591) @@ -156,6 +156,11 @@ /*--- Notification (acquire/discard) helpers ---*/ /*------------------------------------------------------------*/ +/* Gives out unique abstract handles for allocated DebugInfos. See + comment in priv_storage.h, declaration of struct _DebugInfo, for + details. */ +static ULong handle_counter = 1; + /* Allocate and zero out a new DebugInfo record. */ static DebugInfo* alloc_DebugInfo( const UChar* filename, @@ -167,6 +172,7 @@ vg_assert(filename); di = ML_(dinfo_zalloc)(sizeof(DebugInfo)); + di->handle = handle_counter++; di->filename = ML_(dinfo_strdup)(filename); di->memname = memname ? ML_(dinfo_strdup)(memname) : NULL; @@ -490,14 +496,22 @@ will try load debug info if the mapping at 'a' belongs to Valgrind; whereas normally (False) it will not do that. This allows us to carefully control when the thing will read symbols from the - Valgrind executable itself. */ + Valgrind executable itself. -void VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV ) + If a call to VG_(di_notify_mmap) causes debug info to be read, then + the returned ULong is an abstract handle which can later be used to + refer to the debuginfo read as a result of this specific mapping, + in later queries to m_debuginfo. In this case the handle value + will be one or above. If the returned value is zero, no debug info + was read. */ + +ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV ) { NSegment const * seg; HChar* filename; Bool ok, is_rx_map, is_rw_map; DebugInfo* di; + ULong di_handle; SysRes fd; Int nread; HChar buf1k[1024]; @@ -523,12 +537,12 @@ /* Ignore non-file mappings */ if ( ! (seg->kind == SkFileC || (seg->kind == SkFileV && allow_SkFileV)) ) - return; + return 0; /* If the file doesn't have a name, we're hosed. Give up. */ filename = VG_(am_get_filename)( (NSegment*)seg ); if (!filename) - return; + return 0; if (debug) VG_(printf)("di_notify_mmap-2: %s\n", filename); @@ -550,13 +564,13 @@ fake_di.filename = filename; ML_(symerr)(&fake_di, True, "failed to stat64/stat this file"); } - return; + return 0; } /* Finally, the point of all this stattery: if it's not a regular file, don't try to read debug info from it. */ if (! VKI_S_ISREG(statbuf.st_mode)) - return; + return 0; /* no uses of statbuf below here. */ @@ -572,25 +586,25 @@ fake_di.filename = filename; ML_(symerr)(&fake_di, True, "can't open file to inspect ELF header"); } - return; + return 0; } nread = VG_(read)( fd.res, buf1k, sizeof(buf1k) ); VG_(close)( fd.res ); if (nread == 0) - return; + return 0; if (nread < 0) { DebugInfo fake_di; VG_(memset)(&fake_di, 0, sizeof(fake_di)); fake_di.filename = filename; ML_(symerr)(&fake_di, True, "can't read file to inspect ELF header"); - return; + return 0; } vg_assert(nread > 0 && nread <= sizeof(buf1k) ); /* We're only interested in mappings of ELF object files. */ if (!ML_(is_elf_object_file)( buf1k, (SizeT)nread )) - return; + return 0; /* Now we have to guess if this is a text-like mapping, a data-like mapping, neither or both. The rules are: @@ -645,7 +659,7 @@ /* If it is neither text-ish nor data-ish, we're not interested. */ if (!(is_rx_map || is_rw_map)) - return; + return 0; /* See if we have a DebugInfo for this filename. If not, create one. */ @@ -676,48 +690,58 @@ } } - if (di->have_rx_map && di->have_rw_map && !di->have_dinfo) { + /* If we don't have an rx and rw mapping, or if we already have + debuginfo for this mapping for whatever reason, go no + further. */ + if ( ! (di->have_rx_map && di->have_rw_map && !di->have_dinfo) ) + return 0; - vg_assert(di->filename); - TRACE_SYMTAB("\n"); - TRACE_SYMTAB("------ start ELF OBJECT " - "------------------------------\n"); - TRACE_SYMTAB("------ name = %s\n", di->filename); - TRACE_SYMTAB("\n"); + /* Ok, so, finally, let's try to read the debuginfo. */ + vg_assert(di->filename); + TRACE_SYMTAB("\n"); + TRACE_SYMTAB("------ start ELF OBJECT " + "------------------------------\n"); + TRACE_SYMTAB("------ name = %s\n", di->filename); + TRACE_SYMTAB("\n"); - /* We're going to read symbols and debug info for the avma - ranges [rx_map_avma, +rx_map_size) and [rw_map_avma, - +rw_map_size). First get rid of any other DebugInfos which - overlap either of those ranges (to avoid total confusion). */ - discard_DebugInfos_which_overlap_with( di ); + /* We're going to read symbols and debug info for the avma + ranges [rx_map_avma, +rx_map_size) and [rw_map_avma, + +rw_map_size). First get rid of any other DebugInfos which + overlap either of those ranges (to avoid total confusion). */ + discard_DebugInfos_which_overlap_with( di ); - /* .. and acquire new info. */ - ok = ML_(read_elf_debug_info)( di ); + /* .. and acquire new info. */ + ok = ML_(read_elf_debug_info)( di ); - if (ok) { - TRACE_SYMTAB("\n------ Canonicalising the " - "acquired info ------\n"); - /* prepare read data for use */ - ML_(canonicaliseTables)( di ); - /* notify m_redir about it */ - TRACE_SYMTAB("\n------ Notifying m_redir ------\n"); - VG_(redir_notify_new_DebugInfo)( di ); - /* Note that we succeeded */ - di->have_dinfo = True; - } else { - TRACE_SYMTAB("\n------ ELF reading failed ------\n"); - /* Something went wrong (eg. bad ELF file). Should we delete - this DebugInfo? No - it contains info on the rw/rx - mappings, at least. */ - } + if (ok) { - TRACE_SYMTAB("\n"); - TRACE_SYMTAB("------ name = %s\n", di->filename); - TRACE_SYMTAB("------ end ELF OBJECT " - "------------------------------\n"); - TRACE_SYMTAB("\n"); + TRACE_SYMTAB("\n------ Canonicalising the " + "acquired info ------\n"); + /* prepare read data for use */ + ML_(canonicaliseTables)( di ); + /* notify m_redir about it */ + TRACE_SYMTAB("\n------ Notifying m_redir ------\n"); + VG_(redir_notify_new_DebugInfo)( di ); + /* Note that we succeeded */ + di->have_dinfo = True; + tl_assert(di->handle > 0); + di_handle = di->handle; + } else { + TRACE_SYMTAB("\n------ ELF reading failed ------\n"); + /* Something went wrong (eg. bad ELF file). Should we delete + this DebugInfo? No - it contains info on the rw/rx + mappings, at least. */ + di_handle = 0; } + + TRACE_SYMTAB("\n"); + TRACE_SYMTAB("------ name = %s\n", di->filename); + TRACE_SYMTAB("------ end ELF OBJECT " + "------------------------------\n"); + TRACE_SYMTAB("\n"); + + return di_handle; } @@ -1867,7 +1891,6 @@ 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 @@ -2023,7 +2046,7 @@ scope. */ for (di = debugInfo_list; di != NULL; di = di->next) { OSet* global_scope; - Int gs_size; + Word gs_size; Addr zero; DiAddrRange* global_arange; Word i; @@ -2197,6 +2220,373 @@ } +////////////////////////////////////////////////////////////////// +// // +// Support for other kinds of queries to the Dwarf3 var info // +// // +////////////////////////////////////////////////////////////////// + +/* Figure out if the variable 'var' has a location that is linearly + dependent on a stack pointer value, or a frame pointer value, and + if it is, add a description of it to 'blocks'. Otherwise ignore + it. If 'arrays_only' is True, also ignore it unless it has an + array type. */ + +static +void analyse_deps ( /*MOD*/XArray* /* of FrameBlock */ blocks, + Addr ip, Addr data_bias, DiVariable* var, + Bool arrays_only ) +{ + GXResult res_sp_6k, res_sp_7k, res_fp_6k, res_fp_7k; + RegSummary regs; + MaybeUWord muw; + Bool isVec; + + Bool debug = False; + if (0&&debug) + VG_(printf)("adeps: var %s\n", var->name ); + + /* Figure out how big the variable is. */ + muw = ML_(sizeOfType)(var->type); + /* if this var has a type whose size is unknown or zero, it should + never have been added. ML_(addVar) should have rejected it. */ + vg_assert(muw.b == True); + vg_assert(muw.w > 0); + + /* skip if non-array and we're only interested in arrays */ + isVec = var->type->tag == Ty_Array; + if (arrays_only && !isVec) return; + + if (0) {ML_(pp_Type_C_ishly)(var->type); + VG_(printf)(" %s\n", var->name);} + + /* Do some test evaluations of the variable's location expression, + in order to guess whether it is sp-relative, fp-relative, or + none. A crude hack, which can be interpreted roughly as finding + the first derivative of the location expression w.r.t. the + supplied frame and stack pointer values. */ + regs.fp = 0; + regs.ip = ip; + regs.sp = 6 * 1024; + res_sp_6k = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias ); + + regs.fp = 0; + regs.ip = ip; + regs.sp = 7 * 1024; + res_sp_7k = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias ); + + regs.fp = 6 * 1024; + regs.ip = ip; + regs.sp = 0; + res_fp_6k = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias ); + + regs.fp = 7 * 1024; + regs.ip = ip; + regs.sp = 0; + res_fp_7k = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias ); + + vg_assert(res_sp_6k.kind == res_sp_7k.kind); + vg_assert(res_sp_6k.kind == res_fp_6k.kind); + vg_assert(res_sp_6k.kind == res_fp_7k.kind); + + if (res_sp_6k.kind == GXR_Value) { + StackBlock block; + GXResult res; + UWord sp_delta = res_sp_7k.word - res_sp_6k.word; + UWord fp_delta = res_fp_7k.word - res_fp_6k.word; + tl_assert(sp_delta == 0 || sp_delta == 1024); + tl_assert(fp_delta == 0 || fp_delta == 1024); + + if (sp_delta == 0 && fp_delta == 0) { + /* depends neither on sp nor fp, so it can't be a stack + local. Ignore it. */ + } + else + if (sp_delta == 1024 && fp_delta == 0) { + regs.sp = regs.fp = 0; + regs.ip = ip; + res = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias ); + tl_assert(res.kind == GXR_Value); + if (debug) + VG_(printf)(" %5ld .. %5ld (sp) %s\n", + res.word, res.word + muw.w - 1, var->name); + block.base = res.word; + block.szB = muw.w; + block.spRel = True; + block.isVec = isVec; + VG_(memset)( &block.name[0], 0, sizeof(block.name) ); + if (var->name) + VG_(strncpy)( &block.name[0], var->name, sizeof(block.name)-1 ); + block.name[ sizeof(block.name)-1 ] = 0; + VG_(addToXA)( blocks, &block ); + } + else + if (sp_delta == 0 && fp_delta == 1024) { + regs.sp = regs.fp = 0; + regs.ip = ip; + res = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias ); + tl_assert(res.kind == GXR_Value); + if (debug) + VG_(printf)(" %5ld .. %5ld (FP) %s\n", + res.word, res.word + muw.w - 1, var->name); + block.base = res.word; + block.szB = muw.w; + block.spRel = False; + block.isVec = isVec; + VG_(memset)( &block.name[0], 0, sizeof(block.name) ); + if (var->name) + VG_(strncpy)( &block.name[0], var->name, sizeof(block.name)-1 ); + block.name[ sizeof(block.name)-1 ] = 0; + VG_(addToXA)( blocks, &block ); + } + else { + vg_assert(0); + } + } +} + + +/* Get an XArray of StackBlock which describe the stack (auto) blocks + for this ip. The caller is expected to free the XArray at some + point. If 'arrays_only' is True, only array-typed blocks are + returned; otherwise blocks of all types are returned. */ + +void* /* really, XArray* of StackBlock */ + VG_(di_get_stack_blocks_at_ip)( Addr ip, Bool arrays_only ) +{ + /* This is a derivation of consider_vars_in_frame() above. */ + Word i; + DebugInfo* di; + RegSummary regs; + Bool debug = False; + + XArray* res = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free), + sizeof(StackBlock) ); + + static UInt n_search = 0; + static UInt n_steps = 0; + n_search++; + if (debug) + VG_(printf)("QQQQ: dgsbai: ip %#lx\n", ip); + /* 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_present || 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 res; /* currently empty */ + + if (0 && ((n_search & 0x1) == 0)) + VG_(printf)("VG_(di_get_stack_blocks_at_ip): %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 res; /* currently empty */ + + /* 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 = 0; + regs.fp = 0; + + /* "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 (debug) + VG_(printf)("QQQQ: considering scope %ld\n", (Word)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 ); + if (debug) + VG_(printf)("QQQQ: var:name=%s %#lx-%#lx %#lx\n", + var->name,arange->aMin,arange->aMax,ip); + analyse_deps( res, ip, di->data_bias, var, arrays_only ); + } + } + + return res; +} + + +/* Get an array of GlobalBlock which describe the global blocks owned + by the shared object characterised by the given di_handle. Asserts + if the handle is invalid. The caller is responsible for freeing + the array at some point. If 'arrays_only' is True, only + array-typed blocks are returned; otherwise blocks of all types are + returned. */ + +void* /* really, XArray* of GlobalBlock */ + VG_(di_get_global_blocks_from_dihandle) ( ULong di_handle, + Bool arrays_only ) +{ + /* This is a derivation of consider_vars_in_frame() above. */ + + DebugInfo* di; + XArray* gvars; /* XArray* of GlobalBlock */ + Word nScopes, scopeIx; + + /* The first thing to do is find the DebugInfo that + pertains to 'di_handle'. */ + tl_assert(di_handle > 0); + for (di = debugInfo_list; di; di = di->next) { + if (di->handle == di_handle) + break; + } + + /* If this fails, we were unable to find any DebugInfo with the + given handle. This is considered an error on the part of the + caller. */ + tl_assert(di != NULL); + + /* we'll put the collected variables in here. */ + gvars = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free), sizeof(GlobalBlock) ); + tl_assert(gvars); + + /* any var info at all? */ + if (!di->varinfo) + return gvars; + + /* we'll iterate over all the variables we can find, even if + it seems senseless to visit stack-allocated variables */ + /* Iterate over all scopes */ + nScopes = VG_(sizeXA)( di->varinfo ); + for (scopeIx = 0; scopeIx < nScopes; scopeIx++) { + + /* Iterate over each (code) address range at the current scope */ + DiAddrRange* range; + OSet* /* of DiAddrInfo */ scope + = *(OSet**)VG_(indexXA)( di->varinfo, scopeIx ); + tl_assert(scope); + VG_(OSetGen_ResetIter)(scope); + while ( (range = VG_(OSetGen_Next)(scope)) ) { + + /* Iterate over each variable in the current address range */ + Word nVars, varIx; + tl_assert(range->vars); + nVars = VG_(sizeXA)( range->vars ); + for (varIx = 0; varIx < nVars; varIx++) { + + Bool isVec; + GXResult res; + MaybeUWord muw; + GlobalBlock gb; + DiVariable* var = VG_(indexXA)( range->vars, varIx ); + tl_assert(var->name); + if (0) VG_(printf)("at depth %ld var %s ", scopeIx, var->name ); + + /* Now figure out if this variable has a constant address + (that is, independent of FP, SP, phase of moon, etc), + and if so, what the address is. Any variable with a + constant address is deemed to be a global so we collect + it. */ + if (0) { VG_(printf)("EVAL: "); ML_(pp_GX)(var->gexpr); + VG_(printf)("\n"); } + res = ML_(evaluate_trivial_GX)( var->gexpr, di->data_bias ); + + /* Not a constant address => not interesting */ + if (res.kind != GXR_Value) { + if (0) VG_(printf)("FAIL\n"); + continue; + } + + /* Ok, it's a constant address. See if we want to collect + it. */ + if (0) VG_(printf)("%#lx\n", res.word); + + /* Figure out how big the variable is. */ + muw = ML_(sizeOfType)(var->type); + + /* if this var has a type whose size is unknown or zero, + it should never have been added. ML_(addVar) should + have rejected it. */ + vg_assert(muw.b == True); + vg_assert(muw.w > 0); + + /* skip if non-array and we're only interested in + arrays */ + isVec = var->type->tag == Ty_Array; + if (arrays_only && !isVec) continue; + + /* Ok, so collect it! */ + tl_assert(var->name); + tl_assert(di->soname); + if (0) VG_(printf)("XXXX %s %s %d\n", var->name, + var->fileName?(HChar*)var->fileName + :"??",var->lineNo); + VG_(memset)(&gb, 0, sizeof(gb)); + gb.addr = res.word; + gb.szB = muw.w; + gb.isVec = isVec; + VG_(strncpy)(&gb.name[0], var->name, sizeof(gb.name)-1); + VG_(strncpy)(&gb.soname[0], di->soname, sizeof(gb.soname)-1); + tl_assert(gb.name[ sizeof(gb.name)-1 ] == 0); + tl_assert(gb.soname[ sizeof(gb.soname)-1 ] == 0); + + VG_(addToXA)( gvars, &gb ); + + } /* for (varIx = 0; varIx < nVars; varIx++) */ + + } /* while ( (range = VG_(OSetGen_Next)(scope)) ) */ + + } /* for (scopeIx = 0; scopeIx < nScopes; scopeIx++) */ + + return gvars; +} + + + /*------------------------------------------------------------*/ /*--- DebugInfo accessor functions ---*/ /*------------------------------------------------------------*/ Modified: branches/PTRCHECK/coregrind/m_debuginfo/priv_d3basics.h =================================================================== --- branches/PTRCHECK/coregrind/m_debuginfo/priv_d3basics.h 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/m_debuginfo/priv_d3basics.h 2008-09-09 08:49:35 UTC (rev 8591) @@ -635,6 +635,15 @@ Addr data_bias, Bool push_initial_zero ); +/* Evaluate a very simple Guarded (DWARF3) expression. The expression + is expected to denote a constant, with no reference to any + registers nor to any frame base expression. GXR_Failure is + returned if there is more than one guard, or none, a register + location is denoted, a frame base expression is required, or the + expression is not manifestly a constant. The range of addresses + covered by the guard is also ignored. */ +GXResult ML_(evaluate_trivial_GX)( GExpr* gx, Addr data_bias ); + #endif /* ndef __PRIV_D3BASICS_H */ /*--------------------------------------------------------------------*/ Modified: branches/PTRCHECK/coregrind/m_debuginfo/priv_misc.h =================================================================== --- branches/PTRCHECK/coregrind/m_debuginfo/priv_misc.h 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/m_debuginfo/priv_misc.h 2008-09-09 08:49:35 UTC (rev 8591) @@ -42,7 +42,11 @@ void ML_(dinfo_free)( void* v ); UChar* ML_(dinfo_strdup)( const UChar* str ); +/* A handy type, a la Haskell's Maybe type. Yes, I know, C sucks. + Been there. Done that. Seen the movie. Got the T-shirt. Etc. */ +typedef struct { UWord w; Bool b; } MaybeUWord; + #endif /* ndef __PRIV_MISC_H */ /*--------------------------------------------------------------------*/ Modified: branches/PTRCHECK/coregrind/m_debuginfo/priv_storage.h =================================================================== --- branches/PTRCHECK/coregrind/m_debuginfo/priv_storage.h 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/m_debuginfo/priv_storage.h 2008-09-09 08:49:35 UTC (rev 8591) @@ -248,6 +248,16 @@ struct _DebugInfo* next; /* list of DebugInfos */ Bool mark; /* marked for deletion? */ + /* An abstract handle, which can be used by entities outside of + m_debuginfo to (in an abstract datatype sense) refer to this + struct _DebugInfo. A .handle of zero is invalid; valid handles + are 1 and above. The same handle is never issued twice (in any + given run of Valgrind), so a handle becomes invalid when the + associated struct _DebugInfo is discarded, and remains invalid + forever thereafter. The .handle field is set as soon as this + structure is allocated. */ + ULong handle; + /* Used for debugging only - indicate what stuff to dump whilst reading stuff into the seginfo. Are computed as early in the lifetime of the DebugInfo as possible -- at the point when it is Modified: branches/PTRCHECK/coregrind/m_debuginfo/priv_tytypes.h =================================================================== --- branches/PTRCHECK/coregrind/m_debuginfo/priv_tytypes.h 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/m_debuginfo/priv_tytypes.h 2008-09-09 08:49:35 UTC (rev 8591) @@ -153,9 +153,6 @@ /* How big is this type? (post-resolved only) If .b in the returned struct is False, the size is unknown. */ /* FIXME: check all pointers before dereferencing */ - -typedef struct { UWord w; Bool b; } MaybeUWord; - MaybeUWord ML_(sizeOfType)( Type* ty ); /* Describe where in the type 'offset' falls. Caller must Modified: branches/PTRCHECK/coregrind/m_main.c =================================================================== --- branches/PTRCHECK/coregrind/m_main.c 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/m_main.c 2008-09-09 08:49:35 UTC (rev 8591) @@ -1125,6 +1125,11 @@ static IIFinaliseImageInfo the_iifii; +/* A simple pair structure, used for conveying debuginfo handles to + calls to VG_TRACK(new_mem_startup, ...). */ +typedef struct { Addr a; ULong ull; } Addr_n_ULong; + + /* --- Forwards decls to do with shutdown --- */ static void final_tidyup(ThreadId tid); @@ -1185,6 +1190,7 @@ Int loglevel, i; Bool logging_to_fd; struct vki_rlimit zero = { 0, 0 }; + XArray* addr2dihandle = NULL; //============================================================ // @@ -1711,11 +1717,28 @@ // p: setup_code_redirect_table [so that redirs can be recorded] // p: mallocfree // p: probably: setup fds and process CLOs, so that logging works + // + // While doing this, make a note of the debuginfo-handles that + // come back from VG_(di_notify_mmap)/VG_(di_aix5_notify_segchange). + // Later, in "Tell the tool about the initial client memory permissions" + // (just below) we can then hand these handles off to the tool in + // calls to VG_TRACK(new_mem_startup, ...). This gives the tool the + // opportunity to make further queries to m_debuginfo before the + // client is started, if it wants. We put this information into an + // XArray, each handle along with the associated segment start address, + // and search the XArray for the handles later, when calling + // VG_TRACK(new_mem_startup, ...). //-------------------------------------------------------------- VG_(debugLog)(1, "main", "Load initial debug info\n"); + + tl_assert(!addr2dihandle); + addr2dihandle = VG_(newXA)( VG_(malloc), VG_(free), sizeof(Addr_n_ULong) ); + tl_assert(addr2dihandle); + # if defined(VGO_linux) { Addr* seg_starts; Int n_seg_starts; + Addr_n_ULong anu; seg_starts = get_seg_starts( &n_seg_starts ); vg_assert(seg_starts && n_seg_starts >= 0); @@ -1723,14 +1746,22 @@ /* show them all to the debug info reader. allow_SkFileV has to be True here so that we read info from the valgrind executable itself. */ - for (i = 0; i < n_seg_starts; i++) - VG_(di_notify_mmap)( seg_starts[i], True/*allow_SkFileV*/ ); + for (i = 0; i < n_seg_starts; i++) { + anu.ull = VG_(di_notify_mmap)( seg_starts[i], True/*allow_SkFileV*/ ); + /* anu.ull holds the debuginfo handle returned by di_notify_mmap, + if any. */ + if (anu.ull > 0) { + anu.a = seg_starts[i]; + VG_(addToXA)( addr2dihandle, &anu ); + } + } VG_(free)( seg_starts ); } # elif defined(VGO_aix5) { AixCodeSegChange* changes; Int changes_size, changes_used; + Addr_n_ULong anu; /* Find out how many AixCodeSegChange records we will need, and acquire them. */ @@ -1743,17 +1774,23 @@ vg_assert(changes_used >= 0 && changes_used <= changes_size); /* And notify m_debuginfo of the changes. */ - for (i = 0; i < changes_used; i++) - VG_(di_aix5_notify_segchange)( - changes[i].code_start, - changes[i].code_len, - changes[i].data_start, - changes[i].data_len, - changes[i].file_name, - changes[i].mem_name, - changes[i].is_mainexe, - changes[i].acquire - ); + for (i = 0; i < changes_used; i++) { + anu.ull = VG_(di_aix5_notify_segchange)( + changes[i].code_start, + changes[i].code_len, + changes[i].data_start, + changes[i].data_len, + changes[i].file_name, + changes[i].mem_name, + changes[i].is_mainexe, + changes[i].acquire + ); + if (anu.ull > 0) { + tl_assert(changes[i].acquire); + anu.a = changes[i].code_start; /* is this correct? */ + VG_(addToXA)( addr2dihandle, &anu ); + } + } VG_(free)(changes); } @@ -1797,11 +1834,18 @@ // p: mallocfree // p: setup_client_stack // p: setup_client_dataseg + // + // For each segment we tell the client about, look up in + // addr2dihandle as created above, to see if there's a debuginfo + // handle associated with the segment, that we can hand along + // to the tool, to be helpful. //-------------------------------------------------------------- VG_(debugLog)(1, "main", "Tell tool about initial permissions\n"); { Addr* seg_starts; Int n_seg_starts; + tl_assert(addr2dihandle); + /* Mark the main thread as running while we tell the tool about the client memory so that the tool can associate that memory with the main thread. */ @@ -1813,9 +1857,11 @@ /* show interesting ones to the tool */ for (i = 0; i < n_seg_starts; i++) { + Word j, n; NSegment const* seg = VG_(am_find_nsegment)( seg_starts[i] ); vg_assert(seg); + vg_assert(seg->start == seg_starts[i] ); if (seg->kind == SkFileC || seg->kind == SkAnonC) { VG_(debugLog)(2, "main", "tell tool about %010lx-%010lx %c%c%c\n", @@ -1823,12 +1869,28 @@ seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-', seg->hasX ? 'x' : '-' ); + /* search addr2dihandle to see if we have an entry + matching seg->start. */ + n = VG_(sizeXA)( addr2dihandle ); + for (j = 0; j < n; j++) { + Addr_n_ULong* anl = VG_(indexXA)( addr2dihandle, j ); + if (anl->a == seg->start) { + tl_assert(anl->ull > 0); /* check it's a valid handle */ + break; + } + } + vg_assert(j >= 0 && j <= n); VG_TRACK( new_mem_startup, seg->start, seg->end+1-seg->start, - seg->hasR, seg->hasW, seg->hasX ); + seg->hasR, seg->hasW, seg->hasX, + /* and the retrieved debuginfo handle, if any */ + j < n + ? ((Addr_n_ULong*)VG_(indexXA)( addr2dihandle, j ))->ull + : 0 ); } } VG_(free)( seg_starts ); + VG_(deleteXA)( addr2dihandle ); /* Also do the initial stack permissions. */ { NSegment const* seg @@ -1865,7 +1927,8 @@ - (Addr)&VG_(trampoline_stuff_start), False, /* readable? */ False, /* writable? */ - True /* executable? */ ); + True /* executable? */, + 0 /* di_handle: no associated debug info */ ); /* Clear the running thread indicator */ VG_(running_tid) = VG_INVALID_THREADID; Modified: branches/PTRCHECK/coregrind/m_syswrap/syswrap-generic.c =================================================================== --- branches/PTRCHECK/coregrind/m_syswrap/syswrap-generic.c 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/m_syswrap/syswrap-generic.c 2008-09-09 08:49:35 UTC (rev 8591) @@ -65,7 +65,8 @@ void notify_aspacem_of_mmap(Addr a, SizeT len, UInt prot, UInt flags, Int fd, Off64T offset); static -void notify_tool_of_mmap(Addr a, SizeT len, UInt prot, Off64T offset); +void notify_tool_of_mmap(Addr a, SizeT len, UInt prot, Off64T offset, + ULong di_handle); /* Returns True iff address range is something the client can @@ -151,13 +152,22 @@ /* When a client mmap has been successfully done, this function must be called. It notifies both aspacem and the tool of the new mapping. -*/ + + JRS 2008-Aug-14: But notice this is *very* obscure. The only place + it is called from is POST(sys_io_setup). In particular, + ML_(generic_PRE_sys_mmap), further down in this file, is the + "normal case" handler for client mmap. But it doesn't call this + function; instead it does the relevant notifications itself. Here, + we just pass di_handle=0 to notify_tool_of_mmap as we have no + better information. But really this function should be done away + with; problem is I don't understand what POST(sys_io_setup) does or + how it works. */ void ML_(notify_aspacem_and_tool_of_mmap) ( Addr a, SizeT len, UInt prot, UInt flags, Int fd, Off64T offset ) { notify_aspacem_of_mmap(a, len, prot, flags, fd, offset); - notify_tool_of_mmap(a, len, prot, offset); + notify_tool_of_mmap(a, len, prot, offset, 0/*di_handle*/); } static @@ -179,7 +189,8 @@ } static -void notify_tool_of_mmap(Addr a, SizeT len, UInt prot, Off64T offset) +void notify_tool_of_mmap(Addr a, SizeT len, UInt prot, Off64T offset, + ULong di_handle) { Bool rr, ww, xx; @@ -192,7 +203,7 @@ ww = toBool(prot & VKI_PROT_WRITE); xx = toBool(prot & VKI_PROT_EXEC); - VG_TRACK( new_mem_mmap, a, len, rr, ww, xx ); + VG_TRACK( new_mem_mmap, a, len, rr, ww, xx, di_handle ); } /* Expand (or shrink) an existing mapping, potentially moving it at @@ -332,7 +343,8 @@ MIN_SIZET(old_len,new_len) ); if (new_len > old_len) VG_TRACK( new_mem_mmap, new_addr+old_len, new_len-old_len, - old_seg->hasR, old_seg->hasW, old_seg->hasX ); + old_seg->hasR, old_seg->hasW, old_seg->hasX, + 0/*di_handle*/ ); VG_TRACK(die_mem_munmap, old_addr, old_len); if (d) { VG_(discard_translations)( old_addr, old_len, "do_remap(1)" ); @@ -375,7 +387,8 @@ if (ok) { VG_TRACK( new_mem_mmap, needA, needL, old_seg->hasR, - old_seg->hasW, old_seg->hasX ); + old_seg->hasW, old_seg->hasX, + 0/*di_handle*/ ); if (d) VG_(discard_translations)( needA, needL, "do_remap(3)" ); return VG_(mk_SysRes_Success)( old_addr ); @@ -395,7 +408,8 @@ MIN_SIZET(old_len,new_len) ); if (new_len > old_len) VG_TRACK( new_mem_mmap, advised+old_len, new_len-old_len, - old_seg->hasR, old_seg->hasW, old_seg->hasX ); + old_seg->hasR, old_seg->hasW, old_seg->hasX, + 0/*di_handle*/ ); VG_TRACK(die_mem_munmap, old_addr, old_len); if (d) { VG_(discard_translations)( old_addr, old_len, "do_remap(4)" ); @@ -434,7 +448,8 @@ if (!ok) goto eNOMEM; VG_TRACK( new_mem_mmap, needA, needL, - old_seg->hasR, old_seg->hasW, old_seg->hasX ); + old_seg->hasR, old_seg->hasW, old_seg->hasX, + 0/*di_handle*/ ); if (d) VG_(discard_translations)( needA, needL, "do_remap(6)" ); return VG_(mk_SysRes_Success)( old_addr ); @@ -1722,7 +1737,8 @@ /* we don't distinguish whether it's read-only or * read-write -- it doesn't matter really. */ - VG_TRACK( new_mem_mmap, res, segmentSize, True, True, False ); + VG_TRACK( new_mem_mmap, res, segmentSize, True, True, False, + 0/*di_handle*/ ); if (d) VG_(discard_translations)( (Addr64)res, (ULong)VG_PGROUNDUP(segmentSize), @@ -1937,6 +1953,7 @@ } if (!sres.isError) { + ULong di_handle; /* Notify aspacem. */ notify_aspacem_of_mmap( (Addr)sres.res, /* addr kernel actually assigned */ @@ -1947,13 +1964,15 @@ arg6 /* offset */ ); /* Load symbols? */ - VG_(di_notify_mmap)( (Addr)sres.res, False/*allow_SkFileV*/ ); + di_handle = VG_(di_notify_mmap)( (Addr)sres.res, False/*allow_SkFileV*/ ); /* Notify the tool. */ notify_tool_of_mmap( (Addr)sres.res, /* addr kernel actually assigned */ arg2, /* length */ arg3, /* prot */ - arg6 /* offset */ + arg6, /* offset */ + di_handle /* so the tool can refer to the read debuginfo later, + if it wants. */ ); } Modified: branches/PTRCHECK/coregrind/m_tooliface.c =================================================================== --- branches/PTRCHECK/coregrind/m_tooliface.c 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/m_tooliface.c 2008-09-09 08:49:35 UTC (rev 8591) @@ -340,10 +340,10 @@ VG_(tdict).fn = f; \ } -DEF0(track_new_mem_startup, Addr, SizeT, Bool, Bool, Bool) +DEF0(track_new_mem_startup, Addr, SizeT, Bool, Bool, Bool, ULong) DEF0(track_new_mem_stack_signal, Addr, SizeT, UInt) DEF0(track_new_mem_brk, Addr, SizeT, UInt) -DEF0(track_new_mem_mmap, Addr, SizeT, Bool, Bool, Bool) +DEF0(track_new_mem_mmap, Addr, SizeT, Bool, Bool, Bool, ULong) DEF0(track_copy_mem_remap, Addr, Addr, SizeT) DEF0(track_change_mem_mprotect, Addr, SizeT, Bool, Bool, Bool) Modified: branches/PTRCHECK/coregrind/m_wordfm.c =================================================================== --- branches/PTRCHECK/coregrind/m_wordfm.c 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/m_wordfm.c 2008-09-09 08:49:35 UTC (rev 8591) @@ -415,6 +415,39 @@ } } +static +Bool avl_find_bounds ( AvlNode* t, + /*OUT*/UWord* kMinP, /*OUT*/UWord* kMaxP, + UWord minKey, UWord maxKey, UWord key, + Word(*kCmp)(UWord,UWord) ) +{ + UWord lowerBound = minKey; + UWord upperBound = maxKey; + while (t) { + Word cmpresS = kCmp ? kCmp(t->key, key) + : cmp_unsigned_Words(t->key, key); + if (cmpresS < 0) { + lowerBound = t->key; + t = t->child[1]; + continue; + } + if (cmpresS > 0) { + upperBound = t->key; + t = t->child[0]; + continue; + } + /* We should never get here. If we do, it means the given key + is actually present in the tree, which means the original + call was invalid -- an error on the caller's part, and we + cannot give any meaningful values for the bounds. (Well, + maybe we could, but we're not gonna. Ner!) */ + return False; + } + *kMinP = lowerBound; + *kMaxP = upperBound; + return True; +} + // Clear the iterator stack. static void stackClear(WordFM* fm) { @@ -568,7 +601,7 @@ } /* Add (k,v) to fm. */ -void VG_(addToFM) ( WordFM* fm, UWord k, UWord v ) +Bool VG_(addToFM) ( WordFM* fm, UWord k, UWord v ) { MaybeWord oldV; AvlNode* node; @@ -582,6 +615,7 @@ // fm->vFin( oldV.w ); if (oldV.b) fm->dealloc(node); + return oldV.b; } // Delete key from fm, returning associated key and val if found @@ -618,6 +652,15 @@ } } +// See comment in pub_tool_wordfm.h for explanation +Bool VG_(findBoundsFM)( WordFM* fm, + /*OUT*/UWord* kMinP, /*OUT*/UWord* kMaxP, + UWord minKey, UWord maxKey, UWord key ) +{ + return avl_find_bounds( fm->root, kMinP, kMaxP, minKey, maxKey, + key, fm->kCmp ); +} + UWord VG_(sizeFM) ( WordFM* fm ) { // Hmm, this is a bad way to do this Modified: branches/PTRCHECK/coregrind/pub_core_debuginfo.h =================================================================== --- branches/PTRCHECK/coregrind/pub_core_debuginfo.h 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/pub_core_debuginfo.h 2008-09-09 08:49:35 UTC (rev 8591) @@ -45,9 +45,16 @@ allow_SkFileV is True, it will try load debug info if the mapping at 'a' belongs to Valgrind; whereas normally (False) it will not do that. This allows us to carefully control when the thing will read - symbols from the Valgrind executable itself. */ + symbols from the Valgrind executable itself. + + If a call to VG_(di_notify_mmap) causes debug info to be read, then + the returned ULong is an abstract handle which can later be used to + refer to the debuginfo read as a result of this specific mapping, + in later queries to m_debuginfo. In this case the handle value + will be one or above. If the returned value is zero, no debug info + was read. */ #if defined(VGO_linux) -extern void VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV ); +extern ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV ); extern void VG_(di_notify_munmap)( Addr a, SizeT len ); @@ -59,17 +66,20 @@ parameters describe a code segment and its associated data segment, that have recently been mapped in -- so we need to read debug info for it -- or conversely, have recently been dumped, in which case - the relevant debug info has to be unloaded. */ -extern void VG_(di_aix5_notify_segchange)( - Addr code_start, - Word code_len, - Addr data_start, - Word data_len, - UChar* file_name, - UChar* mem_name, - Bool is_mainexe, - Bool acquire - ); + the relevant debug info has to be unloaded. + + The returned ULong has the same meaning as documented for + VG_(di_notify_mmap) just above. */ +extern ULong VG_(di_aix5_notify_segchange)( + Addr code_start, + Word code_len, + Addr data_start, + Word data_len, + UChar* file_name, + UChar* mem_name, + Bool is_mainexe, + Bool acquire + ); #endif extern Bool VG_(get_fnname_nodemangle)( Addr a, Modified: branches/PTRCHECK/coregrind/pub_core_tooliface.h =================================================================== --- branches/PTRCHECK/coregrind/pub_core_tooliface.h 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/coregrind/pub_core_tooliface.h 2008-09-09 08:49:35 UTC (rev 8591) @@ -161,10 +161,10 @@ IRSB* (*tool_final_IR_tidy_pass) (IRSB*); // -- Event tracking functions ------------------------------------ - void (*track_new_mem_startup) (Addr, SizeT, Bool, Bool, Bool); + void (*track_new_mem_startup) (Addr, SizeT, Bool, Bool, Bool, ULong); void (*track_new_mem_stack_signal)(Addr, SizeT, ThreadId); void (*track_new_mem_brk) (Addr, SizeT, ThreadId); - void (*track_new_mem_mmap) (Addr, SizeT, Bool, Bool, Bool); + void (*track_new_mem_mmap) (Addr, SizeT, Bool, Bool, Bool, ULong); void (*track_copy_mem_remap) (Addr src, Addr dst, SizeT); void (*track_change_mem_mprotect) (Addr, SizeT, Bool, Bool, Bool); Modified: branches/PTRCHECK/drd/drd_main.c =================================================================== --- branches/PTRCHECK/drd/drd_main.c 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/drd/drd_main.c 2008-09-09 08:49:35 UTC (rev 8591) @@ -548,7 +548,8 @@ static void drd_start_using_mem_w_perms(const Addr a, const SizeT len, - const Bool rr, const Bool ww, const Bool xx) + const Bool rr, const Bool ww, const Bool xx, + ULong di_handle) { thread_set_vg_running_tid(VG_(get_running_tid)()); Modified: branches/PTRCHECK/helgrind/hg_main.c =================================================================== --- branches/PTRCHECK/helgrind/hg_main.c 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/helgrind/hg_main.c 2008-09-09 08:49:35 UTC (rev 8591) @@ -5435,7 +5435,7 @@ static void evh__new_mem_w_perms ( Addr a, SizeT len, - Bool rr, Bool ww, Bool xx ) { + Bool rr, Bool ww, Bool xx, ULong di_handle ) { if (SHOW_EVENTS >= 1) VG_(printf)("evh__new_mem_w_perms(%p, %lu, %d,%d,%d)\n", (void*)a, len, (Int)rr, (Int)ww, (Int)xx ); Modified: branches/PTRCHECK/include/pub_tool_debuginfo.h =================================================================== --- branches/PTRCHECK/include/pub_tool_debuginfo.h 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/include/pub_tool_debuginfo.h 2008-09-09 08:49:35 UTC (rev 8591) @@ -105,6 +105,48 @@ */ extern Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf); + +/* Get an XArray of StackBlock which describe the stack (auto) blocks + for this ip. The caller is expected to free the XArray at some + point. If 'arrays_only' is True, only array-typed blocks are + returned; otherwise blocks of all types are returned. */ + +typedef + struct { + OffT base; /* offset from sp or fp */ + SizeT szB; /* size in bytes */ + Bool spRel; /* True => sp-rel, False => fp-rel */ + Bool isVec; /* does block have an array type, or not? */ + HChar name[16]; /* first 15 chars of name (asciiz) */ + } + StackBlock; + +extern void* /* really, XArray* of StackBlock */ + VG_(di_get_stack_blocks_at_ip)( Addr ip, Bool arrays_only ); + + +/* Get an array of GlobalBlock which describe the global blocks owned + by the shared object characterised by the given di_handle. Asserts + if the handle is invalid. The caller is responsible for freeing + the array at some point. If 'arrays_only' is True, only + array-typed blocks are returned; otherwise blocks of all types are + returned. */ + +typedef + struct { + Addr addr; + SizeT szB; + Bool isVec; /* does block have an array type, or not? */ + HChar name[16]; /* first 15 chars of name (asciiz) */ + HChar soname[16]; /* first 15 chars of name (asciiz) */ + } + GlobalBlock; + +extern void* /* really, XArray* of GlobalBlock */ +VG_(di_get_global_blocks_from_dihandle) ( ULong di_handle, + Bool arrays_only ); + + /*====================================================================*/ /*=== Obtaining segment information ===*/ /*====================================================================*/ Modified: branches/PTRCHECK/include/pub_tool_tooliface.h =================================================================== --- branches/PTRCHECK/include/pub_tool_tooliface.h 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/include/pub_tool_tooliface.h 2008-09-09 08:49:35 UTC (rev 8591) @@ -471,15 +471,24 @@ These ones occur at startup, upon some signals, and upon some syscalls. - For the new_mem_brk and new_mem_stack_signal, the supplied ThreadId + For new_mem_brk and new_mem_stack_signal, the supplied ThreadId indicates the thread for whom the new memory is being allocated. + + For new_mem_startup and new_mem_mmap, the di_handle argument is a + handle which can be used to retrieve debug info associated with the + mapping or allocation (because it is of a file that Valgrind has + decided to read debug info from). If the value is zero, there is + no associated debug info. If the value exceeds zero, it can be + supplied as an argument to selected queries in m_debuginfo. */ void VG_(track_new_mem_startup) (void(*f)(Addr a, SizeT len, - Bool rr, Bool ww, Bool xx)); + Bool rr, Bool ww, Bool xx, + ULong di_handle)); void VG_(track_new_mem_stack_signal)(void(*f)(Addr a, SizeT len, ThreadId tid)); void VG_(track_new_mem_brk) (void(*f)(Addr a, SizeT len, ThreadId tid)); void VG_(track_new_mem_mmap) (void(*f)(Addr a, SizeT len, - Bool rr, Bool ww, Bool xx)); + Bool rr, Bool ww, Bool xx, + ULong di_handle)); void VG_(track_copy_mem_remap) (void(*f)(Addr from, Addr to, SizeT len)); void VG_(track_change_mem_mprotect) (void(*f)(Addr a, SizeT len, Modified: branches/PTRCHECK/include/pub_tool_wordfm.h =================================================================== --- branches/PTRCHECK/include/pub_tool_wordfm.h 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/include/pub_tool_wordfm.h 2008-09-09 08:49:35 UTC (rev 8591) @@ -86,8 +86,9 @@ /* Add (k,v) to fm. If a binding for k already exists, it is updated to map to this new v. In that case we should really return the - previous v so that caller can finalise it. Oh well. */ -void VG_(addToFM) ( WordFM* fm, UWord k, UWord v ); + previous v so that caller can finalise it. Oh well. Returns + True if a binding for k already exists. */ +Bool VG_(addToFM) ( WordFM* fm, UWord k, UWord v ); // Delete key from fm, returning associated key and val if found Bool VG_(delFromFM) ( WordFM* fm, @@ -97,6 +98,19 @@ Bool VG_(lookupFM) ( WordFM* fm, /*OUT*/UWord* keyP, /*OUT*/UWord* valP, UWord key ); +// Find the closest key values bracketing the given key, assuming the +// given key is not present in the map. minKey and maxKey are the +// minimum and maximum possible key values. The resulting bracket +// values are returned in *kMinP and *kMaxP. It follows that if fm is +// empty then the returned values are simply minKey and maxKey. +// +// If the operation was successful (that is, the given key is not +// present), True is returned. If the given key is in fact present, +// False is returned, and *kMinP and *kMaxP are undefined. +Bool VG_(findBoundsFM)( WordFM* fm, + /*OUT*/UWord* kMinP, /*OUT*/UWord* kMaxP, + UWord minKey, UWord maxKey, UWord key ); + // How many elements are there in fm? UWord VG_(sizeFM) ( WordFM* fm ); Modified: branches/PTRCHECK/memcheck/mc_main.c =================================================================== --- branches/PTRCHECK/memcheck/mc_main.c 2008-09-09 08:42:32 UTC (rev 8590) +++ branches/PTRCHECK/memcheck/mc_main.c 2008-09-09 08:49:35 UTC (rev 8591) @@ -3654,7 +3654,8 @@ } static -void mc_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx ) +void mc_new_mem_startup( Addr a, SizeT len, + Bool rr, Bool ww, Bool xx, ULong di_handle ) { /* Ignore the permissions, just make it defined. Seems to work... */ // Because code is defined, initialised variables get put in the data @@ -3673,7 +3674,8 @@ } static -void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx ) +void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx, + ULong di_handle ) { MC_(make_mem_defined)(a, len); } |