]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add a new mechanism for intercepting calls, which doesn't depend on
authorJulian Seward <jseward@acm.org>
Thu, 10 Jul 2003 00:17:58 +0000 (00:17 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 10 Jul 2003 00:17:58 +0000 (00:17 +0000)
the vagaries of the dynamic linker.  In particular this has been
devised so as to work around errno/h_errno/resolver-state misbehaviour
caused by excessive PLT bypassing in glibc-2.3.2: we need to intercept
calls to __errno_location(), __h_errno_location() and __res_state(),
in threaded programs, but we can't always do that because some calls
made internally within glibc-2.3.2 bypass the PLT.

New mechanism is:

- In vg_symtab2.c, VG_(setup_code_redirect_table), search the
  symbol tables to find the entry points of the above functions,
  and find the corresponding entry points replacements in our
  vg_libpthread.c.  Put these pairs into a table,
  VG_(code_redirect_table).

- In vg_translate.c, VG_(translate), consult the table each time
  a translation is made, and if a hit is found, translate from
  the substitute address instead.

This seems to make corecheck/tests/res_search work properly,
although for some as-yet unknown reason breaks the corecheck
skin.  All other skins appear unaffected.

One unfortunate effect is that the lazy debug info scheme is now
nullified, since we always need to read debug info in order to
generate the redirection table.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1743

coregrind/vg_include.h
coregrind/vg_main.c
coregrind/vg_symtab2.c
coregrind/vg_translate.c

index ca5a1d9c5a7a662e907e86df2e009fbc37cd7f46..db1caf79f17fc09c32638fbd3c24485d62660295 100644 (file)
@@ -1281,6 +1281,18 @@ extern void VG_(maybe_unload_symbols) ( Addr start, UInt length );
 
 extern Bool VG_(get_fnname_nodemangle)( Addr a, Char* fnname, Int n_fnname );
 extern void VG_(mini_stack_dump)      ( ExeContext* ec );
+extern Int  VG_(setup_code_redirect_table) ( void );
+
+typedef
+   struct {
+      Addr entry_pt_orig;
+      Addr entry_pt_subst;
+   }
+   CodeRedirect;
+
+#define VG_N_CODE_REDIRECTS 10
+extern CodeRedirect VG_(code_redirect_table)[VG_N_CODE_REDIRECTS];
+/* Table is terminated by a NULL entry_pt_orig field. */
 
 
 /* ---------------------------------------------------------------------
index 746d681230527bc89b70cc18bbf39a856858a046..d7d6f4aa51ec4a3a1a31b5d21b9a32aec9e80755 100644 (file)
@@ -1505,6 +1505,11 @@ void VG_(main) ( void )
                    "For more details, rerun with: -v");
    }
 
+   /* Force a read of the debug info so that we can look for 
+      glibc entry points to intercept. */
+   VG_(maybe_read_symbols)();
+   VG_(setup_code_redirect_table)();
+
    /* Now it is safe for malloc et al in vg_clientmalloc.c to act
       instrumented-ly. */
    if (VG_(clo_verbosity) > 0)
index 19939510e520c6e4ffe980f307d2f97fbe0c8954..aa34844405451acf068887362764b2a77432b2e7 100644 (file)
@@ -1943,8 +1943,14 @@ void VG_(read_symtab_callback) (
    which happen to correspond to the munmap()d area.  */
 void VG_(maybe_read_symbols) ( void )
 {
-   if (!VG_(using_debug_info))
-      return;
+   /* 9 July 2003: In order to work around PLT bypassing in
+      glibc-2.3.2 (see below VG_(setup_code_redirect_table)), we need
+      to load debug info regardless of the skin, unfortunately.  Hence
+      .. */
+
+   /* if (!VG_(using_debug_info))
+         return;
+   */
 
    VGP_PUSHCC(VgpReadSyms);
       VG_(read_procselfmaps) ( VG_(read_symtab_callback),
@@ -2034,6 +2040,27 @@ static Int search_one_symtab ( SegInfo* si, Addr ptr,
 }
 
 
+/* SLOW (Linear search).  Try and map a symbol name to an address.
+   Since this is searching in the direction opposite to which the
+   table is designed we have no option but to do a complete linear
+   scan of the table.  Returns NULL if not found. */
+
+static Addr reverse_search_one_symtab ( SegInfo* si,
+                                        Char* name )
+{
+   UInt i;
+   for (i = 0; i < si->symtab_used; i++) {
+      /*
+      VG_(printf)("%p %s\n",  si->symtab[i].addr, 
+                  &si->strtab[si->symtab[i].nmoff]);
+      */
+      if (0 == VG_(strcmp)(name, &si->strtab[si->symtab[i].nmoff]))
+         return si->symtab[i].addr;
+   }
+   return (Addr)NULL;
+}
+
+
 /* Search all symtabs that we know about to locate ptr.  If found, set
    *psi to the relevant SegInfo, and *symno to the symtab entry number
    within that.  If not found, *psi is set to NULL.  */
@@ -2348,6 +2375,78 @@ void VG_(mini_stack_dump) ( ExeContext* ec )
 
 #undef APPEND
 
+
+/*------------------------------------------------------------*/
+/*--- Find interesting glibc entry points.                 ---*/
+/*------------------------------------------------------------*/
+
+CodeRedirect VG_(code_redirect_table)[VG_N_CODE_REDIRECTS];
+
+Int VG_(setup_code_redirect_table) ( void )
+{
+#  define N_SUBSTS 3
+
+   Int     i, j;
+   Addr    a_libc, a_pth;
+   SegInfo *si, *si_libc, *si_pth;
+
+   /* Original entry points to look for in libc. */
+   static Char* libc_names[N_SUBSTS]
+     = { "__GI___errno_location",
+         "__GI___h_errno_location",
+         "__GI___res_state" };
+
+   /* Corresponding substitute address in our pthread lib. */
+   static Char* pth_names[N_SUBSTS]
+     = { "__errno_location",
+         "__h_errno_location",
+         "__res_state" };
+
+   /* Look for the SegInfo for glibc and our pthread library. */
+
+   ensure_debug_info_inited();
+   si_libc = si_pth = NULL;
+
+   for (si = segInfo; si != NULL; si = si->next) {
+      if (NULL != VG_(strstr)(si->filename, "/libc.so"))
+         si_libc = si;
+      if (NULL != VG_(strstr)(si->filename, "/libpthread.so"))
+         si_pth = si;
+   }
+
+   if (si_libc == NULL || si_pth == NULL) 
+      return 0;
+
+   /* Build the substitution table. */
+   vg_assert(N_SUBSTS <= VG_N_CODE_REDIRECTS-1);
+
+   j = 0;
+   VG_(code_redirect_table)[j].entry_pt_orig = 0; 
+
+   for (i = 0; i < N_SUBSTS; i++) {
+      a_libc = reverse_search_one_symtab(si_libc, libc_names[i]);
+      a_pth  = reverse_search_one_symtab(si_pth,  pth_names[i]);
+      if (a_libc == 0 || a_pth == 0)
+         continue;
+      /* We've found a substitution pair. */
+      VG_(code_redirect_table)[j].entry_pt_orig  = a_libc;
+      VG_(code_redirect_table)[j].entry_pt_subst = a_pth;
+      j++;
+      vg_assert(j < VG_N_CODE_REDIRECTS);
+      /* Set end marker. */
+      VG_(code_redirect_table)[j].entry_pt_orig = 0; 
+      if (VG_(clo_verbosity) >= 2)
+         VG_(message)(Vg_UserMsg, 
+            "REPLACING libc(%s) with libpthread(%s)",
+            libc_names[i], pth_names[i]
+         );
+   }
+
+   return j;
+
+#  undef N_SUBSTS
+}
+
 /*------------------------------------------------------------*/
 /*--- SegInfo accessor functions                           ---*/
 /*------------------------------------------------------------*/
index 330b4abf60e45137e3f792d914e4e3e23ed0a377..5667970daad7a0672d3c20491c4c75f91aa5faf8 100644 (file)
@@ -2314,7 +2314,7 @@ void VG_(translate) ( /*IN*/  ThreadState* tst,
                       /*OUT*/ UInt* trans_size,
                      /*OUT*/ UShort jumps[VG_MAX_JUMPS])
 {
-   Int         n_disassembled_bytes, final_code_size;
+   Int         n_disassembled_bytes, final_code_size, i;
    Bool        debugging_translation;
    UChar*      final_code;
    UCodeBlock* cb;
@@ -2325,6 +2325,20 @@ void VG_(translate) ( /*IN*/  ThreadState* tst,
    debugging_translation
       = orig_size == NULL || trans_addr == NULL || trans_size == NULL;
 
+   /* Look in the code redirect table to see if we should
+      translate an alternative address for orig_addr. */
+   for (i = 0; VG_(code_redirect_table)[i].entry_pt_orig != 0; i++) {
+      if (orig_addr == VG_(code_redirect_table)[i].entry_pt_orig) {
+         if (VG_(clo_verbosity) >= 2)
+            VG_(message)(Vg_UserMsg, 
+               "TRANSLATE: %p redirected to %p",
+               orig_addr, 
+               VG_(code_redirect_table)[i].entry_pt_subst );
+         orig_addr = VG_(code_redirect_table)[i].entry_pt_subst;
+         break;
+      }
+   }
+
    /* If codegen tracing, don't start tracing until
       notrace_until_limit blocks have gone by.  This avoids printing
       huge amounts of useless junk when all we want to see is the last