blob: 9048b2d846033ad6c197d3dc1a7388a1c5cb0e8b [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"
sewardj55f9d1a2005-04-25 11:11:44 +000045
sewardjcbdddcf2005-03-10 23:23:45 +000046/*------------------------------------------------------------*/
47/*--- General purpose redirection. ---*/
48/*------------------------------------------------------------*/
49
50/*
51 wraps and redirections, indexed by from_addr
52
53 Redirection and wrapping are two distinct mechanisms which Valgrind
54 can use to change the client's control flow.
55
56 Redirection intercepts a call to a client function, and re-points it
57 to a new piece of code (presumably functionally equivalent). The
58 original code is never run.
59
60 Wrapping does call the client's original code, but calls "before"
61 and "after" functions which can inspect (and perhaps modify) the
62 function's arguments and return value.
63 */
64struct _CodeRedirect {
65 enum redir_type {
66 R_REDIRECT, /* plain redirection */
67 R_WRAPPER, /* wrap with valgrind-internal code */
68 R_CLIENT_WRAPPER, /* wrap with client-side code */
69 } type;
70
71 const Char *from_lib; /* library qualifier pattern */
72 const Char *from_sym; /* symbol */
73 Addr from_addr; /* old addr */
74
75 /* used for redirection */
sewardjcbdddcf2005-03-10 23:23:45 +000076 Addr to_addr; /* new addr */
77
78 /* used for wrapping */
79 const FuncWrapper *wrapper;
80
81 CodeRedirect *next; /* next pointer on unresolved list */
82};
83
84static Char *straddr(void *p)
85{
86 static Char buf[16];
87
88 VG_(sprintf)(buf, "%p", *(Addr *)p);
89
90 return buf;
91}
92
njn41f8e4a2005-06-25 20:13:05 +000093static SkipList sk_resolved_redir =
94 VG_SKIPLIST_INIT(CodeRedirect, from_addr, VG_(cmp_Addr),
95 straddr, VG_AR_SYMTAB);
96
sewardjcbdddcf2005-03-10 23:23:45 +000097static CodeRedirect *unresolved_redir = NULL;
98
njn4f612c22005-06-25 20:22:43 +000099static Bool soname_matches(const Char *pattern, const Char* soname)
sewardjcbdddcf2005-03-10 23:23:45 +0000100{
njn41f8e4a2005-06-25 20:13:05 +0000101 // pattern must start with "soname:"
102 vg_assert(NULL != pattern);
103 vg_assert(0 == VG_(strncmp)(pattern, "soname:", 7));
sewardjcbdddcf2005-03-10 23:23:45 +0000104
njn4f612c22005-06-25 20:22:43 +0000105 if (NULL == soname)
sewardjcbdddcf2005-03-10 23:23:45 +0000106 return False;
107
njn4f612c22005-06-25 20:22:43 +0000108 return VG_(string_match)(pattern + 7, soname);
sewardjcbdddcf2005-03-10 23:23:45 +0000109}
110
111static inline Bool from_resolved(const CodeRedirect *redir)
112{
113 return redir->from_addr != 0;
114}
115
sewardjcbdddcf2005-03-10 23:23:45 +0000116Bool VG_(is_resolved)(const CodeRedirect *redir)
117{
njn136b83b2005-06-19 05:14:03 +0000118 return from_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000119}
120
tom748a1312005-04-02 15:53:01 +0000121static void add_resolved(CodeRedirect *redir)
122{
123 switch(redir->type) {
124 case R_REDIRECT:
125 if (VG_(clo_trace_redir)) {
126 VG_(message)(Vg_DebugMsg, " redir resolved (%s:%s=%p -> ",
127 redir->from_lib, redir->from_sym, redir->from_addr);
njn136b83b2005-06-19 05:14:03 +0000128 VG_(message)(Vg_DebugMsg, " %p)", redir->to_addr);
tom748a1312005-04-02 15:53:01 +0000129 }
130
131 if (VG_(search_transtab)(NULL, (Addr64)redir->from_addr, False)) {
132 /* For some given (from, to) redir, the "from" function got
133 called before the .so containing "to" became available. We
134 know this because there is already a translation for the
135 entry point of the original "from". So the redirect will
136 never actually take effect unless that translation is
137 discarded.
138
139 Note, we only really need to discard the first bb of the
140 old entry point, and so we avoid the problem of having to
141 figure out how big that bb was -- since it is at least 1
142 byte of original code, we can just pass 1 as the original
143 size to invalidate_translations() and it will indeed get
144 rid of the translation.
145
146 Note, this is potentially expensive -- discarding
147 translations causes complete unchaining.
148 */
149 if (VG_(clo_verbosity) > 2 && VG_(clo_trace_redir)) {
150 VG_(message)(Vg_UserMsg,
151 "Discarding translation due to redirect of already called function" );
152 VG_(message)(Vg_UserMsg,
153 " %s (%p -> %p)",
154 redir->from_sym, redir->from_addr, redir->to_addr );
155 }
156 VG_(discard_translations)((Addr64)redir->from_addr, 1);
157 }
158
159 {
160 CodeRedirect *r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &redir->from_addr);
161
162 if (r == NULL)
163 VG_(SkipList_Insert)(&sk_resolved_redir, redir);
164 else {
165 /* XXX leak redir */
166 if (VG_(clo_trace_redir))
njn136b83b2005-06-19 05:14:03 +0000167 VG_(message)(Vg_DebugMsg, " redir %s:%s:%p->%p duplicated\n",
tom748a1312005-04-02 15:53:01 +0000168 redir->from_lib, redir->from_sym, redir->from_addr,
njn136b83b2005-06-19 05:14:03 +0000169 redir->to_addr);
tom748a1312005-04-02 15:53:01 +0000170 }
171 }
172 break;
173
174 case R_WRAPPER:
175 if (VG_(clo_trace_redir)) {
176 VG_(message)(Vg_DebugMsg, " wrapper resolved (%s:%s=%p -> wrapper)",
177 redir->from_lib, redir->from_sym, redir->from_addr);
178 }
179
180 /* XXX redir leaked */
181 //VG_(wrap_function)(redir->from_addr, redir->wrapper);
182 break;
183
184 case R_CLIENT_WRAPPER:
185 VG_(core_panic)("not implemented");
186 break;
187 }
188}
189
sewardjcbdddcf2005-03-10 23:23:45 +0000190/* Resolve a redir using si if possible, and add it to the resolved
191 list */
njn17250122005-05-14 17:18:12 +0000192static Bool resolve_redir(CodeRedirect *redir, const SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000193{
194 Bool resolved;
195
196 vg_assert(si != NULL);
sewardjcbdddcf2005-03-10 23:23:45 +0000197
njn748ace42005-06-21 03:36:01 +0000198 resolved = from_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000199 vg_assert(!resolved);
njn748ace42005-06-21 03:36:01 +0000200 vg_assert(redir->from_sym != NULL);
sewardjcbdddcf2005-03-10 23:23:45 +0000201
njn4f612c22005-06-25 20:22:43 +0000202 if (soname_matches(redir->from_lib, VG_(seginfo_soname)(si))) {
njn748ace42005-06-21 03:36:01 +0000203 redir->from_addr = VG_(reverse_search_one_symtab)(si, redir->from_sym);
204 if (VG_(clo_trace_redir) && redir->from_addr != 0)
205 VG_(printf)(" bind FROM: %p = %s:%s\n",
206 redir->from_addr,redir->from_lib, redir->from_sym );
sewardjcbdddcf2005-03-10 23:23:45 +0000207 }
208
njn136b83b2005-06-19 05:14:03 +0000209 resolved = from_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000210
211 if (0 && VG_(clo_trace_redir))
njn136b83b2005-06-19 05:14:03 +0000212 VG_(printf)("resolve_redir: %s:%s from=%p to=%p\n",
sewardjcbdddcf2005-03-10 23:23:45 +0000213 redir->from_lib, redir->from_sym, redir->from_addr,
njn136b83b2005-06-19 05:14:03 +0000214 redir->to_addr);
sewardjcbdddcf2005-03-10 23:23:45 +0000215
tom748a1312005-04-02 15:53:01 +0000216 if (resolved) add_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000217
218 return resolved;
219}
220
njnbf7ca332005-05-14 17:11:06 +0000221static Bool resolve_redir_allsegs(CodeRedirect *redir)
222{
223 const SegInfo *si;
224
225 for(si = VG_(next_seginfo)(NULL);
226 si != NULL;
227 si = VG_(next_seginfo)(si))
228 {
njn17250122005-05-14 17:18:12 +0000229 if (resolve_redir(redir, si))
njnbf7ca332005-05-14 17:11:06 +0000230 return True;
231 }
232 return False;
233}
234
sewardjcbdddcf2005-03-10 23:23:45 +0000235/* Go through the complete redir list, resolving as much as possible with this SegInfo.
236
237 This should be called when a new SegInfo symtab is loaded.
238 */
239void VG_(resolve_seg_redirs)(SegInfo *si)
240{
241 CodeRedirect **prevp = &unresolved_redir;
242 CodeRedirect *redir, *next;
243
244 if (VG_(clo_trace_redir))
245 VG_(printf)("Considering redirs to/from %s(soname=%s)\n",
njn4f612c22005-06-25 20:22:43 +0000246 VG_(seginfo_filename)(si), VG_(seginfo_soname)(si));
sewardjcbdddcf2005-03-10 23:23:45 +0000247
248 /* visit each unresolved redir - if it becomes resolved, then
249 remove it from the unresolved list */
250 for(redir = unresolved_redir; redir != NULL; redir = next) {
251 next = redir->next;
252
njn17250122005-05-14 17:18:12 +0000253 if (resolve_redir(redir, si)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000254 *prevp = next;
255 redir->next = NULL;
256 } else
257 prevp = &redir->next;
258 }
259}
260
njn136b83b2005-06-19 05:14:03 +0000261static void add_redirect_X_to_addr(
262 const Char *from_lib, const Char *from_sym, Addr from_addr, Addr to_addr
njn16eeb4e2005-06-16 03:56:58 +0000263)
sewardjcbdddcf2005-03-10 23:23:45 +0000264{
265 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
266
267 redir->type = R_REDIRECT;
268
njn16eeb4e2005-06-16 03:56:58 +0000269 if (from_lib) redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
tom3c9b8662005-06-16 09:20:43 +0000270 else redir->from_lib = NULL;
njn16eeb4e2005-06-16 03:56:58 +0000271 if (from_sym) redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
tom3c9b8662005-06-16 09:20:43 +0000272 else redir->from_sym = NULL;
sewardjb9bce632005-06-21 01:41:34 +0000273
274 redir->from_addr = from_addr;
sewardjcbdddcf2005-03-10 23:23:45 +0000275
njn136b83b2005-06-19 05:14:03 +0000276 vg_assert(0 != to_addr);
277 redir->to_addr = to_addr;
278 redir->wrapper = 0;
sewardjcbdddcf2005-03-10 23:23:45 +0000279
280 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
281 VG_(message)(Vg_UserMsg,
njn136b83b2005-06-19 05:14:03 +0000282 "REDIRECT %s:%s(%p) to %p",
283 from_lib, from_sym, from_addr, to_addr);
sewardjcbdddcf2005-03-10 23:23:45 +0000284
285 /* Check against all existing segments to see if this redirection
286 can be resolved immediately */
tom3c9b8662005-06-16 09:20:43 +0000287 if (VG_(is_resolved)(redir)) {
288 add_resolved(redir);
289 }
290 else if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000291 /* nope, add to list */
292 redir->next = unresolved_redir;
293 unresolved_redir = redir;
294 }
295}
296
njn16eeb4e2005-06-16 03:56:58 +0000297/* Redirect a lib/symbol reference to a function at addr */
298static void add_redirect_sym_to_addr(const Char *from_lib, const Char *from_sym,
299 Addr to_addr)
300{
njn136b83b2005-06-19 05:14:03 +0000301 add_redirect_X_to_addr(from_lib, from_sym, 0, to_addr);
sewardjcbdddcf2005-03-10 23:23:45 +0000302}
303
tom748a1312005-04-02 15:53:01 +0000304/* Redirect a function at from_addr to a function at to_addr */
njn16eeb4e2005-06-16 03:56:58 +0000305__attribute__((unused)) // It is used, but not on all platforms...
306static void add_redirect_addr_to_addr(Addr from_addr, Addr to_addr)
tom748a1312005-04-02 15:53:01 +0000307{
njn136b83b2005-06-19 05:14:03 +0000308 add_redirect_X_to_addr(NULL, NULL, from_addr, to_addr);
tom748a1312005-04-02 15:53:01 +0000309}
310
sewardjcbdddcf2005-03-10 23:23:45 +0000311CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
312 const FuncWrapper *wrapper)
313{
314 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
315
316 if (0)
317 VG_(printf)("adding wrapper for %s:%s -> (%p,%p)\n",
318 from_lib, from_sym, wrapper->before, wrapper->after);
319
320 redir->type = R_WRAPPER;
321
njn136b83b2005-06-19 05:14:03 +0000322 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
323 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
sewardjcbdddcf2005-03-10 23:23:45 +0000324 redir->from_addr = 0;
njn136b83b2005-06-19 05:14:03 +0000325 redir->to_addr = 0;
326 redir->wrapper = wrapper;
sewardjcbdddcf2005-03-10 23:23:45 +0000327
328 /* Check against all existing segments to see if this redirection
329 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000330 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000331 /* nope, add to list */
332 redir->next = unresolved_redir;
333 unresolved_redir = redir;
334 }
335
336 return redir;
337}
338
sewardjcbdddcf2005-03-10 23:23:45 +0000339/* If address 'a' is being redirected, return the redirected-to
340 address. */
341Addr VG_(code_redirect)(Addr a)
342{
343 CodeRedirect* r;
344
sewardjcbdddcf2005-03-10 23:23:45 +0000345 r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &a);
346 if (r == NULL)
347 return a;
348
349 vg_assert(r->to_addr != 0);
350
351 return r->to_addr;
352}
353
354void VG_(setup_code_redirect_table) ( void )
355{
njnd1af0032005-05-29 17:01:48 +0000356#if defined(VGP_x86_linux)
357 /* Redirect _dl_sysinfo_int80, which is glibc's default system call
sewardjb9bce632005-06-21 01:41:34 +0000358 routine, to our copy so that the special sysinfo unwind hack in
359 m_stacktrace.c will kick in. */
360 add_redirect_sym_to_addr(
361 "soname:ld-linux.so.2", "_dl_sysinfo_int80",
362 (Addr)&VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80)
363 );
364
njnd1af0032005-05-29 17:01:48 +0000365#elif defined(VGP_amd64_linux)
sewardjb9bce632005-06-21 01:41:34 +0000366
njnd1af0032005-05-29 17:01:48 +0000367 /* Redirect vsyscalls to local versions */
sewardjb9bce632005-06-21 01:41:34 +0000368 add_redirect_addr_to_addr(
369 0xFFFFFFFFFF600000ULL,
370 (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)
371 );
372
373 add_redirect_addr_to_addr(
tomf5db3b62005-06-21 13:26:17 +0000374 0xFFFFFFFFFF600400ULL,
sewardjb9bce632005-06-21 01:41:34 +0000375 (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)
376 );
377
cerion85665ca2005-06-20 15:51:07 +0000378#elif defined(VGP_ppc32_linux)
sewardjb9bce632005-06-21 01:41:34 +0000379
380 //CAB: TODO
381
njnd1af0032005-05-29 17:01:48 +0000382#else
383# error Unknown platform
384#endif
385}
sewardjcbdddcf2005-03-10 23:23:45 +0000386
njn16eeb4e2005-06-16 03:56:58 +0000387/* Z-decode a symbol into library:func form, eg
388
389 _vgi_libcZdsoZd6__ZdlPv --> libc.so.6:_ZdlPv
390
391 Uses the Z-encoding scheme described in pub_core_redir.h.
392 Returns True if demangle OK, False otherwise.
393*/
394static Bool Z_decode(const Char* symbol, Char* result, Int nbytes)
395{
396# define EMIT(ch) \
397 do { \
398 if (j >= nbytes) \
399 result[j-1] = 0; \
400 else \
401 result[j++] = ch; \
402 } while (0)
403
404 Bool error = False;
405 Int i, j = 0;
406 Int len = VG_(strlen)(symbol);
407 if (0) VG_(printf)("idm: %s\n", symbol);
408
409 i = VG_REPLACE_FUNCTION_PREFIX_LEN;
410
411 /* Chew though the Z-encoded soname part. */
412 while (True) {
413
414 if (i >= len)
415 break;
416
417 if (symbol[i] == '_')
418 /* We found the underscore following the Z-encoded soname.
419 Just copy the rest literally. */
420 break;
421
422 if (symbol[i] != 'Z') {
423 EMIT(symbol[i]);
424 i++;
425 continue;
426 }
427
428 /* We've got a Z-escape. Act accordingly. */
429 i++;
430 if (i >= len) {
431 /* Hmm, Z right at the end. Something's wrong. */
432 error = True;
433 EMIT('Z');
434 break;
435 }
436 switch (symbol[i]) {
437 case 'a': EMIT('*'); break;
438 case 'p': EMIT('+'); break;
439 case 'c': EMIT(':'); break;
440 case 'd': EMIT('.'); break;
441 case 'u': EMIT('_'); break;
442 case 'h': EMIT('-'); break;
443 case 's': EMIT(' '); break;
444 case 'Z': EMIT('Z'); break;
445 default: error = True; EMIT('Z'); EMIT(symbol[i]); break;
446 }
447 i++;
448 }
449
450 if (error || i >= len || symbol[i] != '_') {
451 /* Something's wrong. Give up. */
452 VG_(message)(Vg_UserMsg, "intercept: error demangling: %s", symbol);
453 EMIT(0);
454 return False;
455 }
456
457 /* Copy the rest of the string verbatim. */
458 i++;
459 EMIT(':');
460 while (True) {
461 if (i >= len)
462 break;
463 EMIT(symbol[i]);
464 i++;
465 }
466
467 EMIT(0);
468 if (0) VG_(printf)("%s\n", result);
469 return True;
470
471# undef EMIT
472}
473
474// Nb: this can change the string pointed to by 'symbol'.
475static void handle_replacement_function( Char* symbol, Addr addr )
476{
477 Bool ok;
478 Int len = VG_(strlen)(symbol) + 1 - VG_REPLACE_FUNCTION_PREFIX_LEN;
479 Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len+8);
480 Char *func;
481
482 // Put "soname:" at the start of lib
483 VG_(strcpy)(lib, "soname:");
484
485 ok = Z_decode(symbol, lib+7, len);
486 if (ok) {
487 // lib is "soname:<libname>:<fnname>". Split the string at the 2nd ':'.
488 func = lib + VG_(strlen)(lib)-1;
489 while(*func != ':') func--;
490 *func = '\0';
491 func++; // Move past the '\0'
492
493 // Now lib is "soname:<libname>" and func is "<fnname>".
494 if (0) VG_(printf)("lib A%sZ, func A%sZ\n", lib, func);
495 add_redirect_sym_to_addr(lib, func, addr);
496
497 // Overwrite the given Z-encoded name with just the fnname.
498 VG_(strcpy)(symbol, func);
499 }
500
501 VG_(arena_free)(VG_AR_SYMTAB, lib);
502}
503
njnbc6d84d2005-06-19 18:58:03 +0000504static Addr __libc_freeres_wrapper = 0;
505
506Addr VG_(get_libc_freeres_wrapper)(void)
507{
508 return __libc_freeres_wrapper;
509}
510
njn16eeb4e2005-06-16 03:56:58 +0000511// This is specifically for stringifying VG_(x) function names. We
512// need to do two macroexpansions to get the VG_ macro expanded before
513// stringifying.
514#define _STR(x) #x
515#define STR(x) _STR(x)
516
517static void handle_load_notifier( Char* symbol, Addr addr )
518{
519 if (VG_(strcmp)(symbol, STR(VG_NOTIFY_ON_LOAD(freeres))) == 0)
njnbc6d84d2005-06-19 18:58:03 +0000520 __libc_freeres_wrapper = addr;
njn16eeb4e2005-06-16 03:56:58 +0000521// else if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) == 0)
522// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value));
523 else
524 vg_assert2(0, "unrecognised load notification function: %s", symbol);
525}
526
527static Bool is_replacement_function(Char* s)
528{
529 return (0 == VG_(strncmp)(s,
530 VG_REPLACE_FUNCTION_PREFIX,
531 VG_REPLACE_FUNCTION_PREFIX_LEN));
532}
533
534static Bool is_load_notifier(Char* s)
535{
536 return (0 == VG_(strncmp)(s,
537 VG_NOTIFY_ON_LOAD_PREFIX,
538 VG_NOTIFY_ON_LOAD_PREFIX_LEN));
539}
540
541// Call this for each symbol loaded. It determines if we need to do
542// anything special with it. It can modify 'symbol' in-place.
543void VG_(maybe_redir_or_notify) ( Char* symbol, Addr addr )
544{
545 if (is_replacement_function(symbol))
546 handle_replacement_function(symbol, addr);
547 else
548 if (is_load_notifier(symbol))
549 handle_load_notifier(symbol, addr);
550}
551
552
sewardjcbdddcf2005-03-10 23:23:45 +0000553//:: /*------------------------------------------------------------*/
554//:: /*--- General function wrapping. ---*/
555//:: /*------------------------------------------------------------*/
556//::
557//:: /*
558//:: TODO:
559//:: - hook into the symtab machinery
560//:: - client-side wrappers?
561//:: - better interfaces for before() functions to get to arguments
562//:: - handle munmap of code (dlclose())
563//:: - handle thread exit
564//:: - handle longjmp
565//:: */
566//:: struct callkey {
567//:: ThreadId tid; /* calling thread */
568//:: Addr esp; /* address of args on stack */
569//:: Addr eip; /* return address */
570//:: };
571//::
572//:: struct call_instance {
573//:: struct callkey key;
574//::
575//:: const FuncWrapper *wrapper;
576//:: void *nonce;
577//:: };
578//::
579//:: static inline Addr addrcmp(Addr a, Addr b)
580//:: {
581//:: if (a < b)
582//:: return -1;
583//:: else if (a > b)
584//:: return 1;
585//:: else
586//:: return 0;
587//:: }
588//::
589//:: static inline Int cmp(UInt a, UInt b)
590//:: {
591//:: if (a < b)
592//:: return -1;
593//:: else if (a > b)
594//:: return 1;
595//:: else
596//:: return 0;
597//:: }
598//::
599//:: static Int keycmp(const void *pa, const void *pb)
600//:: {
601//:: const struct callkey *a = (const struct callkey *)pa;
602//:: const struct callkey *b = (const struct callkey *)pb;
603//:: Int ret;
604//::
605//:: if ((ret = cmp(a->tid, b->tid)))
606//:: return ret;
607//::
608//:: if ((ret = addrcmp(a->esp, b->esp)))
609//:: return ret;
610//::
611//:: return addrcmp(a->eip, b->eip);
612//:: }
613//::
614//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000615//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000616//:: NULL, VG_AR_SYMTAB);
617//::
618//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
619//:: {
620//:: struct callkey key = { tid, argsp, retaddr };
621//::
622//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
623//:: }
624//::
625//:: static void wrapper_return(Addr retaddr);
626//::
627//:: /* Called from generated code via helper */
628//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
629//:: {
njnaf839f52005-06-23 03:27:57 +0000630//:: Addr retaddr = VG_RETADDR(tst->arch);
631//:: Addr argp = (Addr)&VG_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000632//:: void *nonce = NULL;
633//:: Bool mf = VG_(my_fault);
634//:: VG_(my_fault) = True;
635//::
636//:: if (wrapper->before) {
njnaf839f52005-06-23 03:27:57 +0000637//:: va_list args = VG_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000638//:: nonce = (*wrapper->before)(args);
639//:: }
640//::
641//:: if (wrapper->after) {
642//:: /* If there's an after function, make sure it gets called */
643//:: struct call_instance *call;
644//::
645//:: call = find_call(retaddr, argp, tst->tid);
646//::
647//:: if (call != NULL) {
648//:: /* Found a stale outstanding call; clean it up and recycle
649//:: the structure */
650//:: if (call->wrapper->after)
651//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
652//:: } else {
653//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
654//::
655//:: call->key.tid = tst->tid;
656//:: call->key.esp = argp;
657//:: call->key.eip = retaddr;
658//::
659//:: VG_(SkipList_Insert)(&wrapped_frames, call);
660//::
661//:: wrapper_return(retaddr);
662//:: }
663//::
664//:: call->wrapper = wrapper;
665//:: call->nonce = nonce;
666//:: } else
667//:: vg_assert(nonce == NULL);
668//::
669//:: VG_(my_fault) = mf;
670//:: }
671//::
672//:: /* Called from generated code via helper */
673//:: void VG_(wrap_after)(ThreadState *tst)
674//:: {
njnaf839f52005-06-23 03:27:57 +0000675//:: Addr EIP = VG_INSTR_PTR(tst->arch); /* instruction after call */
676//:: Addr ESP = VG_STACK_PTR(tst->arch); /* pointer to args */
677//:: Word ret = VG_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000678//:: struct call_instance *call;
679//:: Bool mf = VG_(my_fault);
680//::
681//:: VG_(my_fault) = True;
682//:: call = find_call(EIP, ESP, tst->tid);
683//::
684//:: if (0)
685//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
686//::
687//:: if (call != NULL) {
688//:: if (call->wrapper->after)
689//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
690//::
691//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
692//:: VG_(SkipNode_Free)(&wrapped_frames, call);
693//:: }
694//:: VG_(my_fault) = mf;
695//:: }
696//::
697//::
698//:: struct wrapped_function {
699//:: Addr eip; /* eip of function entrypoint */
700//:: const FuncWrapper *wrapper;
701//:: };
702//::
703//:: struct wrapper_return {
704//:: Addr eip; /* return address */
705//:: };
706//::
707//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000708//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000709//:: NULL, VG_AR_SYMTAB);
710//::
711//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000712//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000713//:: NULL, VG_AR_SYMTAB);
714//::
715//:: /* Wrap function starting at eip */
716//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
717//:: {
718//:: struct wrapped_function *func;
719//::
720//:: if (0)
721//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
722//::
723//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
724//::
725//:: if (func == NULL) {
726//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
727//:: VG_(invalidate_translations)(eip, 1, True);
728//::
729//:: func->eip = eip;
730//:: VG_(SkipList_Insert)(&wrapped_functions, func);
731//:: }
732//::
733//:: func->wrapper = wrapper;
734//:: }
735//::
736//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
737//:: {
738//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
739//::
740//:: if (func)
741//:: return func->wrapper;
742//:: return NULL;
743//:: }
744//::
745//:: Bool VG_(is_wrapper_return)(Addr eip)
746//:: {
747//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
748//::
749//:: return ret != NULL;
750//:: }
751//::
752//:: /* Mark eip as being the return address of a wrapper, so that the
753//:: codegen will generate the appropriate call. */
754//:: void wrapper_return(Addr eip)
755//:: {
756//:: struct wrapper_return *ret;
757//::
758//:: if (VG_(is_wrapper_return)(eip))
759//:: return;
760//::
761//:: VG_(invalidate_translations)(eip, 1, True);
762//::
763//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
764//:: ret->eip = eip;
765//::
766//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
767//:: }