--- valgrind/memcheck/mc_replace_strmem.c (revision 10919) +++ valgrind/memcheck/mc_replace_strmem.c (revision 10923) @@ -116,6 +116,7 @@ Bool is_overlap ( void* dst, const void* STRRCHR(VG_Z_LIBC_SONAME, strrchr) STRRCHR(VG_Z_LIBC_SONAME, rindex) #if defined(VGO_linux) +STRRCHR(VG_Z_LIBC_SONAME, __GI_strrchr) STRRCHR(VG_Z_LD_LINUX_SO_2, rindex) #elif defined(VGO_darwin) STRRCHR(VG_Z_DYLD, strrchr) @@ -140,6 +141,7 @@ STRRCHR(VG_Z_DYLD, rindex) STRCHR(VG_Z_LIBC_SONAME, strchr) STRCHR(VG_Z_LIBC_SONAME, index) #if defined(VGO_linux) +STRCHR(VG_Z_LIBC_SONAME, __GI_strchr) STRCHR(VG_Z_LD_LINUX_SO_2, strchr) STRCHR(VG_Z_LD_LINUX_SO_2, index) STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr) @@ -172,7 +174,9 @@ STRCHR(VG_Z_DYLD, index) } STRCAT(VG_Z_LIBC_SONAME, strcat) - +#if defined(VGO_linux) +STRCAT(VG_Z_LIBC_SONAME, __GI_strcat) +#endif #define STRNCAT(soname, fnname) \ char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \ @@ -257,6 +261,9 @@ STRLCAT(VG_Z_DYLD, strlcat) } STRNLEN(VG_Z_LIBC_SONAME, strnlen) +#if defined(VGO_linux) +STRNLEN(VG_Z_LIBC_SONAME, __GI_strnlen) +#endif // Note that this replacement often doesn't get used because gcc inlines @@ -274,6 +281,7 @@ STRNLEN(VG_Z_LIBC_SONAME, strnlen) STRLEN(VG_Z_LIBC_SONAME, strlen) #if defined(VGO_linux) +STRLEN(VG_Z_LIBC_SONAME, __GI_strlen) STRLEN(VG_Z_LD_LINUX_SO_2, strlen) STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen) #endif @@ -301,7 +309,9 @@ STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen } STRCPY(VG_Z_LIBC_SONAME, strcpy) -#if defined(VGO_darwin) +#if defined(VGO_linux) +STRCPY(VG_Z_LIBC_SONAME, __GI_strcpy) +#elif defined(VGO_darwin) STRCPY(VG_Z_DYLD, strcpy) #endif @@ -327,7 +337,9 @@ STRCPY(VG_Z_DYLD, strcpy) } STRNCPY(VG_Z_LIBC_SONAME, strncpy) -#if defined(VGO_darwin) +#if defined(VGO_linux) +STRNCPY(VG_Z_LIBC_SONAME, __GI_strncpy) +#elif defined(VGO_darwin) STRNCPY(VG_Z_DYLD, strncpy) #endif @@ -384,7 +396,9 @@ STRLCPY(VG_Z_DYLD, strlcpy) } STRNCMP(VG_Z_LIBC_SONAME, strncmp) -#if defined(VGO_darwin) +#if defined(VGO_linux) +STRNCMP(VG_Z_LIBC_SONAME, __GI_strncmp) +#elif defined(VGO_darwin) STRNCMP(VG_Z_DYLD, strncmp) #endif @@ -411,6 +425,7 @@ STRNCMP(VG_Z_DYLD, strncmp) STRCMP(VG_Z_LIBC_SONAME, strcmp) #if defined(VGO_linux) +STRCMP(VG_Z_LIBC_SONAME, __GI_strcmp) STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp) STRCMP(VG_Z_LD64_SO_1, strcmp) #endif @@ -557,6 +572,7 @@ MEMCMP(VG_Z_DYLD, bcmp) STPCPY(VG_Z_LIBC_SONAME, stpcpy) #if defined(VGO_linux) +STPCPY(VG_Z_LIBC_SONAME, __GI_stpcpy) STPCPY(VG_Z_LD_LINUX_SO_2, stpcpy) STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy) #elif defined(VGO_darwin) @@ -709,7 +725,9 @@ GLIBC232_STRCHRNUL(VG_Z_LIBC_SONAME, str } GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, rawmemchr) - +#if defined (VGO_linux) +GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, __GI___rawmemchr) +#endif /* glibc variant of strcpy that checks the dest is big enough. Copied from glibc-2.5/debug/test-strcpy_chk.c. */ --- valgrind/include/pub_tool_debuginfo.h (revision 10919) +++ valgrind/include/pub_tool_debuginfo.h (revision 10923) @@ -212,7 +212,8 @@ void VG_(DebugInfo_syms_getidx) ( const /*OUT*/Addr* tocptr, /*OUT*/UInt* size, /*OUT*/HChar** name, - /*OUT*/Bool* isText ); + /*OUT*/Bool* isText, + /*OUT*/Bool* isIFunc ); /* A simple enumeration to describe the 'kind' of various kinds of segments that arise from the mapping of object files. */ --- valgrind/coregrind/vg_preloaded.c (revision 10919) +++ valgrind/coregrind/vg_preloaded.c (revision 10923) @@ -47,12 +47,12 @@ #include "pub_core_debuginfo.h" // Needed for pub_core_redir.h #include "pub_core_redir.h" // For VG_NOTIFY_ON_LOAD +#if defined(VGO_linux) || defined(VGO_aix5) + /* --------------------------------------------------------------------- Hook for running __libc_freeres once the program exits. ------------------------------------------------------------------ */ -#if defined(VGO_linux) || defined(VGO_aix5) - void VG_NOTIFY_ON_LOAD(freeres)( void ); void VG_NOTIFY_ON_LOAD(freeres)( void ) { @@ -68,6 +68,31 @@ void VG_NOTIFY_ON_LOAD(freeres)( void ) *(int *)0 = 'x'; } +/* --------------------------------------------------------------------- + Wrapper for indirect functions which need to be redirected. + ------------------------------------------------------------------ */ + +void * VG_NOTIFY_ON_LOAD(ifunc_wrapper) (void); +void * VG_NOTIFY_ON_LOAD(ifunc_wrapper) (void) +{ + OrigFn fn; + Addr result = 0; + int res; + + /* Call the original indirect function and get it's result */ + VALGRIND_GET_ORIG_FN(fn); + CALL_FN_W_v(result, fn); + + /* Ask the valgrind core running on the real CPU (as opposed to this + code which runs on the emulated CPU) to update the redirection that + led to this function. This client request eventually gives control to + the function VG_(redir_add_ifunc_target) in m_redir.c */ + VALGRIND_DO_CLIENT_REQUEST(res, 0, + VG_USERREQ__ADD_IFUNC_TARGET, + fn.nraddr, result, 0, 0, 0); + return result; +} + #elif defined(VGO_darwin) /* --------------------------------------------------------------------- --- valgrind/coregrind/pub_core_clreq.h (revision 10919) +++ valgrind/coregrind/pub_core_clreq.h (revision 10923) @@ -50,6 +50,9 @@ typedef /* Internal equivalent of VALGRIND_PRINTF . */ VG_USERREQ__INTERNAL_PRINTF = 0x3103, + /* Add a target for an indirect function redirection. */ + VG_USERREQ__ADD_IFUNC_TARGET = 0x3104, + } Vg_InternalClientRequest; // Function for printing from code within Valgrind, but which runs on the --- valgrind/coregrind/m_debuginfo/debuginfo.c (revision 10919) +++ valgrind/coregrind/m_debuginfo/debuginfo.c (revision 10923) @@ -3435,14 +3435,16 @@ void VG_(DebugInfo_syms_getidx) ( const /*OUT*/Addr* tocptr, /*OUT*/UInt* size, /*OUT*/HChar** name, - /*OUT*/Bool* isText ) + /*OUT*/Bool* isText, + /*OUT*/Bool* isIFunc ) { vg_assert(idx >= 0 && idx < si->symtab_used); - if (avma) *avma = si->symtab[idx].addr; - if (tocptr) *tocptr = si->symtab[idx].tocptr; - if (size) *size = si->symtab[idx].size; - if (name) *name = (HChar*)si->symtab[idx].name; - if (isText) *isText = si->symtab[idx].isText; + if (avma) *avma = si->symtab[idx].addr; + if (tocptr) *tocptr = si->symtab[idx].tocptr; + if (size) *size = si->symtab[idx].size; + if (name) *name = (HChar*)si->symtab[idx].name; + if (isText) *isText = si->symtab[idx].isText; + if (isIFunc) *isIFunc = si->symtab[idx].isIFunc; } --- valgrind/coregrind/m_debuginfo/readelf.c (revision 10919) +++ valgrind/coregrind/m_debuginfo/readelf.c (revision 10923) @@ -214,7 +214,8 @@ Bool get_elf_symbol_info ( used on entry */ Bool* from_opd_out, /* ppc64-linux only: did we deref an .opd entry? */ - Bool* is_text_out /* is this a text symbol? */ + Bool* is_text_out, /* is this a text symbol? */ + Bool* is_ifunc /* is this a STT_GNU_IFUNC function ?*/ ) { Bool plausible; @@ -232,6 +233,7 @@ Bool get_elf_symbol_info ( *sym_size_out = (Int)sym->st_size; *sym_tocptr_out = 0; /* unknown/inapplicable */ *from_opd_out = False; + *is_ifunc = False; /* Figure out if we're interested in the symbol. Firstly, is it of the right flavour? */ @@ -243,6 +245,9 @@ Bool get_elf_symbol_info ( && (ELFXX_ST_TYPE(sym->st_info) == STT_FUNC || ELFXX_ST_TYPE(sym->st_info) == STT_OBJECT +#ifdef STT_GNU_IFUNC + || ELFXX_ST_TYPE(sym->st_info) == STT_GNU_IFUNC +#endif ); /* Work out the svma and bias for each section as it will appear in @@ -325,6 +330,14 @@ Bool get_elf_symbol_info ( *sym_avma_out += text_bias; } +# ifdef STT_GNU_IFUNC + /* Check for indirect functions. */ + if (*is_text_out + && ELFXX_ST_TYPE(sym->st_info) == STT_GNU_IFUNC) { + *is_ifunc = True; + } +# endif + # if defined(VGP_ppc64_linux) /* Allow STT_NOTYPE in the very special case where we're running on ppc64-linux and the symbol is one which the .opd-chasing hack @@ -570,7 +583,7 @@ void read_elf_symtab__normal( Char *sym_name, *sym_name_really; Int sym_size; Addr sym_tocptr; - Bool from_opd, is_text; + Bool from_opd, is_text, is_ifunc; DiSym risym; ElfXX_Sym *sym; @@ -602,13 +615,14 @@ void read_elf_symtab__normal( &sym_avma_really, &sym_size, &sym_tocptr, - &from_opd, &is_text)) { + &from_opd, &is_text, &is_ifunc)) { - risym.addr = sym_avma_really; - risym.size = sym_size; - risym.name = ML_(addStr) ( di, sym_name_really, -1 ); - risym.tocptr = sym_tocptr; - risym.isText = is_text; + risym.addr = sym_avma_really; + risym.size = sym_size; + risym.name = ML_(addStr) ( di, sym_name_really, -1 ); + risym.tocptr = sym_tocptr; + risym.isText = is_text; + risym.isIFunc = is_ifunc; vg_assert(risym.name != NULL); vg_assert(risym.tocptr == 0); /* has no role except on ppc64-linux */ ML_(addSym) ( di, &risym ); @@ -646,6 +660,7 @@ typedef Int size; Bool from_opd; Bool is_text; + Bool is_ifunc; } TempSym; @@ -671,7 +686,7 @@ void read_elf_symtab__ppc64_linux( Char *sym_name, *sym_name_really; Int sym_size; Addr sym_tocptr; - Bool from_opd, modify_size, modify_tocptr, is_text; + Bool from_opd, modify_size, modify_tocptr, is_text, is_ifunc; DiSym risym; ElfXX_Sym *sym; OSet *oset; @@ -713,7 +728,7 @@ void read_elf_symtab__ppc64_linux( &sym_avma_really, &sym_size, &sym_tocptr, - &from_opd, &is_text)) { + &from_opd, &is_text, &is_ifunc)) { /* Check if we've seen this (name,addr) key before. */ key.addr = sym_avma_really; @@ -785,6 +800,7 @@ void read_elf_symtab__ppc64_linux( elem->size = sym_size; elem->from_opd = from_opd; elem->is_text = is_text; + elem->is_ifunc = is_ifunc; VG_(OSetGen_Insert)(oset, elem); if (di->trace_symtab) { VG_(printf)(" to-oset [%4ld]: " @@ -808,11 +824,12 @@ void read_elf_symtab__ppc64_linux( VG_(OSetGen_ResetIter)( oset ); while ( (elem = VG_(OSetGen_Next)(oset)) ) { - risym.addr = elem->key.addr; - risym.size = elem->size; - risym.name = ML_(addStr) ( di, elem->key.name, -1 ); - risym.tocptr = elem->tocptr; - risym.isText = elem->is_text; + risym.addr = elem->key.addr; + risym.size = elem->size; + risym.name = ML_(addStr) ( di, elem->key.name, -1 ); + risym.tocptr = elem->tocptr; + risym.isText = elem->is_text; + risym.isIFunc = elem->is_ifunc; vg_assert(risym.name != NULL); ML_(addSym) ( di, &risym ); --- valgrind/coregrind/m_debuginfo/priv_storage.h (revision 10919) +++ valgrind/coregrind/m_debuginfo/priv_storage.h (revision 10923) @@ -48,15 +48,16 @@ /* A structure to hold an ELF/XCOFF symbol (very crudely). */ typedef struct { - Addr addr; /* lowest address of entity */ - Addr tocptr; /* ppc64-linux only: value that R2 should have */ - UChar *name; /* name */ + Addr addr; /* lowest address of entity */ + Addr tocptr; /* ppc64-linux only: value that R2 should have */ + UChar *name; /* name */ // XXX: this could be shrunk (on 32-bit platforms) by using 31 bits for // the size and 1 bit for the isText. If you do this, make sure that // all assignments to isText use 0 or 1 (or True or False), and that a // positive number larger than 1 is never used to represent True. - UInt size; /* size in bytes */ + UInt size; /* size in bytes */ Bool isText; + Bool isIFunc; /* symbol is an indirect function? */ } DiSym; --- valgrind/coregrind/m_redir.c (revision 10919) +++ valgrind/coregrind/m_redir.c (revision 10923) @@ -268,12 +268,15 @@ typedef TopSpec* parent_spec; /* the TopSpec which supplied the Spec */ TopSpec* parent_sym; /* the TopSpec which supplied the symbol */ Bool isWrap; /* wrap or replacement? */ + Bool isIFunc; /* indirect function? */ } Active; /* The active set is a fast lookup table */ static OSet* activeSet = NULL; +/* Wrapper routine for indirect functions */ +static Addr iFuncWrapper; /*------------------------------------------------------------*/ /*--- FWDses ---*/ @@ -350,8 +353,8 @@ void VG_(redir_notify_new_DebugInfo)( De nsyms = VG_(DebugInfo_syms_howmany)( newsi ); for (i = 0; i < nsyms; i++) { - VG_(DebugInfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc, - NULL, &sym_name, &isText ); + VG_(DebugInfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc, + NULL, &sym_name, &isText, NULL ); ok = VG_(maybe_Z_demangle)( sym_name, demangled_sopatt, N_DEMANGLED, demangled_fnpatt, N_DEMANGLED, &isWrap ); /* ignore data symbols */ @@ -388,8 +391,8 @@ void VG_(redir_notify_new_DebugInfo)( De if (check_ppcTOCs) { for (i = 0; i < nsyms; i++) { - VG_(DebugInfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc, - NULL, &sym_name, &isText ); + VG_(DebugInfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc, + NULL, &sym_name, &isText, NULL ); ok = isText && VG_(maybe_Z_demangle)( sym_name, demangled_sopatt, N_DEMANGLED, @@ -470,6 +473,30 @@ void VG_(redir_notify_new_DebugInfo)( De #undef N_DEMANGLED +/* Add a new target for an indirect function. Adds a new redirection + for the indirection function with address old_from that redirects + the ordinary function with address new_from to the target address + of the original redirection. */ + +void VG_(redir_add_ifunc_target)( Addr old_from, Addr new_from ) +{ + Active *old, new; + + old = VG_(OSetGen_Lookup)(activeSet, &old_from); + vg_assert(old); + vg_assert(old->isIFunc); + + new = *old; + new.from_addr = new_from; + new.isIFunc = False; + maybe_add_active (new); + + if (VG_(clo_trace_redir)) { + VG_(message)( Vg_DebugMsg, + "Adding redirect for indirect function 0x%llx from 0x%llx -> 0x%llx\n", + (ULong)old_from, (ULong)new_from, (ULong)new.to_addr ); + } +} /* Do one element of the basic cross product: add to the active set, all matches resulting from comparing all the given specs against @@ -487,7 +514,7 @@ void generate_and_add_actives ( ) { Spec* sp; - Bool anyMark, isText; + Bool anyMark, isText, isIFunc; Active act; Int nsyms, i; Addr sym_addr; @@ -513,7 +540,7 @@ void generate_and_add_actives ( nsyms = VG_(DebugInfo_syms_howmany)( di ); for (i = 0; i < nsyms; i++) { VG_(DebugInfo_syms_getidx)( di, i, &sym_addr, NULL, NULL, - &sym_name, &isText ); + &sym_name, &isText, &isIFunc ); /* ignore data symbols */ if (!isText) @@ -539,6 +566,7 @@ void generate_and_add_actives ( act.parent_spec = parent_spec; act.parent_sym = parent_sym; act.isWrap = sp->isWrap; + act.isIFunc = isIFunc; sp->done = True; maybe_add_active( act ); } @@ -780,7 +808,9 @@ Addr VG_(redir_do_lookup) ( Addr orig, B vg_assert(r->to_addr != 0); if (isWrap) - *isWrap = r->isWrap; + *isWrap = r->isWrap || r->isIFunc; + if (r->isIFunc) + return iFuncWrapper; return r->to_addr; } @@ -800,6 +830,7 @@ static void add_hardwired_active ( Addr act.parent_spec = NULL; act.parent_sym = NULL; act.isWrap = False; + act.isIFunc = False; maybe_add_active( act ); } @@ -1096,6 +1127,8 @@ void handle_maybe_load_notifier( const U if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(freeres))) == 0) VG_(client___libc_freeres_wrapper) = addr; + else if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(ifunc_wrapper))) == 0) + iFuncWrapper = addr; else vg_assert2(0, "unrecognised load notification function: %s", symbol); } --- valgrind/coregrind/pub_core_redir.h (revision 10919) +++ valgrind/coregrind/pub_core_redir.h (revision 10923) @@ -58,6 +58,8 @@ extern void VG_(redir_notify_delete_Debu /* Initialise the module, and load initial "hardwired" redirects. */ extern void VG_(redir_initialise)( void ); +/* Notify the module of a new target for an indirect function. */ +extern void VG_(redir_add_ifunc_target)( Addr old_from, Addr new_from ); //-------------------------------------------------------------------- // Queries --- valgrind/coregrind/m_scheduler/scheduler.c (revision 10919) +++ valgrind/coregrind/m_scheduler/scheduler.c (revision 10923) @@ -89,6 +89,7 @@ #include "pub_core_debuginfo.h" // VG_(di_notify_pdb_debuginfo) #include "priv_sema.h" #include "pub_core_scheduler.h" // self +#include "pub_core_redir.h" /* --------------------------------------------------------------------- @@ -1399,6 +1400,11 @@ void do_client_request ( ThreadId tid ) SET_CLREQ_RETVAL( tid, count ); break; } + case VG_USERREQ__ADD_IFUNC_TARGET: { + VG_(redir_add_ifunc_target)( arg[1], arg[2] ); + SET_CLREQ_RETVAL( tid, 0); + break; } + case VG_USERREQ__PRINTF_BACKTRACE: { Int count = VG_(vmessage)( Vg_ClientMsg, (char *)arg[1], (void*)arg[2] );