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