From: Julian Seward Date: Thu, 10 Jul 2003 00:17:58 +0000 (+0000) Subject: Add a new mechanism for intercepting calls, which doesn't depend on X-Git-Tag: svn/VALGRIND_2_0_0~42 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1f01517ca3c510d9646e67ee9afc04ecd2e866f3;p=thirdparty%2Fvalgrind.git Add a new mechanism for intercepting calls, which doesn't depend on 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 --- diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h index ca5a1d9c5a..db1caf79f1 100644 --- a/coregrind/vg_include.h +++ b/coregrind/vg_include.h @@ -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. */ /* --------------------------------------------------------------------- diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c index 746d681230..d7d6f4aa51 100644 --- a/coregrind/vg_main.c +++ b/coregrind/vg_main.c @@ -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) diff --git a/coregrind/vg_symtab2.c b/coregrind/vg_symtab2.c index 19939510e5..aa34844405 100644 --- a/coregrind/vg_symtab2.c +++ b/coregrind/vg_symtab2.c @@ -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 ---*/ /*------------------------------------------------------------*/ diff --git a/coregrind/vg_translate.c b/coregrind/vg_translate.c index 330b4abf60..5667970daa 100644 --- a/coregrind/vg_translate.c +++ b/coregrind/vg_translate.c @@ -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