valgrind/valgrind-3.5.0-ifunc.patch

514 lines
19 KiB
Diff
Raw Normal View History

2010-04-07 14:39:29 +00:00
--- 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] );