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