blob: 81afc96c61f544f20ae2a1c4942b1a030698da5f [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"
sewardjcbdddcf2005-03-10 23:23:45 +000033
sewardj55f9d1a2005-04-25 11:11:44 +000034#include "pub_core_aspacemgr.h"
njn97405b22005-06-02 03:39:33 +000035#include "pub_core_libcbase.h"
njn36a20fa2005-06-03 03:08:39 +000036#include "pub_core_libcprint.h"
njn641d5cc2005-05-12 04:37:27 +000037#include "pub_core_skiplist.h"
njn20242342005-05-16 23:31:24 +000038#include "pub_core_options.h"
njnd1af0032005-05-29 17:01:48 +000039#include "pub_core_redir.h"
njn8bddf582005-05-13 23:40:55 +000040#include "pub_core_transtab.h"
njnea27e462005-05-31 02:38:09 +000041#include "m_debuginfo/priv_symtab.h" // XXX: bad!
sewardj55f9d1a2005-04-25 11:11:44 +000042
sewardjcbdddcf2005-03-10 23:23:45 +000043/*------------------------------------------------------------*/
44/*--- General purpose redirection. ---*/
45/*------------------------------------------------------------*/
46
47/*
48 wraps and redirections, indexed by from_addr
49
50 Redirection and wrapping are two distinct mechanisms which Valgrind
51 can use to change the client's control flow.
52
53 Redirection intercepts a call to a client function, and re-points it
54 to a new piece of code (presumably functionally equivalent). The
55 original code is never run.
56
57 Wrapping does call the client's original code, but calls "before"
58 and "after" functions which can inspect (and perhaps modify) the
59 function's arguments and return value.
60 */
61struct _CodeRedirect {
62 enum redir_type {
63 R_REDIRECT, /* plain redirection */
64 R_WRAPPER, /* wrap with valgrind-internal code */
65 R_CLIENT_WRAPPER, /* wrap with client-side code */
66 } type;
67
68 const Char *from_lib; /* library qualifier pattern */
69 const Char *from_sym; /* symbol */
70 Addr from_addr; /* old addr */
71
72 /* used for redirection */
73 const Char *to_lib; /* library qualifier pattern */
74 const Char *to_sym; /* symbol */
75 Addr to_addr; /* new addr */
76
77 /* used for wrapping */
78 const FuncWrapper *wrapper;
79
80 CodeRedirect *next; /* next pointer on unresolved list */
81};
82
83static Char *straddr(void *p)
84{
85 static Char buf[16];
86
87 VG_(sprintf)(buf, "%p", *(Addr *)p);
88
89 return buf;
90}
91
njnbe91aae2005-03-27 01:42:41 +000092static SkipList sk_resolved_redir = VG_SKIPLIST_INIT(CodeRedirect, from_addr,
sewardjcbdddcf2005-03-10 23:23:45 +000093 VG_(cmp_Addr), straddr, VG_AR_SYMTAB);
94static CodeRedirect *unresolved_redir = NULL;
95
96static Bool match_lib(const Char *pattern, const SegInfo *si)
97{
98 /* pattern == NULL matches everything, otherwise use globbing
99
100 If the pattern starts with:
101 file:, then match filename
102 soname:, then match soname
103 something else, match filename
104 */
105 const Char *name = si->filename;
106
107 if (pattern == NULL)
108 return True;
109
110 if (VG_(strncmp)(pattern, "file:", 5) == 0) {
111 pattern += 5;
112 name = si->filename;
113 }
114 if (VG_(strncmp)(pattern, "soname:", 7) == 0) {
115 pattern += 7;
116 name = si->soname;
117 }
118
119 if (name == NULL)
120 return False;
121
122 return VG_(string_match)(pattern, name);
123}
124
125static inline Bool from_resolved(const CodeRedirect *redir)
126{
127 return redir->from_addr != 0;
128}
129
130static inline Bool to_resolved(const CodeRedirect *redir)
131{
132 if (redir->type == R_REDIRECT)
133 return redir->to_addr != 0;
134 vg_assert(redir->wrapper != NULL);
135 return True;
136}
137
138Bool VG_(is_resolved)(const CodeRedirect *redir)
139{
140 return from_resolved(redir) && to_resolved(redir);
141}
142
tom748a1312005-04-02 15:53:01 +0000143static void add_resolved(CodeRedirect *redir)
144{
145 switch(redir->type) {
146 case R_REDIRECT:
147 if (VG_(clo_trace_redir)) {
148 VG_(message)(Vg_DebugMsg, " redir resolved (%s:%s=%p -> ",
149 redir->from_lib, redir->from_sym, redir->from_addr);
150 VG_(message)(Vg_DebugMsg, " %s:%s=%p)",
151 redir->to_lib, redir->to_sym, redir->to_addr);
152 }
153
154 if (VG_(search_transtab)(NULL, (Addr64)redir->from_addr, False)) {
155 /* For some given (from, to) redir, the "from" function got
156 called before the .so containing "to" became available. We
157 know this because there is already a translation for the
158 entry point of the original "from". So the redirect will
159 never actually take effect unless that translation is
160 discarded.
161
162 Note, we only really need to discard the first bb of the
163 old entry point, and so we avoid the problem of having to
164 figure out how big that bb was -- since it is at least 1
165 byte of original code, we can just pass 1 as the original
166 size to invalidate_translations() and it will indeed get
167 rid of the translation.
168
169 Note, this is potentially expensive -- discarding
170 translations causes complete unchaining.
171 */
172 if (VG_(clo_verbosity) > 2 && VG_(clo_trace_redir)) {
173 VG_(message)(Vg_UserMsg,
174 "Discarding translation due to redirect of already called function" );
175 VG_(message)(Vg_UserMsg,
176 " %s (%p -> %p)",
177 redir->from_sym, redir->from_addr, redir->to_addr );
178 }
179 VG_(discard_translations)((Addr64)redir->from_addr, 1);
180 }
181
182 {
183 CodeRedirect *r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &redir->from_addr);
184
185 if (r == NULL)
186 VG_(SkipList_Insert)(&sk_resolved_redir, redir);
187 else {
188 /* XXX leak redir */
189 if (VG_(clo_trace_redir))
190 VG_(message)(Vg_DebugMsg, " redir %s:%s:%p->%s:%s:%p duplicated\n",
191 redir->from_lib, redir->from_sym, redir->from_addr,
192 redir->to_lib, redir->to_sym, redir->to_addr);
193 }
194 }
195 break;
196
197 case R_WRAPPER:
198 if (VG_(clo_trace_redir)) {
199 VG_(message)(Vg_DebugMsg, " wrapper resolved (%s:%s=%p -> wrapper)",
200 redir->from_lib, redir->from_sym, redir->from_addr);
201 }
202
203 /* XXX redir leaked */
204 //VG_(wrap_function)(redir->from_addr, redir->wrapper);
205 break;
206
207 case R_CLIENT_WRAPPER:
208 VG_(core_panic)("not implemented");
209 break;
210 }
211}
212
sewardjcbdddcf2005-03-10 23:23:45 +0000213/* Resolve a redir using si if possible, and add it to the resolved
214 list */
njn17250122005-05-14 17:18:12 +0000215static Bool resolve_redir(CodeRedirect *redir, const SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000216{
217 Bool resolved;
218
219 vg_assert(si != NULL);
220 vg_assert(si->seg != NULL);
221
222 /* no redirection from Valgrind segments */
223 if (si->seg->flags & SF_VALGRIND)
224 return False;
225
226 resolved = VG_(is_resolved)(redir);
227
228 if (0 && VG_(clo_trace_redir))
229 VG_(printf)(" consider FROM binding %s:%s -> %s:%s in %s(%s)\n",
230 redir->from_lib, redir->from_sym,
231 redir->to_lib, redir->to_sym,
232 si->filename, si->soname);
233
234 vg_assert(!resolved);
235
236 if (!from_resolved(redir)) {
237 vg_assert(redir->from_sym != NULL);
238
239 if (match_lib(redir->from_lib, si)) {
240 redir->from_addr = VG_(reverse_search_one_symtab)(si, redir->from_sym);
241 if (VG_(clo_trace_redir) && redir->from_addr != 0)
242 VG_(printf)(" bind FROM: %p = %s:%s\n",
243 redir->from_addr,redir->from_lib, redir->from_sym );
244 }
245 }
246
247 if (!to_resolved(redir)) {
248 vg_assert(redir->type == R_REDIRECT);
249 vg_assert(redir->to_sym != NULL);
250
251 if (match_lib(redir->to_lib, si)) {
252 redir->to_addr = VG_(reverse_search_one_symtab)(si, redir->to_sym);
253 if (VG_(clo_trace_redir) && redir->to_addr != 0)
254 VG_(printf)(" bind TO: %p = %s:%s\n",
255 redir->to_addr,redir->to_lib, redir->to_sym );
256
257 }
258 }
259
260 resolved = from_resolved(redir) && to_resolved(redir);
261
262 if (0 && VG_(clo_trace_redir))
263 VG_(printf)("resolve_redir: %s:%s from=%p %s:%s to=%p\n",
264 redir->from_lib, redir->from_sym, redir->from_addr,
265 redir->to_lib, redir->to_sym, redir->to_addr);
266
tom748a1312005-04-02 15:53:01 +0000267 if (resolved) add_resolved(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000268
269 return resolved;
270}
271
njnbf7ca332005-05-14 17:11:06 +0000272static Bool resolve_redir_allsegs(CodeRedirect *redir)
273{
274 const SegInfo *si;
275
276 for(si = VG_(next_seginfo)(NULL);
277 si != NULL;
278 si = VG_(next_seginfo)(si))
279 {
njn17250122005-05-14 17:18:12 +0000280 if (resolve_redir(redir, si))
njnbf7ca332005-05-14 17:11:06 +0000281 return True;
282 }
283 return False;
284}
285
sewardjcbdddcf2005-03-10 23:23:45 +0000286/* Go through the complete redir list, resolving as much as possible with this SegInfo.
287
288 This should be called when a new SegInfo symtab is loaded.
289 */
290void VG_(resolve_seg_redirs)(SegInfo *si)
291{
292 CodeRedirect **prevp = &unresolved_redir;
293 CodeRedirect *redir, *next;
294
295 if (VG_(clo_trace_redir))
296 VG_(printf)("Considering redirs to/from %s(soname=%s)\n",
297 si->filename, si->soname);
298
299 /* visit each unresolved redir - if it becomes resolved, then
300 remove it from the unresolved list */
301 for(redir = unresolved_redir; redir != NULL; redir = next) {
302 next = redir->next;
303
njn17250122005-05-14 17:18:12 +0000304 if (resolve_redir(redir, si)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000305 *prevp = next;
306 redir->next = NULL;
307 } else
308 prevp = &redir->next;
309 }
310}
311
312/* Redirect a lib/symbol reference to a function at lib/symbol */
tom748a1312005-04-02 15:53:01 +0000313static void add_redirect_sym_to_sym(const Char *from_lib, const Char *from_sym,
314 const Char *to_lib, const Char *to_sym)
sewardjcbdddcf2005-03-10 23:23:45 +0000315{
316 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
317
318 redir->type = R_REDIRECT;
319
320 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
321 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
322 redir->from_addr = 0;
323
324 redir->to_lib = VG_(arena_strdup)(VG_AR_SYMTAB, to_lib);
325 redir->to_sym = VG_(arena_strdup)(VG_AR_SYMTAB, to_sym);
326 redir->to_addr = 0;
327
328 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
329 VG_(message)(Vg_UserMsg,
330 "REDIRECT %s(%s) to %s(%s)",
331 from_lib, from_sym, to_lib, to_sym);
332
333 /* Check against all existing segments to see if this redirection
334 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000335 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000336 /* nope, add to list */
337 redir->next = unresolved_redir;
338 unresolved_redir = redir;
339 }
340}
341
342/* Redirect a lib/symbol reference to a function at addr */
tom748a1312005-04-02 15:53:01 +0000343void VG_(add_redirect_sym_to_addr)(const Char *from_lib, const Char *from_sym,
344 Addr to_addr)
sewardjcbdddcf2005-03-10 23:23:45 +0000345{
346 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
347
348 redir->type = R_REDIRECT;
349
350 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
351 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
352 redir->from_addr = 0;
353
354 redir->to_lib = NULL;
355 redir->to_sym = NULL;
356 redir->to_addr = to_addr;
357
tom748a1312005-04-02 15:53:01 +0000358 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
359 VG_(message)(Vg_UserMsg,
360 "REDIRECT %s(%s) to %p",
361 from_lib, from_sym, to_addr);
362
sewardjcbdddcf2005-03-10 23:23:45 +0000363 /* Check against all existing segments to see if this redirection
364 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000365 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000366 /* nope, add to list */
367 redir->next = unresolved_redir;
368 unresolved_redir = redir;
369 }
370}
371
tom748a1312005-04-02 15:53:01 +0000372/* Redirect a function at from_addr to a function at to_addr */
373void VG_(add_redirect_addr_to_addr)(Addr from_addr, Addr to_addr)
374{
375 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
376
377 redir->type = R_REDIRECT;
378
379 redir->from_lib = NULL;
380 redir->from_sym = NULL;
381 redir->from_addr = from_addr;
382
383 redir->to_lib = NULL;
384 redir->to_sym = NULL;
385 redir->to_addr = to_addr;
386
387 if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
388 VG_(message)(Vg_UserMsg,
389 "REDIRECT %p to %p",
390 from_addr, to_addr);
391
392 add_resolved(redir);
393}
394
sewardjcbdddcf2005-03-10 23:23:45 +0000395CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
396 const FuncWrapper *wrapper)
397{
398 CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
399
400 if (0)
401 VG_(printf)("adding wrapper for %s:%s -> (%p,%p)\n",
402 from_lib, from_sym, wrapper->before, wrapper->after);
403
404 redir->type = R_WRAPPER;
405
406 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
407 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
408 redir->from_addr = 0;
409
410 redir->to_lib = NULL;
411 redir->to_sym = NULL;
412 redir->to_addr = 0;
413
414 redir->wrapper = wrapper;
415
416 /* Check against all existing segments to see if this redirection
417 can be resolved immediately */
njnbf7ca332005-05-14 17:11:06 +0000418 if (!resolve_redir_allsegs(redir)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000419 /* nope, add to list */
420 redir->next = unresolved_redir;
421 unresolved_redir = redir;
422 }
423
424 return redir;
425}
426
sewardjcbdddcf2005-03-10 23:23:45 +0000427/* If address 'a' is being redirected, return the redirected-to
428 address. */
429Addr VG_(code_redirect)(Addr a)
430{
431 CodeRedirect* r;
432
sewardjcbdddcf2005-03-10 23:23:45 +0000433 r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &a);
434 if (r == NULL)
435 return a;
436
437 vg_assert(r->to_addr != 0);
438
439 return r->to_addr;
440}
441
442void VG_(setup_code_redirect_table) ( void )
443{
sewardjcbdddcf2005-03-10 23:23:45 +0000444 /* Overenthusiastic use of PLT bypassing by the glibc people also
445 means we need to patch the following functions to our own
446 implementations of said, in mac_replace_strmem.c.
447 */
tom748a1312005-04-02 15:53:01 +0000448 add_redirect_sym_to_sym("soname:libc.so.6", "stpcpy",
449 "*vgpreload_memcheck.so*", "stpcpy");
sewardjcbdddcf2005-03-10 23:23:45 +0000450
sewardj9ea09012005-04-20 14:32:32 +0000451 add_redirect_sym_to_sym("soname:ld-linux.so.2", "strlen",
452 "*vgpreload_memcheck.so*", "strlen");
tom748a1312005-04-02 15:53:01 +0000453 add_redirect_sym_to_sym("soname:libc.so.6", "strlen",
454 "*vgpreload_memcheck.so*", "strlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000455
tom748a1312005-04-02 15:53:01 +0000456 add_redirect_sym_to_sym("soname:libc.so.6", "strnlen",
457 "*vgpreload_memcheck.so*", "strnlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000458
tom748a1312005-04-02 15:53:01 +0000459 add_redirect_sym_to_sym("soname:ld-linux.so.2", "stpcpy",
460 "*vgpreload_memcheck.so*", "stpcpy");
461 add_redirect_sym_to_sym("soname:libc.so.6", "stpcpy",
462 "*vgpreload_memcheck.so*", "stpcpy");
sewardjcbdddcf2005-03-10 23:23:45 +0000463
tom748a1312005-04-02 15:53:01 +0000464 add_redirect_sym_to_sym("soname:libc.so.6", "strchr",
465 "*vgpreload_memcheck.so*", "strchr");
466 add_redirect_sym_to_sym("soname:ld-linux.so.2", "strchr",
467 "*vgpreload_memcheck.so*", "strchr");
sewardjcbdddcf2005-03-10 23:23:45 +0000468
sewardjedfa2c22005-05-16 16:39:57 +0000469 /* apparently index is the same thing as strchr */
470 add_redirect_sym_to_sym("soname:ld-linux.so.2", "index",
471 "*vgpreload_memcheck.so*", "strchr");
472
tom748a1312005-04-02 15:53:01 +0000473 add_redirect_sym_to_sym("soname:libc.so.6", "strchrnul",
474 "*vgpreload_memcheck.so*", "glibc232_strchrnul");
sewardjcbdddcf2005-03-10 23:23:45 +0000475
tom748a1312005-04-02 15:53:01 +0000476 add_redirect_sym_to_sym("soname:libc.so.6", "rawmemchr",
477 "*vgpreload_memcheck.so*", "glibc232_rawmemchr");
sewardj7efe7be2005-04-25 17:08:32 +0000478
479 /* amd64-linux (glibc 2.3.3, SuSE 9.2) */
480 /* apparently index is the same thing as strchr */
481 add_redirect_sym_to_sym("soname:libc.so.6", "index",
482 "*vgpreload_memcheck.so*", "strchr");
sewardj86facbc2005-05-12 17:58:57 +0000483 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "index",
484 "*vgpreload_memcheck.so*", "strchr");
485
486 add_redirect_sym_to_sym("soname:libc.so.6", "strcpy",
487 "*vgpreload_memcheck.so*", "strcpy");
sewardj7efe7be2005-04-25 17:08:32 +0000488
489 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "strcmp",
490 "*vgpreload_memcheck.so*", "strcmp");
491 add_redirect_sym_to_sym("soname:libc.so.6", "strcmp",
492 "*vgpreload_memcheck.so*", "strcmp");
493
494 add_redirect_sym_to_sym("soname:ld-linux-x86-64.so.2", "strlen",
495 "*vgpreload_memcheck.so*", "strlen");
sewardjcbdddcf2005-03-10 23:23:45 +0000496
njnd1af0032005-05-29 17:01:48 +0000497#if defined(VGP_x86_linux)
498 /* Redirect _dl_sysinfo_int80, which is glibc's default system call
499 routine, to the routine in our trampoline page so that the
500 special sysinfo unwind hack in m_stacktrace.c will kick in. */
501 VG_(add_redirect_sym_to_addr)("soname:ld-linux.so.2", "_dl_sysinfo_int80",
502 VG_(client_trampoline_code)+VG_(tramp_syscall_offset));
503#elif defined(VGP_amd64_linux)
504 /* Redirect vsyscalls to local versions */
505 VG_(add_redirect_addr_to_addr)(0xFFFFFFFFFF600000ULL,
506 VG_(client_trampoline_code)+VG_(tramp_gettimeofday_offset));
507 VG_(add_redirect_addr_to_addr)(0xFFFFFFFFFF600400ULL,
508 VG_(client_trampoline_code)+VG_(tramp_time_offset));
509#else
510# error Unknown platform
511#endif
512}
sewardjcbdddcf2005-03-10 23:23:45 +0000513
514//:: /*------------------------------------------------------------*/
515//:: /*--- General function wrapping. ---*/
516//:: /*------------------------------------------------------------*/
517//::
518//:: /*
519//:: TODO:
520//:: - hook into the symtab machinery
521//:: - client-side wrappers?
522//:: - better interfaces for before() functions to get to arguments
523//:: - handle munmap of code (dlclose())
524//:: - handle thread exit
525//:: - handle longjmp
526//:: */
527//:: struct callkey {
528//:: ThreadId tid; /* calling thread */
529//:: Addr esp; /* address of args on stack */
530//:: Addr eip; /* return address */
531//:: };
532//::
533//:: struct call_instance {
534//:: struct callkey key;
535//::
536//:: const FuncWrapper *wrapper;
537//:: void *nonce;
538//:: };
539//::
540//:: static inline Addr addrcmp(Addr a, Addr b)
541//:: {
542//:: if (a < b)
543//:: return -1;
544//:: else if (a > b)
545//:: return 1;
546//:: else
547//:: return 0;
548//:: }
549//::
550//:: static inline Int cmp(UInt a, UInt b)
551//:: {
552//:: if (a < b)
553//:: return -1;
554//:: else if (a > b)
555//:: return 1;
556//:: else
557//:: return 0;
558//:: }
559//::
560//:: static Int keycmp(const void *pa, const void *pb)
561//:: {
562//:: const struct callkey *a = (const struct callkey *)pa;
563//:: const struct callkey *b = (const struct callkey *)pb;
564//:: Int ret;
565//::
566//:: if ((ret = cmp(a->tid, b->tid)))
567//:: return ret;
568//::
569//:: if ((ret = addrcmp(a->esp, b->esp)))
570//:: return ret;
571//::
572//:: return addrcmp(a->eip, b->eip);
573//:: }
574//::
575//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000576//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000577//:: NULL, VG_AR_SYMTAB);
578//::
579//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
580//:: {
581//:: struct callkey key = { tid, argsp, retaddr };
582//::
583//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
584//:: }
585//::
586//:: static void wrapper_return(Addr retaddr);
587//::
588//:: /* Called from generated code via helper */
589//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
590//:: {
njndb9b7732005-03-26 00:32:29 +0000591//:: Addr retaddr = VGA_RETADDR(tst->arch);
592//:: Addr argp = (Addr)&VGA_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000593//:: void *nonce = NULL;
594//:: Bool mf = VG_(my_fault);
595//:: VG_(my_fault) = True;
596//::
597//:: if (wrapper->before) {
njndb9b7732005-03-26 00:32:29 +0000598//:: va_list args = VGA_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000599//:: nonce = (*wrapper->before)(args);
600//:: }
601//::
602//:: if (wrapper->after) {
603//:: /* If there's an after function, make sure it gets called */
604//:: struct call_instance *call;
605//::
606//:: call = find_call(retaddr, argp, tst->tid);
607//::
608//:: if (call != NULL) {
609//:: /* Found a stale outstanding call; clean it up and recycle
610//:: the structure */
611//:: if (call->wrapper->after)
612//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
613//:: } else {
614//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
615//::
616//:: call->key.tid = tst->tid;
617//:: call->key.esp = argp;
618//:: call->key.eip = retaddr;
619//::
620//:: VG_(SkipList_Insert)(&wrapped_frames, call);
621//::
622//:: wrapper_return(retaddr);
623//:: }
624//::
625//:: call->wrapper = wrapper;
626//:: call->nonce = nonce;
627//:: } else
628//:: vg_assert(nonce == NULL);
629//::
630//:: VG_(my_fault) = mf;
631//:: }
632//::
633//:: /* Called from generated code via helper */
634//:: void VG_(wrap_after)(ThreadState *tst)
635//:: {
njn35172bc2005-03-26 00:04:03 +0000636//:: Addr EIP = VGA_INSTR_PTR(tst->arch); /* instruction after call */
637//:: Addr ESP = VGA_STACK_PTR(tst->arch); /* pointer to args */
638//:: Word ret = VGA_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000639//:: struct call_instance *call;
640//:: Bool mf = VG_(my_fault);
641//::
642//:: VG_(my_fault) = True;
643//:: call = find_call(EIP, ESP, tst->tid);
644//::
645//:: if (0)
646//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
647//::
648//:: if (call != NULL) {
649//:: if (call->wrapper->after)
650//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
651//::
652//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
653//:: VG_(SkipNode_Free)(&wrapped_frames, call);
654//:: }
655//:: VG_(my_fault) = mf;
656//:: }
657//::
658//::
659//:: struct wrapped_function {
660//:: Addr eip; /* eip of function entrypoint */
661//:: const FuncWrapper *wrapper;
662//:: };
663//::
664//:: struct wrapper_return {
665//:: Addr eip; /* return address */
666//:: };
667//::
668//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000669//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000670//:: NULL, VG_AR_SYMTAB);
671//::
672//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000673//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000674//:: NULL, VG_AR_SYMTAB);
675//::
676//:: /* Wrap function starting at eip */
677//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
678//:: {
679//:: struct wrapped_function *func;
680//::
681//:: if (0)
682//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
683//::
684//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
685//::
686//:: if (func == NULL) {
687//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
688//:: VG_(invalidate_translations)(eip, 1, True);
689//::
690//:: func->eip = eip;
691//:: VG_(SkipList_Insert)(&wrapped_functions, func);
692//:: }
693//::
694//:: func->wrapper = wrapper;
695//:: }
696//::
697//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
698//:: {
699//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
700//::
701//:: if (func)
702//:: return func->wrapper;
703//:: return NULL;
704//:: }
705//::
706//:: Bool VG_(is_wrapper_return)(Addr eip)
707//:: {
708//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
709//::
710//:: return ret != NULL;
711//:: }
712//::
713//:: /* Mark eip as being the return address of a wrapper, so that the
714//:: codegen will generate the appropriate call. */
715//:: void wrapper_return(Addr eip)
716//:: {
717//:: struct wrapper_return *ret;
718//::
719//:: if (VG_(is_wrapper_return)(eip))
720//:: return;
721//::
722//:: VG_(invalidate_translations)(eip, 1, True);
723//::
724//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
725//:: ret->eip = eip;
726//::
727//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
728//:: }