blob: 4615b7283c5e044b9641e09e9eaf736993cc3bb1 [file] [log] [blame]
sewardjcbdddcf2005-03-10 23:23:45 +00001/*--------------------------------------------------------------------*/
2/*--- Management of function redirection and wrapping. ---*/
3/*--- vg_redir.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, an extensible x86 protected-mode
8 emulator for monitoring program execution on x86-Unixes.
9
njn53612422005-03-12 16:22:54 +000010 Copyright (C) 2000-2005 Julian Seward
sewardjcbdddcf2005-03-10 23:23:45 +000011 jseward@acm.org
12 Copyright (C) 2003-2005 Jeremy Fitzhardinge
13 jeremy@goop.org
14
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
30 The GNU General Public License is contained in the file COPYING.
31*/
sewardjcbdddcf2005-03-10 23:23:45 +000032
njnc7561b92005-06-19 01:24:32 +000033#include "pub_core_basics.h"
njn899ce732005-06-21 00:28:11 +000034#include "pub_core_debuginfo.h" // Needed for pub_core_aspacemgr :(
35#include "pub_core_aspacemgr.h" // Needed for pub_core_redir.h :(
njn97405b22005-06-02 03:39:33 +000036#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000037#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_core_libcprint.h"
njnaf1d7df2005-06-11 01:31:52 +000039#include "pub_core_mallocfree.h"
njn20242342005-05-16 23:31:24 +000040#include "pub_core_options.h"
njnd1af0032005-05-29 17:01:48 +000041#include "pub_core_redir.h"
njnaf1d7df2005-06-11 01:31:52 +000042#include "pub_core_skiplist.h"
njna7598f62005-06-18 03:27:58 +000043#include "pub_core_trampoline.h"
njn8bddf582005-05-13 23:40:55 +000044#include "pub_core_transtab.h"
njn24a6efb2005-06-20 03:36:51 +000045#include "m_debuginfo/priv_symtab.h" // XXX: bad! For SegInfo internals
sewardj55f9d1a2005-04-25 11:11:44 +000046
sewardjcbdddcf2005-03-10 23:23:45 +000047/*------------------------------------------------------------*/
48/*--- General purpose redirection. ---*/
49/*------------------------------------------------------------*/
50
51/*
52 wraps and redirections, indexed by from_addr
53
54 Redirection and wrapping are two distinct mechanisms which Valgrind
55 can use to change the client's control flow.
56
57 Redirection intercepts a call to a client function, and re-points it
58 to a new piece of code (presumably functionally equivalent). The
59 original code is never run.
60
61 Wrapping does call the client's original code, but calls "before"
62 and "after" functions which can inspect (and perhaps modify) the
63 function's arguments and return value.
64 */
65struct _CodeRedirect {
66 enum redir_type {
67 R_REDIRECT, /* plain redirection */
68 R_WRAPPER, /* wrap with valgrind-internal code */
69 R_CLIENT_WRAPPER, /* wrap with client-side code */
70 } type;
71
72 const Char *from_lib; /* library qualifier pattern */
73 const Char *from_sym; /* symbol */
74 Addr from_addr; /* old addr */
75
76 /* used for redirection */
sewardjcbdddcf2005-03-10 23:23:45 +000077 Addr to_addr; /* new addr */
78
79 /* used for wrapping */
80 const FuncWrapper *wrapper;
81
82 CodeRedirect *next; /* next pointer on unresolved list */
83};
84
85static Char *straddr(void *p)
86{
87 static Char buf[16];
88
89 VG_(sprintf)(buf, "%p", *(Addr *)p);
90
91 return buf;
92}
93
njnbe91aae2005-03-27 01:42:41 +000094static SkipList sk_resolved_redir = VG_SKIPLIST_INIT(CodeRedirect, from_addr,
sewardjcbdddcf2005-03-10 23:23:45 +000095 VG_(cmp_Addr), straddr, VG_AR_SYMTAB);
96static CodeRedirect *unresolved_redir = NULL;
97
98static Bool match_lib(const Char *pattern, const SegInfo *si)
99{
100 /* pattern == NULL matches everything, otherwise use globbing
101
102 If the pattern starts with:
103 file:, then match filename
104 soname:, then match soname
105 something else, match filename
106 */
107 const Char *name = si->filename;
108
109 if (pattern == NULL)
110 return True;
111
112 if (VG_(strncmp)(pattern, "file:", 5) == 0) {
113 pattern += 5;
114 name = si->filename;
115 }
116 if (VG_(strncmp)(pattern, "soname:", 7) == 0) {
117 pattern += 7;
118 name = si->soname;
119 }
120
121 if (name == NULL)
122 return False;
123
124 return VG_(string_match)(pattern, name);
125}
126
127static inline Bool from_resolved(const CodeRedirect *redir)
128{
129 return redir->from_addr != 0;
130}
131
sewardjcbdddcf2005-03-10 23:23:45 +0000132Bool VG_(is_resolved)(const CodeRedirect *redir)
133{
njn136b83b2005-06-19 05:14:03 +0000134 return from_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000135}
136
tom748a1312005-04-02 15:53:01 +0000137static void add_resolved(CodeRedirect *redir)
138{
139 switch(redir->type) {
140 case R_REDIRECT:
141 if (VG_(clo_trace_redir)) {
142 VG_(message)(Vg_DebugMsg, " redir resolved (%s:%s=%p -> ",
143 redir->from_lib, redir->from_sym, redir->from_addr);
njn136b83b2005-06-19 05:14:03 +0000144 VG_(message)(Vg_DebugMsg, " %p)", redir->to_addr);
tom748a1312005-04-02 15:53:01 +0000145 }
146
147 if (VG_(search_transtab)(NULL, (Addr64)redir->from_addr, False)) {
148 /* For some given (from, to) redir, the "from" function got
149 called before the .so containing "to" became available. We
150 know this because there is already a translation for the
151 entry point of the original "from". So the redirect will
152 never actually take effect unless that translation is
153 discarded.
154
155 Note, we only really need to discard the first bb of the
156 old entry point, and so we avoid the problem of having to
157 figure out how big that bb was -- since it is at least 1
158 byte of original code, we can just pass 1 as the original
159 size to invalidate_translations() and it will indeed get
160 rid of the translation.
161
162 Note, this is potentially expensive -- discarding
163 translations causes complete unchaining.
164 */
165 if (VG_(clo_verbosity) > 2 && VG_(clo_trace_redir)) {
166 VG_(message)(Vg_UserMsg,
167 "Discarding translation due to redirect of already called function" );
168 VG_(message)(Vg_UserMsg,
169 " %s (%p -> %p)",
170 redir->from_sym, redir->from_addr, redir->to_addr );
171 }
172 VG_(discard_translations)((Addr64)redir->from_addr, 1);
173 }
174
175 {
176 CodeRedirect *r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &redir->from_addr);
177
178 if (r == NULL)
179 VG_(SkipList_Insert)(&sk_resolved_redir, redir);
180 else {
181 /* XXX leak redir */
182 if (VG_(clo_trace_redir))
njn136b83b2005-06-19 05:14:03 +0000183 VG_(message)(Vg_DebugMsg, " redir %s:%s:%p->%p duplicated\n",
tom748a1312005-04-02 15:53:01 +0000184 redir->from_lib, redir->from_sym, redir->from_addr,
njn136b83b2005-06-19 05:14:03 +0000185 redir->to_addr);
tom748a1312005-04-02 15:53:01 +0000186 }
187 }
188 break;
189
190 case R_WRAPPER:
191 if (VG_(clo_trace_redir)) {
192 VG_(message)(Vg_DebugMsg, " wrapper resolved (%s:%s=%p -> wrapper)",
193 redir->from_lib, redir->from_sym, redir->from_addr);
194 }
195
196 /* XXX redir leaked */
197 //VG_(wrap_function)(redir->from_addr, redir->wrapper);
198 break;
199
200 case R_CLIENT_WRAPPER:
201 VG_(core_panic)("not implemented");
202 break;
203 }
204}
205
sewardjcbdddcf2005-03-10 23:23:45 +0000206/* Resolve a redir using si if possible, and add it to the resolved
207 list */
njn17250122005-05-14 17:18:12 +0000208static Bool resolve_redir(CodeRedirect *redir, const SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000209{
210 Bool resolved;
211
212 vg_assert(si != NULL);
213 vg_assert(si->seg != NULL);
214
215 /* no redirection from Valgrind segments */
216 if (si->seg->flags & SF_VALGRIND)
217 return False;
218
njn748ace42005-06-21 03:36:01 +0000219 resolved = from_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000220 vg_assert(!resolved);
njn748ace42005-06-21 03:36:01 +0000221 vg_assert(redir->from_sym != NULL);
sewardjcbdddcf2005-03-10 23:23:45 +0000222
njn748ace42005-06-21 03:36:01 +0000223 if (match_lib(redir->from_lib, si)) {
224 redir->from_addr = VG_(reverse_search_one_symtab)(si, redir->from_sym);
225 if (VG_(clo_trace_redir) && redir->from_addr != 0)
226 VG_(printf)(" bind FROM: %p = %s:%s\n",
227 redir->from_addr,redir->from_lib, redir->from_sym );
sewardjcbdddcf2005-03-10 23:23:45 +0000228 }
229
njn136b83b2005-06-19 05:14:03 +0000230 resolved = from_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000231
232 if (0 && VG_(clo_trace_redir))
njn136b83b2005-06-19 05:14:03 +0000233 VG_(printf)("resolve_redir: %s:%s from=%p to=%p\n",
sewardjcbdddcf2005-03-10 23:23:45 +0000234 redir->from_lib, redir->from_sym, redir->from_addr,
njn136b83b2005-06-19 05:14:03 +0000235 redir->to_addr);
sewardjcbdddcf2005-03-10 23:23:45 +0000236
tom748a1312005-04-02 15:53:01 +0000237 if (resolved) add_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000238
239 return resolved;
240}
241
njnbf7ca332005-05-14 17:11:06 +0000242static Bool resolve_redir_allsegs(CodeRedirect *redir)
243{
244 const SegInfo *si;
245
246 for(si = VG_(next_seginfo)(NULL);
247 si != NULL;
248 si = VG_(next_seginfo)(si))
249 {
njn17250122005-05-14 17:18:12 +0000250 if (resolve_redir(redir, si))
njnbf7ca332005-05-14 17:11:06 +0000251 return True;
252 }
253 return False;
254}
255
sewardjcbdddcf2005-03-10 23:23:45 +0000256/* Go through the complete redir list, resolving as much as possible with this SegInfo.
257
258 This should be called when a new SegInfo symtab is loaded.
259 */
260void VG_(resolve_seg_redirs)(SegInfo *si)
261{
262 CodeRedirect **prevp = &unresolved_redir;
263 CodeRedirect *redir, *next;
264
265 if (VG_(clo_trace_redir))
266 VG_(printf)("Considering redirs to/from %s(soname=%s)\n",
267 si->filename, si->soname);
268
269 /* visit each unresolved redir - if it becomes resolved, then
270 remove it from the unresolved list */
271 for(redir = unresolved_redir; redir != NULL; redir = next) {
272 next = redir->next;
273
njn17250122005-05-14 17:18:12 +0000274 if (resolve_redir(redir, si)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000275 *prevp = next;
276 redir->next = NULL;
277 } else
278 prevp = &redir->next;
279 }
280}
281
njn136b83b2005-06-19 05:14:03 +0000282static void add_redirect_X_to_addr(
283 const Char *from_lib, const Char *from_sym, Addr from_addr, Addr to_addr
njn16eeb4e2005-06-16 03:56:58 +0000284)
sewardjcbdddcf2005-03-10 23:23:45 +0000285{
286 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
287
288 redir->type = R_REDIRECT;
289
njn16eeb4e2005-06-16 03:56:58 +0000290 if (from_lib) redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
tom3c9b8662005-06-16 09:20:43 +0000291 else redir->from_lib = NULL;
njn16eeb4e2005-06-16 03:56:58 +0000292 if (from_sym) redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
tom3c9b8662005-06-16 09:20:43 +0000293 else redir->from_sym = NULL;
sewardjb9bce632005-06-21 01:41:34 +0000294
295 redir->from_addr = from_addr;
sewardjcbdddcf2005-03-10 23:23:45 +0000296
njn136b83b2005-06-19 05:14:03 +0000297 vg_assert(0 != to_addr);
298 redir->to_addr = to_addr;
299 redir->wrapper = 0;
sewardjcbdddcf2005-03-10 23:23:45 +0000300
301 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
302 VG_(message)(Vg_UserMsg,
njn136b83b2005-06-19 05:14:03 +0000303 "REDIRECT %s:%s(%p) to %p",
304 from_lib, from_sym, from_addr, to_addr);
sewardjcbdddcf2005-03-10 23:23:45 +0000305
306 /* Check against all existing segments to see if this redirection
307 can be resolved immediately */
tom3c9b8662005-06-16 09:20:43 +0000308 if (VG_(is_resolved)(redir)) {
309 add_resolved(redir);
310 }
311 else if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000312 /* nope, add to list */
313 redir->next = unresolved_redir;
314 unresolved_redir = redir;
315 }
316}
317
njn16eeb4e2005-06-16 03:56:58 +0000318/* Redirect a lib/symbol reference to a function at addr */
319static void add_redirect_sym_to_addr(const Char *from_lib, const Char *from_sym,
320 Addr to_addr)
321{
njn136b83b2005-06-19 05:14:03 +0000322 add_redirect_X_to_addr(from_lib, from_sym, 0, to_addr);
sewardjcbdddcf2005-03-10 23:23:45 +0000323}
324
tom748a1312005-04-02 15:53:01 +0000325/* Redirect a function at from_addr to a function at to_addr */
njn16eeb4e2005-06-16 03:56:58 +0000326__attribute__((unused)) // It is used, but not on all platforms...
327static void add_redirect_addr_to_addr(Addr from_addr, Addr to_addr)
tom748a1312005-04-02 15:53:01 +0000328{
njn136b83b2005-06-19 05:14:03 +0000329 add_redirect_X_to_addr(NULL, NULL, from_addr, to_addr);
tom748a1312005-04-02 15:53:01 +0000330}
331
sewardjcbdddcf2005-03-10 23:23:45 +0000332CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
333 const FuncWrapper *wrapper)
334{
335 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
336
337 if (0)
338 VG_(printf)("adding wrapper for %s:%s -> (%p,%p)\n",
339 from_lib, from_sym, wrapper->before, wrapper->after);
340
341 redir->type = R_WRAPPER;
342
njn136b83b2005-06-19 05:14:03 +0000343 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
344 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
sewardjcbdddcf2005-03-10 23:23:45 +0000345 redir->from_addr = 0;
njn136b83b2005-06-19 05:14:03 +0000346 redir->to_addr = 0;
347 redir->wrapper = wrapper;
sewardjcbdddcf2005-03-10 23:23:45 +0000348
349 /* Check against all existing segments to see if this redirection
350 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000351 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000352 /* nope, add to list */
353 redir->next = unresolved_redir;
354 unresolved_redir = redir;
355 }
356
357 return redir;
358}
359
sewardjcbdddcf2005-03-10 23:23:45 +0000360/* If address 'a' is being redirected, return the redirected-to
361 address. */
362Addr VG_(code_redirect)(Addr a)
363{
364 CodeRedirect* r;
365
sewardjcbdddcf2005-03-10 23:23:45 +0000366 r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &a);
367 if (r == NULL)
368 return a;
369
370 vg_assert(r->to_addr != 0);
371
372 return r->to_addr;
373}
374
375void VG_(setup_code_redirect_table) ( void )
376{
njnd1af0032005-05-29 17:01:48 +0000377#if defined(VGP_x86_linux)
378 /* Redirect _dl_sysinfo_int80, which is glibc's default system call
sewardjb9bce632005-06-21 01:41:34 +0000379 routine, to our copy so that the special sysinfo unwind hack in
380 m_stacktrace.c will kick in. */
381 add_redirect_sym_to_addr(
382 "soname:ld-linux.so.2", "_dl_sysinfo_int80",
383 (Addr)&VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80)
384 );
385
njnd1af0032005-05-29 17:01:48 +0000386#elif defined(VGP_amd64_linux)
sewardjb9bce632005-06-21 01:41:34 +0000387
njnd1af0032005-05-29 17:01:48 +0000388 /* Redirect vsyscalls to local versions */
sewardjb9bce632005-06-21 01:41:34 +0000389 add_redirect_addr_to_addr(
390 0xFFFFFFFFFF600000ULL,
391 (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)
392 );
393
394 add_redirect_addr_to_addr(
395 0xFFFFFFFFFF600000ULL,
396 (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)
397 );
398
cerion85665ca2005-06-20 15:51:07 +0000399#elif defined(VGP_ppc32_linux)
sewardjb9bce632005-06-21 01:41:34 +0000400
401 //CAB: TODO
402
njnd1af0032005-05-29 17:01:48 +0000403#else
404# error Unknown platform
405#endif
406}
sewardjcbdddcf2005-03-10 23:23:45 +0000407
njn16eeb4e2005-06-16 03:56:58 +0000408/* Z-decode a symbol into library:func form, eg
409
410 _vgi_libcZdsoZd6__ZdlPv --> libc.so.6:_ZdlPv
411
412 Uses the Z-encoding scheme described in pub_core_redir.h.
413 Returns True if demangle OK, False otherwise.
414*/
415static Bool Z_decode(const Char* symbol, Char* result, Int nbytes)
416{
417# define EMIT(ch) \
418 do { \
419 if (j >= nbytes) \
420 result[j-1] = 0; \
421 else \
422 result[j++] = ch; \
423 } while (0)
424
425 Bool error = False;
426 Int i, j = 0;
427 Int len = VG_(strlen)(symbol);
428 if (0) VG_(printf)("idm: %s\n", symbol);
429
430 i = VG_REPLACE_FUNCTION_PREFIX_LEN;
431
432 /* Chew though the Z-encoded soname part. */
433 while (True) {
434
435 if (i >= len)
436 break;
437
438 if (symbol[i] == '_')
439 /* We found the underscore following the Z-encoded soname.
440 Just copy the rest literally. */
441 break;
442
443 if (symbol[i] != 'Z') {
444 EMIT(symbol[i]);
445 i++;
446 continue;
447 }
448
449 /* We've got a Z-escape. Act accordingly. */
450 i++;
451 if (i >= len) {
452 /* Hmm, Z right at the end. Something's wrong. */
453 error = True;
454 EMIT('Z');
455 break;
456 }
457 switch (symbol[i]) {
458 case 'a': EMIT('*'); break;
459 case 'p': EMIT('+'); break;
460 case 'c': EMIT(':'); break;
461 case 'd': EMIT('.'); break;
462 case 'u': EMIT('_'); break;
463 case 'h': EMIT('-'); break;
464 case 's': EMIT(' '); break;
465 case 'Z': EMIT('Z'); break;
466 default: error = True; EMIT('Z'); EMIT(symbol[i]); break;
467 }
468 i++;
469 }
470
471 if (error || i >= len || symbol[i] != '_') {
472 /* Something's wrong. Give up. */
473 VG_(message)(Vg_UserMsg, "intercept: error demangling: %s", symbol);
474 EMIT(0);
475 return False;
476 }
477
478 /* Copy the rest of the string verbatim. */
479 i++;
480 EMIT(':');
481 while (True) {
482 if (i >= len)
483 break;
484 EMIT(symbol[i]);
485 i++;
486 }
487
488 EMIT(0);
489 if (0) VG_(printf)("%s\n", result);
490 return True;
491
492# undef EMIT
493}
494
495// Nb: this can change the string pointed to by 'symbol'.
496static void handle_replacement_function( Char* symbol, Addr addr )
497{
498 Bool ok;
499 Int len = VG_(strlen)(symbol) + 1 - VG_REPLACE_FUNCTION_PREFIX_LEN;
500 Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len+8);
501 Char *func;
502
503 // Put "soname:" at the start of lib
504 VG_(strcpy)(lib, "soname:");
505
506 ok = Z_decode(symbol, lib+7, len);
507 if (ok) {
508 // lib is "soname:<libname>:<fnname>". Split the string at the 2nd ':'.
509 func = lib + VG_(strlen)(lib)-1;
510 while(*func != ':') func--;
511 *func = '\0';
512 func++; // Move past the '\0'
513
514 // Now lib is "soname:<libname>" and func is "<fnname>".
515 if (0) VG_(printf)("lib A%sZ, func A%sZ\n", lib, func);
516 add_redirect_sym_to_addr(lib, func, addr);
517
518 // Overwrite the given Z-encoded name with just the fnname.
519 VG_(strcpy)(symbol, func);
520 }
521
522 VG_(arena_free)(VG_AR_SYMTAB, lib);
523}
524
njnbc6d84d2005-06-19 18:58:03 +0000525static Addr __libc_freeres_wrapper = 0;
526
527Addr VG_(get_libc_freeres_wrapper)(void)
528{
529 return __libc_freeres_wrapper;
530}
531
njn16eeb4e2005-06-16 03:56:58 +0000532// This is specifically for stringifying VG_(x) function names. We
533// need to do two macroexpansions to get the VG_ macro expanded before
534// stringifying.
535#define _STR(x) #x
536#define STR(x) _STR(x)
537
538static void handle_load_notifier( Char* symbol, Addr addr )
539{
540 if (VG_(strcmp)(symbol, STR(VG_NOTIFY_ON_LOAD(freeres))) == 0)
njnbc6d84d2005-06-19 18:58:03 +0000541 __libc_freeres_wrapper = addr;
njn16eeb4e2005-06-16 03:56:58 +0000542// else if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) == 0)
543// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value));
544 else
545 vg_assert2(0, "unrecognised load notification function: %s", symbol);
546}
547
548static Bool is_replacement_function(Char* s)
549{
550 return (0 == VG_(strncmp)(s,
551 VG_REPLACE_FUNCTION_PREFIX,
552 VG_REPLACE_FUNCTION_PREFIX_LEN));
553}
554
555static Bool is_load_notifier(Char* s)
556{
557 return (0 == VG_(strncmp)(s,
558 VG_NOTIFY_ON_LOAD_PREFIX,
559 VG_NOTIFY_ON_LOAD_PREFIX_LEN));
560}
561
562// Call this for each symbol loaded. It determines if we need to do
563// anything special with it. It can modify 'symbol' in-place.
564void VG_(maybe_redir_or_notify) ( Char* symbol, Addr addr )
565{
566 if (is_replacement_function(symbol))
567 handle_replacement_function(symbol, addr);
568 else
569 if (is_load_notifier(symbol))
570 handle_load_notifier(symbol, addr);
571}
572
573
sewardjcbdddcf2005-03-10 23:23:45 +0000574//:: /*------------------------------------------------------------*/
575//:: /*--- General function wrapping. ---*/
576//:: /*------------------------------------------------------------*/
577//::
578//:: /*
579//:: TODO:
580//:: - hook into the symtab machinery
581//:: - client-side wrappers?
582//:: - better interfaces for before() functions to get to arguments
583//:: - handle munmap of code (dlclose())
584//:: - handle thread exit
585//:: - handle longjmp
586//:: */
587//:: struct callkey {
588//:: ThreadId tid; /* calling thread */
589//:: Addr esp; /* address of args on stack */
590//:: Addr eip; /* return address */
591//:: };
592//::
593//:: struct call_instance {
594//:: struct callkey key;
595//::
596//:: const FuncWrapper *wrapper;
597//:: void *nonce;
598//:: };
599//::
600//:: static inline Addr addrcmp(Addr a, Addr b)
601//:: {
602//:: if (a < b)
603//:: return -1;
604//:: else if (a > b)
605//:: return 1;
606//:: else
607//:: return 0;
608//:: }
609//::
610//:: static inline Int cmp(UInt a, UInt b)
611//:: {
612//:: if (a < b)
613//:: return -1;
614//:: else if (a > b)
615//:: return 1;
616//:: else
617//:: return 0;
618//:: }
619//::
620//:: static Int keycmp(const void *pa, const void *pb)
621//:: {
622//:: const struct callkey *a = (const struct callkey *)pa;
623//:: const struct callkey *b = (const struct callkey *)pb;
624//:: Int ret;
625//::
626//:: if ((ret = cmp(a->tid, b->tid)))
627//:: return ret;
628//::
629//:: if ((ret = addrcmp(a->esp, b->esp)))
630//:: return ret;
631//::
632//:: return addrcmp(a->eip, b->eip);
633//:: }
634//::
635//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000636//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000637//:: NULL, VG_AR_SYMTAB);
638//::
639//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
640//:: {
641//:: struct callkey key = { tid, argsp, retaddr };
642//::
643//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
644//:: }
645//::
646//:: static void wrapper_return(Addr retaddr);
647//::
648//:: /* Called from generated code via helper */
649//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
650//:: {
njndb9b7732005-03-26 00:32:29 +0000651//:: Addr retaddr = VGA_RETADDR(tst->arch);
652//:: Addr argp = (Addr)&VGA_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000653//:: void *nonce = NULL;
654//:: Bool mf = VG_(my_fault);
655//:: VG_(my_fault) = True;
656//::
657//:: if (wrapper->before) {
njndb9b7732005-03-26 00:32:29 +0000658//:: va_list args = VGA_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000659//:: nonce = (*wrapper->before)(args);
660//:: }
661//::
662//:: if (wrapper->after) {
663//:: /* If there's an after function, make sure it gets called */
664//:: struct call_instance *call;
665//::
666//:: call = find_call(retaddr, argp, tst->tid);
667//::
668//:: if (call != NULL) {
669//:: /* Found a stale outstanding call; clean it up and recycle
670//:: the structure */
671//:: if (call->wrapper->after)
672//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
673//:: } else {
674//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
675//::
676//:: call->key.tid = tst->tid;
677//:: call->key.esp = argp;
678//:: call->key.eip = retaddr;
679//::
680//:: VG_(SkipList_Insert)(&wrapped_frames, call);
681//::
682//:: wrapper_return(retaddr);
683//:: }
684//::
685//:: call->wrapper = wrapper;
686//:: call->nonce = nonce;
687//:: } else
688//:: vg_assert(nonce == NULL);
689//::
690//:: VG_(my_fault) = mf;
691//:: }
692//::
693//:: /* Called from generated code via helper */
694//:: void VG_(wrap_after)(ThreadState *tst)
695//:: {
njn35172bc2005-03-26 00:04:03 +0000696//:: Addr EIP = VGA_INSTR_PTR(tst->arch); /* instruction after call */
697//:: Addr ESP = VGA_STACK_PTR(tst->arch); /* pointer to args */
698//:: Word ret = VGA_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000699//:: struct call_instance *call;
700//:: Bool mf = VG_(my_fault);
701//::
702//:: VG_(my_fault) = True;
703//:: call = find_call(EIP, ESP, tst->tid);
704//::
705//:: if (0)
706//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
707//::
708//:: if (call != NULL) {
709//:: if (call->wrapper->after)
710//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
711//::
712//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
713//:: VG_(SkipNode_Free)(&wrapped_frames, call);
714//:: }
715//:: VG_(my_fault) = mf;
716//:: }
717//::
718//::
719//:: struct wrapped_function {
720//:: Addr eip; /* eip of function entrypoint */
721//:: const FuncWrapper *wrapper;
722//:: };
723//::
724//:: struct wrapper_return {
725//:: Addr eip; /* return address */
726//:: };
727//::
728//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000729//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000730//:: NULL, VG_AR_SYMTAB);
731//::
732//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000733//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000734//:: NULL, VG_AR_SYMTAB);
735//::
736//:: /* Wrap function starting at eip */
737//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
738//:: {
739//:: struct wrapped_function *func;
740//::
741//:: if (0)
742//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
743//::
744//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
745//::
746//:: if (func == NULL) {
747//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
748//:: VG_(invalidate_translations)(eip, 1, True);
749//::
750//:: func->eip = eip;
751//:: VG_(SkipList_Insert)(&wrapped_functions, func);
752//:: }
753//::
754//:: func->wrapper = wrapper;
755//:: }
756//::
757//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
758//:: {
759//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
760//::
761//:: if (func)
762//:: return func->wrapper;
763//:: return NULL;
764//:: }
765//::
766//:: Bool VG_(is_wrapper_return)(Addr eip)
767//:: {
768//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
769//::
770//:: return ret != NULL;
771//:: }
772//::
773//:: /* Mark eip as being the return address of a wrapper, so that the
774//:: codegen will generate the appropriate call. */
775//:: void wrapper_return(Addr eip)
776//:: {
777//:: struct wrapper_return *ret;
778//::
779//:: if (VG_(is_wrapper_return)(eip))
780//:: return;
781//::
782//:: VG_(invalidate_translations)(eip, 1, True);
783//::
784//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
785//:: ret->eip = eip;
786//::
787//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
788//:: }