|
[Valgrind-developers] valgrind: r8531 - in branches/SGCHECK:
coregrind coregrind/m_debuginfo include
From: <sv...@va...> - 2008-08-19 11:38:43
|
Author: sewardj
Date: 2008-08-19 12:38:51 +0100 (Tue, 19 Aug 2008)
New Revision: 8531
Log:
Extend the query side of m_debuginfo, so as to be able to extract
information on available stack and global variables, as in-scope
at a given program-counter value. Said information is obtained
from the Dwarf3 variable location/type information, of course.
Commit contains some fragments which are logically part of
r8529 (enhancement of the core-tool iface
events "new_mem_startup" and "new_mem_mmap"), but which cannot be
cleanly separated from the Dwarf3 var-info stuff because both
sets of changes are in the same source file.
Modified:
branches/SGCHECK/coregrind/m_debuginfo/d3basics.c
branches/SGCHECK/coregrind/m_debuginfo/debuginfo.c
branches/SGCHECK/coregrind/m_debuginfo/priv_d3basics.h
branches/SGCHECK/coregrind/m_debuginfo/priv_misc.h
branches/SGCHECK/coregrind/m_debuginfo/priv_storage.h
branches/SGCHECK/coregrind/m_debuginfo/priv_tytypes.h
branches/SGCHECK/coregrind/pub_core_debuginfo.h
branches/SGCHECK/include/pub_tool_debuginfo.h
Modified: branches/SGCHECK/coregrind/m_debuginfo/d3basics.c
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/d3basics.c 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/d3basics.c 2008-08-19 11:38:51 UTC (rev 8531)
@@ -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 )
@@ -674,6 +676,141 @@
}
+/* 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 >= 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/SGCHECK/coregrind/m_debuginfo/debuginfo.c
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/debuginfo.c 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/debuginfo.c 2008-08-19 11:38:51 UTC (rev 8531)
@@ -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;
@@ -479,14 +485,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];
@@ -512,12 +526,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);
@@ -539,13 +553,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. */
@@ -561,25 +575,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:
@@ -634,7 +648,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. */
@@ -665,48 +679,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;
}
@@ -1856,7 +1880,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
@@ -2012,7 +2035,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;
@@ -2186,6 +2209,372 @@
}
+//////////////////////////////////////////////////////////////////
+// //
+// 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);
+ 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/SGCHECK/coregrind/m_debuginfo/priv_d3basics.h
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/priv_d3basics.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/priv_d3basics.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -636,6 +636,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/SGCHECK/coregrind/m_debuginfo/priv_misc.h
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/priv_misc.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/priv_misc.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -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/SGCHECK/coregrind/m_debuginfo/priv_storage.h
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/priv_storage.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/priv_storage.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -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/SGCHECK/coregrind/m_debuginfo/priv_tytypes.h
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/priv_tytypes.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/priv_tytypes.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -152,9 +152,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/SGCHECK/coregrind/pub_core_debuginfo.h
===================================================================
--- branches/SGCHECK/coregrind/pub_core_debuginfo.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/pub_core_debuginfo.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -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/SGCHECK/include/pub_tool_debuginfo.h
===================================================================
--- branches/SGCHECK/include/pub_tool_debuginfo.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/include/pub_tool_debuginfo.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -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 ===*/
/*====================================================================*/
|