|
From: <sv...@va...> - 2005-12-04 21:55:28
|
Author: sewardj
Date: 2005-12-04 21:55:24 +0000 (Sun, 04 Dec 2005)
New Revision: 5282
Log:
Dump of work in progress (does not compile).
Modified:
branches/FNWRAP/coregrind/m_debuginfo/priv_symtab.h
branches/FNWRAP/coregrind/m_redir.c
branches/FNWRAP/coregrind/pub_core_redir.h
branches/FNWRAP/include/pub_tool_debuginfo.h
Modified: branches/FNWRAP/coregrind/m_debuginfo/priv_symtab.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/FNWRAP/coregrind/m_debuginfo/priv_symtab.h 2005-12-04 19:33:=
03 UTC (rev 5281)
+++ branches/FNWRAP/coregrind/m_debuginfo/priv_symtab.h 2005-12-04 21:55:=
24 UTC (rev 5282)
@@ -164,7 +164,8 @@
=20
=20
/* A structure which contains information pertaining to one mapped
- text segment. (typedef in tool.h) */
+ text segment. This type is exported only abstractly - in
+ pub_tool_debuginfo.h. */
struct _SegInfo {
struct _SegInfo* next; /* list of SegInfos */
=20
Modified: branches/FNWRAP/coregrind/m_redir.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/FNWRAP/coregrind/m_redir.c 2005-12-04 19:33:03 UTC (rev 5281=
)
+++ branches/FNWRAP/coregrind/m_redir.c 2005-12-04 21:55:24 UTC (rev 5282=
)
@@ -44,53 +44,497 @@
#include "pub_core_transtab.h"
#include "pub_core_tooliface.h" // VG_(needs).malloc_replacement
=20
-
/*------------------------------------------------------------*/
-/*--- General purpose redirection. ---*/
+/*--- Semantics ---*/
/*------------------------------------------------------------*/
=20
+/* The redirector holds two pieces of state:
+
+ Specs - a set of (soname pattern, fnname pattern) -> redir addr
+ Active - a set of orig addr -> redir addr
+
+ Active is the currently active set of bindings that the translator
+ consults. Specs is the current set of specifications as harvested
+ from reading symbol tables of the currently loaded objects.
+
+ Active is a pure function of Specs and the current symbol table
+ state (maintained by m_debuginfo). Call the latter SyminfoState.
+
+ Therefore whenever either Specs or SyminfoState changes, Active
+ must be recomputed. [Inefficient if done naively, but this is a
+ spec].
+
+ Active is computed as follows:
+
+ Active =3D empty
+ for spec in Specs {
+ sopatt =3D spec.soname pattern
+ fnpatt =3D spec.fnname pattern
+ redir =3D spec.redir addr
+ for so matching sopatt in SyminfoState {
+ for fn matching fnpatt in fnnames_of(so) {
+ &fn -> redir is added to Active
+ }
+ }
+ }
+
+ [as an implementation detail, when a binding (orig -> redir) is
+ deleted from Active as a result of recomputing it, then all
+ translations intersecting redir must be deleted. However, this is
+ not part of the spec].
+
+ [Active also depends on where the aspacemgr has decided to put all
+ the pieces of code -- that affects the "orig addr" and "redir addr"
+ values.]
+
+ ---------------------
+
+ That completes the spec, apart from one difficult issue: duplicates.
+
+ Clearly we must impose the requirement that domain(Active) contains
+ no duplicates. The difficulty is how to constrain Specs enough to
+ avoid getting into that situation. It's easy to write specs which
+ could cause conflicting bindings in Active, eg:
+
+ (libpthread.so, pthread_mutex_lock) -> a1
+ (libpthread.so, pthread_*) -> a2
+
+ for a1 !=3D a2. Or even hairier:
+
+ (libpthread.so, pthread_mutex_*) -> a1
+ (libpthread.so, pthread_*_lock) -> a2
+
+ I can't think of any sane way of detecting when an addition to
+ Specs would generate conflicts. However, considering we don't
+ actually want to have a system that allows this, I propose this:
+ all changes to Specs are acceptable. But, when recomputing Active
+ following the change, if the same orig is bound to more than one
+ redir, then all bindings for orig are thrown out (of Active) and a
+ warning message printed. That's pretty much what we have at
+ present anyway (warning, but no throwout; instead just keep the
+ first).
+
+ =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
+ =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
+ Incremental implementation:
+
+ When a new SegInfo appears:
+ - it may be the source of new specs
+ - it may be the source of new matches for existing specs
+ Therefore:
+
+ - (new Specs x existing SegInfos): scan all symbols in the new=20
+ SegInfo to find new specs. Each of these needs to be compared=20
+ against all symbols in all the existing SegInfos to generate=20
+ new actives.
+ =20
+ - (existing Specs x new SegInfo): scan all symbols in the SegInfo,
+ trying to match them to any existing specs, also generating
+ new actives.
+
+ - (new Specs x new SegInfo): scan all symbols in the new SegInfo,
+ trying to match them against the new specs, to generate new
+ actives.
+
+ - Finally, add new new specs to the current set of specs.
+
+ When adding a new active (s,d) to the Actives:
+ lookup s in Actives
+ if already bound to d, ignore
+ if already bound to something other than d, complain loudly and =
ignore
+ else add (s,d) to Actives
+ and discard (s,1) and (d,1) (maybe overly conservative)
+
+ When a SegInfo disappears:
+ - delete all specs acquired from the seginfo
+ - delete all actives derived from the just-deleted specs
+ - if each active (s,d) deleted, discard (s,1) and (d,1)
+*/
+
#define TRACE_REDIR(format, args...) \
if (VG_(clo_trace_redir)) { VG_(message)(Vg_DebugMsg, format, ## args=
); }
=20
-/*
- wraps and redirections, indexed by from_addr
+/*------------------------------------------------------------*/
+/*--- REDIRECTION SPECIFICATIONS ---*/
+/*------------------------------------------------------------*/
=20
- Redirection and wrapping are two distinct mechanisms which Valgrind
- can use to change the client's control flow.
+/* A specification of a redirection we want to do. Note that because
+ both the "from" soname and function name may contain wildcards, the
+ spec can match an arbitrary number of times. */
+typedef
+ struct _Spec {
+ struct _Spec* next; /* linked list */
+ HChar* from_sopatt; /* from soname pattern */
+ const Char* from_fnpatt; /* from fnname pattern */
+ Addr to_addr; /* where redirecting to */
+ Bool mark; /* transient temporary used during matching */
+ }
+ Spec;
=20
- Redirection intercepts a call to a client function, and re-points it
- to a new piece of code (presumably functionally equivalent). The
- original code is never run.
+/* Top-level data structure. It contains a pointer to a SegInfo and
+ also a list of the specs harvested from that SegInfo. Note that
+ seginfo is allowed to be NULL, meaning that the specs are
+ pre-loaded ones at startup and are not associated with any
+ particular seginfo. */
+typedef
+ struct _TopSpec {
+ struct _TopSpec* next; /* linked list */
+ SegInfo* seginfo; /* symbols etc */
+ Spec* specs; /* specs pulled out of seginfo */
+ Bool mark; /* transient temporary used during deletion */
+ }
+ TopSpec;
=20
- Wrapping does call the client's original code, but calls "before"
- and "after" functions which can inspect (and perhaps modify) the
- function's arguments and return value.
- */
-struct _CodeRedirect {
- Addr from_addr; /* old addr -- MUST BE THE FIRST WORD! */
+/* This is the top level list of redirections. m_debuginfo maintains
+ a list of SegInfos, and the idea here is to maintain a list with
+ the same number of elements (in fact, with one more element, so as
+ to record abovementioned preloaded specifications.) */
+static TopSpec* topSpecs =3D NULL;
=20
- enum redir_type {
- R_REDIRECT, /* plain redirection */
- R_WRAPPER, /* wrap with valgrind-internal code */
- R_CLIENT_WRAPPER, /* wrap with client-side code */
- } type;
- =20
- const Char *from_lib; /* library qualifier pattern */
- const Char *from_sym; /* symbol */
=20
- Addr to_addr; /* used for redirection -- new addr */
- const FuncWrapper *wrapper; /* used for wrapping */
+/*------------------------------------------------------------*/
+/*--- CURRENTLY ACTIVE REDIRECTIONS ---*/
+/*------------------------------------------------------------*/
=20
- CodeRedirect *next; /* next pointer on unresolved list */
-};
+/* Represents a currently active binding. If either parent_spec or
+ parent_sym is NULL, then this binding was hardwired at startup and
+ should not be deleted. Same is true if either parent's seginfo
+ field is NULL. */
+typedef
+ struct {
+ Addr from_addr; /* old addr -- MUST BE THE FIRST WORD! */
+ Addr to_addr; /* where redirecting to */
+ TopSpec* parent_spec; /* the TopSpec which supplied the Spec */
+ TopSpec* parent_sym; /* the TopSpec which supplied the symbol */
+ }
+ Active;
=20
-static OSet* resolved_redirs;
+/* The active set is a fast lookup table */
+static OSet* activeSet =3D NULL;
=20
-// We use a linked list here rather than an OSet, because we want to
-// traverse it and possibly remove elements as we look at them. OSet
-// doesn't support this very well.
-static CodeRedirect *unresolved_redirs =3D NULL;
+static void maybe_add_active ( Active /*by value; callee copies*/ );
=20
+
+/*------------------------------------------------------------*/
+/*--- NOTIFICATIONS ---*/
+/*------------------------------------------------------------*/
+
+/* Notify m_redir of the arrival of a new SegInfo. This is fairly
+ complex, but the net effect is to (1) add a new entry to the
+ topspecs list, and (2) figure out what new binding are now active,
+ and, as a result, add them to the actives mapping. */
+
+#define N_DEMANGLED 256
+
+void VG_(redir_notify_new_SegInfo)( SegInfo* newsi )
+{
+ TopSpec* ts, newts;
+ HChar* sym_name;
+ UInt sym_size;
+ Addr sym_addr;
+ HChar demangled_sopatt[N_DEMANGLED];
+ HChar demangled_fnpatt[N_DEMANGLED];
+
+ vg_assert(newsi);
+
+ /* stay sane: we don't already have this. */
+ for (ts =3D topSpecs; ts; ts =3D ts->next)
+ vg_assert(ts->seginfo !=3D newsi);
+
+ /* scan this SegInfo's symbol table, pulling out and demangling
+ any specs found */
+
+ specList =3D NULL; /* the spec list we're building up */
+
+ nsyms =3D VG_(seginfo_syms_howmany)( newsi );
+ for (i =3D 0; i < nsyms; i++) {
+ VG_(seginfo_syms_getidx)( newsi, i, &sym_addr, NULL, &sym_name );
+ ok =3D VG_(maybe_Z_demangle)( sym_name, demangled_sopatt, N_DEMANG=
LED,
+ demangled_fnpatt, N_DEMANGLED );
+ if (!ok) continue;
+ spec =3D symtab_alloc(sizeof(Spec));
+ vg_assert(spec);
+ spec->from_sopatt =3D symtab_strdup(demangled_sopatt);
+ spec->from_fnpatt =3D symtab_strdup(demangled_fnpatt);
+ vg_assert(spec->from_sopatt);
+ vg_assert(spec->from_fnpatt);
+ spec->to_addr =3D sym_addr;
+ /* check we're not adding manifestly stupid destinations */
+ vg_assert(is_plausible_guest_addr(sym_addr));
+ spec->next =3D specList;
+ spec->mark =3D False; /* not significant */
+ specList =3D spec;
+ }
+
+ /* Ok. Now specList holds the list of specs from the SegInfo.=20
+ Build a new TopSpec, but don't add it to topSpecs yet. */
+ newts =3D symtab_alloc(sizeof(TopSpec));
+ vg_assert(newts);
+ newts->next =3D NULL; /* not significant */
+ newts->seginfo =3D newsi;
+ newts->specs =3D specList;
+ newts->mark =3D False; /* not significant */
+
+ /* We now need to augment the active set with the following partial
+ cross product:
+
+ (1) actives formed by matching the new specs in specList against
+ all symbols currently listed in topSpecs
+
+ (2) actives formed by matching the new symbols in newsi against
+ all specs currently listed in topSpecs
+
+ (3) actives formed by matching the new symbols in newsi against
+ the new specs in specList
+
+ This is necessary in order to maintain the invariant that
+ Actives contains all bindings generated by matching ALL specs in
+ topSpecs against ALL symbols in topSpecs (that is, a cross
+ product of ALL known specs against ALL known symbols).
+ */
+ /* Case (1) */
+ for (ts =3D topSpecs; ts; ts =3D ts->next) {
+ if (ts->seginfo)
+ generate_and_add_actives( specList,newts, ts->seginfo );
+ }
+=09
+ /* Case (2) */
+ for (ts =3D topSpecs; ts; ts =3D ts->next) {
+ generate_and_add_actives( ts->specs,ts, newsi );
+ }
+
+ /* Case (3) */
+ generate_and_add_actives( specList,newts, newsi );
+
+ /* Finally, add the new TopSpec. */
+ newts->next =3D topSpecs;
+ topSpecs =3D newts;
+}
+
+#undef N_DEMANGLED
+
+
+/* Do one element of the basic cross product: add to the active set,
+ all matches resulting from comparing all the given specs against
+ all the symbols in the given seginfo. If a conflicting binding
+ would thereby arise, don't add it, but do complain. */
+
+static=20
+void generate_and_add_actives ( Spec* specs, void* parent_topspec,
+ SegInfo* si )
+{
+ Spec* sp;
+ Bool anyMark;
+ Active act;
+
+ /* First figure out which of the specs match the seginfo's
+ soname. */
+ anyMark =3D False;
+ for (sp =3D specs; sp; sp =3D sp->next) {
+ sp->mark =3D VG_(string_match)( sp->from_sopatt, si->soname );
+ anyMark =3D anyMark || sp->mark;
+ }
+
+ /* shortcut: if none of the sonames match, there will be no bindings.=
*/
+ if (!anyMark)
+ return;
+
+ /* Iterate outermost over the symbols in the seginfo, in the hope
+ of trashing the caches less. */
+ nsyms =3D VG_(seginfo_syms_howmany)( si );
+ for (i =3D 0; i < nsyms; i++) {
+ VG_(seginfo_syms_getidx)( si, i, &sym_addr, NULL, &sym_name );
+ for (sp =3D specs; sp; sp =3D sp->next) {
+ if (!sp->mark)
+ continue; /* soname doesn't match */
+ if (VG_(string_match)( sp->from_fnpatt, sym_name )) {
+ /* got a new binding. Add to collection. */
+ act.from_addr =3D sym_addr;
+ act.to_addr =3D sp->to_addr;
+ act.parent_spec =3D parent_topspec;
+ act.parent_sym =3D si;
+ maybe_add_active( act );
+ }
+ }
+ }
+}
+
+
+/* Add an act (passed by value; is copied here) and deal with
+ conflicting bindings. */
+static void add_to_active ( Active act )
+{
+ Active* old =3D VG_(OSet_Lookup)( activeSet, &act.from_addr );
+ if (old) {
+ /* Dodgy. Conflicting binding. */
+ vg_assert(old->from_addr =3D=3D act.from_addr);
+ if (old->to_addr !=3D act.to_addr) {
+ /* COMPLAIN */
+ /* we have to ignore it -- otherwise activeSet would contain
+ conflicting bindings. */
+ } else {
+ /* This appears to be a duplicate of an existing binding.
+ Safe(ish) -- ignore. */
+ /* COMPLAIN if new and old parents differ */
+ }
+ } else {
+ Active* a =3D VG_(OSet_AllocNode)(active, sizeof(Active));
+ vg_assert(a);
+ *a =3D act;
+ VG_(OSet_Insert)(activeSet, a);
+ }
+}
+
+
+/* Notify m_redir of the deletion of a SegInfo. This is relatively
+ simple -- just get rid of all actives derived from it, and free up
+ the associated list elements. */
+
+void VG_(redir_notify_delete_SegInfo)( SegInfo* delsi )
+{
+ TopSpec* ts;
+ OSet* tmpSet;
+
+ vg_assert(delsi);
+
+ /* Search for it. */
+ for (ts =3D topSpecs; ts; ts =3D ts->next)
+ if (ts->seginfo =3D=3D delsi)
+ break;
+
+ vg_assert(ts); /* else we don't have the deleted SegInfo */
+
+ /* Traverse the actives, copying the addresses of those we intend
+ to delete into tmpSet. */
+ tmpSet =3D VG_(OSet_Create, 0/*keyOff*/, NULL/*fastCmp*/,
+ symtab_alloc, symtab_free);
+
+ ts->mark =3D True;
+
+ VG_(OSet_ResetIter)( activeSet );
+ while ( (act =3D VG_(OSet_Next)(activeSet)) ) {
+ delMe =3D act->parent_spec !=3D NULL
+ && act->parent_sym !=3D NULL
+ && act->parent_spec->seginfo !=3D NULL
+ && act->parent_sym->seginfo !=3D NULL
+ && (act->parent_spec->mark || act->parent_sym->mark);
+ if (delMe) {
+ addrP =3D VG_(OSet_AllocNode)( tmpSet, sizeof(Addr) );
+ *addrP =3D act->from_addr;
+ VG_(OSet_Insert)( tmpSet, addrP );
+ }
+ }
+
+ /* Now traverse tmpSet, deleting corresponding elements in
+ activeSet. */
+ VG_(OSet_ResetIter)( tmpSet );
+ while ( (addrP =3D VG_(OSet_Next)(tmpSet)) ) {
+ VG_(OSet_Remove)( activeSet, *addrP );
+ VG_(OSet_FreeNode)( activeSet, *addrP );
+ }
+
+ VG_(OSet_Destroy)( tmpSet );
+}
+
+
+//////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////
+
+static void* symtab_alloc(SizeT n)
+{
+ return VG_(arena_malloc)(VG_AR_SYMTAB, n);
+}
+
+static void symtab_free(void* p)
+{
+ return VG_(arena_free)(VG_AR_SYMTAB, p);
+}
+
+/* Initialise the redir system, and create the initial Spec list and
+ for amd64-linux a couple of permanent active mappings. The initial
+ Specs are not converted into Actives yet, on the (checked)
+ assumption that no SegInfos have so far been created, and so when
+ they are created, that will happen. */
+
+void VG_(redir_init) ( void )
+{
+ vg_assert( VG_(next_seginfo)(NULL) =3D=3D NULL );
+
+ // Initialise spec list.
+ specs =3D NULL;
+
+ // Initialise active mapping.
+ active =3D VG_(OSet_Create)(offsetof(Active, from_addr),
+ NULL, // Use fast comparison
+ symtab_alloc,
+ symtab_free);
+
+ // The rest of this function just adds initial Specs. =20
+
+# if defined(VGP_x86_linux)
+ /* Redirect _dl_sysinfo_int80, which is glibc's default system call
+ routine, to our copy so that the special sysinfo unwind hack in
+ m_stacktrace.c will kick in. */
+ add_to_specs(
+ Spec{NULL,=20
+ "soname:ld-linux.so.2", "_dl_sysinfo_int80",
+ (Addr)&VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80),
+ NULL}
+ );
+ /* If we're using memcheck, use this intercept right from the
+ start, otherwise ld.so (glibc-2.3.5) makes a lot of noise. */
+ if (0=3D=3DVG_(strcmp)("Memcheck", VG_(details).name)) {
+ add_to_specs(
+ Spec{NULL,
+ "soname:ld-linux.so.2", "index",
+ (Addr)&VG_(x86_linux_REDIR_FOR_index),
+ NULL}
+ );
+ }
+
+# elif defined(VGP_amd64_linux)
+ /* Redirect vsyscalls to local versions */
+ add_to_actives(
+ 0xFFFFFFFFFF600000ULL,
+ (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)=20
+ );
+ add_to_actives(=20
+ 0xFFFFFFFFFF600400ULL,
+ (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)=20
+ );
+
+# elif defined(VGP_ppc32_linux)
+ /* If we're using memcheck, use these intercepts right from
+ the start, otherwise ld.so makes a lot of noise. */
+ if (0=3D=3DVG_(strcmp)("Memcheck", VG_(details).name)) {
+
+ add_to_specs(
+ Spec{NULL,
+ "soname:ld.so.1", "strlen",
+ (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen),
+ NULL}
+ ); =20
+ add_to_specs(
+ Spec{NULL,
+ "soname:ld.so.1", "strcmp",
+ (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp),
+ NULL}
+ );
+
+ }
+
+# elif defined(VGP_ppc64_linux)
+ // we'll have to stick some godawful hacks in here, no doubt
+
+# else
+# error Unknown platform
+# endif
+}
+
+
+//////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////
+
static Bool soname_matches(const Char *pattern, const Char* soname)
{
// pattern must start with "soname:"
@@ -103,24 +547,17 @@
return VG_(string_match)(pattern + 7, soname);
}
=20
-Bool VG_(is_resolved)(const CodeRedirect *redir)
-{
- return redir->from_addr !=3D 0;
-}
-
// Prepends redir to the unresolved list.
-static void add_redir_to_unresolved_list(CodeRedirect *redir)
+static void add_redir_to_unresolved_list(Spec *redir)
{
- redir->next =3D unresolved_redirs;
- unresolved_redirs =3D redir;
+ redir->next =3D specs;
+ specs =3D redir;
}
=20
-static void add_redir_to_resolved_list(CodeRedirect *redir, Bool need_di=
scard)
+static void add_redir_to_resolved_list(Spec *redir, Bool need_discard)
{
vg_assert(redir->from_addr);
=20
- switch (redir->type) {
- case R_REDIRECT: {
TRACE_REDIR(" redir resolved (%s:%s=3D%p -> %p)",=20
redir->from_lib, redir->from_sym, redir->from_addr,
redir->to_addr);
@@ -154,8 +591,8 @@
// This entails a possible double OSet lookup -- one for Contains(=
),
// one for Insert(). If we had OSet_InsertIfNonDup() we could do =
it
// with one lookup.
- if ( ! VG_(OSet_Contains)(resolved_redirs, &redir->from_addr) ) {
- VG_(OSet_Insert)(resolved_redirs, redir);
+ if ( ! VG_(OSet_Contains)(active, &redir->from_addr) ) {
+ VG_(OSet_Insert)(active, redir);
} else {
TRACE_REDIR(" redir %s:%s:%p->%p duplicated\n",
redir->from_lib, redir->from_sym, redir->from_addr,
@@ -166,28 +603,10 @@
// XXX leak?
//VG_(arena_free)(VG_AR_SYMTAB, redir);
}
- break;
- }
-
- case R_WRAPPER:
- TRACE_REDIR(" wrapper resolved (%s:%s=3D%p -> wrapper)",
- redir->from_lib, redir->from_sym, redir->from_addr);
-
- vg_assert(redir->wrapper);
-
- /* XXX redir leaked */
- //VG_(wrap_function)(redir->from_addr, redir->wrapper);
- break;
-
- case R_CLIENT_WRAPPER:
- vg_assert(redir->wrapper);
- VG_(core_panic)("not implemented");
- break;
- }
}
=20
// Resolve a redir using si if possible. Returns True if it succeeded.
-static Bool resolve_redir_with_seginfo(CodeRedirect *redir, const SegInf=
o *si)
+static Bool resolve_redir_with_seginfo(Spec *redir, const SegInfo *si)
{
Bool ok;
=20
@@ -207,7 +626,7 @@
// Resolve a redir using any SegInfo if possible. This is called whenev=
er
// a new sym-to-addr redir is created. It covers the case where a
// replacement function is loaded after its replacee.
-static Bool resolve_redir_with_existing_seginfos(CodeRedirect *redir)
+static Bool resolve_redir_with_existing_seginfos(Spec *redir)
{
const SegInfo *si;
=20
@@ -226,8 +645,8 @@
// where a replacee function is loaded after its replacement function.
void VG_(resolve_existing_redirs_with_seginfo)(SegInfo *si)
{
- CodeRedirect **prevp =3D &unresolved_redirs;
- CodeRedirect *redir, *next;
+ Spec **prevp =3D &specs;
+ Spec *redir, *next;
=20
TRACE_REDIR("Just loaded %s (soname=3D%s),",
VG_(seginfo_filename)(si), VG_(seginfo_soname)(si));
@@ -235,7 +654,7 @@
=20
// Visit each unresolved redir - if it becomes resolved, then
// move it from the unresolved list to the resolved list.
- for (redir =3D unresolved_redirs; redir !=3D NULL; redir =3D next) {
+ for (redir =3D specs; redir !=3D NULL; redir =3D next) {
next =3D redir->next;
=20
if (resolve_redir_with_seginfo(redir, si)) {
@@ -253,18 +672,15 @@
__attribute__((unused)) // It is used, but not on all platforms...
static void add_redirect_addr_to_addr( Addr from_addr, Addr to_addr )
{
- CodeRedirect* redir =3D VG_(OSet_AllocNode)(resolved_redirs,
- sizeof(CodeRedirect));
+ Spec* redir =3D VG_(OSet_AllocNode)(active,
+ sizeof(Spec));
vg_assert(0 !=3D from_addr && 0 !=3D to_addr);
=20
- redir->type =3D R_REDIRECT;
-
redir->from_lib =3D NULL;
redir->from_sym =3D NULL;
redir->from_addr =3D from_addr;
=20
redir->to_addr =3D to_addr;
- redir->wrapper =3D 0;
=20
TRACE_REDIR("REDIRECT addr to addr: %p to %p", from_addr, to_addr);
=20
@@ -277,16 +693,14 @@
const Char *from_lib, const Char *from_sym, Addr to_addr
)
{
- CodeRedirect* redir =3D VG_(OSet_AllocNode)(resolved_redirs,
- sizeof(CodeRedirect));
+ Spec* redir =3D VG_(OSet_AllocNode)(active,
+ sizeof(Spec));
vg_assert(from_lib && from_sym && 0 !=3D to_addr);
=20
- redir->type =3D R_REDIRECT;
redir->from_lib =3D VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
redir->from_sym =3D VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
redir->from_addr =3D 0;
redir->to_addr =3D to_addr;
- redir->wrapper =3D 0;
=20
TRACE_REDIR("REDIR sym to addr: %s:%s to %p", from_lib, from_sym, to_=
addr);
=20
@@ -301,37 +715,11 @@
}
}
=20
-CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sy=
m,
- const FuncWrapper *wrapper)
-{
- CodeRedirect* redir =3D VG_(OSet_AllocNode)(resolved_redirs,
- sizeof(CodeRedirect));
- redir->type =3D R_WRAPPER;
- redir->from_lib =3D VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
- redir->from_sym =3D VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
- redir->from_addr =3D 0;
- redir->to_addr =3D 0;
- redir->wrapper =3D wrapper;
- =20
- TRACE_REDIR("REDIR sym to wrapper: %s:%s to (%p,%p)",
- from_lib, from_sym, wrapper->before, wrapper->after);
-
- // Check against all existing segments to see if this redirection
- // can be resolved immediately. Then add it to the appropriate list.
- if (resolve_redir_with_existing_seginfos(redir)) {
- add_redir_to_resolved_list(redir, True);
- } else {
- add_redir_to_unresolved_list(redir);
- }
-
- return redir;
-}
-
/* If address 'a' is being redirected, return the redirected-to
address. */
Addr VG_(code_redirect)(Addr a)
{
- CodeRedirect* r =3D VG_(OSet_Lookup)(resolved_redirs, &a);
+ Spec* r =3D VG_(OSet_Lookup)(active, &a);
if (r =3D=3D NULL)
return a;
=20
@@ -352,67 +740,13 @@
=20
void VG_(setup_code_redirect_table) ( void )
{
- // Initialise resolved_redirs list.
- resolved_redirs =3D VG_(OSet_Create)(offsetof(CodeRedirect, from_addr=
),
- NULL, // Use fast comparison
- symtab_alloc,
- symtab_free);
+ // Initialise active list.
+ active =3D VG_(OSet_Create)(offsetof(Spec, from_addr),
+ NULL, // Use fast comparison
+ symtab_alloc,
+} symtab_free));
=20
-#if defined(VGP_x86_linux)
- /* Redirect _dl_sysinfo_int80, which is glibc's default system call
- routine, to our copy so that the special sysinfo unwind hack in
- m_stacktrace.c will kick in. */
- add_redirect_sym_to_addr(
- "soname:ld-linux.so.2", "_dl_sysinfo_int80",
- (Addr)&VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80)
- );
- /* If we're using memcheck, use this intercept right from the
- start, otherwise ld.so (glibc-2.3.5) makes a lot of noise. */
- if (0=3D=3DVG_(strcmp)("Memcheck", VG_(details).name)) {
- add_redirect_sym_to_addr(
- "soname:ld-linux.so.2", "index",
- (Addr)&VG_(x86_linux_REDIR_FOR_index)
- ); =20
- }
=20
-#elif defined(VGP_amd64_linux)
-
- /* Redirect vsyscalls to local versions */
- add_redirect_addr_to_addr(
- 0xFFFFFFFFFF600000ULL,
- (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)=20
- );
- add_redirect_addr_to_addr(=20
- 0xFFFFFFFFFF600400ULL,
- (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)=20
- );
-
-#elif defined(VGP_ppc32_linux)
-
- /* If we're using memcheck, use these intercepts right from
- the start, otherwise ld.so makes a lot of noise. */
- if (0=3D=3DVG_(strcmp)("Memcheck", VG_(details).name)) {
-
- add_redirect_sym_to_addr(
- "soname:ld.so.1", "strlen",
- (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen)
- ); =20
- add_redirect_sym_to_addr(
- "soname:ld.so.1", "strcmp",
- (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp)
- );
-
- }
-
-#elif defined(VGP_ppc64_linux)
-
- // we'll have to stick some godawful hacks in here, no doubt
-
-#else
-# error Unknown platform
-#endif
-}
-
/* Z-decode a symbol into library:func form, eg=20
=20
_vgi_libcZdsoZd6__ZdlPv --> libc.so.6:_ZdlPv
@@ -547,8 +881,9 @@
{
if (VG_(strcmp)(symbol, STR(VG_NOTIFY_ON_LOAD(freeres))) =3D=3D 0)
__libc_freeres_wrapper =3D addr;
-// else if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapp=
er))) =3D=3D 0)
-// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value=
));
+// else
+// if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) =3D=
=3D 0)
+// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value))=
;
else
vg_assert2(0, "unrecognised load notification function: %s", symbo=
l);
}
@@ -579,222 +914,155 @@
}
=20
=20
-//:: /*------------------------------------------------------------*/
-//:: /*--- General function wrapping. ---*/
-//:: /*------------------------------------------------------------*/
-//::=20
-//:: /*=20
-//:: TODO:
-//:: - hook into the symtab machinery
-//:: - client-side wrappers?
-//:: - better interfaces for before() functions to get to arguments
-//:: - handle munmap of code (dlclose())
-//:: - handle thread exit
-//:: - handle longjmp
-//:: */
-//:: struct callkey {
-//:: ThreadId tid; /* calling thread */
-//:: Addr esp; /* address of args on stack */
-//:: Addr eip; /* return address */
-//:: };
-//::=20
-//:: struct call_instance {
-//:: struct callkey key;
-//::=20
-//:: const FuncWrapper *wrapper;
-//:: void *nonce;
-//:: };
-//::=20
-//:: static inline Addr addrcmp(Addr a, Addr b)
-//:: {
-//:: if (a < b)
-//:: return -1;
-//:: else if (a > b)
-//:: return 1;
-//:: else=20
-//:: return 0;
-//:: }
-//::=20
-//:: static inline Int cmp(UInt a, UInt b)
-//:: {
-//:: if (a < b)
-//:: return -1;
-//:: else if (a > b)
-//:: return 1;
-//:: else=20
-//:: return 0;
-//:: }
-//::=20
-//:: static Int keycmp(const void *pa, const void *pb)
-//:: {
-//:: const struct callkey *a =3D (const struct callkey *)pa;
-//:: const struct callkey *b =3D (const struct callkey *)pb;
-//:: Int ret;
-//::=20
-//:: if ((ret =3D cmp(a->tid, b->tid)))
-//:: return ret;
-//::=20
-//:: if ((ret =3D addrcmp(a->esp, b->esp)))
-//:: return ret;
-//::=20
-//:: return addrcmp(a->eip, b->eip);
-//:: }
-//::=20
-//:: /* List of wrapped call invocations which are currently active */
-//:: static SkipList wrapped_frames =3D VG_SKIPLIST_INIT(struct call_ins=
tance, key, keycmp,=20
-//:: NULL, VG_AR_SYMTAB);
-//::=20
-//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, Th=
readId tid)
-//:: {
-//:: struct callkey key =3D { tid, argsp, retaddr };
-//::=20
-//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
-//:: }
-//::=20
-//:: static void wrapper_return(Addr retaddr);
-//::=20
-//:: /* Called from generated code via helper */
-//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
-//:: {
-//:: Addr retaddr =3D VG_RETADDR(tst->arch);
-//:: Addr argp =3D (Addr)&VG_FUNC_ARG(tst->arch, 0);
-//:: void *nonce =3D NULL;
-//:: Bool mf =3D VG_(my_fault);
-//:: VG_(my_fault) =3D True;
-//::=20
-//:: if (wrapper->before) {
-//:: va_list args =3D VG_VA_LIST(tst->arch);
-//:: nonce =3D (*wrapper->before)(args);
-//:: }
-//::=20
-//:: if (wrapper->after) {
-//:: /* If there's an after function, make sure it gets called */
-//:: struct call_instance *call;
-//::=20
-//:: call =3D find_call(retaddr, argp, tst->tid);
-//::=20
-//:: if (call !=3D NULL) {
-//:: /* Found a stale outstanding call; clean it up and recycle
-//:: the structure */
-//:: if (call->wrapper->after)
-//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
-//:: } else {
-//:: call =3D VG_(SkipNode_Alloc)(&wrapped_frames);
-//:: =20
-//:: call->key.tid =3D tst->tid;
-//:: call->key.esp =3D argp;
-//:: call->key.eip =3D retaddr;
-//::=20
-//:: VG_(SkipList_Insert)(&wrapped_frames, call);
-//::=20
-//:: wrapper_return(retaddr);
-//:: }
-//::=20
-//:: call->wrapper =3D wrapper;
-//:: call->nonce =3D nonce;
-//:: } else=20
-//:: vg_assert(nonce =3D=3D NULL);
-//::=20
-//:: VG_(my_fault) =3D mf;
-//:: }
-//::=20
-//:: /* Called from generated code via helper */
-//:: void VG_(wrap_after)(ThreadState *tst)
-//:: {
-//:: Addr EIP =3D VG_INSTR_PTR(tst->arch); /* instruction after call =
*/
-//:: Addr ESP =3D VG_STACK_PTR(tst->arch); /* pointer to args */
-//:: Word ret =3D VG_RETVAL(tst->arch); /* return value */
-//:: struct call_instance *call;
-//:: Bool mf =3D VG_(my_fault);
-//::=20
-//:: VG_(my_fault) =3D True;
-//:: call =3D find_call(EIP, ESP, tst->tid);
-//::=20
-//:: if (0)
-//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->ti=
d, call);
-//::=20
-//:: if (call !=3D NULL) {
-//:: if (call->wrapper->after)
-//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
-//::=20
-//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
-//:: VG_(SkipNode_Free)(&wrapped_frames, call);
-//:: }
-//:: VG_(my_fault) =3D mf;
-//:: }
-//::=20
-//::=20
-//:: struct wrapped_function {
-//:: Addr eip; /* eip of function entrypoint */
-//:: const FuncWrapper *wrapper;
-//:: };
-//::=20
-//:: struct wrapper_return {
-//:: Addr eip; /* return address */
-//:: };
-//::=20
-//:: /* A mapping from eip of wrapped function entrypoints to actual wra=
ppers */
-//:: static SkipList wrapped_functions =3D VG_SKIPLIST_INIT(struct wrapp=
ed_function, eip, VG_(cmp_Addr),
-//:: NULL, VG_AR_SYMTAB);
-//::=20
-//:: /* A set of EIPs which are return addresses for wrapped functions *=
/
-//:: static SkipList wrapper_returns =3D VG_SKIPLIST_INIT(struct wrapper=
_return, eip, VG_(cmp_Addr),
-//:: NULL, VG_AR_SYMTAB);
-//::=20
-//:: /* Wrap function starting at eip */
-//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
-//:: {
-//:: struct wrapped_function *func;
-//::=20
-//:: if (0)
-//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->befor=
e, wrapper->after);
-//::=20
-//:: func =3D VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
-//::=20
-//:: if (func =3D=3D NULL) {
-//:: func =3D VG_(SkipNode_Alloc)(&wrapped_functions);
-//:: VG_(invalidate_translations)(eip, 1, True);
-//::=20
-//:: func->eip =3D eip;
-//:: VG_(SkipList_Insert)(&wrapped_functions, func);
-//:: }
-//::=20
-//:: func->wrapper =3D wrapper;
-//:: }
-//::=20
-//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
-//:: {
-//:: struct wrapped_function *func =3D VG_(SkipList_Find_Exact)(&wrap=
ped_functions, &eip);
-//::=20
-//:: if (func)
-//:: return func->wrapper;
-//:: return NULL;
-//:: }
-//::=20
-//:: Bool VG_(is_wrapper_return)(Addr eip)
-//:: {
-//:: struct wrapper_return *ret =3D VG_(SkipList_Find_Exact)(&wrapper=
_returns, &eip);
-//::=20
-//:: return ret !=3D NULL;
-//:: }
-//::=20
-//:: /* Mark eip as being the return address of a wrapper, so that the
-//:: codegen will generate the appropriate call. */
-//:: void wrapper_return(Addr eip)
-//:: {
-//:: struct wrapper_return *ret;
-//::=20
-//:: if (VG_(is_wrapper_return)(eip))
-//:: return;
-//::=20
-//:: VG_(invalidate_translations)(eip, 1, True);
-//::=20
-//:: ret =3D VG_(SkipNode_Alloc)(&wrapper_returns);
-//:: ret->eip =3D eip;
-//::=20
-//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
-//:: }
+/*------------------------------------------------------------*/
+/*--- THE DEMANGLER ---*/
+/*------------------------------------------------------------*/
=20
+/* Demangle 'sym' into its soname and fnname parts, putting them in
+ the specified buffers. Returns a Bool indicating whether the
+ demangled failed or not. A failure can occur because the prefix
+ isn't recognised, the internal Z-escaping is wrong, or because one
+ or the other (or both) of the output buffers becomes full. */
+
+Bool VG_(maybe_Z_demangle) ( const HChar* sym,=20
+ /*OUT*/HChar* so, Int soLen,
+ /*OUT*/HChar* fn, Int fnLen )
+{
+# define EMITSO(ch) \
+ do { \
+ if (soi >=3D soLen) { \
+ so[soLen-1] =3D 0; oflow =3D True; \
+ } else { \
+ so[soi++] =3D ch; so[soi] =3D 0; \
+ } \
+ } while (0)
+# define EMITFN(ch) \
+ do { \
+ if (fni >=3D fnLen) { \
+ fn[fnLen-1] =3D 0; oflow =3D True; \
+ } else { \
+ fn[fni++] =3D ch; fn[fni] =3D 0; \
+ } \
+ } while (0)
+
+ vg_assert(solen > 0);
+ vg_assert(fnlen > 0);
+ error =3D False;
+ oflow =3D False;
+ soi =3D 0;
+ fni =3D 0;
+
+ valid =3D sym[0] =3D=3D '_'
+ && sym[1] =3D=3D 'v'
+ && sym[2] =3D=3D 'g'
+ && (sym[3] =3D=3D 'r' || sym[3] =3D=3D 'n')
+ && sym[4] =3D=3D 'Z'
+ && (sym[5] =3D=3D 'Z' || sym[5] =3D=3D 'U')
+ && sym[6] =3D=3D '_';
+ if (!valid)
+ return False;
+
+ fn_is_encoded =3D sym[5] =3D=3D 'Z';
+
+ /* Now scan the Z-encoded soname. */
+ i =3D 7;
+ while (True) {
+
+ if (sym[i] =3D=3D '_')
+ /* Found the delimiter. Move on to the fnname loop. */
+ break;
+
+ if (sym[i] =3D=3D 0) {
+ error =3D True;
+ goto out;
+ }
+
+ if (sym[i] !=3D 'Z') {
+ EMITSO(sym[i]);
+ i++;
+ continue;
+ }
+
+ /* We've got a Z-escape. */
+ i++;
+ switch (symbol[i]) {
+ case 'a': EMITSO('*'); break;
+ case 'p': EMITSO('+'); break;
+ case 'c': EMITSO(':'); break;
+ case 'd': EMITSO('.'); break;
+ case 'u': EMITSO('_'); break;
+ case 'h': EMITSO('-'); break;
+ case 's': EMITSO(' '); break;
+ case 'Z': EMITSO('Z'); break;
+ default: error =3D True; goto out;
+ }
+ i++;
+ }
+
+ vg_assert(sym[i] =3D=3D '_');
+ i++;
+
+ /* Now deal with the function name part. */
+ if (!fn_is_encoded) {
+
+ /* simple; just copy. */
+ while (True) {
+ if (sym[i] =3D=3D 0)
+ break;
+ EMITFN(sym[i]);
+ i++;
+ }
+ goto out;
+
+ }
+
+ /* else use a Z-decoding loop like with soname */
+ while (True) {
+
+ if (sym[i] =3D=3D 0)
+ break;
+
+ if (sym[i] !=3D 'Z') {
+ EMITFN(sym[i]);
+ i++;
+ continue;
+ }
+
+ /* We've got a Z-escape. */
+ i++;
+ switch (symbol[i]) {
+ case 'a': EMITFN('*'); break;
+ case 'p': EMITFN('+'); break;
+ case 'c': EMITFN(':'); break;
+ case 'd': EMITFN('.'); break;
+ case 'u': EMITFN('_'); break;
+ case 'h': EMITFN('-'); break;
+ case 's': EMITFN(' '); break;
+ case 'Z': EMITFN('Z'); break;
+ default: error =3D True; goto out;
+ }
+ i++;
+ }
+
+ out:
+ EMITSO(0);
+ EMITFN(0);
+
+ if (error) {
+ /* Something's wrong. Give up. */
+ VG_(message)(Vg_UserMsg, "m_redir: error demangling: %s", symbol);
+ return False;
+ }
+ if (oflow) {
+ /* It didn't fit. Give up. */
+ VG_(message)(Vg_UserMsg, "m_debuginfo: oflow demangling: %s", symb=
ol);
+ return False;
+ }
+
+ return True;
+}
+
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
Modified: branches/FNWRAP/coregrind/pub_core_redir.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/FNWRAP/coregrind/pub_core_redir.h 2005-12-04 19:33:03 UTC (r=
ev 5281)
+++ branches/FNWRAP/coregrind/pub_core_redir.h 2005-12-04 21:55:24 UTC (r=
ev 5282)
@@ -99,28 +99,28 @@
// This is currently not working(?) --njn
=20
/* Wrapping machinery */
-enum return_type {
- RT_RETURN,
- RT_LONGJMP,
- RT_EXIT,
-};
+//enum return_type {
+ // RT_RETURN,
+ // RT_LONGJMP,
+ // RT_EXIT,
+ //};
+//
+//typedef struct _FuncWrapper FuncWrapper;
+//struct _FuncWrapper {
+ // void *(*before)(va_list args);
+ // void (*after) (void *nonce, enum return_type, Word retval);
+ //};
+//
+//extern void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper);
+//extern const FuncWrapper *VG_(is_wrapped)(Addr eip);
+//extern Bool VG_(is_wrapper_return)(Addr eip);
=20
-typedef struct _FuncWrapper FuncWrapper;
-struct _FuncWrapper {
- void *(*before)(va_list args);
- void (*after) (void *nonce, enum return_type, Word retval);
-};
-
-extern void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper);
-extern const FuncWrapper *VG_(is_wrapped)(Addr eip);
-extern Bool VG_(is_wrapper_return)(Addr eip);
-
/* Primary interface for adding wrappers for client-side functions. */
-extern CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *=
from_sym,
- const FuncWrapper *wrapper);
+//extern CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char=
*from_sym,
+// const FuncWrapper *wrapper);
+//
+//extern Bool VG_(is_resolved)(const CodeRedirect *redir);
=20
-extern Bool VG_(is_resolved)(const CodeRedirect *redir);
-
#endif // __PUB_CORE_REDIR_H
=20
/*--------------------------------------------------------------------*/
Modified: branches/FNWRAP/include/pub_tool_debuginfo.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/FNWRAP/include/pub_tool_debuginfo.h 2005-12-04 19:33:03 UTC =
(rev 5281)
+++ branches/FNWRAP/include/pub_tool_debuginfo.h 2005-12-04 21:55:24 UTC =
(rev 5282)
@@ -102,13 +102,29 @@
is present or not. */
extern SegInfo* VG_(find_seginfo) ( Addr a );
=20
-extern const SegInfo* VG_(next_seginfo) ( const SegInfo *si );
+/* Fish bits out of SegInfos. */
extern Addr VG_(seginfo_start) ( const SegInfo *si );
extern SizeT VG_(seginfo_size) ( const SegInfo *si );
extern const UChar* VG_(seginfo_soname) ( const SegInfo *si );
extern const UChar* VG_(seginfo_filename) ( const SegInfo *si );
extern ULong VG_(seginfo_sym_offset)( const SegInfo *si );
=20
+/* Function for traversing the seginfo list. When called with NULL it
+ returns the first element; otherwise it returns the given element's
+ successor. */
+extern const SegInfo* VG_(next_seginfo) ( const SegInfo *si );
+
+/* Functions for traversing all the symbols in a SegInfo. _howmany
+ tells how many there are. _getidx retrieves the n'th, for n in 0
+ .. _howmany-1. You may not modify the function name thereby
+ acquired; if you want to do so, first strdup it. */
+extern Int VG_(seginfo_syms_howmany) ( const SegInfo *si );
+extern void VG_(seginfo_syms_getidx) ( const SegInfo *si,=20
+ Int idx,
+ /*OUT*/Addr* addr,
+ /*OUT*/UInt size,
+ /*OUT*/HChar** name );
+
typedef
enum {
Vg_SectUnknown,
|