Blob Blame History Raw
--- 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] );