blob: f0840b7f090c12e227ba05774950145ca4f85786 [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"
33#include "vg_symtab2.h"
34
sewardj55f9d1a2005-04-25 11:11:44 +000035#include "pub_core_aspacemgr.h"
njn641d5cc2005-05-12 04:37:27 +000036#include "pub_core_skiplist.h"
njn8bddf582005-05-13 23:40:55 +000037#include "pub_core_transtab.h"
sewardj55f9d1a2005-04-25 11:11:44 +000038
sewardjcbdddcf2005-03-10 23:23:45 +000039/*------------------------------------------------------------*/
40/*--- General purpose redirection. ---*/
41/*------------------------------------------------------------*/
42
43/*
44 wraps and redirections, indexed by from_addr
45
46 Redirection and wrapping are two distinct mechanisms which Valgrind
47 can use to change the client's control flow.
48
49 Redirection intercepts a call to a client function, and re-points it
50 to a new piece of code (presumably functionally equivalent). The
51 original code is never run.
52
53 Wrapping does call the client's original code, but calls "before"
54 and "after" functions which can inspect (and perhaps modify) the
55 function's arguments and return value.
56 */
57struct _CodeRedirect {
58 enum redir_type {
59 R_REDIRECT, /* plain redirection */
60 R_WRAPPER, /* wrap with valgrind-internal code */
61 R_CLIENT_WRAPPER, /* wrap with client-side code */
62 } type;
63
64 const Char *from_lib; /* library qualifier pattern */
65 const Char *from_sym; /* symbol */
66 Addr from_addr; /* old addr */
67
68 /* used for redirection */
69 const Char *to_lib; /* library qualifier pattern */
70 const Char *to_sym; /* symbol */
71 Addr to_addr; /* new addr */
72
73 /* used for wrapping */
74 const FuncWrapper *wrapper;
75
76 CodeRedirect *next; /* next pointer on unresolved list */
77};
78
79static Char *straddr(void *p)
80{
81 static Char buf[16];
82
83 VG_(sprintf)(buf, "%p", *(Addr *)p);
84
85 return buf;
86}
87
njnbe91aae2005-03-27 01:42:41 +000088static SkipList sk_resolved_redir = VG_SKIPLIST_INIT(CodeRedirect, from_addr,
sewardjcbdddcf2005-03-10 23:23:45 +000089 VG_(cmp_Addr), straddr, VG_AR_SYMTAB);
90static CodeRedirect *unresolved_redir = NULL;
91
92static Bool match_lib(const Char *pattern, const SegInfo *si)
93{
94 /* pattern == NULL matches everything, otherwise use globbing
95
96 If the pattern starts with:
97 file:, then match filename
98 soname:, then match soname
99 something else, match filename
100 */
101 const Char *name = si->filename;
102
103 if (pattern == NULL)
104 return True;
105
106 if (VG_(strncmp)(pattern, "file:", 5) == 0) {
107 pattern += 5;
108 name = si->filename;
109 }
110 if (VG_(strncmp)(pattern, "soname:", 7) == 0) {
111 pattern += 7;
112 name = si->soname;
113 }
114
115 if (name == NULL)
116 return False;
117
118 return VG_(string_match)(pattern, name);
119}
120
121static inline Bool from_resolved(const CodeRedirect *redir)
122{
123 return redir->from_addr != 0;
124}
125
126static inline Bool to_resolved(const CodeRedirect *redir)
127{
128 if (redir->type == R_REDIRECT)
129 return redir->to_addr != 0;
130 vg_assert(redir->wrapper != NULL);
131 return True;
132}
133
134Bool VG_(is_resolved)(const CodeRedirect *redir)
135{
136 return from_resolved(redir) && to_resolved(redir);
137}
138
tom748a1312005-04-02 15:53:01 +0000139static void add_resolved(CodeRedirect *redir)
140{
141 switch(redir->type) {
142 case R_REDIRECT:
143 if (VG_(clo_trace_redir)) {
144 VG_(message)(Vg_DebugMsg, " redir resolved (%s:%s=%p -> ",
145 redir->from_lib, redir->from_sym, redir->from_addr);
146 VG_(message)(Vg_DebugMsg, " %s:%s=%p)",
147 redir->to_lib, redir->to_sym, redir->to_addr);
148 }
149
150 if (VG_(search_transtab)(NULL, (Addr64)redir->from_addr, False)) {
151 /* For some given (from, to) redir, the "from" function got
152 called before the .so containing "to" became available. We
153 know this because there is already a translation for the
154 entry point of the original "from". So the redirect will
155 never actually take effect unless that translation is
156 discarded.
157
158 Note, we only really need to discard the first bb of the
159 old entry point, and so we avoid the problem of having to
160 figure out how big that bb was -- since it is at least 1
161 byte of original code, we can just pass 1 as the original
162 size to invalidate_translations() and it will indeed get
163 rid of the translation.
164
165 Note, this is potentially expensive -- discarding
166 translations causes complete unchaining.
167 */
168 if (VG_(clo_verbosity) > 2 && VG_(clo_trace_redir)) {
169 VG_(message)(Vg_UserMsg,
170 "Discarding translation due to redirect of already called function" );
171 VG_(message)(Vg_UserMsg,
172 " %s (%p -> %p)",
173 redir->from_sym, redir->from_addr, redir->to_addr );
174 }
175 VG_(discard_translations)((Addr64)redir->from_addr, 1);
176 }
177
178 {
179 CodeRedirect *r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &redir->from_addr);
180
181 if (r == NULL)
182 VG_(SkipList_Insert)(&sk_resolved_redir, redir);
183 else {
184 /* XXX leak redir */
185 if (VG_(clo_trace_redir))
186 VG_(message)(Vg_DebugMsg, " redir %s:%s:%p->%s:%s:%p duplicated\n",
187 redir->from_lib, redir->from_sym, redir->from_addr,
188 redir->to_lib, redir->to_sym, redir->to_addr);
189 }
190 }
191 break;
192
193 case R_WRAPPER:
194 if (VG_(clo_trace_redir)) {
195 VG_(message)(Vg_DebugMsg, " wrapper resolved (%s:%s=%p -> wrapper)",
196 redir->from_lib, redir->from_sym, redir->from_addr);
197 }
198
199 /* XXX redir leaked */
200 //VG_(wrap_function)(redir->from_addr, redir->wrapper);
201 break;
202
203 case R_CLIENT_WRAPPER:
204 VG_(core_panic)("not implemented");
205 break;
206 }
207}
208
sewardjcbdddcf2005-03-10 23:23:45 +0000209/* Resolve a redir using si if possible, and add it to the resolved
210 list */
211Bool VG_(resolve_redir)(CodeRedirect *redir, const SegInfo *si)
212{
213 Bool resolved;
214
215 vg_assert(si != NULL);
216 vg_assert(si->seg != NULL);
217
218 /* no redirection from Valgrind segments */
219 if (si->seg->flags & SF_VALGRIND)
220 return False;
221
222 resolved = VG_(is_resolved)(redir);
223
224 if (0 && VG_(clo_trace_redir))
225 VG_(printf)(" consider FROM binding %s:%s -> %s:%s in %s(%s)\n",
226 redir->from_lib, redir->from_sym,
227 redir->to_lib, redir->to_sym,
228 si->filename, si->soname);
229
230 vg_assert(!resolved);
231
232 if (!from_resolved(redir)) {
233 vg_assert(redir->from_sym != NULL);
234
235 if (match_lib(redir->from_lib, si)) {
236 redir->from_addr = VG_(reverse_search_one_symtab)(si, redir->from_sym);
237 if (VG_(clo_trace_redir) && redir->from_addr != 0)
238 VG_(printf)(" bind FROM: %p = %s:%s\n",
239 redir->from_addr,redir->from_lib, redir->from_sym );
240 }
241 }
242
243 if (!to_resolved(redir)) {
244 vg_assert(redir->type == R_REDIRECT);
245 vg_assert(redir->to_sym != NULL);
246
247 if (match_lib(redir->to_lib, si)) {
248 redir->to_addr = VG_(reverse_search_one_symtab)(si, redir->to_sym);
249 if (VG_(clo_trace_redir) && redir->to_addr != 0)
250 VG_(printf)(" bind TO: %p = %s:%s\n",
251 redir->to_addr,redir->to_lib, redir->to_sym );
252
253 }
254 }
255
256 resolved = from_resolved(redir) && to_resolved(redir);
257
258 if (0 && VG_(clo_trace_redir))
259 VG_(printf)("resolve_redir: %s:%s from=%p %s:%s to=%p\n",
260 redir->from_lib, redir->from_sym, redir->from_addr,
261 redir->to_lib, redir->to_sym, redir->to_addr);
262
tom748a1312005-04-02 15:53:01 +0000263 if (resolved) add_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000264
265 return resolved;
266}
267
268/* Go through the complete redir list, resolving as much as possible with this SegInfo.
269
270 This should be called when a new SegInfo symtab is loaded.
271 */
272void VG_(resolve_seg_redirs)(SegInfo *si)
273{
274 CodeRedirect **prevp = &unresolved_redir;
275 CodeRedirect *redir, *next;
276
277 if (VG_(clo_trace_redir))
278 VG_(printf)("Considering redirs to/from %s(soname=%s)\n",
279 si->filename, si->soname);
280
281 /* visit each unresolved redir - if it becomes resolved, then
282 remove it from the unresolved list */
283 for(redir = unresolved_redir; redir != NULL; redir = next) {
284 next = redir->next;
285
286 if (VG_(resolve_redir)(redir, si)) {
287 *prevp = next;
288 redir->next = NULL;
289 } else
290 prevp = &redir->next;
291 }
292}
293
294/* Redirect a lib/symbol reference to a function at lib/symbol */
tom748a1312005-04-02 15:53:01 +0000295static void add_redirect_sym_to_sym(const Char *from_lib, const Char *from_sym,
296 const Char *to_lib, const Char *to_sym)
sewardjcbdddcf2005-03-10 23:23:45 +0000297{
298 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
299
300 redir->type = R_REDIRECT;
301
302 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
303 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
304 redir->from_addr = 0;
305
306 redir->to_lib = VG_(arena_strdup)(VG_AR_SYMTAB, to_lib);
307 redir->to_sym = VG_(arena_strdup)(VG_AR_SYMTAB, to_sym);
308 redir->to_addr = 0;
309
310 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
311 VG_(message)(Vg_UserMsg,
312 "REDIRECT %s(%s) to %s(%s)",
313 from_lib, from_sym, to_lib, to_sym);
314
315 /* Check against all existing segments to see if this redirection
316 can be resolved immediately */
317 if (!VG_(resolve_redir_allsegs)(redir)) {
318 /* nope, add to list */
319 redir->next = unresolved_redir;
320 unresolved_redir = redir;
321 }
322}
323
324/* Redirect a lib/symbol reference to a function at addr */
tom748a1312005-04-02 15:53:01 +0000325void VG_(add_redirect_sym_to_addr)(const Char *from_lib, const Char *from_sym,
326 Addr to_addr)
sewardjcbdddcf2005-03-10 23:23:45 +0000327{
328 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
329
330 redir->type = R_REDIRECT;
331
332 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
333 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
334 redir->from_addr = 0;
335
336 redir->to_lib = NULL;
337 redir->to_sym = NULL;
338 redir->to_addr = to_addr;
339
tom748a1312005-04-02 15:53:01 +0000340 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
341 VG_(message)(Vg_UserMsg,
342 "REDIRECT %s(%s) to %p",
343 from_lib, from_sym, to_addr);
344
sewardjcbdddcf2005-03-10 23:23:45 +0000345 /* Check against all existing segments to see if this redirection
346 can be resolved immediately */
347 if (!VG_(resolve_redir_allsegs)(redir)) {
348 /* nope, add to list */
349 redir->next = unresolved_redir;
350 unresolved_redir = redir;
351 }
352}
353
tom748a1312005-04-02 15:53:01 +0000354/* Redirect a function at from_addr to a function at to_addr */
355void VG_(add_redirect_addr_to_addr)(Addr from_addr, Addr to_addr)
356{
357 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
358
359 redir->type = R_REDIRECT;
360
361 redir->from_lib = NULL;
362 redir->from_sym = NULL;
363 redir->from_addr = from_addr;
364
365 redir->to_lib = NULL;
366 redir->to_sym = NULL;
367 redir->to_addr = to_addr;
368
369 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
370 VG_(message)(Vg_UserMsg,
371 "REDIRECT %p to %p",
372 from_addr, to_addr);
373
374 add_resolved(redir);
375}
376
sewardjcbdddcf2005-03-10 23:23:45 +0000377CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
378 const FuncWrapper *wrapper)
379{
380 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
381
382 if (0)
383 VG_(printf)("adding wrapper for %s:%s -> (%p,%p)\n",
384 from_lib, from_sym, wrapper->before, wrapper->after);
385
386 redir->type = R_WRAPPER;
387
388 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
389 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
390 redir->from_addr = 0;
391
392 redir->to_lib = NULL;
393 redir->to_sym = NULL;
394 redir->to_addr = 0;
395
396 redir->wrapper = wrapper;
397
398 /* Check against all existing segments to see if this redirection
399 can be resolved immediately */
400 if (!VG_(resolve_redir_allsegs)(redir)) {
401 /* nope, add to list */
402 redir->next = unresolved_redir;
403 unresolved_redir = redir;
404 }
405
406 return redir;
407}
408
sewardjcbdddcf2005-03-10 23:23:45 +0000409/* If address 'a' is being redirected, return the redirected-to
410 address. */
411Addr VG_(code_redirect)(Addr a)
412{
413 CodeRedirect* r;
414
sewardjcbdddcf2005-03-10 23:23:45 +0000415 r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &a);
416 if (r == NULL)
417 return a;
418
419 vg_assert(r->to_addr != 0);
420
421 return r->to_addr;
422}
423
424void VG_(setup_code_redirect_table) ( void )
425{
sewardjcbdddcf2005-03-10 23:23:45 +0000426 /* Overenthusiastic use of PLT bypassing by the glibc people also
427 means we need to patch the following functions to our own
428 implementations of said, in mac_replace_strmem.c.
429 */
tom748a1312005-04-02 15:53:01 +0000430 add_redirect_sym_to_sym("soname:libc.so.6", "stpcpy",
431 "*vgpreload_memcheck.so*", "stpcpy");
sewardjcbdddcf2005-03-10 23:23:45 +0000432
sewardj9ea09012005-04-20 14:32:32 +0000433 add_redirect_sym_to_sym("soname:ld-linux.so.2", "strlen",
434 "*vgpreload_memcheck.so*", "strlen");
tom748a1312005-04-02 15:53:01 +0000435 add_redirect_sym_to_sym("soname:libc.so.6", "strlen",
436 "*vgpreload_memcheck.so*", "strlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000437
tom748a1312005-04-02 15:53:01 +0000438 add_redirect_sym_to_sym("soname:libc.so.6", "strnlen",
439 "*vgpreload_memcheck.so*", "strnlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000440
tom748a1312005-04-02 15:53:01 +0000441 add_redirect_sym_to_sym("soname:ld-linux.so.2", "stpcpy",
442 "*vgpreload_memcheck.so*", "stpcpy");
443 add_redirect_sym_to_sym("soname:libc.so.6", "stpcpy",
444 "*vgpreload_memcheck.so*", "stpcpy");
sewardjcbdddcf2005-03-10 23:23:45 +0000445
tom748a1312005-04-02 15:53:01 +0000446 add_redirect_sym_to_sym("soname:libc.so.6", "strchr",
447 "*vgpreload_memcheck.so*", "strchr");
448 add_redirect_sym_to_sym("soname:ld-linux.so.2", "strchr",
449 "*vgpreload_memcheck.so*", "strchr");
sewardjcbdddcf2005-03-10 23:23:45 +0000450
tom748a1312005-04-02 15:53:01 +0000451 add_redirect_sym_to_sym("soname:libc.so.6", "strchrnul",
452 "*vgpreload_memcheck.so*", "glibc232_strchrnul");
sewardjcbdddcf2005-03-10 23:23:45 +0000453
tom748a1312005-04-02 15:53:01 +0000454 add_redirect_sym_to_sym("soname:libc.so.6", "rawmemchr",
455 "*vgpreload_memcheck.so*", "glibc232_rawmemchr");
sewardj7efe7be2005-04-25 17:08:32 +0000456
457 /* amd64-linux (glibc 2.3.3, SuSE 9.2) */
458 /* apparently index is the same thing as strchr */
459 add_redirect_sym_to_sym("soname:libc.so.6", "index",
460 "*vgpreload_memcheck.so*", "strchr");
sewardj86facbc2005-05-12 17:58:57 +0000461 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "index",
462 "*vgpreload_memcheck.so*", "strchr");
463
464 add_redirect_sym_to_sym("soname:libc.so.6", "strcpy",
465 "*vgpreload_memcheck.so*", "strcpy");
sewardj7efe7be2005-04-25 17:08:32 +0000466
467 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "strcmp",
468 "*vgpreload_memcheck.so*", "strcmp");
469 add_redirect_sym_to_sym("soname:libc.so.6", "strcmp",
470 "*vgpreload_memcheck.so*", "strcmp");
471
472 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "strlen",
473 "*vgpreload_memcheck.so*", "strlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000474}
475
476
477//:: /*------------------------------------------------------------*/
478//:: /*--- General function wrapping. ---*/
479//:: /*------------------------------------------------------------*/
480//::
481//:: /*
482//:: TODO:
483//:: - hook into the symtab machinery
484//:: - client-side wrappers?
485//:: - better interfaces for before() functions to get to arguments
486//:: - handle munmap of code (dlclose())
487//:: - handle thread exit
488//:: - handle longjmp
489//:: */
490//:: struct callkey {
491//:: ThreadId tid; /* calling thread */
492//:: Addr esp; /* address of args on stack */
493//:: Addr eip; /* return address */
494//:: };
495//::
496//:: struct call_instance {
497//:: struct callkey key;
498//::
499//:: const FuncWrapper *wrapper;
500//:: void *nonce;
501//:: };
502//::
503//:: static inline Addr addrcmp(Addr a, Addr b)
504//:: {
505//:: if (a < b)
506//:: return -1;
507//:: else if (a > b)
508//:: return 1;
509//:: else
510//:: return 0;
511//:: }
512//::
513//:: static inline Int cmp(UInt a, UInt b)
514//:: {
515//:: if (a < b)
516//:: return -1;
517//:: else if (a > b)
518//:: return 1;
519//:: else
520//:: return 0;
521//:: }
522//::
523//:: static Int keycmp(const void *pa, const void *pb)
524//:: {
525//:: const struct callkey *a = (const struct callkey *)pa;
526//:: const struct callkey *b = (const struct callkey *)pb;
527//:: Int ret;
528//::
529//:: if ((ret = cmp(a->tid, b->tid)))
530//:: return ret;
531//::
532//:: if ((ret = addrcmp(a->esp, b->esp)))
533//:: return ret;
534//::
535//:: return addrcmp(a->eip, b->eip);
536//:: }
537//::
538//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000539//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000540//:: NULL, VG_AR_SYMTAB);
541//::
542//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
543//:: {
544//:: struct callkey key = { tid, argsp, retaddr };
545//::
546//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
547//:: }
548//::
549//:: static void wrapper_return(Addr retaddr);
550//::
551//:: /* Called from generated code via helper */
552//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
553//:: {
njndb9b7732005-03-26 00:32:29 +0000554//:: Addr retaddr = VGA_RETADDR(tst->arch);
555//:: Addr argp = (Addr)&VGA_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000556//:: void *nonce = NULL;
557//:: Bool mf = VG_(my_fault);
558//:: VG_(my_fault) = True;
559//::
560//:: if (wrapper->before) {
njndb9b7732005-03-26 00:32:29 +0000561//:: va_list args = VGA_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000562//:: nonce = (*wrapper->before)(args);
563//:: }
564//::
565//:: if (wrapper->after) {
566//:: /* If there's an after function, make sure it gets called */
567//:: struct call_instance *call;
568//::
569//:: call = find_call(retaddr, argp, tst->tid);
570//::
571//:: if (call != NULL) {
572//:: /* Found a stale outstanding call; clean it up and recycle
573//:: the structure */
574//:: if (call->wrapper->after)
575//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
576//:: } else {
577//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
578//::
579//:: call->key.tid = tst->tid;
580//:: call->key.esp = argp;
581//:: call->key.eip = retaddr;
582//::
583//:: VG_(SkipList_Insert)(&wrapped_frames, call);
584//::
585//:: wrapper_return(retaddr);
586//:: }
587//::
588//:: call->wrapper = wrapper;
589//:: call->nonce = nonce;
590//:: } else
591//:: vg_assert(nonce == NULL);
592//::
593//:: VG_(my_fault) = mf;
594//:: }
595//::
596//:: /* Called from generated code via helper */
597//:: void VG_(wrap_after)(ThreadState *tst)
598//:: {
njn35172bc2005-03-26 00:04:03 +0000599//:: Addr EIP = VGA_INSTR_PTR(tst->arch); /* instruction after call */
600//:: Addr ESP = VGA_STACK_PTR(tst->arch); /* pointer to args */
601//:: Word ret = VGA_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000602//:: struct call_instance *call;
603//:: Bool mf = VG_(my_fault);
604//::
605//:: VG_(my_fault) = True;
606//:: call = find_call(EIP, ESP, tst->tid);
607//::
608//:: if (0)
609//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
610//::
611//:: if (call != NULL) {
612//:: if (call->wrapper->after)
613//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
614//::
615//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
616//:: VG_(SkipNode_Free)(&wrapped_frames, call);
617//:: }
618//:: VG_(my_fault) = mf;
619//:: }
620//::
621//::
622//:: struct wrapped_function {
623//:: Addr eip; /* eip of function entrypoint */
624//:: const FuncWrapper *wrapper;
625//:: };
626//::
627//:: struct wrapper_return {
628//:: Addr eip; /* return address */
629//:: };
630//::
631//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000632//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000633//:: NULL, VG_AR_SYMTAB);
634//::
635//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000636//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000637//:: NULL, VG_AR_SYMTAB);
638//::
639//:: /* Wrap function starting at eip */
640//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
641//:: {
642//:: struct wrapped_function *func;
643//::
644//:: if (0)
645//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
646//::
647//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
648//::
649//:: if (func == NULL) {
650//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
651//:: VG_(invalidate_translations)(eip, 1, True);
652//::
653//:: func->eip = eip;
654//:: VG_(SkipList_Insert)(&wrapped_functions, func);
655//:: }
656//::
657//:: func->wrapper = wrapper;
658//:: }
659//::
660//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
661//:: {
662//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
663//::
664//:: if (func)
665//:: return func->wrapper;
666//:: return NULL;
667//:: }
668//::
669//:: Bool VG_(is_wrapper_return)(Addr eip)
670//:: {
671//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
672//::
673//:: return ret != NULL;
674//:: }
675//::
676//:: /* Mark eip as being the return address of a wrapper, so that the
677//:: codegen will generate the appropriate call. */
678//:: void wrapper_return(Addr eip)
679//:: {
680//:: struct wrapper_return *ret;
681//::
682//:: if (VG_(is_wrapper_return)(eip))
683//:: return;
684//::
685//:: VG_(invalidate_translations)(eip, 1, True);
686//::
687//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
688//:: ret->eip = eip;
689//::
690//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
691//:: }