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