From: Julian Seward Date: Tue, 17 Oct 2006 01:39:30 +0000 (+0000) Subject: Merge r6132: X-Git-Tag: svn/VALGRIND_3_3_0~607 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ecb2ce653633bc349a6bff5e3044019b7026fd97;p=thirdparty%2Fvalgrind.git Merge r6132: Minor changes for redirection on AIX. The only significant change is that it now checks for, warns about and disallows, attempts to redirect to, or wrap with, a function for which no TOC pointer can be found, since that would be really asking for trouble (a segfault). git-svn-id: svn://svn.valgrind.org/valgrind/trunk@6269 --- diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c index a0bacf002c..693401c7cf 100644 --- a/coregrind/m_redir.c +++ b/coregrind/m_redir.c @@ -43,7 +43,7 @@ #include "pub_core_trampoline.h" #include "pub_core_transtab.h" #include "pub_core_tooliface.h" // VG_(needs).malloc_replacement -#include "pub_tool_machine.h" // VG_(fnptr_to_fnentry) +#include "pub_core_machine.h" // VG_(fnptr_to_fnentry) #include "pub_core_aspacemgr.h" // VG_(am_find_nsegment) #include "pub_core_clientstate.h" // VG_(client___libc_freeres_wrapper) #include "pub_core_demangle.h" // VG_(maybe_Z_demangle) @@ -269,6 +269,7 @@ static void* symtab_alloc(SizeT); static void symtab_free(void*); static HChar* symtab_strdup(HChar*); static Bool is_plausible_guest_addr(Addr); +static Bool is_aix5_glink_idiom(Addr); static void show_redir_state ( HChar* who ); static void show_active ( HChar* left, Active* act ); @@ -300,19 +301,23 @@ void generate_and_add_actives ( void VG_(redir_notify_new_SegInfo)( SegInfo* newsi ) { - Bool ok, isWrap; - Int i, nsyms; - Spec* specList; - Spec* spec; - TopSpec* ts; - TopSpec* newts; - HChar* sym_name; - Addr sym_addr; - HChar demangled_sopatt[N_DEMANGLED]; - HChar demangled_fnpatt[N_DEMANGLED]; - + Bool ok, isWrap; + Int i, nsyms; + Spec* specList; + Spec* spec; + TopSpec* ts; + TopSpec* newts; + HChar* sym_name; + Addr sym_addr, sym_toc; + HChar demangled_sopatt[N_DEMANGLED]; + HChar demangled_fnpatt[N_DEMANGLED]; + Bool check_ppcTOCs = False; const UChar* newsi_soname; +# if defined(VG_PLAT_USES_PPCTOC) + check_ppcTOCs = True; +# endif + vg_assert(newsi); newsi_soname = VG_(seginfo_soname)(newsi); vg_assert(newsi_soname != NULL); @@ -328,15 +333,23 @@ void VG_(redir_notify_new_SegInfo)( SegInfo* newsi ) nsyms = VG_(seginfo_syms_howmany)( newsi ); for (i = 0; i < nsyms; i++) { - VG_(seginfo_syms_getidx)( newsi, i, &sym_addr, NULL, &sym_name ); + VG_(seginfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc, + NULL, &sym_name ); ok = VG_(maybe_Z_demangle)( sym_name, demangled_sopatt, N_DEMANGLED, - demangled_fnpatt, N_DEMANGLED, &isWrap ); + demangled_fnpatt, N_DEMANGLED, &isWrap ); if (!ok) { /* It's not a full-scale redirect, but perhaps it is a load-notify fn? Let the load-notify department see it. */ handle_maybe_load_notifier( newsi_soname, sym_name, sym_addr ); continue; } + if (check_ppcTOCs && sym_toc == 0) { + /* This platform uses toc pointers, but none could be found + for this symbol, so we can't safely redirect/wrap to it. + Just skip it; we'll make a second pass over the symbols in + the following loop, and complain at that point. */ + continue; + } spec = symtab_alloc(sizeof(Spec)); vg_assert(spec); spec->from_sopatt = symtab_strdup(demangled_sopatt); @@ -352,6 +365,35 @@ void VG_(redir_notify_new_SegInfo)( SegInfo* newsi ) specList = spec; } + if (check_ppcTOCs) { + for (i = 0; i < nsyms; i++) { + VG_(seginfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc, + NULL, &sym_name ); + ok = VG_(maybe_Z_demangle)( sym_name, demangled_sopatt, N_DEMANGLED, + demangled_fnpatt, N_DEMANGLED, &isWrap ); + if (!ok) + /* not a redirect. Ignore. */ + continue; + if (sym_toc != 0) + /* has a valid toc pointer. Ignore. */ + continue; + + for (spec = specList; spec; spec = spec->next) + if (0 == VG_(strcmp)(spec->from_sopatt, demangled_sopatt) + && 0 == VG_(strcmp)(spec->from_fnpatt, demangled_fnpatt)) + break; + if (spec) + /* a redirect to some other copy of that symbol, which does have + a TOC value, already exists */ + continue; + + /* Complain */ + VG_(message)(Vg_DebugMsg, + "WARNING: no TOC ptr for redir/wrap to %s %s", + demangled_sopatt, demangled_fnpatt); + } + } + /* Ok. Now specList holds the list of specs from the SegInfo. Build a new TopSpec, but don't add it to topSpecs yet. */ newts = symtab_alloc(sizeof(TopSpec)); @@ -384,7 +426,7 @@ void VG_(redir_notify_new_SegInfo)( SegInfo* newsi ) generate_and_add_actives( specList, newts, ts->seginfo, ts ); } - + /* Case (2) */ for (ts = topSpecs; ts; ts = ts->next) { generate_and_add_actives( ts->specs, ts, @@ -445,7 +487,18 @@ void generate_and_add_actives ( of trashing the caches less. */ nsyms = VG_(seginfo_syms_howmany)( si ); for (i = 0; i < nsyms; i++) { - VG_(seginfo_syms_getidx)( si, i, &sym_addr, NULL, &sym_name ); + VG_(seginfo_syms_getidx)( si, i, &sym_addr, NULL, NULL, &sym_name ); + + /* On AIX, we cannot redirect calls to a so-called glink + function for reasons which are not obvious - something to do + with saving r2 across the call. Not a problem, as we don't + want to anyway; presumably it is the target of the glink we + need to redirect. Hence just spot them and ignore them. + They are always of a very specific (more or less + ABI-mandated) form. */ + if (is_aix5_glink_idiom(sym_addr)) + continue; + for (sp = specs; sp; sp = sp->next) { if (!sp->mark) continue; /* soname doesn't match */ @@ -785,6 +838,12 @@ void VG_(redir_initialise) ( void ) } +# elif defined(VGP_ppc32_aix5) + /* nothing so far */ + +# elif defined(VGP_ppc64_aix5) + /* nothing so far */ + # else # error Unknown platform # endif @@ -817,12 +876,48 @@ static HChar* symtab_strdup(HChar* str) in m_translate. */ static Bool is_plausible_guest_addr(Addr a) { - NSegment* seg = VG_(am_find_nsegment)(a); + NSegment const* seg = VG_(am_find_nsegment)(a); return seg != NULL && (seg->kind == SkAnonC || seg->kind == SkFileC) && (seg->hasX || seg->hasR); /* crude x86-specific hack */ } +/* A function which spots AIX 'glink' functions. A 'glink' function + is a stub function which has something to do with AIX-style dynamic + linking, and jumps to the real target (with which it typically + shares the same name). See also comment where this function is + used (above). */ +static Bool is_aix5_glink_idiom ( Addr sym_addr ) +{ +# if defined(VGP_ppc32_aix5) + UInt* w = (UInt*)sym_addr; + if (VG_IS_4_ALIGNED(w) + && is_plausible_guest_addr((Addr)(w+0)) + && is_plausible_guest_addr((Addr)(w+6)) + && (w[0] & 0xFFFF0000) == 0x81820000 /* lwz r12,func@toc(r2) */ + && w[1] == 0x90410014 /* stw r2,20(r1) */ + && w[2] == 0x800c0000 /* lwz r0,0(r12) */ + && w[3] == 0x804c0004 /* lwz r2,4(r12) */ + && w[4] == 0x7c0903a6 /* mtctr r0 */ + && w[5] == 0x4e800420 /* bctr */ + && w[6] == 0x00000000 /* illegal */) + return True; +# elif defined(VGP_ppc64_aix5) + UInt* w = (UInt*)sym_addr; + if (VG_IS_4_ALIGNED(w) + && is_plausible_guest_addr((Addr)(w+0)) + && is_plausible_guest_addr((Addr)(w+6)) + && (w[0] & 0xFFFF0000) == 0xE9820000 /* ld r12,func@toc(r2) */ + && w[1] == 0xF8410028 /* std r2,40(r1) */ + && w[2] == 0xE80C0000 /* ld r0,0(r12) */ + && w[3] == 0xE84C0008 /* ld r2,8(r12) */ + && w[4] == 0x7c0903a6 /* mtctr r0 */ + && w[5] == 0x4e800420 /* bctr */ + && w[6] == 0x00000000 /* illegal */) + return True; +# endif + return False; +} /*------------------------------------------------------------*/ /*--- NOTIFY-ON-LOAD FUNCTIONS ---*/ @@ -866,7 +961,7 @@ void handle_maybe_load_notifier( const UChar* soname, static void show_spec ( HChar* left, Spec* spec ) { VG_(message)(Vg_DebugMsg, - "%s%18s %30s %s-> 0x%08llx", + "%s%25s %30s %s-> 0x%08llx", left, spec->from_sopatt, spec->from_fnpatt, spec->isWrap ? "W" : "R", @@ -884,7 +979,7 @@ static void show_active ( HChar* left, Active* act ) ok = VG_(get_fnname_w_offset)(act->to_addr, name2, 64); if (!ok) VG_(strcpy)(name2, "???"); - VG_(message)(Vg_DebugMsg, "%s0x%08llx (%10s) %s-> 0x%08llx %s", + VG_(message)(Vg_DebugMsg, "%s0x%08llx (%20s) %s-> 0x%08llx %s", left, (ULong)act->from_addr, name1, act->isWrap ? "W" : "R", diff --git a/include/pub_tool_redir.h b/include/pub_tool_redir.h index f3fc471318..21f3c30ab8 100644 --- a/include/pub_tool_redir.h +++ b/include/pub_tool_redir.h @@ -136,8 +136,10 @@ _ --> Zu (underscore) - --> Zh (hyphen) (space) --> Zs (space) - @ -> ZA (at) + @ --> ZA (at) Z --> ZZ (Z) + ( --> ZL (left) + ) --> ZR (right) Everything else is left unchanged. */ @@ -146,11 +148,16 @@ changed accordingly. NOTE: duplicates I_{WRAP,REPLACE}_SONAME_FNNAME_Z{U,Z} in valgrind.h. */ -#define VG_REPLACE_FUNCTION_ZU(soname,fnname) _vgrZU_##soname##_##fnname -#define VG_REPLACE_FUNCTION_ZZ(soname,fnname) _vgrZZ_##soname##_##fnname +/* Use an extra level of macroisation so as to ensure the soname/fnname + args are fully macro-expanded before pasting them together. */ +#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd + +#define VG_REPLACE_FUNCTION_ZU(soname,fnname) VG_CONCAT4(_vgrZU_,soname,_,fnname) +#define VG_REPLACE_FUNCTION_ZZ(soname,fnname) VG_CONCAT4(_vgrZZ_,soname,_,fnname) + +#define VG_WRAP_FUNCTION_ZU(soname,fnname) VG_CONCAT4(_vgwZU_,soname,_,fnname) +#define VG_WRAP_FUNCTION_ZZ(soname,fnname) VG_CONCAT4(_vgwZZ_,soname,_,fnname) -#define VG_WRAP_FUNCTION_ZU(soname,fnname) _vgwZU_##soname##_##fnname -#define VG_WRAP_FUNCTION_ZZ(soname,fnname) _vgwZZ_##soname##_##fnname #endif // __PUB_TOOL_REDIR_H