blob: 0f66a578329b2136d98f6b1c2784355c0b3f6cf3 [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"
njn88c51482005-06-25 20:49:33 +000034#include "pub_core_debuginfo.h"
njn97405b22005-06-02 03:39:33 +000035#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000036#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000037#include "pub_core_libcprint.h"
njnaf1d7df2005-06-11 01:31:52 +000038#include "pub_core_mallocfree.h"
njn20242342005-05-16 23:31:24 +000039#include "pub_core_options.h"
njnd1af0032005-05-29 17:01:48 +000040#include "pub_core_redir.h"
njnaf1d7df2005-06-11 01:31:52 +000041#include "pub_core_skiplist.h"
njna7598f62005-06-18 03:27:58 +000042#include "pub_core_trampoline.h"
njn8bddf582005-05-13 23:40:55 +000043#include "pub_core_transtab.h"
sewardj55f9d1a2005-04-25 11:11:44 +000044
sewardjcbdddcf2005-03-10 23:23:45 +000045/*------------------------------------------------------------*/
46/*--- General purpose redirection. ---*/
47/*------------------------------------------------------------*/
48
njnd9109c62005-06-26 04:49:25 +000049#define TRACE_REDIR(format, args...) \
50 if (VG_(clo_trace_redir)) { VG_(message)(Vg_DebugMsg, format, ## args); }
51
sewardjcbdddcf2005-03-10 23:23:45 +000052/*
53 wraps and redirections, indexed by from_addr
54
55 Redirection and wrapping are two distinct mechanisms which Valgrind
56 can use to change the client's control flow.
57
58 Redirection intercepts a call to a client function, and re-points it
59 to a new piece of code (presumably functionally equivalent). The
60 original code is never run.
61
62 Wrapping does call the client's original code, but calls "before"
63 and "after" functions which can inspect (and perhaps modify) the
64 function's arguments and return value.
65 */
66struct _CodeRedirect {
67 enum redir_type {
68 R_REDIRECT, /* plain redirection */
69 R_WRAPPER, /* wrap with valgrind-internal code */
70 R_CLIENT_WRAPPER, /* wrap with client-side code */
71 } type;
72
73 const Char *from_lib; /* library qualifier pattern */
74 const Char *from_sym; /* symbol */
75 Addr from_addr; /* old addr */
76
njnd9109c62005-06-26 04:49:25 +000077 Addr to_addr; /* used for redirection -- new addr */
78 const FuncWrapper *wrapper; /* used for wrapping */
sewardjcbdddcf2005-03-10 23:23:45 +000079
njnd9109c62005-06-26 04:49:25 +000080 CodeRedirect *next; /* next pointer on unresolved list */
sewardjcbdddcf2005-03-10 23:23:45 +000081};
82
83static Char *straddr(void *p)
84{
85 static Char buf[16];
sewardjcbdddcf2005-03-10 23:23:45 +000086 VG_(sprintf)(buf, "%p", *(Addr *)p);
sewardjcbdddcf2005-03-10 23:23:45 +000087 return buf;
88}
89
njnd9109c62005-06-26 04:49:25 +000090static SkipList sk_resolved_redirs =
njn41f8e4a2005-06-25 20:13:05 +000091 VG_SKIPLIST_INIT(CodeRedirect, from_addr, VG_(cmp_Addr),
92 straddr, VG_AR_SYMTAB);
93
njnd9109c62005-06-26 04:49:25 +000094static CodeRedirect *unresolved_redirs = NULL;
sewardjcbdddcf2005-03-10 23:23:45 +000095
njn4f612c22005-06-25 20:22:43 +000096static Bool soname_matches(const Char *pattern, const Char* soname)
sewardjcbdddcf2005-03-10 23:23:45 +000097{
njn41f8e4a2005-06-25 20:13:05 +000098 // pattern must start with "soname:"
99 vg_assert(NULL != pattern);
100 vg_assert(0 == VG_(strncmp)(pattern, "soname:", 7));
sewardjcbdddcf2005-03-10 23:23:45 +0000101
njn4f612c22005-06-25 20:22:43 +0000102 if (NULL == soname)
sewardjcbdddcf2005-03-10 23:23:45 +0000103 return False;
104
njn4f612c22005-06-25 20:22:43 +0000105 return VG_(string_match)(pattern + 7, soname);
sewardjcbdddcf2005-03-10 23:23:45 +0000106}
107
njnd9109c62005-06-26 04:49:25 +0000108Bool VG_(is_resolved)(const CodeRedirect *redir)
sewardjcbdddcf2005-03-10 23:23:45 +0000109{
110 return redir->from_addr != 0;
111}
112
njnd9109c62005-06-26 04:49:25 +0000113// Prepends redir to the unresolved list.
114static void add_redir_to_unresolved_list(CodeRedirect *redir)
sewardjcbdddcf2005-03-10 23:23:45 +0000115{
njnd9109c62005-06-26 04:49:25 +0000116 redir->next = unresolved_redirs;
117 unresolved_redirs = redir;
sewardjcbdddcf2005-03-10 23:23:45 +0000118}
119
njnd9109c62005-06-26 04:49:25 +0000120static void add_redir_to_resolved_list(CodeRedirect *redir)
tom748a1312005-04-02 15:53:01 +0000121{
njnd9109c62005-06-26 04:49:25 +0000122 vg_assert(redir->from_addr);
123
124 switch (redir->type) {
125 case R_REDIRECT: {
126 CodeRedirect* r;
127
128 TRACE_REDIR(" redir resolved (%s:%s=%p -> %p)",
129 redir->from_lib, redir->from_sym, redir->from_addr,
130 redir->to_addr);
131
132 vg_assert(redir->to_addr != 0);
tom748a1312005-04-02 15:53:01 +0000133
134 if (VG_(search_transtab)(NULL, (Addr64)redir->from_addr, False)) {
135 /* For some given (from, to) redir, the "from" function got
136 called before the .so containing "to" became available. We
137 know this because there is already a translation for the
138 entry point of the original "from". So the redirect will
139 never actually take effect unless that translation is
140 discarded.
141
142 Note, we only really need to discard the first bb of the
143 old entry point, and so we avoid the problem of having to
144 figure out how big that bb was -- since it is at least 1
145 byte of original code, we can just pass 1 as the original
146 size to invalidate_translations() and it will indeed get
147 rid of the translation.
148
149 Note, this is potentially expensive -- discarding
150 translations causes complete unchaining.
151 */
njnd9109c62005-06-26 04:49:25 +0000152 TRACE_REDIR("Discarding translation due to redirect of already called function" );
153 TRACE_REDIR(" %s:%s(%p) -> %p)", redir->from_lib, redir->from_sym,
154 redir->from_addr, redir->to_addr );
tom748a1312005-04-02 15:53:01 +0000155 VG_(discard_translations)((Addr64)redir->from_addr, 1);
156 }
157
njnd9109c62005-06-26 04:49:25 +0000158 r = VG_(SkipList_Find_Exact)(&sk_resolved_redirs, &redir->from_addr);
tom748a1312005-04-02 15:53:01 +0000159
njnd9109c62005-06-26 04:49:25 +0000160 if (r == NULL) {
161 VG_(SkipList_Insert)(&sk_resolved_redirs, redir);
162 } else {
163 /* XXX leak redir */
164 TRACE_REDIR(" redir %s:%s:%p->%p duplicated\n",
165 redir->from_lib, redir->from_sym, redir->from_addr,
166 redir->to_addr);
tom748a1312005-04-02 15:53:01 +0000167 }
168 break;
njnd9109c62005-06-26 04:49:25 +0000169 }
tom748a1312005-04-02 15:53:01 +0000170
171 case R_WRAPPER:
njnd9109c62005-06-26 04:49:25 +0000172 TRACE_REDIR(" wrapper resolved (%s:%s=%p -> wrapper)",
173 redir->from_lib, redir->from_sym, redir->from_addr);
174
175 vg_assert(redir->wrapper);
tom748a1312005-04-02 15:53:01 +0000176
177 /* XXX redir leaked */
178 //VG_(wrap_function)(redir->from_addr, redir->wrapper);
179 break;
180
181 case R_CLIENT_WRAPPER:
njnd9109c62005-06-26 04:49:25 +0000182 vg_assert(redir->wrapper);
tom748a1312005-04-02 15:53:01 +0000183 VG_(core_panic)("not implemented");
184 break;
185 }
186}
187
njnd9109c62005-06-26 04:49:25 +0000188// Resolve a redir using si if possible. Returns True if it succeeded.
189static Bool resolve_redir_with_seginfo(CodeRedirect *redir, const SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000190{
njnd9109c62005-06-26 04:49:25 +0000191 Bool ok;
sewardjcbdddcf2005-03-10 23:23:45 +0000192
193 vg_assert(si != NULL);
njnd9109c62005-06-26 04:49:25 +0000194 vg_assert(redir->from_addr == 0 );
195 vg_assert(redir->from_sym != NULL);
sewardjcbdddcf2005-03-10 23:23:45 +0000196
njnd9109c62005-06-26 04:49:25 +0000197 // Resolved if the soname matches and we find the symbol.
198 ok = soname_matches(redir->from_lib, VG_(seginfo_soname)(si));
199 if (ok) {
njn748ace42005-06-21 03:36:01 +0000200 redir->from_addr = VG_(reverse_search_one_symtab)(si, redir->from_sym);
njnd9109c62005-06-26 04:49:25 +0000201 ok = ( redir->from_addr == 0 ? False : True );
sewardjcbdddcf2005-03-10 23:23:45 +0000202 }
njnd9109c62005-06-26 04:49:25 +0000203 return ok;
sewardjcbdddcf2005-03-10 23:23:45 +0000204}
205
njnd9109c62005-06-26 04:49:25 +0000206// Resolve a redir using any SegInfo if possible.
207static Bool resolve_redir_with_existing_seginfos(CodeRedirect *redir)
njnbf7ca332005-05-14 17:11:06 +0000208{
209 const SegInfo *si;
210
njnd9109c62005-06-26 04:49:25 +0000211 for (si = VG_(next_seginfo)(NULL);
212 si != NULL;
213 si = VG_(next_seginfo)(si))
njnbf7ca332005-05-14 17:11:06 +0000214 {
njnd9109c62005-06-26 04:49:25 +0000215 if (resolve_redir_with_seginfo(redir, si))
njnbf7ca332005-05-14 17:11:06 +0000216 return True;
217 }
218 return False;
219}
220
njnd9109c62005-06-26 04:49:25 +0000221// Resolve as many unresolved redirs as possible with this SegInfo. This
222// should be called when a new SegInfo symtab is loaded.
223void VG_(resolve_existing_redirs_with_seginfo)(SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000224{
njnd9109c62005-06-26 04:49:25 +0000225 CodeRedirect **prevp = &unresolved_redirs;
sewardjcbdddcf2005-03-10 23:23:45 +0000226 CodeRedirect *redir, *next;
227
njnd9109c62005-06-26 04:49:25 +0000228 TRACE_REDIR("Just loaded %s (soname=%s),",
229 VG_(seginfo_filename)(si), VG_(seginfo_soname)(si));
230 TRACE_REDIR(" resolving any unresolved redirs with it");
sewardjcbdddcf2005-03-10 23:23:45 +0000231
njnd9109c62005-06-26 04:49:25 +0000232 // Visit each unresolved redir - if it becomes resolved, then
233 // move it from the unresolved list to the resolved list.
234 for (redir = unresolved_redirs; redir != NULL; redir = next) {
sewardjcbdddcf2005-03-10 23:23:45 +0000235 next = redir->next;
236
njnd9109c62005-06-26 04:49:25 +0000237 if (resolve_redir_with_seginfo(redir, si)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000238 *prevp = next;
239 redir->next = NULL;
njnd9109c62005-06-26 04:49:25 +0000240 add_redir_to_resolved_list(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000241 } else
242 prevp = &redir->next;
243 }
sewardjcbdddcf2005-03-10 23:23:45 +0000244
njnd9109c62005-06-26 04:49:25 +0000245 TRACE_REDIR(" Finished resolving");
sewardjcbdddcf2005-03-10 23:23:45 +0000246}
247
tom748a1312005-04-02 15:53:01 +0000248/* Redirect a function at from_addr to a function at to_addr */
njn16eeb4e2005-06-16 03:56:58 +0000249__attribute__((unused)) // It is used, but not on all platforms...
njnd9109c62005-06-26 04:49:25 +0000250static void add_redirect_addr_to_addr( Addr from_addr, Addr to_addr )
tom748a1312005-04-02 15:53:01 +0000251{
njnd9109c62005-06-26 04:49:25 +0000252 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redirs);
253
254 vg_assert(0 != from_addr && 0 != to_addr);
255
256 redir->type = R_REDIRECT;
257
258 redir->from_lib = NULL;
259 redir->from_sym = NULL;
260 redir->from_addr = from_addr;
261
262 redir->to_addr = to_addr;
263 redir->wrapper = 0;
264
265 TRACE_REDIR("REDIRECT addr to addr: %p to %p", from_addr, to_addr);
266
267 // This redirection is already resolved, put it straight in the list.
268 add_redir_to_resolved_list(redir);
269}
270
271/* Redirect a lib/symbol reference to a function at addr */
272static void add_redirect_sym_to_addr(
273 const Char *from_lib, const Char *from_sym, Addr to_addr
274)
275{
276 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redirs);
277
278 vg_assert(from_lib && from_sym && 0 != to_addr);
279
280 redir->type = R_REDIRECT;
281 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
282 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
283 redir->from_addr = 0;
284 redir->to_addr = to_addr;
285 redir->wrapper = 0;
286
287 TRACE_REDIR("REDIR sym to addr: %s:%s to %p", from_lib, from_sym, to_addr);
288
289 // Check against all existing segments to see if this redirection
290 // can be resolved immediately. Then add it to the appropriate list.
291 if (resolve_redir_with_existing_seginfos(redir)) {
292 add_redir_to_resolved_list(redir);
293 } else {
294 add_redir_to_unresolved_list(redir);
295 }
tom748a1312005-04-02 15:53:01 +0000296}
297
sewardjcbdddcf2005-03-10 23:23:45 +0000298CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
299 const FuncWrapper *wrapper)
300{
njnd9109c62005-06-26 04:49:25 +0000301 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redirs);
sewardjcbdddcf2005-03-10 23:23:45 +0000302
njnd9109c62005-06-26 04:49:25 +0000303 redir->type = R_WRAPPER;
njn136b83b2005-06-19 05:14:03 +0000304 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
305 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
sewardjcbdddcf2005-03-10 23:23:45 +0000306 redir->from_addr = 0;
njn136b83b2005-06-19 05:14:03 +0000307 redir->to_addr = 0;
308 redir->wrapper = wrapper;
sewardjcbdddcf2005-03-10 23:23:45 +0000309
njnd9109c62005-06-26 04:49:25 +0000310 TRACE_REDIR("REDIR sym to wrapper: %s:%s to (%p,%p)",
311 from_lib, from_sym, wrapper->before, wrapper->after);
312
313 // Check against all existing segments to see if this redirection
314 // can be resolved immediately. Then add it to the appropriate list.
315 if (resolve_redir_with_existing_seginfos(redir)) {
316 add_redir_to_resolved_list(redir);
317 } else {
318 add_redir_to_unresolved_list(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000319 }
320
321 return redir;
322}
323
sewardjcbdddcf2005-03-10 23:23:45 +0000324/* If address 'a' is being redirected, return the redirected-to
325 address. */
326Addr VG_(code_redirect)(Addr a)
327{
328 CodeRedirect* r;
329
njnd9109c62005-06-26 04:49:25 +0000330 r = VG_(SkipList_Find_Exact)(&sk_resolved_redirs, &a);
sewardjcbdddcf2005-03-10 23:23:45 +0000331 if (r == NULL)
332 return a;
333
334 vg_assert(r->to_addr != 0);
335
336 return r->to_addr;
337}
338
339void VG_(setup_code_redirect_table) ( void )
340{
njnd1af0032005-05-29 17:01:48 +0000341#if defined(VGP_x86_linux)
342 /* Redirect _dl_sysinfo_int80, which is glibc's default system call
sewardjb9bce632005-06-21 01:41:34 +0000343 routine, to our copy so that the special sysinfo unwind hack in
344 m_stacktrace.c will kick in. */
345 add_redirect_sym_to_addr(
346 "soname:ld-linux.so.2", "_dl_sysinfo_int80",
347 (Addr)&VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80)
348 );
349
njnd1af0032005-05-29 17:01:48 +0000350#elif defined(VGP_amd64_linux)
sewardjb9bce632005-06-21 01:41:34 +0000351
njnd1af0032005-05-29 17:01:48 +0000352 /* Redirect vsyscalls to local versions */
sewardjb9bce632005-06-21 01:41:34 +0000353 add_redirect_addr_to_addr(
354 0xFFFFFFFFFF600000ULL,
355 (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)
356 );
357
358 add_redirect_addr_to_addr(
tomf5db3b62005-06-21 13:26:17 +0000359 0xFFFFFFFFFF600400ULL,
sewardjb9bce632005-06-21 01:41:34 +0000360 (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)
361 );
362
cerion85665ca2005-06-20 15:51:07 +0000363#elif defined(VGP_ppc32_linux)
sewardjb9bce632005-06-21 01:41:34 +0000364
365 //CAB: TODO
366
njnd1af0032005-05-29 17:01:48 +0000367#else
368# error Unknown platform
369#endif
370}
sewardjcbdddcf2005-03-10 23:23:45 +0000371
njn16eeb4e2005-06-16 03:56:58 +0000372/* Z-decode a symbol into library:func form, eg
373
374 _vgi_libcZdsoZd6__ZdlPv --> libc.so.6:_ZdlPv
375
376 Uses the Z-encoding scheme described in pub_core_redir.h.
377 Returns True if demangle OK, False otherwise.
378*/
379static Bool Z_decode(const Char* symbol, Char* result, Int nbytes)
380{
381# define EMIT(ch) \
382 do { \
383 if (j >= nbytes) \
384 result[j-1] = 0; \
385 else \
386 result[j++] = ch; \
387 } while (0)
388
389 Bool error = False;
390 Int i, j = 0;
391 Int len = VG_(strlen)(symbol);
392 if (0) VG_(printf)("idm: %s\n", symbol);
393
394 i = VG_REPLACE_FUNCTION_PREFIX_LEN;
395
396 /* Chew though the Z-encoded soname part. */
397 while (True) {
398
399 if (i >= len)
400 break;
401
402 if (symbol[i] == '_')
403 /* We found the underscore following the Z-encoded soname.
404 Just copy the rest literally. */
405 break;
406
407 if (symbol[i] != 'Z') {
408 EMIT(symbol[i]);
409 i++;
410 continue;
411 }
412
413 /* We've got a Z-escape. Act accordingly. */
414 i++;
415 if (i >= len) {
416 /* Hmm, Z right at the end. Something's wrong. */
417 error = True;
418 EMIT('Z');
419 break;
420 }
421 switch (symbol[i]) {
422 case 'a': EMIT('*'); break;
423 case 'p': EMIT('+'); break;
424 case 'c': EMIT(':'); break;
425 case 'd': EMIT('.'); break;
426 case 'u': EMIT('_'); break;
427 case 'h': EMIT('-'); break;
428 case 's': EMIT(' '); break;
429 case 'Z': EMIT('Z'); break;
430 default: error = True; EMIT('Z'); EMIT(symbol[i]); break;
431 }
432 i++;
433 }
434
435 if (error || i >= len || symbol[i] != '_') {
436 /* Something's wrong. Give up. */
437 VG_(message)(Vg_UserMsg, "intercept: error demangling: %s", symbol);
438 EMIT(0);
439 return False;
440 }
441
442 /* Copy the rest of the string verbatim. */
443 i++;
444 EMIT(':');
445 while (True) {
446 if (i >= len)
447 break;
448 EMIT(symbol[i]);
449 i++;
450 }
451
452 EMIT(0);
453 if (0) VG_(printf)("%s\n", result);
454 return True;
455
456# undef EMIT
457}
458
459// Nb: this can change the string pointed to by 'symbol'.
460static void handle_replacement_function( Char* symbol, Addr addr )
461{
462 Bool ok;
463 Int len = VG_(strlen)(symbol) + 1 - VG_REPLACE_FUNCTION_PREFIX_LEN;
464 Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len+8);
465 Char *func;
466
467 // Put "soname:" at the start of lib
468 VG_(strcpy)(lib, "soname:");
469
470 ok = Z_decode(symbol, lib+7, len);
471 if (ok) {
472 // lib is "soname:<libname>:<fnname>". Split the string at the 2nd ':'.
473 func = lib + VG_(strlen)(lib)-1;
474 while(*func != ':') func--;
475 *func = '\0';
476 func++; // Move past the '\0'
477
478 // Now lib is "soname:<libname>" and func is "<fnname>".
479 if (0) VG_(printf)("lib A%sZ, func A%sZ\n", lib, func);
480 add_redirect_sym_to_addr(lib, func, addr);
481
482 // Overwrite the given Z-encoded name with just the fnname.
483 VG_(strcpy)(symbol, func);
484 }
485
486 VG_(arena_free)(VG_AR_SYMTAB, lib);
487}
488
njnbc6d84d2005-06-19 18:58:03 +0000489static Addr __libc_freeres_wrapper = 0;
490
491Addr VG_(get_libc_freeres_wrapper)(void)
492{
493 return __libc_freeres_wrapper;
494}
495
njn16eeb4e2005-06-16 03:56:58 +0000496// This is specifically for stringifying VG_(x) function names. We
497// need to do two macroexpansions to get the VG_ macro expanded before
498// stringifying.
499#define _STR(x) #x
500#define STR(x) _STR(x)
501
502static void handle_load_notifier( Char* symbol, Addr addr )
503{
504 if (VG_(strcmp)(symbol, STR(VG_NOTIFY_ON_LOAD(freeres))) == 0)
njnbc6d84d2005-06-19 18:58:03 +0000505 __libc_freeres_wrapper = addr;
njn16eeb4e2005-06-16 03:56:58 +0000506// else if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) == 0)
507// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value));
508 else
509 vg_assert2(0, "unrecognised load notification function: %s", symbol);
510}
511
512static Bool is_replacement_function(Char* s)
513{
514 return (0 == VG_(strncmp)(s,
515 VG_REPLACE_FUNCTION_PREFIX,
516 VG_REPLACE_FUNCTION_PREFIX_LEN));
517}
518
519static Bool is_load_notifier(Char* s)
520{
521 return (0 == VG_(strncmp)(s,
522 VG_NOTIFY_ON_LOAD_PREFIX,
523 VG_NOTIFY_ON_LOAD_PREFIX_LEN));
524}
525
526// Call this for each symbol loaded. It determines if we need to do
527// anything special with it. It can modify 'symbol' in-place.
528void VG_(maybe_redir_or_notify) ( Char* symbol, Addr addr )
529{
530 if (is_replacement_function(symbol))
531 handle_replacement_function(symbol, addr);
532 else
533 if (is_load_notifier(symbol))
534 handle_load_notifier(symbol, addr);
535}
536
537
sewardjcbdddcf2005-03-10 23:23:45 +0000538//:: /*------------------------------------------------------------*/
539//:: /*--- General function wrapping. ---*/
540//:: /*------------------------------------------------------------*/
541//::
542//:: /*
543//:: TODO:
544//:: - hook into the symtab machinery
545//:: - client-side wrappers?
546//:: - better interfaces for before() functions to get to arguments
547//:: - handle munmap of code (dlclose())
548//:: - handle thread exit
549//:: - handle longjmp
550//:: */
551//:: struct callkey {
552//:: ThreadId tid; /* calling thread */
553//:: Addr esp; /* address of args on stack */
554//:: Addr eip; /* return address */
555//:: };
556//::
557//:: struct call_instance {
558//:: struct callkey key;
559//::
560//:: const FuncWrapper *wrapper;
561//:: void *nonce;
562//:: };
563//::
564//:: static inline Addr addrcmp(Addr a, Addr b)
565//:: {
566//:: if (a < b)
567//:: return -1;
568//:: else if (a > b)
569//:: return 1;
570//:: else
571//:: return 0;
572//:: }
573//::
574//:: static inline Int cmp(UInt a, UInt b)
575//:: {
576//:: if (a < b)
577//:: return -1;
578//:: else if (a > b)
579//:: return 1;
580//:: else
581//:: return 0;
582//:: }
583//::
584//:: static Int keycmp(const void *pa, const void *pb)
585//:: {
586//:: const struct callkey *a = (const struct callkey *)pa;
587//:: const struct callkey *b = (const struct callkey *)pb;
588//:: Int ret;
589//::
590//:: if ((ret = cmp(a->tid, b->tid)))
591//:: return ret;
592//::
593//:: if ((ret = addrcmp(a->esp, b->esp)))
594//:: return ret;
595//::
596//:: return addrcmp(a->eip, b->eip);
597//:: }
598//::
599//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000600//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000601//:: NULL, VG_AR_SYMTAB);
602//::
603//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
604//:: {
605//:: struct callkey key = { tid, argsp, retaddr };
606//::
607//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
608//:: }
609//::
610//:: static void wrapper_return(Addr retaddr);
611//::
612//:: /* Called from generated code via helper */
613//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
614//:: {
njnaf839f52005-06-23 03:27:57 +0000615//:: Addr retaddr = VG_RETADDR(tst->arch);
616//:: Addr argp = (Addr)&VG_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000617//:: void *nonce = NULL;
618//:: Bool mf = VG_(my_fault);
619//:: VG_(my_fault) = True;
620//::
621//:: if (wrapper->before) {
njnaf839f52005-06-23 03:27:57 +0000622//:: va_list args = VG_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000623//:: nonce = (*wrapper->before)(args);
624//:: }
625//::
626//:: if (wrapper->after) {
627//:: /* If there's an after function, make sure it gets called */
628//:: struct call_instance *call;
629//::
630//:: call = find_call(retaddr, argp, tst->tid);
631//::
632//:: if (call != NULL) {
633//:: /* Found a stale outstanding call; clean it up and recycle
634//:: the structure */
635//:: if (call->wrapper->after)
636//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
637//:: } else {
638//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
639//::
640//:: call->key.tid = tst->tid;
641//:: call->key.esp = argp;
642//:: call->key.eip = retaddr;
643//::
644//:: VG_(SkipList_Insert)(&wrapped_frames, call);
645//::
646//:: wrapper_return(retaddr);
647//:: }
648//::
649//:: call->wrapper = wrapper;
650//:: call->nonce = nonce;
651//:: } else
652//:: vg_assert(nonce == NULL);
653//::
654//:: VG_(my_fault) = mf;
655//:: }
656//::
657//:: /* Called from generated code via helper */
658//:: void VG_(wrap_after)(ThreadState *tst)
659//:: {
njnaf839f52005-06-23 03:27:57 +0000660//:: Addr EIP = VG_INSTR_PTR(tst->arch); /* instruction after call */
661//:: Addr ESP = VG_STACK_PTR(tst->arch); /* pointer to args */
662//:: Word ret = VG_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000663//:: struct call_instance *call;
664//:: Bool mf = VG_(my_fault);
665//::
666//:: VG_(my_fault) = True;
667//:: call = find_call(EIP, ESP, tst->tid);
668//::
669//:: if (0)
670//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
671//::
672//:: if (call != NULL) {
673//:: if (call->wrapper->after)
674//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
675//::
676//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
677//:: VG_(SkipNode_Free)(&wrapped_frames, call);
678//:: }
679//:: VG_(my_fault) = mf;
680//:: }
681//::
682//::
683//:: struct wrapped_function {
684//:: Addr eip; /* eip of function entrypoint */
685//:: const FuncWrapper *wrapper;
686//:: };
687//::
688//:: struct wrapper_return {
689//:: Addr eip; /* return address */
690//:: };
691//::
692//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000693//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000694//:: NULL, VG_AR_SYMTAB);
695//::
696//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000697//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000698//:: NULL, VG_AR_SYMTAB);
699//::
700//:: /* Wrap function starting at eip */
701//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
702//:: {
703//:: struct wrapped_function *func;
704//::
705//:: if (0)
706//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
707//::
708//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
709//::
710//:: if (func == NULL) {
711//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
712//:: VG_(invalidate_translations)(eip, 1, True);
713//::
714//:: func->eip = eip;
715//:: VG_(SkipList_Insert)(&wrapped_functions, func);
716//:: }
717//::
718//:: func->wrapper = wrapper;
719//:: }
720//::
721//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
722//:: {
723//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
724//::
725//:: if (func)
726//:: return func->wrapper;
727//:: return NULL;
728//:: }
729//::
730//:: Bool VG_(is_wrapper_return)(Addr eip)
731//:: {
732//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
733//::
734//:: return ret != NULL;
735//:: }
736//::
737//:: /* Mark eip as being the return address of a wrapper, so that the
738//:: codegen will generate the appropriate call. */
739//:: void wrapper_return(Addr eip)
740//:: {
741//:: struct wrapper_return *ret;
742//::
743//:: if (VG_(is_wrapper_return)(eip))
744//:: return;
745//::
746//:: VG_(invalidate_translations)(eip, 1, True);
747//::
748//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
749//:: ret->eip = eip;
750//::
751//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
752//:: }