blob: b00645b6912aff099e4de330d54895b70d54bb36 [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*/
32#include "core.h"
sewardjcbdddcf2005-03-10 23:23:45 +000033
sewardj55f9d1a2005-04-25 11:11:44 +000034#include "pub_core_aspacemgr.h"
njn97405b22005-06-02 03:39:33 +000035#include "pub_core_libcbase.h"
njn641d5cc2005-05-12 04:37:27 +000036#include "pub_core_skiplist.h"
njn20242342005-05-16 23:31:24 +000037#include "pub_core_options.h"
njnd1af0032005-05-29 17:01:48 +000038#include "pub_core_redir.h"
njn8bddf582005-05-13 23:40:55 +000039#include "pub_core_transtab.h"
njnea27e462005-05-31 02:38:09 +000040#include "m_debuginfo/priv_symtab.h" // XXX: bad!
sewardj55f9d1a2005-04-25 11:11:44 +000041
sewardjcbdddcf2005-03-10 23:23:45 +000042/*------------------------------------------------------------*/
43/*--- General purpose redirection. ---*/
44/*------------------------------------------------------------*/
45
46/*
47 wraps and redirections, indexed by from_addr
48
49 Redirection and wrapping are two distinct mechanisms which Valgrind
50 can use to change the client's control flow.
51
52 Redirection intercepts a call to a client function, and re-points it
53 to a new piece of code (presumably functionally equivalent). The
54 original code is never run.
55
56 Wrapping does call the client's original code, but calls "before"
57 and "after" functions which can inspect (and perhaps modify) the
58 function's arguments and return value.
59 */
60struct _CodeRedirect {
61 enum redir_type {
62 R_REDIRECT, /* plain redirection */
63 R_WRAPPER, /* wrap with valgrind-internal code */
64 R_CLIENT_WRAPPER, /* wrap with client-side code */
65 } type;
66
67 const Char *from_lib; /* library qualifier pattern */
68 const Char *from_sym; /* symbol */
69 Addr from_addr; /* old addr */
70
71 /* used for redirection */
72 const Char *to_lib; /* library qualifier pattern */
73 const Char *to_sym; /* symbol */
74 Addr to_addr; /* new addr */
75
76 /* used for wrapping */
77 const FuncWrapper *wrapper;
78
79 CodeRedirect *next; /* next pointer on unresolved list */
80};
81
82static Char *straddr(void *p)
83{
84 static Char buf[16];
85
86 VG_(sprintf)(buf, "%p", *(Addr *)p);
87
88 return buf;
89}
90
njnbe91aae2005-03-27 01:42:41 +000091static SkipList sk_resolved_redir = VG_SKIPLIST_INIT(CodeRedirect, from_addr,
sewardjcbdddcf2005-03-10 23:23:45 +000092 VG_(cmp_Addr), straddr, VG_AR_SYMTAB);
93static CodeRedirect *unresolved_redir = NULL;
94
95static Bool match_lib(const Char *pattern, const SegInfo *si)
96{
97 /* pattern == NULL matches everything, otherwise use globbing
98
99 If the pattern starts with:
100 file:, then match filename
101 soname:, then match soname
102 something else, match filename
103 */
104 const Char *name = si->filename;
105
106 if (pattern == NULL)
107 return True;
108
109 if (VG_(strncmp)(pattern, "file:", 5) == 0) {
110 pattern += 5;
111 name = si->filename;
112 }
113 if (VG_(strncmp)(pattern, "soname:", 7) == 0) {
114 pattern += 7;
115 name = si->soname;
116 }
117
118 if (name == NULL)
119 return False;
120
121 return VG_(string_match)(pattern, name);
122}
123
124static inline Bool from_resolved(const CodeRedirect *redir)
125{
126 return redir->from_addr != 0;
127}
128
129static inline Bool to_resolved(const CodeRedirect *redir)
130{
131 if (redir->type == R_REDIRECT)
132 return redir->to_addr != 0;
133 vg_assert(redir->wrapper != NULL);
134 return True;
135}
136
137Bool VG_(is_resolved)(const CodeRedirect *redir)
138{
139 return from_resolved(redir) && to_resolved(redir);
140}
141
tom748a1312005-04-02 15:53:01 +0000142static void add_resolved(CodeRedirect *redir)
143{
144 switch(redir->type) {
145 case R_REDIRECT:
146 if (VG_(clo_trace_redir)) {
147 VG_(message)(Vg_DebugMsg, " redir resolved (%s:%s=%p -> ",
148 redir->from_lib, redir->from_sym, redir->from_addr);
149 VG_(message)(Vg_DebugMsg, " %s:%s=%p)",
150 redir->to_lib, redir->to_sym, redir->to_addr);
151 }
152
153 if (VG_(search_transtab)(NULL, (Addr64)redir->from_addr, False)) {
154 /* For some given (from, to) redir, the "from" function got
155 called before the .so containing "to" became available. We
156 know this because there is already a translation for the
157 entry point of the original "from". So the redirect will
158 never actually take effect unless that translation is
159 discarded.
160
161 Note, we only really need to discard the first bb of the
162 old entry point, and so we avoid the problem of having to
163 figure out how big that bb was -- since it is at least 1
164 byte of original code, we can just pass 1 as the original
165 size to invalidate_translations() and it will indeed get
166 rid of the translation.
167
168 Note, this is potentially expensive -- discarding
169 translations causes complete unchaining.
170 */
171 if (VG_(clo_verbosity) > 2 && VG_(clo_trace_redir)) {
172 VG_(message)(Vg_UserMsg,
173 "Discarding translation due to redirect of already called function" );
174 VG_(message)(Vg_UserMsg,
175 " %s (%p -> %p)",
176 redir->from_sym, redir->from_addr, redir->to_addr );
177 }
178 VG_(discard_translations)((Addr64)redir->from_addr, 1);
179 }
180
181 {
182 CodeRedirect *r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &redir->from_addr);
183
184 if (r == NULL)
185 VG_(SkipList_Insert)(&sk_resolved_redir, redir);
186 else {
187 /* XXX leak redir */
188 if (VG_(clo_trace_redir))
189 VG_(message)(Vg_DebugMsg, " redir %s:%s:%p->%s:%s:%p duplicated\n",
190 redir->from_lib, redir->from_sym, redir->from_addr,
191 redir->to_lib, redir->to_sym, redir->to_addr);
192 }
193 }
194 break;
195
196 case R_WRAPPER:
197 if (VG_(clo_trace_redir)) {
198 VG_(message)(Vg_DebugMsg, " wrapper resolved (%s:%s=%p -> wrapper)",
199 redir->from_lib, redir->from_sym, redir->from_addr);
200 }
201
202 /* XXX redir leaked */
203 //VG_(wrap_function)(redir->from_addr, redir->wrapper);
204 break;
205
206 case R_CLIENT_WRAPPER:
207 VG_(core_panic)("not implemented");
208 break;
209 }
210}
211
sewardjcbdddcf2005-03-10 23:23:45 +0000212/* Resolve a redir using si if possible, and add it to the resolved
213 list */
njn17250122005-05-14 17:18:12 +0000214static Bool resolve_redir(CodeRedirect *redir, const SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000215{
216 Bool resolved;
217
218 vg_assert(si != NULL);
219 vg_assert(si->seg != NULL);
220
221 /* no redirection from Valgrind segments */
222 if (si->seg->flags & SF_VALGRIND)
223 return False;
224
225 resolved = VG_(is_resolved)(redir);
226
227 if (0 && VG_(clo_trace_redir))
228 VG_(printf)(" consider FROM binding %s:%s -> %s:%s in %s(%s)\n",
229 redir->from_lib, redir->from_sym,
230 redir->to_lib, redir->to_sym,
231 si->filename, si->soname);
232
233 vg_assert(!resolved);
234
235 if (!from_resolved(redir)) {
236 vg_assert(redir->from_sym != NULL);
237
238 if (match_lib(redir->from_lib, si)) {
239 redir->from_addr = VG_(reverse_search_one_symtab)(si, redir->from_sym);
240 if (VG_(clo_trace_redir) && redir->from_addr != 0)
241 VG_(printf)(" bind FROM: %p = %s:%s\n",
242 redir->from_addr,redir->from_lib, redir->from_sym );
243 }
244 }
245
246 if (!to_resolved(redir)) {
247 vg_assert(redir->type == R_REDIRECT);
248 vg_assert(redir->to_sym != NULL);
249
250 if (match_lib(redir->to_lib, si)) {
251 redir->to_addr = VG_(reverse_search_one_symtab)(si, redir->to_sym);
252 if (VG_(clo_trace_redir) && redir->to_addr != 0)
253 VG_(printf)(" bind TO: %p = %s:%s\n",
254 redir->to_addr,redir->to_lib, redir->to_sym );
255
256 }
257 }
258
259 resolved = from_resolved(redir) && to_resolved(redir);
260
261 if (0 && VG_(clo_trace_redir))
262 VG_(printf)("resolve_redir: %s:%s from=%p %s:%s to=%p\n",
263 redir->from_lib, redir->from_sym, redir->from_addr,
264 redir->to_lib, redir->to_sym, redir->to_addr);
265
tom748a1312005-04-02 15:53:01 +0000266 if (resolved) add_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000267
268 return resolved;
269}
270
njnbf7ca332005-05-14 17:11:06 +0000271static Bool resolve_redir_allsegs(CodeRedirect *redir)
272{
273 const SegInfo *si;
274
275 for(si = VG_(next_seginfo)(NULL);
276 si != NULL;
277 si = VG_(next_seginfo)(si))
278 {
njn17250122005-05-14 17:18:12 +0000279 if (resolve_redir(redir, si))
njnbf7ca332005-05-14 17:11:06 +0000280 return True;
281 }
282 return False;
283}
284
sewardjcbdddcf2005-03-10 23:23:45 +0000285/* Go through the complete redir list, resolving as much as possible with this SegInfo.
286
287 This should be called when a new SegInfo symtab is loaded.
288 */
289void VG_(resolve_seg_redirs)(SegInfo *si)
290{
291 CodeRedirect **prevp = &unresolved_redir;
292 CodeRedirect *redir, *next;
293
294 if (VG_(clo_trace_redir))
295 VG_(printf)("Considering redirs to/from %s(soname=%s)\n",
296 si->filename, si->soname);
297
298 /* visit each unresolved redir - if it becomes resolved, then
299 remove it from the unresolved list */
300 for(redir = unresolved_redir; redir != NULL; redir = next) {
301 next = redir->next;
302
njn17250122005-05-14 17:18:12 +0000303 if (resolve_redir(redir, si)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000304 *prevp = next;
305 redir->next = NULL;
306 } else
307 prevp = &redir->next;
308 }
309}
310
311/* Redirect a lib/symbol reference to a function at lib/symbol */
tom748a1312005-04-02 15:53:01 +0000312static void add_redirect_sym_to_sym(const Char *from_lib, const Char *from_sym,
313 const Char *to_lib, const Char *to_sym)
sewardjcbdddcf2005-03-10 23:23:45 +0000314{
315 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
316
317 redir->type = R_REDIRECT;
318
319 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
320 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
321 redir->from_addr = 0;
322
323 redir->to_lib = VG_(arena_strdup)(VG_AR_SYMTAB, to_lib);
324 redir->to_sym = VG_(arena_strdup)(VG_AR_SYMTAB, to_sym);
325 redir->to_addr = 0;
326
327 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
328 VG_(message)(Vg_UserMsg,
329 "REDIRECT %s(%s) to %s(%s)",
330 from_lib, from_sym, to_lib, to_sym);
331
332 /* Check against all existing segments to see if this redirection
333 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000334 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000335 /* nope, add to list */
336 redir->next = unresolved_redir;
337 unresolved_redir = redir;
338 }
339}
340
341/* Redirect a lib/symbol reference to a function at addr */
tom748a1312005-04-02 15:53:01 +0000342void VG_(add_redirect_sym_to_addr)(const Char *from_lib, const Char *from_sym,
343 Addr to_addr)
sewardjcbdddcf2005-03-10 23:23:45 +0000344{
345 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
346
347 redir->type = R_REDIRECT;
348
349 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
350 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
351 redir->from_addr = 0;
352
353 redir->to_lib = NULL;
354 redir->to_sym = NULL;
355 redir->to_addr = to_addr;
356
tom748a1312005-04-02 15:53:01 +0000357 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
358 VG_(message)(Vg_UserMsg,
359 "REDIRECT %s(%s) to %p",
360 from_lib, from_sym, to_addr);
361
sewardjcbdddcf2005-03-10 23:23:45 +0000362 /* Check against all existing segments to see if this redirection
363 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000364 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000365 /* nope, add to list */
366 redir->next = unresolved_redir;
367 unresolved_redir = redir;
368 }
369}
370
tom748a1312005-04-02 15:53:01 +0000371/* Redirect a function at from_addr to a function at to_addr */
372void VG_(add_redirect_addr_to_addr)(Addr from_addr, Addr to_addr)
373{
374 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
375
376 redir->type = R_REDIRECT;
377
378 redir->from_lib = NULL;
379 redir->from_sym = NULL;
380 redir->from_addr = from_addr;
381
382 redir->to_lib = NULL;
383 redir->to_sym = NULL;
384 redir->to_addr = to_addr;
385
386 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
387 VG_(message)(Vg_UserMsg,
388 "REDIRECT %p to %p",
389 from_addr, to_addr);
390
391 add_resolved(redir);
392}
393
sewardjcbdddcf2005-03-10 23:23:45 +0000394CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
395 const FuncWrapper *wrapper)
396{
397 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
398
399 if (0)
400 VG_(printf)("adding wrapper for %s:%s -> (%p,%p)\n",
401 from_lib, from_sym, wrapper->before, wrapper->after);
402
403 redir->type = R_WRAPPER;
404
405 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
406 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
407 redir->from_addr = 0;
408
409 redir->to_lib = NULL;
410 redir->to_sym = NULL;
411 redir->to_addr = 0;
412
413 redir->wrapper = wrapper;
414
415 /* Check against all existing segments to see if this redirection
416 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000417 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000418 /* nope, add to list */
419 redir->next = unresolved_redir;
420 unresolved_redir = redir;
421 }
422
423 return redir;
424}
425
sewardjcbdddcf2005-03-10 23:23:45 +0000426/* If address 'a' is being redirected, return the redirected-to
427 address. */
428Addr VG_(code_redirect)(Addr a)
429{
430 CodeRedirect* r;
431
sewardjcbdddcf2005-03-10 23:23:45 +0000432 r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &a);
433 if (r == NULL)
434 return a;
435
436 vg_assert(r->to_addr != 0);
437
438 return r->to_addr;
439}
440
441void VG_(setup_code_redirect_table) ( void )
442{
sewardjcbdddcf2005-03-10 23:23:45 +0000443 /* Overenthusiastic use of PLT bypassing by the glibc people also
444 means we need to patch the following functions to our own
445 implementations of said, in mac_replace_strmem.c.
446 */
tom748a1312005-04-02 15:53:01 +0000447 add_redirect_sym_to_sym("soname:libc.so.6", "stpcpy",
448 "*vgpreload_memcheck.so*", "stpcpy");
sewardjcbdddcf2005-03-10 23:23:45 +0000449
sewardj9ea09012005-04-20 14:32:32 +0000450 add_redirect_sym_to_sym("soname:ld-linux.so.2", "strlen",
451 "*vgpreload_memcheck.so*", "strlen");
tom748a1312005-04-02 15:53:01 +0000452 add_redirect_sym_to_sym("soname:libc.so.6", "strlen",
453 "*vgpreload_memcheck.so*", "strlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000454
tom748a1312005-04-02 15:53:01 +0000455 add_redirect_sym_to_sym("soname:libc.so.6", "strnlen",
456 "*vgpreload_memcheck.so*", "strnlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000457
tom748a1312005-04-02 15:53:01 +0000458 add_redirect_sym_to_sym("soname:ld-linux.so.2", "stpcpy",
459 "*vgpreload_memcheck.so*", "stpcpy");
460 add_redirect_sym_to_sym("soname:libc.so.6", "stpcpy",
461 "*vgpreload_memcheck.so*", "stpcpy");
sewardjcbdddcf2005-03-10 23:23:45 +0000462
tom748a1312005-04-02 15:53:01 +0000463 add_redirect_sym_to_sym("soname:libc.so.6", "strchr",
464 "*vgpreload_memcheck.so*", "strchr");
465 add_redirect_sym_to_sym("soname:ld-linux.so.2", "strchr",
466 "*vgpreload_memcheck.so*", "strchr");
sewardjcbdddcf2005-03-10 23:23:45 +0000467
sewardjedfa2c22005-05-16 16:39:57 +0000468 /* apparently index is the same thing as strchr */
469 add_redirect_sym_to_sym("soname:ld-linux.so.2", "index",
470 "*vgpreload_memcheck.so*", "strchr");
471
tom748a1312005-04-02 15:53:01 +0000472 add_redirect_sym_to_sym("soname:libc.so.6", "strchrnul",
473 "*vgpreload_memcheck.so*", "glibc232_strchrnul");
sewardjcbdddcf2005-03-10 23:23:45 +0000474
tom748a1312005-04-02 15:53:01 +0000475 add_redirect_sym_to_sym("soname:libc.so.6", "rawmemchr",
476 "*vgpreload_memcheck.so*", "glibc232_rawmemchr");
sewardj7efe7be2005-04-25 17:08:32 +0000477
478 /* amd64-linux (glibc 2.3.3, SuSE 9.2) */
479 /* apparently index is the same thing as strchr */
480 add_redirect_sym_to_sym("soname:libc.so.6", "index",
481 "*vgpreload_memcheck.so*", "strchr");
sewardj86facbc2005-05-12 17:58:57 +0000482 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "index",
483 "*vgpreload_memcheck.so*", "strchr");
484
485 add_redirect_sym_to_sym("soname:libc.so.6", "strcpy",
486 "*vgpreload_memcheck.so*", "strcpy");
sewardj7efe7be2005-04-25 17:08:32 +0000487
488 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "strcmp",
489 "*vgpreload_memcheck.so*", "strcmp");
490 add_redirect_sym_to_sym("soname:libc.so.6", "strcmp",
491 "*vgpreload_memcheck.so*", "strcmp");
492
493 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "strlen",
494 "*vgpreload_memcheck.so*", "strlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000495
njnd1af0032005-05-29 17:01:48 +0000496#if defined(VGP_x86_linux)
497 /* Redirect _dl_sysinfo_int80, which is glibc's default system call
498 routine, to the routine in our trampoline page so that the
499 special sysinfo unwind hack in m_stacktrace.c will kick in. */
500 VG_(add_redirect_sym_to_addr)("soname:ld-linux.so.2", "_dl_sysinfo_int80",
501 VG_(client_trampoline_code)+VG_(tramp_syscall_offset));
502#elif defined(VGP_amd64_linux)
503 /* Redirect vsyscalls to local versions */
504 VG_(add_redirect_addr_to_addr)(0xFFFFFFFFFF600000ULL,
505 VG_(client_trampoline_code)+VG_(tramp_gettimeofday_offset));
506 VG_(add_redirect_addr_to_addr)(0xFFFFFFFFFF600400ULL,
507 VG_(client_trampoline_code)+VG_(tramp_time_offset));
508#else
509# error Unknown platform
510#endif
511}
sewardjcbdddcf2005-03-10 23:23:45 +0000512
513//:: /*------------------------------------------------------------*/
514//:: /*--- General function wrapping. ---*/
515//:: /*------------------------------------------------------------*/
516//::
517//:: /*
518//:: TODO:
519//:: - hook into the symtab machinery
520//:: - client-side wrappers?
521//:: - better interfaces for before() functions to get to arguments
522//:: - handle munmap of code (dlclose())
523//:: - handle thread exit
524//:: - handle longjmp
525//:: */
526//:: struct callkey {
527//:: ThreadId tid; /* calling thread */
528//:: Addr esp; /* address of args on stack */
529//:: Addr eip; /* return address */
530//:: };
531//::
532//:: struct call_instance {
533//:: struct callkey key;
534//::
535//:: const FuncWrapper *wrapper;
536//:: void *nonce;
537//:: };
538//::
539//:: static inline Addr addrcmp(Addr a, Addr b)
540//:: {
541//:: if (a < b)
542//:: return -1;
543//:: else if (a > b)
544//:: return 1;
545//:: else
546//:: return 0;
547//:: }
548//::
549//:: static inline Int cmp(UInt a, UInt b)
550//:: {
551//:: if (a < b)
552//:: return -1;
553//:: else if (a > b)
554//:: return 1;
555//:: else
556//:: return 0;
557//:: }
558//::
559//:: static Int keycmp(const void *pa, const void *pb)
560//:: {
561//:: const struct callkey *a = (const struct callkey *)pa;
562//:: const struct callkey *b = (const struct callkey *)pb;
563//:: Int ret;
564//::
565//:: if ((ret = cmp(a->tid, b->tid)))
566//:: return ret;
567//::
568//:: if ((ret = addrcmp(a->esp, b->esp)))
569//:: return ret;
570//::
571//:: return addrcmp(a->eip, b->eip);
572//:: }
573//::
574//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000575//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000576//:: NULL, VG_AR_SYMTAB);
577//::
578//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
579//:: {
580//:: struct callkey key = { tid, argsp, retaddr };
581//::
582//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
583//:: }
584//::
585//:: static void wrapper_return(Addr retaddr);
586//::
587//:: /* Called from generated code via helper */
588//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
589//:: {
njndb9b7732005-03-26 00:32:29 +0000590//:: Addr retaddr = VGA_RETADDR(tst->arch);
591//:: Addr argp = (Addr)&VGA_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000592//:: void *nonce = NULL;
593//:: Bool mf = VG_(my_fault);
594//:: VG_(my_fault) = True;
595//::
596//:: if (wrapper->before) {
njndb9b7732005-03-26 00:32:29 +0000597//:: va_list args = VGA_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000598//:: nonce = (*wrapper->before)(args);
599//:: }
600//::
601//:: if (wrapper->after) {
602//:: /* If there's an after function, make sure it gets called */
603//:: struct call_instance *call;
604//::
605//:: call = find_call(retaddr, argp, tst->tid);
606//::
607//:: if (call != NULL) {
608//:: /* Found a stale outstanding call; clean it up and recycle
609//:: the structure */
610//:: if (call->wrapper->after)
611//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
612//:: } else {
613//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
614//::
615//:: call->key.tid = tst->tid;
616//:: call->key.esp = argp;
617//:: call->key.eip = retaddr;
618//::
619//:: VG_(SkipList_Insert)(&wrapped_frames, call);
620//::
621//:: wrapper_return(retaddr);
622//:: }
623//::
624//:: call->wrapper = wrapper;
625//:: call->nonce = nonce;
626//:: } else
627//:: vg_assert(nonce == NULL);
628//::
629//:: VG_(my_fault) = mf;
630//:: }
631//::
632//:: /* Called from generated code via helper */
633//:: void VG_(wrap_after)(ThreadState *tst)
634//:: {
njn35172bc2005-03-26 00:04:03 +0000635//:: Addr EIP = VGA_INSTR_PTR(tst->arch); /* instruction after call */
636//:: Addr ESP = VGA_STACK_PTR(tst->arch); /* pointer to args */
637//:: Word ret = VGA_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000638//:: struct call_instance *call;
639//:: Bool mf = VG_(my_fault);
640//::
641//:: VG_(my_fault) = True;
642//:: call = find_call(EIP, ESP, tst->tid);
643//::
644//:: if (0)
645//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
646//::
647//:: if (call != NULL) {
648//:: if (call->wrapper->after)
649//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
650//::
651//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
652//:: VG_(SkipNode_Free)(&wrapped_frames, call);
653//:: }
654//:: VG_(my_fault) = mf;
655//:: }
656//::
657//::
658//:: struct wrapped_function {
659//:: Addr eip; /* eip of function entrypoint */
660//:: const FuncWrapper *wrapper;
661//:: };
662//::
663//:: struct wrapper_return {
664//:: Addr eip; /* return address */
665//:: };
666//::
667//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000668//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000669//:: NULL, VG_AR_SYMTAB);
670//::
671//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000672//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000673//:: NULL, VG_AR_SYMTAB);
674//::
675//:: /* Wrap function starting at eip */
676//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
677//:: {
678//:: struct wrapped_function *func;
679//::
680//:: if (0)
681//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
682//::
683//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
684//::
685//:: if (func == NULL) {
686//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
687//:: VG_(invalidate_translations)(eip, 1, True);
688//::
689//:: func->eip = eip;
690//:: VG_(SkipList_Insert)(&wrapped_functions, func);
691//:: }
692//::
693//:: func->wrapper = wrapper;
694//:: }
695//::
696//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
697//:: {
698//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
699//::
700//:: if (func)
701//:: return func->wrapper;
702//:: return NULL;
703//:: }
704//::
705//:: Bool VG_(is_wrapper_return)(Addr eip)
706//:: {
707//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
708//::
709//:: return ret != NULL;
710//:: }
711//::
712//:: /* Mark eip as being the return address of a wrapper, so that the
713//:: codegen will generate the appropriate call. */
714//:: void wrapper_return(Addr eip)
715//:: {
716//:: struct wrapper_return *ret;
717//::
718//:: if (VG_(is_wrapper_return)(eip))
719//:: return;
720//::
721//:: VG_(invalidate_translations)(eip, 1, True);
722//::
723//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
724//:: ret->eip = eip;
725//::
726//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
727//:: }