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