blob: 5d8056dd172b638900bc63db48663875b149fe6e [file] [log] [blame]
njnc0ae7052005-08-25 22:55:19 +00001
sewardjcbdddcf2005-03-10 23:23:45 +00002/*--------------------------------------------------------------------*/
njnc0ae7052005-08-25 22:55:19 +00003/*--- Function replacement and wrapping. m_redir.c ---*/
sewardjcbdddcf2005-03-10 23:23:45 +00004/*--------------------------------------------------------------------*/
5
6/*
njnc0ae7052005-08-25 22:55:19 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
sewardjcbdddcf2005-03-10 23:23:45 +00009
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*/
sewardjcbdddcf2005-03-10 23:23:45 +000032
njnc7561b92005-06-19 01:24:32 +000033#include "pub_core_basics.h"
sewardj45f4e7c2005-09-27 19:20:21 +000034#include "pub_core_debuglog.h"
njn88c51482005-06-25 20:49:33 +000035#include "pub_core_debuginfo.h"
njn97405b22005-06-02 03:39:33 +000036#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000037#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_core_libcprint.h"
njnaf1d7df2005-06-11 01:31:52 +000039#include "pub_core_mallocfree.h"
njn20242342005-05-16 23:31:24 +000040#include "pub_core_options.h"
njn8a96ec52005-10-15 15:48:52 +000041#include "pub_core_oset.h"
njnd1af0032005-05-29 17:01:48 +000042#include "pub_core_redir.h"
njna7598f62005-06-18 03:27:58 +000043#include "pub_core_trampoline.h"
njn8bddf582005-05-13 23:40:55 +000044#include "pub_core_transtab.h"
sewardj461c69d2005-11-17 20:15:04 +000045#include "pub_core_tooliface.h" // VG_(needs).malloc_replacement
46
sewardj55f9d1a2005-04-25 11:11:44 +000047
sewardjcbdddcf2005-03-10 23:23:45 +000048/*------------------------------------------------------------*/
49/*--- General purpose redirection. ---*/
50/*------------------------------------------------------------*/
51
njnd9109c62005-06-26 04:49:25 +000052#define TRACE_REDIR(format, args...) \
53 if (VG_(clo_trace_redir)) { VG_(message)(Vg_DebugMsg, format, ## args); }
54
sewardjcbdddcf2005-03-10 23:23:45 +000055/*
56 wraps and redirections, indexed by from_addr
57
58 Redirection and wrapping are two distinct mechanisms which Valgrind
59 can use to change the client's control flow.
60
61 Redirection intercepts a call to a client function, and re-points it
62 to a new piece of code (presumably functionally equivalent). The
63 original code is never run.
64
65 Wrapping does call the client's original code, but calls "before"
66 and "after" functions which can inspect (and perhaps modify) the
67 function's arguments and return value.
68 */
69struct _CodeRedirect {
njn8a96ec52005-10-15 15:48:52 +000070 Addr from_addr; /* old addr -- MUST BE THE FIRST WORD! */
71
sewardjcbdddcf2005-03-10 23:23:45 +000072 enum redir_type {
73 R_REDIRECT, /* plain redirection */
74 R_WRAPPER, /* wrap with valgrind-internal code */
75 R_CLIENT_WRAPPER, /* wrap with client-side code */
76 } type;
77
78 const Char *from_lib; /* library qualifier pattern */
79 const Char *from_sym; /* symbol */
sewardjcbdddcf2005-03-10 23:23:45 +000080
njnd9109c62005-06-26 04:49:25 +000081 Addr to_addr; /* used for redirection -- new addr */
82 const FuncWrapper *wrapper; /* used for wrapping */
sewardjcbdddcf2005-03-10 23:23:45 +000083
njnd9109c62005-06-26 04:49:25 +000084 CodeRedirect *next; /* next pointer on unresolved list */
sewardjcbdddcf2005-03-10 23:23:45 +000085};
86
njn8a96ec52005-10-15 15:48:52 +000087static OSet* resolved_redirs;
sewardjcbdddcf2005-03-10 23:23:45 +000088
njn8a96ec52005-10-15 15:48:52 +000089// We use a linked list here rather than an OSet, because we want to
90// traverse it and possibly remove elements as we look at them. OSet
91// doesn't support this very well.
njnd9109c62005-06-26 04:49:25 +000092static CodeRedirect *unresolved_redirs = NULL;
sewardjcbdddcf2005-03-10 23:23:45 +000093
njn4f612c22005-06-25 20:22:43 +000094static Bool soname_matches(const Char *pattern, const Char* soname)
sewardjcbdddcf2005-03-10 23:23:45 +000095{
njn41f8e4a2005-06-25 20:13:05 +000096 // pattern must start with "soname:"
97 vg_assert(NULL != pattern);
98 vg_assert(0 == VG_(strncmp)(pattern, "soname:", 7));
sewardjcbdddcf2005-03-10 23:23:45 +000099
njn4f612c22005-06-25 20:22:43 +0000100 if (NULL == soname)
sewardjcbdddcf2005-03-10 23:23:45 +0000101 return False;
102
njn4f612c22005-06-25 20:22:43 +0000103 return VG_(string_match)(pattern + 7, soname);
sewardjcbdddcf2005-03-10 23:23:45 +0000104}
105
njnd9109c62005-06-26 04:49:25 +0000106Bool VG_(is_resolved)(const CodeRedirect *redir)
sewardjcbdddcf2005-03-10 23:23:45 +0000107{
108 return redir->from_addr != 0;
109}
110
njnd9109c62005-06-26 04:49:25 +0000111// Prepends redir to the unresolved list.
112static void add_redir_to_unresolved_list(CodeRedirect *redir)
sewardjcbdddcf2005-03-10 23:23:45 +0000113{
njnd9109c62005-06-26 04:49:25 +0000114 redir->next = unresolved_redirs;
115 unresolved_redirs = redir;
sewardjcbdddcf2005-03-10 23:23:45 +0000116}
117
sewardjf9a82d12005-07-23 09:52:21 +0000118static void add_redir_to_resolved_list(CodeRedirect *redir, Bool need_discard)
tom748a1312005-04-02 15:53:01 +0000119{
njnd9109c62005-06-26 04:49:25 +0000120 vg_assert(redir->from_addr);
121
122 switch (redir->type) {
123 case R_REDIRECT: {
njnd9109c62005-06-26 04:49:25 +0000124 TRACE_REDIR(" redir resolved (%s:%s=%p -> %p)",
125 redir->from_lib, redir->from_sym, redir->from_addr,
126 redir->to_addr);
127
128 vg_assert(redir->to_addr != 0);
tom748a1312005-04-02 15:53:01 +0000129
sewardjf9a82d12005-07-23 09:52:21 +0000130 if (need_discard) {
tom748a1312005-04-02 15:53:01 +0000131 /* For some given (from, to) redir, the "from" function got
sewardjf9a82d12005-07-23 09:52:21 +0000132 loaded before the .so containing "to" became available so
133 we need to discard any existing translations involving
134 the "from" function.
tom748a1312005-04-02 15:53:01 +0000135
136 Note, we only really need to discard the first bb of the
137 old entry point, and so we avoid the problem of having to
138 figure out how big that bb was -- since it is at least 1
139 byte of original code, we can just pass 1 as the original
140 size to invalidate_translations() and it will indeed get
141 rid of the translation.
142
143 Note, this is potentially expensive -- discarding
sewardjeccb2d82005-07-23 11:36:03 +0000144 translations requires a complete search through all of
145 them.
tom748a1312005-04-02 15:53:01 +0000146 */
sewardjf9a82d12005-07-23 09:52:21 +0000147 TRACE_REDIR("Discarding translation due to redirect of already loaded function" );
njnd9109c62005-06-26 04:49:25 +0000148 TRACE_REDIR(" %s:%s(%p) -> %p)", redir->from_lib, redir->from_sym,
149 redir->from_addr, redir->to_addr );
sewardj45f4e7c2005-09-27 19:20:21 +0000150 VG_(discard_translations)((Addr64)redir->from_addr, 1,
151 "add_redir_to_resolved_list");
tom748a1312005-04-02 15:53:01 +0000152 }
153
njn8a96ec52005-10-15 15:48:52 +0000154 // This entails a possible double OSet lookup -- one for Contains(),
155 // one for Insert(). If we had OSet_InsertIfNonDup() we could do it
156 // with one lookup.
157 if ( ! VG_(OSet_Contains)(resolved_redirs, &redir->from_addr) ) {
158 VG_(OSet_Insert)(resolved_redirs, redir);
njnd9109c62005-06-26 04:49:25 +0000159 } else {
njnd9109c62005-06-26 04:49:25 +0000160 TRACE_REDIR(" redir %s:%s:%p->%p duplicated\n",
161 redir->from_lib, redir->from_sym, redir->from_addr,
162 redir->to_addr);
njn8a96ec52005-10-15 15:48:52 +0000163 VG_(arena_free)(VG_AR_SYMTAB, redir);
tom748a1312005-04-02 15:53:01 +0000164 }
165 break;
njnd9109c62005-06-26 04:49:25 +0000166 }
tom748a1312005-04-02 15:53:01 +0000167
168 case R_WRAPPER:
njnd9109c62005-06-26 04:49:25 +0000169 TRACE_REDIR(" wrapper resolved (%s:%s=%p -> wrapper)",
170 redir->from_lib, redir->from_sym, redir->from_addr);
171
172 vg_assert(redir->wrapper);
tom748a1312005-04-02 15:53:01 +0000173
174 /* XXX redir leaked */
175 //VG_(wrap_function)(redir->from_addr, redir->wrapper);
176 break;
177
178 case R_CLIENT_WRAPPER:
njnd9109c62005-06-26 04:49:25 +0000179 vg_assert(redir->wrapper);
tom748a1312005-04-02 15:53:01 +0000180 VG_(core_panic)("not implemented");
181 break;
182 }
183}
184
njnd9109c62005-06-26 04:49:25 +0000185// Resolve a redir using si if possible. Returns True if it succeeded.
186static Bool resolve_redir_with_seginfo(CodeRedirect *redir, const SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000187{
njnd9109c62005-06-26 04:49:25 +0000188 Bool ok;
sewardjcbdddcf2005-03-10 23:23:45 +0000189
190 vg_assert(si != NULL);
njnd9109c62005-06-26 04:49:25 +0000191 vg_assert(redir->from_addr == 0 );
192 vg_assert(redir->from_sym != NULL);
sewardjcbdddcf2005-03-10 23:23:45 +0000193
njnd9109c62005-06-26 04:49:25 +0000194 // Resolved if the soname matches and we find the symbol.
195 ok = soname_matches(redir->from_lib, VG_(seginfo_soname)(si));
196 if (ok) {
njn748ace42005-06-21 03:36:01 +0000197 redir->from_addr = VG_(reverse_search_one_symtab)(si, redir->from_sym);
njnd9109c62005-06-26 04:49:25 +0000198 ok = ( redir->from_addr == 0 ? False : True );
sewardjcbdddcf2005-03-10 23:23:45 +0000199 }
njnd9109c62005-06-26 04:49:25 +0000200 return ok;
sewardjcbdddcf2005-03-10 23:23:45 +0000201}
202
njn2025cf92005-06-26 20:44:48 +0000203// Resolve a redir using any SegInfo if possible. This is called whenever
204// a new sym-to-addr redir is created. It covers the case where a
205// replacement function is loaded after its replacee.
njnd9109c62005-06-26 04:49:25 +0000206static Bool resolve_redir_with_existing_seginfos(CodeRedirect *redir)
njnbf7ca332005-05-14 17:11:06 +0000207{
208 const SegInfo *si;
209
njnd9109c62005-06-26 04:49:25 +0000210 for (si = VG_(next_seginfo)(NULL);
211 si != NULL;
212 si = VG_(next_seginfo)(si))
njnbf7ca332005-05-14 17:11:06 +0000213 {
njnd9109c62005-06-26 04:49:25 +0000214 if (resolve_redir_with_seginfo(redir, si))
njnbf7ca332005-05-14 17:11:06 +0000215 return True;
216 }
217 return False;
218}
219
njnd9109c62005-06-26 04:49:25 +0000220// Resolve as many unresolved redirs as possible with this SegInfo. This
njn2025cf92005-06-26 20:44:48 +0000221// should be called when a new SegInfo symtab is loaded. It covers the case
222// where a replacee function is loaded after its replacement function.
njnd9109c62005-06-26 04:49:25 +0000223void VG_(resolve_existing_redirs_with_seginfo)(SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000224{
njnd9109c62005-06-26 04:49:25 +0000225 CodeRedirect **prevp = &unresolved_redirs;
sewardjcbdddcf2005-03-10 23:23:45 +0000226 CodeRedirect *redir, *next;
227
njnd9109c62005-06-26 04:49:25 +0000228 TRACE_REDIR("Just loaded %s (soname=%s),",
229 VG_(seginfo_filename)(si), VG_(seginfo_soname)(si));
230 TRACE_REDIR(" resolving any unresolved redirs with it");
sewardjcbdddcf2005-03-10 23:23:45 +0000231
njnd9109c62005-06-26 04:49:25 +0000232 // Visit each unresolved redir - if it becomes resolved, then
233 // move it from the unresolved list to the resolved list.
234 for (redir = unresolved_redirs; redir != NULL; redir = next) {
sewardjcbdddcf2005-03-10 23:23:45 +0000235 next = redir->next;
236
njnd9109c62005-06-26 04:49:25 +0000237 if (resolve_redir_with_seginfo(redir, si)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000238 *prevp = next;
239 redir->next = NULL;
sewardjf9a82d12005-07-23 09:52:21 +0000240 add_redir_to_resolved_list(redir, False);
sewardjcbdddcf2005-03-10 23:23:45 +0000241 } else
242 prevp = &redir->next;
243 }
sewardjcbdddcf2005-03-10 23:23:45 +0000244
njnd9109c62005-06-26 04:49:25 +0000245 TRACE_REDIR(" Finished resolving");
sewardjcbdddcf2005-03-10 23:23:45 +0000246}
247
tom748a1312005-04-02 15:53:01 +0000248/* Redirect a function at from_addr to a function at to_addr */
njn16eeb4e2005-06-16 03:56:58 +0000249__attribute__((unused)) // It is used, but not on all platforms...
njnd9109c62005-06-26 04:49:25 +0000250static void add_redirect_addr_to_addr( Addr from_addr, Addr to_addr )
tom748a1312005-04-02 15:53:01 +0000251{
njn8a96ec52005-10-15 15:48:52 +0000252 CodeRedirect* redir = VG_(OSet_AllocNode)(resolved_redirs,
253 sizeof(CodeRedirect));
njnd9109c62005-06-26 04:49:25 +0000254 vg_assert(0 != from_addr && 0 != to_addr);
255
256 redir->type = R_REDIRECT;
257
258 redir->from_lib = NULL;
259 redir->from_sym = NULL;
260 redir->from_addr = from_addr;
261
262 redir->to_addr = to_addr;
263 redir->wrapper = 0;
264
265 TRACE_REDIR("REDIRECT addr to addr: %p to %p", from_addr, to_addr);
266
267 // This redirection is already resolved, put it straight in the list.
sewardjf9a82d12005-07-23 09:52:21 +0000268 add_redir_to_resolved_list(redir, True);
njnd9109c62005-06-26 04:49:25 +0000269}
270
271/* Redirect a lib/symbol reference to a function at addr */
272static void add_redirect_sym_to_addr(
273 const Char *from_lib, const Char *from_sym, Addr to_addr
274)
275{
njn8a96ec52005-10-15 15:48:52 +0000276 CodeRedirect* redir = VG_(OSet_AllocNode)(resolved_redirs,
277 sizeof(CodeRedirect));
njnd9109c62005-06-26 04:49:25 +0000278 vg_assert(from_lib && from_sym && 0 != to_addr);
279
280 redir->type = R_REDIRECT;
281 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
282 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
283 redir->from_addr = 0;
284 redir->to_addr = to_addr;
285 redir->wrapper = 0;
286
287 TRACE_REDIR("REDIR sym to addr: %s:%s to %p", from_lib, from_sym, to_addr);
288
289 // Check against all existing segments to see if this redirection
njn2025cf92005-06-26 20:44:48 +0000290 // can be resolved immediately (as will be the case when the replacement
291 // function is loaded after the replacee). Then add it to the
292 // appropriate list.
njnd9109c62005-06-26 04:49:25 +0000293 if (resolve_redir_with_existing_seginfos(redir)) {
sewardjf9a82d12005-07-23 09:52:21 +0000294 add_redir_to_resolved_list(redir, True);
njnd9109c62005-06-26 04:49:25 +0000295 } else {
296 add_redir_to_unresolved_list(redir);
297 }
tom748a1312005-04-02 15:53:01 +0000298}
299
sewardjcbdddcf2005-03-10 23:23:45 +0000300CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
301 const FuncWrapper *wrapper)
302{
njn8a96ec52005-10-15 15:48:52 +0000303 CodeRedirect* redir = VG_(OSet_AllocNode)(resolved_redirs,
304 sizeof(CodeRedirect));
njnd9109c62005-06-26 04:49:25 +0000305 redir->type = R_WRAPPER;
njn136b83b2005-06-19 05:14:03 +0000306 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
307 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
sewardjcbdddcf2005-03-10 23:23:45 +0000308 redir->from_addr = 0;
njn136b83b2005-06-19 05:14:03 +0000309 redir->to_addr = 0;
310 redir->wrapper = wrapper;
sewardjcbdddcf2005-03-10 23:23:45 +0000311
njnd9109c62005-06-26 04:49:25 +0000312 TRACE_REDIR("REDIR sym to wrapper: %s:%s to (%p,%p)",
313 from_lib, from_sym, wrapper->before, wrapper->after);
314
315 // Check against all existing segments to see if this redirection
316 // can be resolved immediately. Then add it to the appropriate list.
317 if (resolve_redir_with_existing_seginfos(redir)) {
sewardjf9a82d12005-07-23 09:52:21 +0000318 add_redir_to_resolved_list(redir, True);
njnd9109c62005-06-26 04:49:25 +0000319 } else {
320 add_redir_to_unresolved_list(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000321 }
322
323 return redir;
324}
325
sewardjcbdddcf2005-03-10 23:23:45 +0000326/* If address 'a' is being redirected, return the redirected-to
327 address. */
328Addr VG_(code_redirect)(Addr a)
329{
njn8a96ec52005-10-15 15:48:52 +0000330 CodeRedirect* r = VG_(OSet_Lookup)(resolved_redirs, &a);
sewardjcbdddcf2005-03-10 23:23:45 +0000331 if (r == NULL)
332 return a;
333
334 vg_assert(r->to_addr != 0);
335
336 return r->to_addr;
337}
338
njn8a96ec52005-10-15 15:48:52 +0000339static void* symtab_alloc(SizeT n)
340{
341 return VG_(arena_malloc)(VG_AR_SYMTAB, n);
342}
343
344static void symtab_free(void* p)
345{
346 return VG_(arena_free)(VG_AR_SYMTAB, p);
347}
348
sewardjcbdddcf2005-03-10 23:23:45 +0000349void VG_(setup_code_redirect_table) ( void )
350{
njn8a96ec52005-10-15 15:48:52 +0000351 // Initialise resolved_redirs list.
352 resolved_redirs = VG_(OSet_Create)(offsetof(CodeRedirect, from_addr),
353 NULL, // Use fast comparison
354 symtab_alloc,
355 symtab_free);
356
njnd1af0032005-05-29 17:01:48 +0000357#if defined(VGP_x86_linux)
358 /* Redirect _dl_sysinfo_int80, which is glibc's default system call
sewardjb9bce632005-06-21 01:41:34 +0000359 routine, to our copy so that the special sysinfo unwind hack in
360 m_stacktrace.c will kick in. */
361 add_redirect_sym_to_addr(
362 "soname:ld-linux.so.2", "_dl_sysinfo_int80",
363 (Addr)&VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80)
364 );
365
njnd1af0032005-05-29 17:01:48 +0000366#elif defined(VGP_amd64_linux)
sewardjb9bce632005-06-21 01:41:34 +0000367
njnd1af0032005-05-29 17:01:48 +0000368 /* Redirect vsyscalls to local versions */
sewardjb9bce632005-06-21 01:41:34 +0000369 add_redirect_addr_to_addr(
370 0xFFFFFFFFFF600000ULL,
371 (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)
372 );
sewardjb9bce632005-06-21 01:41:34 +0000373 add_redirect_addr_to_addr(
tomf5db3b62005-06-21 13:26:17 +0000374 0xFFFFFFFFFF600400ULL,
sewardjb9bce632005-06-21 01:41:34 +0000375 (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)
376 );
377
cerion85665ca2005-06-20 15:51:07 +0000378#elif defined(VGP_ppc32_linux)
sewardjb9bce632005-06-21 01:41:34 +0000379
sewardj96fcfc82005-11-18 21:12:52 +0000380 /* If we're using memcheck, use these intercepts right from
381 the start, otherwise ld.so makes a lot of noise. */
382 if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
383
384 add_redirect_sym_to_addr(
385 "soname:ld.so.1", "strlen",
386 (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen)
387 );
388 add_redirect_sym_to_addr(
389 "soname:ld.so.1", "strcmp",
390 (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp)
391 );
392
393 }
sewardjb9bce632005-06-21 01:41:34 +0000394
njnd1af0032005-05-29 17:01:48 +0000395#else
396# error Unknown platform
397#endif
398}
sewardjcbdddcf2005-03-10 23:23:45 +0000399
njn16eeb4e2005-06-16 03:56:58 +0000400/* Z-decode a symbol into library:func form, eg
401
402 _vgi_libcZdsoZd6__ZdlPv --> libc.so.6:_ZdlPv
403
404 Uses the Z-encoding scheme described in pub_core_redir.h.
405 Returns True if demangle OK, False otherwise.
406*/
407static Bool Z_decode(const Char* symbol, Char* result, Int nbytes)
408{
409# define EMIT(ch) \
410 do { \
411 if (j >= nbytes) \
412 result[j-1] = 0; \
413 else \
414 result[j++] = ch; \
415 } while (0)
416
417 Bool error = False;
418 Int i, j = 0;
419 Int len = VG_(strlen)(symbol);
420 if (0) VG_(printf)("idm: %s\n", symbol);
421
422 i = VG_REPLACE_FUNCTION_PREFIX_LEN;
423
424 /* Chew though the Z-encoded soname part. */
425 while (True) {
426
427 if (i >= len)
428 break;
429
430 if (symbol[i] == '_')
431 /* We found the underscore following the Z-encoded soname.
432 Just copy the rest literally. */
433 break;
434
435 if (symbol[i] != 'Z') {
436 EMIT(symbol[i]);
437 i++;
438 continue;
439 }
440
441 /* We've got a Z-escape. Act accordingly. */
442 i++;
443 if (i >= len) {
444 /* Hmm, Z right at the end. Something's wrong. */
445 error = True;
446 EMIT('Z');
447 break;
448 }
449 switch (symbol[i]) {
450 case 'a': EMIT('*'); break;
451 case 'p': EMIT('+'); break;
452 case 'c': EMIT(':'); break;
453 case 'd': EMIT('.'); break;
454 case 'u': EMIT('_'); break;
455 case 'h': EMIT('-'); break;
456 case 's': EMIT(' '); break;
457 case 'Z': EMIT('Z'); break;
458 default: error = True; EMIT('Z'); EMIT(symbol[i]); break;
459 }
460 i++;
461 }
462
463 if (error || i >= len || symbol[i] != '_') {
464 /* Something's wrong. Give up. */
465 VG_(message)(Vg_UserMsg, "intercept: error demangling: %s", symbol);
466 EMIT(0);
467 return False;
468 }
469
470 /* Copy the rest of the string verbatim. */
471 i++;
472 EMIT(':');
473 while (True) {
474 if (i >= len)
475 break;
476 EMIT(symbol[i]);
477 i++;
478 }
479
480 EMIT(0);
481 if (0) VG_(printf)("%s\n", result);
482 return True;
483
484# undef EMIT
485}
486
487// Nb: this can change the string pointed to by 'symbol'.
488static void handle_replacement_function( Char* symbol, Addr addr )
489{
490 Bool ok;
491 Int len = VG_(strlen)(symbol) + 1 - VG_REPLACE_FUNCTION_PREFIX_LEN;
492 Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len+8);
493 Char *func;
494
495 // Put "soname:" at the start of lib
496 VG_(strcpy)(lib, "soname:");
497
498 ok = Z_decode(symbol, lib+7, len);
499 if (ok) {
500 // lib is "soname:<libname>:<fnname>". Split the string at the 2nd ':'.
501 func = lib + VG_(strlen)(lib)-1;
502 while(*func != ':') func--;
503 *func = '\0';
504 func++; // Move past the '\0'
505
506 // Now lib is "soname:<libname>" and func is "<fnname>".
507 if (0) VG_(printf)("lib A%sZ, func A%sZ\n", lib, func);
508 add_redirect_sym_to_addr(lib, func, addr);
509
510 // Overwrite the given Z-encoded name with just the fnname.
511 VG_(strcpy)(symbol, func);
512 }
513
514 VG_(arena_free)(VG_AR_SYMTAB, lib);
515}
516
njnbc6d84d2005-06-19 18:58:03 +0000517static Addr __libc_freeres_wrapper = 0;
518
519Addr VG_(get_libc_freeres_wrapper)(void)
520{
521 return __libc_freeres_wrapper;
522}
523
njn16eeb4e2005-06-16 03:56:58 +0000524// This is specifically for stringifying VG_(x) function names. We
525// need to do two macroexpansions to get the VG_ macro expanded before
526// stringifying.
527#define _STR(x) #x
528#define STR(x) _STR(x)
529
530static void handle_load_notifier( Char* symbol, Addr addr )
531{
532 if (VG_(strcmp)(symbol, STR(VG_NOTIFY_ON_LOAD(freeres))) == 0)
njnbc6d84d2005-06-19 18:58:03 +0000533 __libc_freeres_wrapper = addr;
njn16eeb4e2005-06-16 03:56:58 +0000534// else if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) == 0)
535// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value));
536 else
537 vg_assert2(0, "unrecognised load notification function: %s", symbol);
538}
539
540static Bool is_replacement_function(Char* s)
541{
542 return (0 == VG_(strncmp)(s,
543 VG_REPLACE_FUNCTION_PREFIX,
544 VG_REPLACE_FUNCTION_PREFIX_LEN));
545}
546
547static Bool is_load_notifier(Char* s)
548{
549 return (0 == VG_(strncmp)(s,
550 VG_NOTIFY_ON_LOAD_PREFIX,
551 VG_NOTIFY_ON_LOAD_PREFIX_LEN));
552}
553
554// Call this for each symbol loaded. It determines if we need to do
555// anything special with it. It can modify 'symbol' in-place.
556void VG_(maybe_redir_or_notify) ( Char* symbol, Addr addr )
557{
558 if (is_replacement_function(symbol))
559 handle_replacement_function(symbol, addr);
560 else
561 if (is_load_notifier(symbol))
562 handle_load_notifier(symbol, addr);
563}
564
565
sewardjcbdddcf2005-03-10 23:23:45 +0000566//:: /*------------------------------------------------------------*/
567//:: /*--- General function wrapping. ---*/
568//:: /*------------------------------------------------------------*/
569//::
570//:: /*
571//:: TODO:
572//:: - hook into the symtab machinery
573//:: - client-side wrappers?
574//:: - better interfaces for before() functions to get to arguments
575//:: - handle munmap of code (dlclose())
576//:: - handle thread exit
577//:: - handle longjmp
578//:: */
579//:: struct callkey {
580//:: ThreadId tid; /* calling thread */
581//:: Addr esp; /* address of args on stack */
582//:: Addr eip; /* return address */
583//:: };
584//::
585//:: struct call_instance {
586//:: struct callkey key;
587//::
588//:: const FuncWrapper *wrapper;
589//:: void *nonce;
590//:: };
591//::
592//:: static inline Addr addrcmp(Addr a, Addr b)
593//:: {
594//:: if (a < b)
595//:: return -1;
596//:: else if (a > b)
597//:: return 1;
598//:: else
599//:: return 0;
600//:: }
601//::
602//:: static inline Int cmp(UInt a, UInt b)
603//:: {
604//:: if (a < b)
605//:: return -1;
606//:: else if (a > b)
607//:: return 1;
608//:: else
609//:: return 0;
610//:: }
611//::
612//:: static Int keycmp(const void *pa, const void *pb)
613//:: {
614//:: const struct callkey *a = (const struct callkey *)pa;
615//:: const struct callkey *b = (const struct callkey *)pb;
616//:: Int ret;
617//::
618//:: if ((ret = cmp(a->tid, b->tid)))
619//:: return ret;
620//::
621//:: if ((ret = addrcmp(a->esp, b->esp)))
622//:: return ret;
623//::
624//:: return addrcmp(a->eip, b->eip);
625//:: }
626//::
627//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000628//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000629//:: NULL, VG_AR_SYMTAB);
630//::
631//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
632//:: {
633//:: struct callkey key = { tid, argsp, retaddr };
634//::
635//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
636//:: }
637//::
638//:: static void wrapper_return(Addr retaddr);
639//::
640//:: /* Called from generated code via helper */
641//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
642//:: {
njnaf839f52005-06-23 03:27:57 +0000643//:: Addr retaddr = VG_RETADDR(tst->arch);
644//:: Addr argp = (Addr)&VG_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000645//:: void *nonce = NULL;
646//:: Bool mf = VG_(my_fault);
647//:: VG_(my_fault) = True;
648//::
649//:: if (wrapper->before) {
njnaf839f52005-06-23 03:27:57 +0000650//:: va_list args = VG_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000651//:: nonce = (*wrapper->before)(args);
652//:: }
653//::
654//:: if (wrapper->after) {
655//:: /* If there's an after function, make sure it gets called */
656//:: struct call_instance *call;
657//::
658//:: call = find_call(retaddr, argp, tst->tid);
659//::
660//:: if (call != NULL) {
661//:: /* Found a stale outstanding call; clean it up and recycle
662//:: the structure */
663//:: if (call->wrapper->after)
664//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
665//:: } else {
666//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
667//::
668//:: call->key.tid = tst->tid;
669//:: call->key.esp = argp;
670//:: call->key.eip = retaddr;
671//::
672//:: VG_(SkipList_Insert)(&wrapped_frames, call);
673//::
674//:: wrapper_return(retaddr);
675//:: }
676//::
677//:: call->wrapper = wrapper;
678//:: call->nonce = nonce;
679//:: } else
680//:: vg_assert(nonce == NULL);
681//::
682//:: VG_(my_fault) = mf;
683//:: }
684//::
685//:: /* Called from generated code via helper */
686//:: void VG_(wrap_after)(ThreadState *tst)
687//:: {
njnaf839f52005-06-23 03:27:57 +0000688//:: Addr EIP = VG_INSTR_PTR(tst->arch); /* instruction after call */
689//:: Addr ESP = VG_STACK_PTR(tst->arch); /* pointer to args */
690//:: Word ret = VG_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000691//:: struct call_instance *call;
692//:: Bool mf = VG_(my_fault);
693//::
694//:: VG_(my_fault) = True;
695//:: call = find_call(EIP, ESP, tst->tid);
696//::
697//:: if (0)
698//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
699//::
700//:: if (call != NULL) {
701//:: if (call->wrapper->after)
702//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
703//::
704//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
705//:: VG_(SkipNode_Free)(&wrapped_frames, call);
706//:: }
707//:: VG_(my_fault) = mf;
708//:: }
709//::
710//::
711//:: struct wrapped_function {
712//:: Addr eip; /* eip of function entrypoint */
713//:: const FuncWrapper *wrapper;
714//:: };
715//::
716//:: struct wrapper_return {
717//:: Addr eip; /* return address */
718//:: };
719//::
720//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000721//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000722//:: NULL, VG_AR_SYMTAB);
723//::
724//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000725//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000726//:: NULL, VG_AR_SYMTAB);
727//::
728//:: /* Wrap function starting at eip */
729//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
730//:: {
731//:: struct wrapped_function *func;
732//::
733//:: if (0)
734//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
735//::
736//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
737//::
738//:: if (func == NULL) {
739//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
740//:: VG_(invalidate_translations)(eip, 1, True);
741//::
742//:: func->eip = eip;
743//:: VG_(SkipList_Insert)(&wrapped_functions, func);
744//:: }
745//::
746//:: func->wrapper = wrapper;
747//:: }
748//::
749//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
750//:: {
751//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
752//::
753//:: if (func)
754//:: return func->wrapper;
755//:: return NULL;
756//:: }
757//::
758//:: Bool VG_(is_wrapper_return)(Addr eip)
759//:: {
760//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
761//::
762//:: return ret != NULL;
763//:: }
764//::
765//:: /* Mark eip as being the return address of a wrapper, so that the
766//:: codegen will generate the appropriate call. */
767//:: void wrapper_return(Addr eip)
768//:: {
769//:: struct wrapper_return *ret;
770//::
771//:: if (VG_(is_wrapper_return)(eip))
772//:: return;
773//::
774//:: VG_(invalidate_translations)(eip, 1, True);
775//::
776//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
777//:: ret->eip = eip;
778//::
779//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
780//:: }
njnc0ae7052005-08-25 22:55:19 +0000781
782/*--------------------------------------------------------------------*/
783/*--- end ---*/
784/*--------------------------------------------------------------------*/