blob: 1d6c33255385181b385e904772eb6f00cf7d8edc [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
njnbf7ca332005-05-14 17:11:06 +0000268static Bool resolve_redir_allsegs(CodeRedirect *redir)
269{
270 const SegInfo *si;
271
272 for(si = VG_(next_seginfo)(NULL);
273 si != NULL;
274 si = VG_(next_seginfo)(si))
275 {
276 if (VG_(resolve_redir)(redir, si))
277 return True;
278 }
279 return False;
280}
281
sewardjcbdddcf2005-03-10 23:23:45 +0000282/* Go through the complete redir list, resolving as much as possible with this SegInfo.
283
284 This should be called when a new SegInfo symtab is loaded.
285 */
286void VG_(resolve_seg_redirs)(SegInfo *si)
287{
288 CodeRedirect **prevp = &unresolved_redir;
289 CodeRedirect *redir, *next;
290
291 if (VG_(clo_trace_redir))
292 VG_(printf)("Considering redirs to/from %s(soname=%s)\n",
293 si->filename, si->soname);
294
295 /* visit each unresolved redir - if it becomes resolved, then
296 remove it from the unresolved list */
297 for(redir = unresolved_redir; redir != NULL; redir = next) {
298 next = redir->next;
299
300 if (VG_(resolve_redir)(redir, si)) {
301 *prevp = next;
302 redir->next = NULL;
303 } else
304 prevp = &redir->next;
305 }
306}
307
308/* Redirect a lib/symbol reference to a function at lib/symbol */
tom748a1312005-04-02 15:53:01 +0000309static void add_redirect_sym_to_sym(const Char *from_lib, const Char *from_sym,
310 const Char *to_lib, const Char *to_sym)
sewardjcbdddcf2005-03-10 23:23:45 +0000311{
312 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
313
314 redir->type = R_REDIRECT;
315
316 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
317 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
318 redir->from_addr = 0;
319
320 redir->to_lib = VG_(arena_strdup)(VG_AR_SYMTAB, to_lib);
321 redir->to_sym = VG_(arena_strdup)(VG_AR_SYMTAB, to_sym);
322 redir->to_addr = 0;
323
324 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
325 VG_(message)(Vg_UserMsg,
326 "REDIRECT %s(%s) to %s(%s)",
327 from_lib, from_sym, to_lib, to_sym);
328
329 /* Check against all existing segments to see if this redirection
330 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000331 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000332 /* nope, add to list */
333 redir->next = unresolved_redir;
334 unresolved_redir = redir;
335 }
336}
337
338/* Redirect a lib/symbol reference to a function at addr */
tom748a1312005-04-02 15:53:01 +0000339void VG_(add_redirect_sym_to_addr)(const Char *from_lib, const Char *from_sym,
340 Addr to_addr)
sewardjcbdddcf2005-03-10 23:23:45 +0000341{
342 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
343
344 redir->type = R_REDIRECT;
345
346 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
347 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
348 redir->from_addr = 0;
349
350 redir->to_lib = NULL;
351 redir->to_sym = NULL;
352 redir->to_addr = to_addr;
353
tom748a1312005-04-02 15:53:01 +0000354 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
355 VG_(message)(Vg_UserMsg,
356 "REDIRECT %s(%s) to %p",
357 from_lib, from_sym, to_addr);
358
sewardjcbdddcf2005-03-10 23:23:45 +0000359 /* Check against all existing segments to see if this redirection
360 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000361 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000362 /* nope, add to list */
363 redir->next = unresolved_redir;
364 unresolved_redir = redir;
365 }
366}
367
tom748a1312005-04-02 15:53:01 +0000368/* Redirect a function at from_addr to a function at to_addr */
369void VG_(add_redirect_addr_to_addr)(Addr from_addr, Addr to_addr)
370{
371 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
372
373 redir->type = R_REDIRECT;
374
375 redir->from_lib = NULL;
376 redir->from_sym = NULL;
377 redir->from_addr = from_addr;
378
379 redir->to_lib = NULL;
380 redir->to_sym = NULL;
381 redir->to_addr = to_addr;
382
383 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
384 VG_(message)(Vg_UserMsg,
385 "REDIRECT %p to %p",
386 from_addr, to_addr);
387
388 add_resolved(redir);
389}
390
sewardjcbdddcf2005-03-10 23:23:45 +0000391CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
392 const FuncWrapper *wrapper)
393{
394 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
395
396 if (0)
397 VG_(printf)("adding wrapper for %s:%s -> (%p,%p)\n",
398 from_lib, from_sym, wrapper->before, wrapper->after);
399
400 redir->type = R_WRAPPER;
401
402 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
403 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
404 redir->from_addr = 0;
405
406 redir->to_lib = NULL;
407 redir->to_sym = NULL;
408 redir->to_addr = 0;
409
410 redir->wrapper = wrapper;
411
412 /* Check against all existing segments to see if this redirection
413 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000414 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000415 /* nope, add to list */
416 redir->next = unresolved_redir;
417 unresolved_redir = redir;
418 }
419
420 return redir;
421}
422
sewardjcbdddcf2005-03-10 23:23:45 +0000423/* If address 'a' is being redirected, return the redirected-to
424 address. */
425Addr VG_(code_redirect)(Addr a)
426{
427 CodeRedirect* r;
428
sewardjcbdddcf2005-03-10 23:23:45 +0000429 r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &a);
430 if (r == NULL)
431 return a;
432
433 vg_assert(r->to_addr != 0);
434
435 return r->to_addr;
436}
437
438void VG_(setup_code_redirect_table) ( void )
439{
sewardjcbdddcf2005-03-10 23:23:45 +0000440 /* Overenthusiastic use of PLT bypassing by the glibc people also
441 means we need to patch the following functions to our own
442 implementations of said, in mac_replace_strmem.c.
443 */
tom748a1312005-04-02 15:53:01 +0000444 add_redirect_sym_to_sym("soname:libc.so.6", "stpcpy",
445 "*vgpreload_memcheck.so*", "stpcpy");
sewardjcbdddcf2005-03-10 23:23:45 +0000446
sewardj9ea09012005-04-20 14:32:32 +0000447 add_redirect_sym_to_sym("soname:ld-linux.so.2", "strlen",
448 "*vgpreload_memcheck.so*", "strlen");
tom748a1312005-04-02 15:53:01 +0000449 add_redirect_sym_to_sym("soname:libc.so.6", "strlen",
450 "*vgpreload_memcheck.so*", "strlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000451
tom748a1312005-04-02 15:53:01 +0000452 add_redirect_sym_to_sym("soname:libc.so.6", "strnlen",
453 "*vgpreload_memcheck.so*", "strnlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000454
tom748a1312005-04-02 15:53:01 +0000455 add_redirect_sym_to_sym("soname:ld-linux.so.2", "stpcpy",
456 "*vgpreload_memcheck.so*", "stpcpy");
457 add_redirect_sym_to_sym("soname:libc.so.6", "stpcpy",
458 "*vgpreload_memcheck.so*", "stpcpy");
sewardjcbdddcf2005-03-10 23:23:45 +0000459
tom748a1312005-04-02 15:53:01 +0000460 add_redirect_sym_to_sym("soname:libc.so.6", "strchr",
461 "*vgpreload_memcheck.so*", "strchr");
462 add_redirect_sym_to_sym("soname:ld-linux.so.2", "strchr",
463 "*vgpreload_memcheck.so*", "strchr");
sewardjcbdddcf2005-03-10 23:23:45 +0000464
tom748a1312005-04-02 15:53:01 +0000465 add_redirect_sym_to_sym("soname:libc.so.6", "strchrnul",
466 "*vgpreload_memcheck.so*", "glibc232_strchrnul");
sewardjcbdddcf2005-03-10 23:23:45 +0000467
tom748a1312005-04-02 15:53:01 +0000468 add_redirect_sym_to_sym("soname:libc.so.6", "rawmemchr",
469 "*vgpreload_memcheck.so*", "glibc232_rawmemchr");
sewardj7efe7be2005-04-25 17:08:32 +0000470
471 /* amd64-linux (glibc 2.3.3, SuSE 9.2) */
472 /* apparently index is the same thing as strchr */
473 add_redirect_sym_to_sym("soname:libc.so.6", "index",
474 "*vgpreload_memcheck.so*", "strchr");
sewardj86facbc2005-05-12 17:58:57 +0000475 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "index",
476 "*vgpreload_memcheck.so*", "strchr");
477
478 add_redirect_sym_to_sym("soname:libc.so.6", "strcpy",
479 "*vgpreload_memcheck.so*", "strcpy");
sewardj7efe7be2005-04-25 17:08:32 +0000480
481 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "strcmp",
482 "*vgpreload_memcheck.so*", "strcmp");
483 add_redirect_sym_to_sym("soname:libc.so.6", "strcmp",
484 "*vgpreload_memcheck.so*", "strcmp");
485
486 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "strlen",
487 "*vgpreload_memcheck.so*", "strlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000488}
489
490
491//:: /*------------------------------------------------------------*/
492//:: /*--- General function wrapping. ---*/
493//:: /*------------------------------------------------------------*/
494//::
495//:: /*
496//:: TODO:
497//:: - hook into the symtab machinery
498//:: - client-side wrappers?
499//:: - better interfaces for before() functions to get to arguments
500//:: - handle munmap of code (dlclose())
501//:: - handle thread exit
502//:: - handle longjmp
503//:: */
504//:: struct callkey {
505//:: ThreadId tid; /* calling thread */
506//:: Addr esp; /* address of args on stack */
507//:: Addr eip; /* return address */
508//:: };
509//::
510//:: struct call_instance {
511//:: struct callkey key;
512//::
513//:: const FuncWrapper *wrapper;
514//:: void *nonce;
515//:: };
516//::
517//:: static inline Addr addrcmp(Addr a, Addr b)
518//:: {
519//:: if (a < b)
520//:: return -1;
521//:: else if (a > b)
522//:: return 1;
523//:: else
524//:: return 0;
525//:: }
526//::
527//:: static inline Int cmp(UInt a, UInt b)
528//:: {
529//:: if (a < b)
530//:: return -1;
531//:: else if (a > b)
532//:: return 1;
533//:: else
534//:: return 0;
535//:: }
536//::
537//:: static Int keycmp(const void *pa, const void *pb)
538//:: {
539//:: const struct callkey *a = (const struct callkey *)pa;
540//:: const struct callkey *b = (const struct callkey *)pb;
541//:: Int ret;
542//::
543//:: if ((ret = cmp(a->tid, b->tid)))
544//:: return ret;
545//::
546//:: if ((ret = addrcmp(a->esp, b->esp)))
547//:: return ret;
548//::
549//:: return addrcmp(a->eip, b->eip);
550//:: }
551//::
552//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000553//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000554//:: NULL, VG_AR_SYMTAB);
555//::
556//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
557//:: {
558//:: struct callkey key = { tid, argsp, retaddr };
559//::
560//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
561//:: }
562//::
563//:: static void wrapper_return(Addr retaddr);
564//::
565//:: /* Called from generated code via helper */
566//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
567//:: {
njndb9b7732005-03-26 00:32:29 +0000568//:: Addr retaddr = VGA_RETADDR(tst->arch);
569//:: Addr argp = (Addr)&VGA_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000570//:: void *nonce = NULL;
571//:: Bool mf = VG_(my_fault);
572//:: VG_(my_fault) = True;
573//::
574//:: if (wrapper->before) {
njndb9b7732005-03-26 00:32:29 +0000575//:: va_list args = VGA_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000576//:: nonce = (*wrapper->before)(args);
577//:: }
578//::
579//:: if (wrapper->after) {
580//:: /* If there's an after function, make sure it gets called */
581//:: struct call_instance *call;
582//::
583//:: call = find_call(retaddr, argp, tst->tid);
584//::
585//:: if (call != NULL) {
586//:: /* Found a stale outstanding call; clean it up and recycle
587//:: the structure */
588//:: if (call->wrapper->after)
589//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
590//:: } else {
591//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
592//::
593//:: call->key.tid = tst->tid;
594//:: call->key.esp = argp;
595//:: call->key.eip = retaddr;
596//::
597//:: VG_(SkipList_Insert)(&wrapped_frames, call);
598//::
599//:: wrapper_return(retaddr);
600//:: }
601//::
602//:: call->wrapper = wrapper;
603//:: call->nonce = nonce;
604//:: } else
605//:: vg_assert(nonce == NULL);
606//::
607//:: VG_(my_fault) = mf;
608//:: }
609//::
610//:: /* Called from generated code via helper */
611//:: void VG_(wrap_after)(ThreadState *tst)
612//:: {
njn35172bc2005-03-26 00:04:03 +0000613//:: Addr EIP = VGA_INSTR_PTR(tst->arch); /* instruction after call */
614//:: Addr ESP = VGA_STACK_PTR(tst->arch); /* pointer to args */
615//:: Word ret = VGA_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000616//:: struct call_instance *call;
617//:: Bool mf = VG_(my_fault);
618//::
619//:: VG_(my_fault) = True;
620//:: call = find_call(EIP, ESP, tst->tid);
621//::
622//:: if (0)
623//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
624//::
625//:: if (call != NULL) {
626//:: if (call->wrapper->after)
627//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
628//::
629//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
630//:: VG_(SkipNode_Free)(&wrapped_frames, call);
631//:: }
632//:: VG_(my_fault) = mf;
633//:: }
634//::
635//::
636//:: struct wrapped_function {
637//:: Addr eip; /* eip of function entrypoint */
638//:: const FuncWrapper *wrapper;
639//:: };
640//::
641//:: struct wrapper_return {
642//:: Addr eip; /* return address */
643//:: };
644//::
645//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000646//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000647//:: NULL, VG_AR_SYMTAB);
648//::
649//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000650//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000651//:: NULL, VG_AR_SYMTAB);
652//::
653//:: /* Wrap function starting at eip */
654//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
655//:: {
656//:: struct wrapped_function *func;
657//::
658//:: if (0)
659//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
660//::
661//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
662//::
663//:: if (func == NULL) {
664//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
665//:: VG_(invalidate_translations)(eip, 1, True);
666//::
667//:: func->eip = eip;
668//:: VG_(SkipList_Insert)(&wrapped_functions, func);
669//:: }
670//::
671//:: func->wrapper = wrapper;
672//:: }
673//::
674//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
675//:: {
676//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
677//::
678//:: if (func)
679//:: return func->wrapper;
680//:: return NULL;
681//:: }
682//::
683//:: Bool VG_(is_wrapper_return)(Addr eip)
684//:: {
685//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
686//::
687//:: return ret != NULL;
688//:: }
689//::
690//:: /* Mark eip as being the return address of a wrapper, so that the
691//:: codegen will generate the appropriate call. */
692//:: void wrapper_return(Addr eip)
693//:: {
694//:: struct wrapper_return *ret;
695//::
696//:: if (VG_(is_wrapper_return)(eip))
697//:: return;
698//::
699//:: VG_(invalidate_translations)(eip, 1, True);
700//::
701//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
702//:: ret->eip = eip;
703//::
704//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
705//:: }