blob: ec892e34d5a046b320d6be3f02cf4d058ebbd281 [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
sewardjf9a82d12005-07-23 09:52:21 +0000120static void add_redir_to_resolved_list(CodeRedirect *redir, Bool need_discard)
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
sewardjf9a82d12005-07-23 09:52:21 +0000134 if (need_discard) {
tom748a1312005-04-02 15:53:01 +0000135 /* For some given (from, to) redir, the "from" function got
sewardjf9a82d12005-07-23 09:52:21 +0000136 loaded before the .so containing "to" became available so
137 we need to discard any existing translations involving
138 the "from" function.
tom748a1312005-04-02 15:53:01 +0000139
140 Note, we only really need to discard the first bb of the
141 old entry point, and so we avoid the problem of having to
142 figure out how big that bb was -- since it is at least 1
143 byte of original code, we can just pass 1 as the original
144 size to invalidate_translations() and it will indeed get
145 rid of the translation.
146
147 Note, this is potentially expensive -- discarding
sewardjeccb2d82005-07-23 11:36:03 +0000148 translations requires a complete search through all of
149 them.
tom748a1312005-04-02 15:53:01 +0000150 */
sewardjf9a82d12005-07-23 09:52:21 +0000151 TRACE_REDIR("Discarding translation due to redirect of already loaded function" );
njnd9109c62005-06-26 04:49:25 +0000152 TRACE_REDIR(" %s:%s(%p) -> %p)", redir->from_lib, redir->from_sym,
153 redir->from_addr, redir->to_addr );
tom748a1312005-04-02 15:53:01 +0000154 VG_(discard_translations)((Addr64)redir->from_addr, 1);
155 }
156
njnd9109c62005-06-26 04:49:25 +0000157 r = VG_(SkipList_Find_Exact)(&sk_resolved_redirs, &redir->from_addr);
tom748a1312005-04-02 15:53:01 +0000158
njnd9109c62005-06-26 04:49:25 +0000159 if (r == NULL) {
160 VG_(SkipList_Insert)(&sk_resolved_redirs, redir);
161 } else {
162 /* XXX leak redir */
163 TRACE_REDIR(" redir %s:%s:%p->%p duplicated\n",
164 redir->from_lib, redir->from_sym, redir->from_addr,
165 redir->to_addr);
tom748a1312005-04-02 15:53:01 +0000166 }
167 break;
njnd9109c62005-06-26 04:49:25 +0000168 }
tom748a1312005-04-02 15:53:01 +0000169
170 case R_WRAPPER:
njnd9109c62005-06-26 04:49:25 +0000171 TRACE_REDIR(" wrapper resolved (%s:%s=%p -> wrapper)",
172 redir->from_lib, redir->from_sym, redir->from_addr);
173
174 vg_assert(redir->wrapper);
tom748a1312005-04-02 15:53:01 +0000175
176 /* XXX redir leaked */
177 //VG_(wrap_function)(redir->from_addr, redir->wrapper);
178 break;
179
180 case R_CLIENT_WRAPPER:
njnd9109c62005-06-26 04:49:25 +0000181 vg_assert(redir->wrapper);
tom748a1312005-04-02 15:53:01 +0000182 VG_(core_panic)("not implemented");
183 break;
184 }
185}
186
njnd9109c62005-06-26 04:49:25 +0000187// Resolve a redir using si if possible. Returns True if it succeeded.
188static Bool resolve_redir_with_seginfo(CodeRedirect *redir, const SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000189{
njnd9109c62005-06-26 04:49:25 +0000190 Bool ok;
sewardjcbdddcf2005-03-10 23:23:45 +0000191
192 vg_assert(si != NULL);
njnd9109c62005-06-26 04:49:25 +0000193 vg_assert(redir->from_addr == 0 );
194 vg_assert(redir->from_sym != NULL);
sewardjcbdddcf2005-03-10 23:23:45 +0000195
njnd9109c62005-06-26 04:49:25 +0000196 // Resolved if the soname matches and we find the symbol.
197 ok = soname_matches(redir->from_lib, VG_(seginfo_soname)(si));
198 if (ok) {
njn748ace42005-06-21 03:36:01 +0000199 redir->from_addr = VG_(reverse_search_one_symtab)(si, redir->from_sym);
njnd9109c62005-06-26 04:49:25 +0000200 ok = ( redir->from_addr == 0 ? False : True );
sewardjcbdddcf2005-03-10 23:23:45 +0000201 }
njnd9109c62005-06-26 04:49:25 +0000202 return ok;
sewardjcbdddcf2005-03-10 23:23:45 +0000203}
204
njn2025cf92005-06-26 20:44:48 +0000205// Resolve a redir using any SegInfo if possible. This is called whenever
206// a new sym-to-addr redir is created. It covers the case where a
207// replacement function is loaded after its replacee.
njnd9109c62005-06-26 04:49:25 +0000208static Bool resolve_redir_with_existing_seginfos(CodeRedirect *redir)
njnbf7ca332005-05-14 17:11:06 +0000209{
210 const SegInfo *si;
211
njnd9109c62005-06-26 04:49:25 +0000212 for (si = VG_(next_seginfo)(NULL);
213 si != NULL;
214 si = VG_(next_seginfo)(si))
njnbf7ca332005-05-14 17:11:06 +0000215 {
njnd9109c62005-06-26 04:49:25 +0000216 if (resolve_redir_with_seginfo(redir, si))
njnbf7ca332005-05-14 17:11:06 +0000217 return True;
218 }
219 return False;
220}
221
njnd9109c62005-06-26 04:49:25 +0000222// Resolve as many unresolved redirs as possible with this SegInfo. This
njn2025cf92005-06-26 20:44:48 +0000223// should be called when a new SegInfo symtab is loaded. It covers the case
224// where a replacee function is loaded after its replacement function.
njnd9109c62005-06-26 04:49:25 +0000225void VG_(resolve_existing_redirs_with_seginfo)(SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000226{
njnd9109c62005-06-26 04:49:25 +0000227 CodeRedirect **prevp = &unresolved_redirs;
sewardjcbdddcf2005-03-10 23:23:45 +0000228 CodeRedirect *redir, *next;
229
njnd9109c62005-06-26 04:49:25 +0000230 TRACE_REDIR("Just loaded %s (soname=%s),",
231 VG_(seginfo_filename)(si), VG_(seginfo_soname)(si));
232 TRACE_REDIR(" resolving any unresolved redirs with it");
sewardjcbdddcf2005-03-10 23:23:45 +0000233
njnd9109c62005-06-26 04:49:25 +0000234 // Visit each unresolved redir - if it becomes resolved, then
235 // move it from the unresolved list to the resolved list.
236 for (redir = unresolved_redirs; redir != NULL; redir = next) {
sewardjcbdddcf2005-03-10 23:23:45 +0000237 next = redir->next;
238
njnd9109c62005-06-26 04:49:25 +0000239 if (resolve_redir_with_seginfo(redir, si)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000240 *prevp = next;
241 redir->next = NULL;
sewardjf9a82d12005-07-23 09:52:21 +0000242 add_redir_to_resolved_list(redir, False);
sewardjcbdddcf2005-03-10 23:23:45 +0000243 } else
244 prevp = &redir->next;
245 }
sewardjcbdddcf2005-03-10 23:23:45 +0000246
njnd9109c62005-06-26 04:49:25 +0000247 TRACE_REDIR(" Finished resolving");
sewardjcbdddcf2005-03-10 23:23:45 +0000248}
249
tom748a1312005-04-02 15:53:01 +0000250/* Redirect a function at from_addr to a function at to_addr */
njn16eeb4e2005-06-16 03:56:58 +0000251__attribute__((unused)) // It is used, but not on all platforms...
njnd9109c62005-06-26 04:49:25 +0000252static void add_redirect_addr_to_addr( Addr from_addr, Addr to_addr )
tom748a1312005-04-02 15:53:01 +0000253{
njnd9109c62005-06-26 04:49:25 +0000254 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redirs);
255
256 vg_assert(0 != from_addr && 0 != to_addr);
257
258 redir->type = R_REDIRECT;
259
260 redir->from_lib = NULL;
261 redir->from_sym = NULL;
262 redir->from_addr = from_addr;
263
264 redir->to_addr = to_addr;
265 redir->wrapper = 0;
266
267 TRACE_REDIR("REDIRECT addr to addr: %p to %p", from_addr, to_addr);
268
269 // This redirection is already resolved, put it straight in the list.
sewardjf9a82d12005-07-23 09:52:21 +0000270 add_redir_to_resolved_list(redir, True);
njnd9109c62005-06-26 04:49:25 +0000271}
272
273/* Redirect a lib/symbol reference to a function at addr */
274static void add_redirect_sym_to_addr(
275 const Char *from_lib, const Char *from_sym, Addr to_addr
276)
277{
278 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redirs);
279
280 vg_assert(from_lib && from_sym && 0 != to_addr);
281
282 redir->type = R_REDIRECT;
283 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
284 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
285 redir->from_addr = 0;
286 redir->to_addr = to_addr;
287 redir->wrapper = 0;
288
289 TRACE_REDIR("REDIR sym to addr: %s:%s to %p", from_lib, from_sym, to_addr);
290
291 // Check against all existing segments to see if this redirection
njn2025cf92005-06-26 20:44:48 +0000292 // can be resolved immediately (as will be the case when the replacement
293 // function is loaded after the replacee). Then add it to the
294 // appropriate list.
njnd9109c62005-06-26 04:49:25 +0000295 if (resolve_redir_with_existing_seginfos(redir)) {
sewardjf9a82d12005-07-23 09:52:21 +0000296 add_redir_to_resolved_list(redir, True);
njnd9109c62005-06-26 04:49:25 +0000297 } else {
298 add_redir_to_unresolved_list(redir);
299 }
tom748a1312005-04-02 15:53:01 +0000300}
301
sewardjcbdddcf2005-03-10 23:23:45 +0000302CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
303 const FuncWrapper *wrapper)
304{
njnd9109c62005-06-26 04:49:25 +0000305 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redirs);
sewardjcbdddcf2005-03-10 23:23:45 +0000306
njnd9109c62005-06-26 04:49:25 +0000307 redir->type = R_WRAPPER;
njn136b83b2005-06-19 05:14:03 +0000308 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
309 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
sewardjcbdddcf2005-03-10 23:23:45 +0000310 redir->from_addr = 0;
njn136b83b2005-06-19 05:14:03 +0000311 redir->to_addr = 0;
312 redir->wrapper = wrapper;
sewardjcbdddcf2005-03-10 23:23:45 +0000313
njnd9109c62005-06-26 04:49:25 +0000314 TRACE_REDIR("REDIR sym to wrapper: %s:%s to (%p,%p)",
315 from_lib, from_sym, wrapper->before, wrapper->after);
316
317 // Check against all existing segments to see if this redirection
318 // can be resolved immediately. Then add it to the appropriate list.
319 if (resolve_redir_with_existing_seginfos(redir)) {
sewardjf9a82d12005-07-23 09:52:21 +0000320 add_redir_to_resolved_list(redir, True);
njnd9109c62005-06-26 04:49:25 +0000321 } else {
322 add_redir_to_unresolved_list(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000323 }
324
325 return redir;
326}
327
sewardjcbdddcf2005-03-10 23:23:45 +0000328/* If address 'a' is being redirected, return the redirected-to
329 address. */
330Addr VG_(code_redirect)(Addr a)
331{
332 CodeRedirect* r;
333
njnd9109c62005-06-26 04:49:25 +0000334 r = VG_(SkipList_Find_Exact)(&sk_resolved_redirs, &a);
sewardjcbdddcf2005-03-10 23:23:45 +0000335 if (r == NULL)
336 return a;
337
338 vg_assert(r->to_addr != 0);
339
340 return r->to_addr;
341}
342
343void VG_(setup_code_redirect_table) ( void )
344{
njnd1af0032005-05-29 17:01:48 +0000345#if defined(VGP_x86_linux)
346 /* Redirect _dl_sysinfo_int80, which is glibc's default system call
sewardjb9bce632005-06-21 01:41:34 +0000347 routine, to our copy so that the special sysinfo unwind hack in
348 m_stacktrace.c will kick in. */
349 add_redirect_sym_to_addr(
350 "soname:ld-linux.so.2", "_dl_sysinfo_int80",
351 (Addr)&VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80)
352 );
353
njnd1af0032005-05-29 17:01:48 +0000354#elif defined(VGP_amd64_linux)
sewardjb9bce632005-06-21 01:41:34 +0000355
njnd1af0032005-05-29 17:01:48 +0000356 /* Redirect vsyscalls to local versions */
sewardjb9bce632005-06-21 01:41:34 +0000357 add_redirect_addr_to_addr(
358 0xFFFFFFFFFF600000ULL,
359 (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)
360 );
361
362 add_redirect_addr_to_addr(
tomf5db3b62005-06-21 13:26:17 +0000363 0xFFFFFFFFFF600400ULL,
sewardjb9bce632005-06-21 01:41:34 +0000364 (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)
365 );
366
cerion85665ca2005-06-20 15:51:07 +0000367#elif defined(VGP_ppc32_linux)
sewardjb9bce632005-06-21 01:41:34 +0000368
369 //CAB: TODO
370
njnd1af0032005-05-29 17:01:48 +0000371#else
372# error Unknown platform
373#endif
374}
sewardjcbdddcf2005-03-10 23:23:45 +0000375
njn16eeb4e2005-06-16 03:56:58 +0000376/* Z-decode a symbol into library:func form, eg
377
378 _vgi_libcZdsoZd6__ZdlPv --> libc.so.6:_ZdlPv
379
380 Uses the Z-encoding scheme described in pub_core_redir.h.
381 Returns True if demangle OK, False otherwise.
382*/
383static Bool Z_decode(const Char* symbol, Char* result, Int nbytes)
384{
385# define EMIT(ch) \
386 do { \
387 if (j >= nbytes) \
388 result[j-1] = 0; \
389 else \
390 result[j++] = ch; \
391 } while (0)
392
393 Bool error = False;
394 Int i, j = 0;
395 Int len = VG_(strlen)(symbol);
396 if (0) VG_(printf)("idm: %s\n", symbol);
397
398 i = VG_REPLACE_FUNCTION_PREFIX_LEN;
399
400 /* Chew though the Z-encoded soname part. */
401 while (True) {
402
403 if (i >= len)
404 break;
405
406 if (symbol[i] == '_')
407 /* We found the underscore following the Z-encoded soname.
408 Just copy the rest literally. */
409 break;
410
411 if (symbol[i] != 'Z') {
412 EMIT(symbol[i]);
413 i++;
414 continue;
415 }
416
417 /* We've got a Z-escape. Act accordingly. */
418 i++;
419 if (i >= len) {
420 /* Hmm, Z right at the end. Something's wrong. */
421 error = True;
422 EMIT('Z');
423 break;
424 }
425 switch (symbol[i]) {
426 case 'a': EMIT('*'); break;
427 case 'p': EMIT('+'); break;
428 case 'c': EMIT(':'); break;
429 case 'd': EMIT('.'); break;
430 case 'u': EMIT('_'); break;
431 case 'h': EMIT('-'); break;
432 case 's': EMIT(' '); break;
433 case 'Z': EMIT('Z'); break;
434 default: error = True; EMIT('Z'); EMIT(symbol[i]); break;
435 }
436 i++;
437 }
438
439 if (error || i >= len || symbol[i] != '_') {
440 /* Something's wrong. Give up. */
441 VG_(message)(Vg_UserMsg, "intercept: error demangling: %s", symbol);
442 EMIT(0);
443 return False;
444 }
445
446 /* Copy the rest of the string verbatim. */
447 i++;
448 EMIT(':');
449 while (True) {
450 if (i >= len)
451 break;
452 EMIT(symbol[i]);
453 i++;
454 }
455
456 EMIT(0);
457 if (0) VG_(printf)("%s\n", result);
458 return True;
459
460# undef EMIT
461}
462
463// Nb: this can change the string pointed to by 'symbol'.
464static void handle_replacement_function( Char* symbol, Addr addr )
465{
466 Bool ok;
467 Int len = VG_(strlen)(symbol) + 1 - VG_REPLACE_FUNCTION_PREFIX_LEN;
468 Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len+8);
469 Char *func;
470
471 // Put "soname:" at the start of lib
472 VG_(strcpy)(lib, "soname:");
473
474 ok = Z_decode(symbol, lib+7, len);
475 if (ok) {
476 // lib is "soname:<libname>:<fnname>". Split the string at the 2nd ':'.
477 func = lib + VG_(strlen)(lib)-1;
478 while(*func != ':') func--;
479 *func = '\0';
480 func++; // Move past the '\0'
481
482 // Now lib is "soname:<libname>" and func is "<fnname>".
483 if (0) VG_(printf)("lib A%sZ, func A%sZ\n", lib, func);
484 add_redirect_sym_to_addr(lib, func, addr);
485
486 // Overwrite the given Z-encoded name with just the fnname.
487 VG_(strcpy)(symbol, func);
488 }
489
490 VG_(arena_free)(VG_AR_SYMTAB, lib);
491}
492
njnbc6d84d2005-06-19 18:58:03 +0000493static Addr __libc_freeres_wrapper = 0;
494
495Addr VG_(get_libc_freeres_wrapper)(void)
496{
497 return __libc_freeres_wrapper;
498}
499
njn16eeb4e2005-06-16 03:56:58 +0000500// This is specifically for stringifying VG_(x) function names. We
501// need to do two macroexpansions to get the VG_ macro expanded before
502// stringifying.
503#define _STR(x) #x
504#define STR(x) _STR(x)
505
506static void handle_load_notifier( Char* symbol, Addr addr )
507{
508 if (VG_(strcmp)(symbol, STR(VG_NOTIFY_ON_LOAD(freeres))) == 0)
njnbc6d84d2005-06-19 18:58:03 +0000509 __libc_freeres_wrapper = addr;
njn16eeb4e2005-06-16 03:56:58 +0000510// else if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) == 0)
511// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value));
512 else
513 vg_assert2(0, "unrecognised load notification function: %s", symbol);
514}
515
516static Bool is_replacement_function(Char* s)
517{
518 return (0 == VG_(strncmp)(s,
519 VG_REPLACE_FUNCTION_PREFIX,
520 VG_REPLACE_FUNCTION_PREFIX_LEN));
521}
522
523static Bool is_load_notifier(Char* s)
524{
525 return (0 == VG_(strncmp)(s,
526 VG_NOTIFY_ON_LOAD_PREFIX,
527 VG_NOTIFY_ON_LOAD_PREFIX_LEN));
528}
529
530// Call this for each symbol loaded. It determines if we need to do
531// anything special with it. It can modify 'symbol' in-place.
532void VG_(maybe_redir_or_notify) ( Char* symbol, Addr addr )
533{
534 if (is_replacement_function(symbol))
535 handle_replacement_function(symbol, addr);
536 else
537 if (is_load_notifier(symbol))
538 handle_load_notifier(symbol, addr);
539}
540
541
sewardjcbdddcf2005-03-10 23:23:45 +0000542//:: /*------------------------------------------------------------*/
543//:: /*--- General function wrapping. ---*/
544//:: /*------------------------------------------------------------*/
545//::
546//:: /*
547//:: TODO:
548//:: - hook into the symtab machinery
549//:: - client-side wrappers?
550//:: - better interfaces for before() functions to get to arguments
551//:: - handle munmap of code (dlclose())
552//:: - handle thread exit
553//:: - handle longjmp
554//:: */
555//:: struct callkey {
556//:: ThreadId tid; /* calling thread */
557//:: Addr esp; /* address of args on stack */
558//:: Addr eip; /* return address */
559//:: };
560//::
561//:: struct call_instance {
562//:: struct callkey key;
563//::
564//:: const FuncWrapper *wrapper;
565//:: void *nonce;
566//:: };
567//::
568//:: static inline Addr addrcmp(Addr a, Addr b)
569//:: {
570//:: if (a < b)
571//:: return -1;
572//:: else if (a > b)
573//:: return 1;
574//:: else
575//:: return 0;
576//:: }
577//::
578//:: static inline Int cmp(UInt a, UInt b)
579//:: {
580//:: if (a < b)
581//:: return -1;
582//:: else if (a > b)
583//:: return 1;
584//:: else
585//:: return 0;
586//:: }
587//::
588//:: static Int keycmp(const void *pa, const void *pb)
589//:: {
590//:: const struct callkey *a = (const struct callkey *)pa;
591//:: const struct callkey *b = (const struct callkey *)pb;
592//:: Int ret;
593//::
594//:: if ((ret = cmp(a->tid, b->tid)))
595//:: return ret;
596//::
597//:: if ((ret = addrcmp(a->esp, b->esp)))
598//:: return ret;
599//::
600//:: return addrcmp(a->eip, b->eip);
601//:: }
602//::
603//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000604//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000605//:: NULL, VG_AR_SYMTAB);
606//::
607//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
608//:: {
609//:: struct callkey key = { tid, argsp, retaddr };
610//::
611//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
612//:: }
613//::
614//:: static void wrapper_return(Addr retaddr);
615//::
616//:: /* Called from generated code via helper */
617//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
618//:: {
njnaf839f52005-06-23 03:27:57 +0000619//:: Addr retaddr = VG_RETADDR(tst->arch);
620//:: Addr argp = (Addr)&VG_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000621//:: void *nonce = NULL;
622//:: Bool mf = VG_(my_fault);
623//:: VG_(my_fault) = True;
624//::
625//:: if (wrapper->before) {
njnaf839f52005-06-23 03:27:57 +0000626//:: va_list args = VG_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000627//:: nonce = (*wrapper->before)(args);
628//:: }
629//::
630//:: if (wrapper->after) {
631//:: /* If there's an after function, make sure it gets called */
632//:: struct call_instance *call;
633//::
634//:: call = find_call(retaddr, argp, tst->tid);
635//::
636//:: if (call != NULL) {
637//:: /* Found a stale outstanding call; clean it up and recycle
638//:: the structure */
639//:: if (call->wrapper->after)
640//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
641//:: } else {
642//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
643//::
644//:: call->key.tid = tst->tid;
645//:: call->key.esp = argp;
646//:: call->key.eip = retaddr;
647//::
648//:: VG_(SkipList_Insert)(&wrapped_frames, call);
649//::
650//:: wrapper_return(retaddr);
651//:: }
652//::
653//:: call->wrapper = wrapper;
654//:: call->nonce = nonce;
655//:: } else
656//:: vg_assert(nonce == NULL);
657//::
658//:: VG_(my_fault) = mf;
659//:: }
660//::
661//:: /* Called from generated code via helper */
662//:: void VG_(wrap_after)(ThreadState *tst)
663//:: {
njnaf839f52005-06-23 03:27:57 +0000664//:: Addr EIP = VG_INSTR_PTR(tst->arch); /* instruction after call */
665//:: Addr ESP = VG_STACK_PTR(tst->arch); /* pointer to args */
666//:: Word ret = VG_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000667//:: struct call_instance *call;
668//:: Bool mf = VG_(my_fault);
669//::
670//:: VG_(my_fault) = True;
671//:: call = find_call(EIP, ESP, tst->tid);
672//::
673//:: if (0)
674//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
675//::
676//:: if (call != NULL) {
677//:: if (call->wrapper->after)
678//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
679//::
680//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
681//:: VG_(SkipNode_Free)(&wrapped_frames, call);
682//:: }
683//:: VG_(my_fault) = mf;
684//:: }
685//::
686//::
687//:: struct wrapped_function {
688//:: Addr eip; /* eip of function entrypoint */
689//:: const FuncWrapper *wrapper;
690//:: };
691//::
692//:: struct wrapper_return {
693//:: Addr eip; /* return address */
694//:: };
695//::
696//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000697//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000698//:: NULL, VG_AR_SYMTAB);
699//::
700//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000701//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000702//:: NULL, VG_AR_SYMTAB);
703//::
704//:: /* Wrap function starting at eip */
705//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
706//:: {
707//:: struct wrapped_function *func;
708//::
709//:: if (0)
710//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
711//::
712//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
713//::
714//:: if (func == NULL) {
715//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
716//:: VG_(invalidate_translations)(eip, 1, True);
717//::
718//:: func->eip = eip;
719//:: VG_(SkipList_Insert)(&wrapped_functions, func);
720//:: }
721//::
722//:: func->wrapper = wrapper;
723//:: }
724//::
725//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
726//:: {
727//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
728//::
729//:: if (func)
730//:: return func->wrapper;
731//:: return NULL;
732//:: }
733//::
734//:: Bool VG_(is_wrapper_return)(Addr eip)
735//:: {
736//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
737//::
738//:: return ret != NULL;
739//:: }
740//::
741//:: /* Mark eip as being the return address of a wrapper, so that the
742//:: codegen will generate the appropriate call. */
743//:: void wrapper_return(Addr eip)
744//:: {
745//:: struct wrapper_return *ret;
746//::
747//:: if (VG_(is_wrapper_return)(eip))
748//:: return;
749//::
750//:: VG_(invalidate_translations)(eip, 1, True);
751//::
752//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
753//:: ret->eip = eip;
754//::
755//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
756//:: }