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