blob: 253f2789513a60cff7a82c4b989c297595456d30 [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
njn2025cf92005-06-26 20:44:48 +0000206// Resolve a redir using any SegInfo if possible. This is called whenever
207// a new sym-to-addr redir is created. It covers the case where a
208// replacement function is loaded after its replacee.
njnd9109c62005-06-26 04:49:25 +0000209static Bool resolve_redir_with_existing_seginfos(CodeRedirect *redir)
njnbf7ca332005-05-14 17:11:06 +0000210{
211 const SegInfo *si;
212
njnd9109c62005-06-26 04:49:25 +0000213 for (si = VG_(next_seginfo)(NULL);
214 si != NULL;
215 si = VG_(next_seginfo)(si))
njnbf7ca332005-05-14 17:11:06 +0000216 {
njnd9109c62005-06-26 04:49:25 +0000217 if (resolve_redir_with_seginfo(redir, si))
njnbf7ca332005-05-14 17:11:06 +0000218 return True;
219 }
220 return False;
221}
222
njnd9109c62005-06-26 04:49:25 +0000223// Resolve as many unresolved redirs as possible with this SegInfo. This
njn2025cf92005-06-26 20:44:48 +0000224// should be called when a new SegInfo symtab is loaded. It covers the case
225// where a replacee function is loaded after its replacement function.
njnd9109c62005-06-26 04:49:25 +0000226void VG_(resolve_existing_redirs_with_seginfo)(SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000227{
njnd9109c62005-06-26 04:49:25 +0000228 CodeRedirect **prevp = &unresolved_redirs;
sewardjcbdddcf2005-03-10 23:23:45 +0000229 CodeRedirect *redir, *next;
230
njnd9109c62005-06-26 04:49:25 +0000231 TRACE_REDIR("Just loaded %s (soname=%s),",
232 VG_(seginfo_filename)(si), VG_(seginfo_soname)(si));
233 TRACE_REDIR(" resolving any unresolved redirs with it");
sewardjcbdddcf2005-03-10 23:23:45 +0000234
njnd9109c62005-06-26 04:49:25 +0000235 // Visit each unresolved redir - if it becomes resolved, then
236 // move it from the unresolved list to the resolved list.
237 for (redir = unresolved_redirs; redir != NULL; redir = next) {
sewardjcbdddcf2005-03-10 23:23:45 +0000238 next = redir->next;
239
njnd9109c62005-06-26 04:49:25 +0000240 if (resolve_redir_with_seginfo(redir, si)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000241 *prevp = next;
242 redir->next = NULL;
njnd9109c62005-06-26 04:49:25 +0000243 add_redir_to_resolved_list(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000244 } else
245 prevp = &redir->next;
246 }
sewardjcbdddcf2005-03-10 23:23:45 +0000247
njnd9109c62005-06-26 04:49:25 +0000248 TRACE_REDIR(" Finished resolving");
sewardjcbdddcf2005-03-10 23:23:45 +0000249}
250
tom748a1312005-04-02 15:53:01 +0000251/* Redirect a function at from_addr to a function at to_addr */
njn16eeb4e2005-06-16 03:56:58 +0000252__attribute__((unused)) // It is used, but not on all platforms...
njnd9109c62005-06-26 04:49:25 +0000253static void add_redirect_addr_to_addr( Addr from_addr, Addr to_addr )
tom748a1312005-04-02 15:53:01 +0000254{
njnd9109c62005-06-26 04:49:25 +0000255 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redirs);
256
257 vg_assert(0 != from_addr && 0 != to_addr);
258
259 redir->type = R_REDIRECT;
260
261 redir->from_lib = NULL;
262 redir->from_sym = NULL;
263 redir->from_addr = from_addr;
264
265 redir->to_addr = to_addr;
266 redir->wrapper = 0;
267
268 TRACE_REDIR("REDIRECT addr to addr: %p to %p", from_addr, to_addr);
269
270 // This redirection is already resolved, put it straight in the list.
271 add_redir_to_resolved_list(redir);
272}
273
274/* Redirect a lib/symbol reference to a function at addr */
275static void add_redirect_sym_to_addr(
276 const Char *from_lib, const Char *from_sym, Addr to_addr
277)
278{
279 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redirs);
280
281 vg_assert(from_lib && from_sym && 0 != to_addr);
282
283 redir->type = R_REDIRECT;
284 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
285 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
286 redir->from_addr = 0;
287 redir->to_addr = to_addr;
288 redir->wrapper = 0;
289
290 TRACE_REDIR("REDIR sym to addr: %s:%s to %p", from_lib, from_sym, to_addr);
291
292 // Check against all existing segments to see if this redirection
njn2025cf92005-06-26 20:44:48 +0000293 // can be resolved immediately (as will be the case when the replacement
294 // function is loaded after the replacee). Then add it to the
295 // appropriate list.
njnd9109c62005-06-26 04:49:25 +0000296 if (resolve_redir_with_existing_seginfos(redir)) {
297 add_redir_to_resolved_list(redir);
298 } else {
299 add_redir_to_unresolved_list(redir);
300 }
tom748a1312005-04-02 15:53:01 +0000301}
302
sewardjcbdddcf2005-03-10 23:23:45 +0000303CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
304 const FuncWrapper *wrapper)
305{
njnd9109c62005-06-26 04:49:25 +0000306 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redirs);
sewardjcbdddcf2005-03-10 23:23:45 +0000307
njnd9109c62005-06-26 04:49:25 +0000308 redir->type = R_WRAPPER;
njn136b83b2005-06-19 05:14:03 +0000309 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
310 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
sewardjcbdddcf2005-03-10 23:23:45 +0000311 redir->from_addr = 0;
njn136b83b2005-06-19 05:14:03 +0000312 redir->to_addr = 0;
313 redir->wrapper = wrapper;
sewardjcbdddcf2005-03-10 23:23:45 +0000314
njnd9109c62005-06-26 04:49:25 +0000315 TRACE_REDIR("REDIR sym to wrapper: %s:%s to (%p,%p)",
316 from_lib, from_sym, wrapper->before, wrapper->after);
317
318 // Check against all existing segments to see if this redirection
319 // can be resolved immediately. Then add it to the appropriate list.
320 if (resolve_redir_with_existing_seginfos(redir)) {
321 add_redir_to_resolved_list(redir);
322 } else {
323 add_redir_to_unresolved_list(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000324 }
325
326 return redir;
327}
328
sewardjcbdddcf2005-03-10 23:23:45 +0000329/* If address 'a' is being redirected, return the redirected-to
330 address. */
331Addr VG_(code_redirect)(Addr a)
332{
333 CodeRedirect* r;
334
njnd9109c62005-06-26 04:49:25 +0000335 r = VG_(SkipList_Find_Exact)(&sk_resolved_redirs, &a);
sewardjcbdddcf2005-03-10 23:23:45 +0000336 if (r == NULL)
337 return a;
338
339 vg_assert(r->to_addr != 0);
340
341 return r->to_addr;
342}
343
344void VG_(setup_code_redirect_table) ( void )
345{
njnd1af0032005-05-29 17:01:48 +0000346#if defined(VGP_x86_linux)
347 /* Redirect _dl_sysinfo_int80, which is glibc's default system call
sewardjb9bce632005-06-21 01:41:34 +0000348 routine, to our copy so that the special sysinfo unwind hack in
349 m_stacktrace.c will kick in. */
350 add_redirect_sym_to_addr(
351 "soname:ld-linux.so.2", "_dl_sysinfo_int80",
352 (Addr)&VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80)
353 );
354
njnd1af0032005-05-29 17:01:48 +0000355#elif defined(VGP_amd64_linux)
sewardjb9bce632005-06-21 01:41:34 +0000356
njnd1af0032005-05-29 17:01:48 +0000357 /* Redirect vsyscalls to local versions */
sewardjb9bce632005-06-21 01:41:34 +0000358 add_redirect_addr_to_addr(
359 0xFFFFFFFFFF600000ULL,
360 (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)
361 );
362
363 add_redirect_addr_to_addr(
tomf5db3b62005-06-21 13:26:17 +0000364 0xFFFFFFFFFF600400ULL,
sewardjb9bce632005-06-21 01:41:34 +0000365 (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)
366 );
367
cerion85665ca2005-06-20 15:51:07 +0000368#elif defined(VGP_ppc32_linux)
sewardjb9bce632005-06-21 01:41:34 +0000369
370 //CAB: TODO
371
njnd1af0032005-05-29 17:01:48 +0000372#else
373# error Unknown platform
374#endif
375}
sewardjcbdddcf2005-03-10 23:23:45 +0000376
njn16eeb4e2005-06-16 03:56:58 +0000377/* Z-decode a symbol into library:func form, eg
378
379 _vgi_libcZdsoZd6__ZdlPv --> libc.so.6:_ZdlPv
380
381 Uses the Z-encoding scheme described in pub_core_redir.h.
382 Returns True if demangle OK, False otherwise.
383*/
384static Bool Z_decode(const Char* symbol, Char* result, Int nbytes)
385{
386# define EMIT(ch) \
387 do { \
388 if (j >= nbytes) \
389 result[j-1] = 0; \
390 else \
391 result[j++] = ch; \
392 } while (0)
393
394 Bool error = False;
395 Int i, j = 0;
396 Int len = VG_(strlen)(symbol);
397 if (0) VG_(printf)("idm: %s\n", symbol);
398
399 i = VG_REPLACE_FUNCTION_PREFIX_LEN;
400
401 /* Chew though the Z-encoded soname part. */
402 while (True) {
403
404 if (i >= len)
405 break;
406
407 if (symbol[i] == '_')
408 /* We found the underscore following the Z-encoded soname.
409 Just copy the rest literally. */
410 break;
411
412 if (symbol[i] != 'Z') {
413 EMIT(symbol[i]);
414 i++;
415 continue;
416 }
417
418 /* We've got a Z-escape. Act accordingly. */
419 i++;
420 if (i >= len) {
421 /* Hmm, Z right at the end. Something's wrong. */
422 error = True;
423 EMIT('Z');
424 break;
425 }
426 switch (symbol[i]) {
427 case 'a': EMIT('*'); break;
428 case 'p': EMIT('+'); break;
429 case 'c': EMIT(':'); break;
430 case 'd': EMIT('.'); break;
431 case 'u': EMIT('_'); break;
432 case 'h': EMIT('-'); break;
433 case 's': EMIT(' '); break;
434 case 'Z': EMIT('Z'); break;
435 default: error = True; EMIT('Z'); EMIT(symbol[i]); break;
436 }
437 i++;
438 }
439
440 if (error || i >= len || symbol[i] != '_') {
441 /* Something's wrong. Give up. */
442 VG_(message)(Vg_UserMsg, "intercept: error demangling: %s", symbol);
443 EMIT(0);
444 return False;
445 }
446
447 /* Copy the rest of the string verbatim. */
448 i++;
449 EMIT(':');
450 while (True) {
451 if (i >= len)
452 break;
453 EMIT(symbol[i]);
454 i++;
455 }
456
457 EMIT(0);
458 if (0) VG_(printf)("%s\n", result);
459 return True;
460
461# undef EMIT
462}
463
464// Nb: this can change the string pointed to by 'symbol'.
465static void handle_replacement_function( Char* symbol, Addr addr )
466{
467 Bool ok;
468 Int len = VG_(strlen)(symbol) + 1 - VG_REPLACE_FUNCTION_PREFIX_LEN;
469 Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len+8);
470 Char *func;
471
472 // Put "soname:" at the start of lib
473 VG_(strcpy)(lib, "soname:");
474
475 ok = Z_decode(symbol, lib+7, len);
476 if (ok) {
477 // lib is "soname:<libname>:<fnname>". Split the string at the 2nd ':'.
478 func = lib + VG_(strlen)(lib)-1;
479 while(*func != ':') func--;
480 *func = '\0';
481 func++; // Move past the '\0'
482
483 // Now lib is "soname:<libname>" and func is "<fnname>".
484 if (0) VG_(printf)("lib A%sZ, func A%sZ\n", lib, func);
485 add_redirect_sym_to_addr(lib, func, addr);
486
487 // Overwrite the given Z-encoded name with just the fnname.
488 VG_(strcpy)(symbol, func);
489 }
490
491 VG_(arena_free)(VG_AR_SYMTAB, lib);
492}
493
njnbc6d84d2005-06-19 18:58:03 +0000494static Addr __libc_freeres_wrapper = 0;
495
496Addr VG_(get_libc_freeres_wrapper)(void)
497{
498 return __libc_freeres_wrapper;
499}
500
njn16eeb4e2005-06-16 03:56:58 +0000501// This is specifically for stringifying VG_(x) function names. We
502// need to do two macroexpansions to get the VG_ macro expanded before
503// stringifying.
504#define _STR(x) #x
505#define STR(x) _STR(x)
506
507static void handle_load_notifier( Char* symbol, Addr addr )
508{
509 if (VG_(strcmp)(symbol, STR(VG_NOTIFY_ON_LOAD(freeres))) == 0)
njnbc6d84d2005-06-19 18:58:03 +0000510 __libc_freeres_wrapper = addr;
njn16eeb4e2005-06-16 03:56:58 +0000511// else if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) == 0)
512// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value));
513 else
514 vg_assert2(0, "unrecognised load notification function: %s", symbol);
515}
516
517static Bool is_replacement_function(Char* s)
518{
519 return (0 == VG_(strncmp)(s,
520 VG_REPLACE_FUNCTION_PREFIX,
521 VG_REPLACE_FUNCTION_PREFIX_LEN));
522}
523
524static Bool is_load_notifier(Char* s)
525{
526 return (0 == VG_(strncmp)(s,
527 VG_NOTIFY_ON_LOAD_PREFIX,
528 VG_NOTIFY_ON_LOAD_PREFIX_LEN));
529}
530
531// Call this for each symbol loaded. It determines if we need to do
532// anything special with it. It can modify 'symbol' in-place.
533void VG_(maybe_redir_or_notify) ( Char* symbol, Addr addr )
534{
535 if (is_replacement_function(symbol))
536 handle_replacement_function(symbol, addr);
537 else
538 if (is_load_notifier(symbol))
539 handle_load_notifier(symbol, addr);
540}
541
542
sewardjcbdddcf2005-03-10 23:23:45 +0000543//:: /*------------------------------------------------------------*/
544//:: /*--- General function wrapping. ---*/
545//:: /*------------------------------------------------------------*/
546//::
547//:: /*
548//:: TODO:
549//:: - hook into the symtab machinery
550//:: - client-side wrappers?
551//:: - better interfaces for before() functions to get to arguments
552//:: - handle munmap of code (dlclose())
553//:: - handle thread exit
554//:: - handle longjmp
555//:: */
556//:: struct callkey {
557//:: ThreadId tid; /* calling thread */
558//:: Addr esp; /* address of args on stack */
559//:: Addr eip; /* return address */
560//:: };
561//::
562//:: struct call_instance {
563//:: struct callkey key;
564//::
565//:: const FuncWrapper *wrapper;
566//:: void *nonce;
567//:: };
568//::
569//:: static inline Addr addrcmp(Addr a, Addr b)
570//:: {
571//:: if (a < b)
572//:: return -1;
573//:: else if (a > b)
574//:: return 1;
575//:: else
576//:: return 0;
577//:: }
578//::
579//:: static inline Int cmp(UInt a, UInt 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 Int keycmp(const void *pa, const void *pb)
590//:: {
591//:: const struct callkey *a = (const struct callkey *)pa;
592//:: const struct callkey *b = (const struct callkey *)pb;
593//:: Int ret;
594//::
595//:: if ((ret = cmp(a->tid, b->tid)))
596//:: return ret;
597//::
598//:: if ((ret = addrcmp(a->esp, b->esp)))
599//:: return ret;
600//::
601//:: return addrcmp(a->eip, b->eip);
602//:: }
603//::
604//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000605//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000606//:: NULL, VG_AR_SYMTAB);
607//::
608//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
609//:: {
610//:: struct callkey key = { tid, argsp, retaddr };
611//::
612//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
613//:: }
614//::
615//:: static void wrapper_return(Addr retaddr);
616//::
617//:: /* Called from generated code via helper */
618//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
619//:: {
njnaf839f52005-06-23 03:27:57 +0000620//:: Addr retaddr = VG_RETADDR(tst->arch);
621//:: Addr argp = (Addr)&VG_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000622//:: void *nonce = NULL;
623//:: Bool mf = VG_(my_fault);
624//:: VG_(my_fault) = True;
625//::
626//:: if (wrapper->before) {
njnaf839f52005-06-23 03:27:57 +0000627//:: va_list args = VG_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000628//:: nonce = (*wrapper->before)(args);
629//:: }
630//::
631//:: if (wrapper->after) {
632//:: /* If there's an after function, make sure it gets called */
633//:: struct call_instance *call;
634//::
635//:: call = find_call(retaddr, argp, tst->tid);
636//::
637//:: if (call != NULL) {
638//:: /* Found a stale outstanding call; clean it up and recycle
639//:: the structure */
640//:: if (call->wrapper->after)
641//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
642//:: } else {
643//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
644//::
645//:: call->key.tid = tst->tid;
646//:: call->key.esp = argp;
647//:: call->key.eip = retaddr;
648//::
649//:: VG_(SkipList_Insert)(&wrapped_frames, call);
650//::
651//:: wrapper_return(retaddr);
652//:: }
653//::
654//:: call->wrapper = wrapper;
655//:: call->nonce = nonce;
656//:: } else
657//:: vg_assert(nonce == NULL);
658//::
659//:: VG_(my_fault) = mf;
660//:: }
661//::
662//:: /* Called from generated code via helper */
663//:: void VG_(wrap_after)(ThreadState *tst)
664//:: {
njnaf839f52005-06-23 03:27:57 +0000665//:: Addr EIP = VG_INSTR_PTR(tst->arch); /* instruction after call */
666//:: Addr ESP = VG_STACK_PTR(tst->arch); /* pointer to args */
667//:: Word ret = VG_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000668//:: struct call_instance *call;
669//:: Bool mf = VG_(my_fault);
670//::
671//:: VG_(my_fault) = True;
672//:: call = find_call(EIP, ESP, tst->tid);
673//::
674//:: if (0)
675//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
676//::
677//:: if (call != NULL) {
678//:: if (call->wrapper->after)
679//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
680//::
681//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
682//:: VG_(SkipNode_Free)(&wrapped_frames, call);
683//:: }
684//:: VG_(my_fault) = mf;
685//:: }
686//::
687//::
688//:: struct wrapped_function {
689//:: Addr eip; /* eip of function entrypoint */
690//:: const FuncWrapper *wrapper;
691//:: };
692//::
693//:: struct wrapper_return {
694//:: Addr eip; /* return address */
695//:: };
696//::
697//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000698//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000699//:: NULL, VG_AR_SYMTAB);
700//::
701//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000702//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000703//:: NULL, VG_AR_SYMTAB);
704//::
705//:: /* Wrap function starting at eip */
706//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
707//:: {
708//:: struct wrapped_function *func;
709//::
710//:: if (0)
711//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
712//::
713//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
714//::
715//:: if (func == NULL) {
716//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
717//:: VG_(invalidate_translations)(eip, 1, True);
718//::
719//:: func->eip = eip;
720//:: VG_(SkipList_Insert)(&wrapped_functions, func);
721//:: }
722//::
723//:: func->wrapper = wrapper;
724//:: }
725//::
726//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
727//:: {
728//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
729//::
730//:: if (func)
731//:: return func->wrapper;
732//:: return NULL;
733//:: }
734//::
735//:: Bool VG_(is_wrapper_return)(Addr eip)
736//:: {
737//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
738//::
739//:: return ret != NULL;
740//:: }
741//::
742//:: /* Mark eip as being the return address of a wrapper, so that the
743//:: codegen will generate the appropriate call. */
744//:: void wrapper_return(Addr eip)
745//:: {
746//:: struct wrapper_return *ret;
747//::
748//:: if (VG_(is_wrapper_return)(eip))
749//:: return;
750//::
751//:: VG_(invalidate_translations)(eip, 1, True);
752//::
753//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
754//:: ret->eip = eip;
755//::
756//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
757//:: }