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