blob: a20574f77e9b1dfba7271b92406e20d755145915 [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"
sewardj55f9d1a2005-04-25 11:11:44 +000045
sewardjcbdddcf2005-03-10 23:23:45 +000046/*------------------------------------------------------------*/
47/*--- General purpose redirection. ---*/
48/*------------------------------------------------------------*/
49
njnd9109c62005-06-26 04:49:25 +000050#define TRACE_REDIR(format, args...) \
51 if (VG_(clo_trace_redir)) { VG_(message)(Vg_DebugMsg, format, ## args); }
52
sewardjcbdddcf2005-03-10 23:23:45 +000053/*
54 wraps and redirections, indexed by from_addr
55
56 Redirection and wrapping are two distinct mechanisms which Valgrind
57 can use to change the client's control flow.
58
59 Redirection intercepts a call to a client function, and re-points it
60 to a new piece of code (presumably functionally equivalent). The
61 original code is never run.
62
63 Wrapping does call the client's original code, but calls "before"
64 and "after" functions which can inspect (and perhaps modify) the
65 function's arguments and return value.
66 */
67struct _CodeRedirect {
njn8a96ec52005-10-15 15:48:52 +000068 Addr from_addr; /* old addr -- MUST BE THE FIRST WORD! */
69
sewardjcbdddcf2005-03-10 23:23:45 +000070 enum redir_type {
71 R_REDIRECT, /* plain redirection */
72 R_WRAPPER, /* wrap with valgrind-internal code */
73 R_CLIENT_WRAPPER, /* wrap with client-side code */
74 } type;
75
76 const Char *from_lib; /* library qualifier pattern */
77 const Char *from_sym; /* symbol */
sewardjcbdddcf2005-03-10 23:23:45 +000078
njnd9109c62005-06-26 04:49:25 +000079 Addr to_addr; /* used for redirection -- new addr */
80 const FuncWrapper *wrapper; /* used for wrapping */
sewardjcbdddcf2005-03-10 23:23:45 +000081
njnd9109c62005-06-26 04:49:25 +000082 CodeRedirect *next; /* next pointer on unresolved list */
sewardjcbdddcf2005-03-10 23:23:45 +000083};
84
njn8a96ec52005-10-15 15:48:52 +000085static OSet* resolved_redirs;
sewardjcbdddcf2005-03-10 23:23:45 +000086
njn8a96ec52005-10-15 15:48:52 +000087// We use a linked list here rather than an OSet, because we want to
88// traverse it and possibly remove elements as we look at them. OSet
89// doesn't support this very well.
njnd9109c62005-06-26 04:49:25 +000090static CodeRedirect *unresolved_redirs = NULL;
sewardjcbdddcf2005-03-10 23:23:45 +000091
njn4f612c22005-06-25 20:22:43 +000092static Bool soname_matches(const Char *pattern, const Char* soname)
sewardjcbdddcf2005-03-10 23:23:45 +000093{
njn41f8e4a2005-06-25 20:13:05 +000094 // pattern must start with "soname:"
95 vg_assert(NULL != pattern);
96 vg_assert(0 == VG_(strncmp)(pattern, "soname:", 7));
sewardjcbdddcf2005-03-10 23:23:45 +000097
njn4f612c22005-06-25 20:22:43 +000098 if (NULL == soname)
sewardjcbdddcf2005-03-10 23:23:45 +000099 return False;
100
njn4f612c22005-06-25 20:22:43 +0000101 return VG_(string_match)(pattern + 7, soname);
sewardjcbdddcf2005-03-10 23:23:45 +0000102}
103
njnd9109c62005-06-26 04:49:25 +0000104Bool VG_(is_resolved)(const CodeRedirect *redir)
sewardjcbdddcf2005-03-10 23:23:45 +0000105{
106 return redir->from_addr != 0;
107}
108
njnd9109c62005-06-26 04:49:25 +0000109// Prepends redir to the unresolved list.
110static void add_redir_to_unresolved_list(CodeRedirect *redir)
sewardjcbdddcf2005-03-10 23:23:45 +0000111{
njnd9109c62005-06-26 04:49:25 +0000112 redir->next = unresolved_redirs;
113 unresolved_redirs = redir;
sewardjcbdddcf2005-03-10 23:23:45 +0000114}
115
sewardjf9a82d12005-07-23 09:52:21 +0000116static void add_redir_to_resolved_list(CodeRedirect *redir, Bool need_discard)
tom748a1312005-04-02 15:53:01 +0000117{
njnd9109c62005-06-26 04:49:25 +0000118 vg_assert(redir->from_addr);
119
120 switch (redir->type) {
121 case R_REDIRECT: {
njnd9109c62005-06-26 04:49:25 +0000122 TRACE_REDIR(" redir resolved (%s:%s=%p -> %p)",
123 redir->from_lib, redir->from_sym, redir->from_addr,
124 redir->to_addr);
125
126 vg_assert(redir->to_addr != 0);
tom748a1312005-04-02 15:53:01 +0000127
sewardjf9a82d12005-07-23 09:52:21 +0000128 if (need_discard) {
tom748a1312005-04-02 15:53:01 +0000129 /* For some given (from, to) redir, the "from" function got
sewardjf9a82d12005-07-23 09:52:21 +0000130 loaded before the .so containing "to" became available so
131 we need to discard any existing translations involving
132 the "from" function.
tom748a1312005-04-02 15:53:01 +0000133
134 Note, we only really need to discard the first bb of the
135 old entry point, and so we avoid the problem of having to
136 figure out how big that bb was -- since it is at least 1
137 byte of original code, we can just pass 1 as the original
138 size to invalidate_translations() and it will indeed get
139 rid of the translation.
140
141 Note, this is potentially expensive -- discarding
sewardjeccb2d82005-07-23 11:36:03 +0000142 translations requires a complete search through all of
143 them.
tom748a1312005-04-02 15:53:01 +0000144 */
sewardjf9a82d12005-07-23 09:52:21 +0000145 TRACE_REDIR("Discarding translation due to redirect of already loaded function" );
njnd9109c62005-06-26 04:49:25 +0000146 TRACE_REDIR(" %s:%s(%p) -> %p)", redir->from_lib, redir->from_sym,
147 redir->from_addr, redir->to_addr );
sewardj45f4e7c2005-09-27 19:20:21 +0000148 VG_(discard_translations)((Addr64)redir->from_addr, 1,
149 "add_redir_to_resolved_list");
tom748a1312005-04-02 15:53:01 +0000150 }
151
njn8a96ec52005-10-15 15:48:52 +0000152 // This entails a possible double OSet lookup -- one for Contains(),
153 // one for Insert(). If we had OSet_InsertIfNonDup() we could do it
154 // with one lookup.
155 if ( ! VG_(OSet_Contains)(resolved_redirs, &redir->from_addr) ) {
156 VG_(OSet_Insert)(resolved_redirs, redir);
njnd9109c62005-06-26 04:49:25 +0000157 } else {
njnd9109c62005-06-26 04:49:25 +0000158 TRACE_REDIR(" redir %s:%s:%p->%p duplicated\n",
159 redir->from_lib, redir->from_sym, redir->from_addr,
160 redir->to_addr);
njn8a96ec52005-10-15 15:48:52 +0000161 VG_(arena_free)(VG_AR_SYMTAB, redir);
tom748a1312005-04-02 15:53:01 +0000162 }
163 break;
njnd9109c62005-06-26 04:49:25 +0000164 }
tom748a1312005-04-02 15:53:01 +0000165
166 case R_WRAPPER:
njnd9109c62005-06-26 04:49:25 +0000167 TRACE_REDIR(" wrapper resolved (%s:%s=%p -> wrapper)",
168 redir->from_lib, redir->from_sym, redir->from_addr);
169
170 vg_assert(redir->wrapper);
tom748a1312005-04-02 15:53:01 +0000171
172 /* XXX redir leaked */
173 //VG_(wrap_function)(redir->from_addr, redir->wrapper);
174 break;
175
176 case R_CLIENT_WRAPPER:
njnd9109c62005-06-26 04:49:25 +0000177 vg_assert(redir->wrapper);
tom748a1312005-04-02 15:53:01 +0000178 VG_(core_panic)("not implemented");
179 break;
180 }
181}
182
njnd9109c62005-06-26 04:49:25 +0000183// Resolve a redir using si if possible. Returns True if it succeeded.
184static Bool resolve_redir_with_seginfo(CodeRedirect *redir, const SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000185{
njnd9109c62005-06-26 04:49:25 +0000186 Bool ok;
sewardjcbdddcf2005-03-10 23:23:45 +0000187
188 vg_assert(si != NULL);
njnd9109c62005-06-26 04:49:25 +0000189 vg_assert(redir->from_addr == 0 );
190 vg_assert(redir->from_sym != NULL);
sewardjcbdddcf2005-03-10 23:23:45 +0000191
njnd9109c62005-06-26 04:49:25 +0000192 // Resolved if the soname matches and we find the symbol.
193 ok = soname_matches(redir->from_lib, VG_(seginfo_soname)(si));
194 if (ok) {
njn748ace42005-06-21 03:36:01 +0000195 redir->from_addr = VG_(reverse_search_one_symtab)(si, redir->from_sym);
njnd9109c62005-06-26 04:49:25 +0000196 ok = ( redir->from_addr == 0 ? False : True );
sewardjcbdddcf2005-03-10 23:23:45 +0000197 }
njnd9109c62005-06-26 04:49:25 +0000198 return ok;
sewardjcbdddcf2005-03-10 23:23:45 +0000199}
200
njn2025cf92005-06-26 20:44:48 +0000201// Resolve a redir using any SegInfo if possible. This is called whenever
202// a new sym-to-addr redir is created. It covers the case where a
203// replacement function is loaded after its replacee.
njnd9109c62005-06-26 04:49:25 +0000204static Bool resolve_redir_with_existing_seginfos(CodeRedirect *redir)
njnbf7ca332005-05-14 17:11:06 +0000205{
206 const SegInfo *si;
207
njnd9109c62005-06-26 04:49:25 +0000208 for (si = VG_(next_seginfo)(NULL);
209 si != NULL;
210 si = VG_(next_seginfo)(si))
njnbf7ca332005-05-14 17:11:06 +0000211 {
njnd9109c62005-06-26 04:49:25 +0000212 if (resolve_redir_with_seginfo(redir, si))
njnbf7ca332005-05-14 17:11:06 +0000213 return True;
214 }
215 return False;
216}
217
njnd9109c62005-06-26 04:49:25 +0000218// Resolve as many unresolved redirs as possible with this SegInfo. This
njn2025cf92005-06-26 20:44:48 +0000219// should be called when a new SegInfo symtab is loaded. It covers the case
220// where a replacee function is loaded after its replacement function.
njnd9109c62005-06-26 04:49:25 +0000221void VG_(resolve_existing_redirs_with_seginfo)(SegInfo *si)
sewardjcbdddcf2005-03-10 23:23:45 +0000222{
njnd9109c62005-06-26 04:49:25 +0000223 CodeRedirect **prevp = &unresolved_redirs;
sewardjcbdddcf2005-03-10 23:23:45 +0000224 CodeRedirect *redir, *next;
225
njnd9109c62005-06-26 04:49:25 +0000226 TRACE_REDIR("Just loaded %s (soname=%s),",
227 VG_(seginfo_filename)(si), VG_(seginfo_soname)(si));
228 TRACE_REDIR(" resolving any unresolved redirs with it");
sewardjcbdddcf2005-03-10 23:23:45 +0000229
njnd9109c62005-06-26 04:49:25 +0000230 // Visit each unresolved redir - if it becomes resolved, then
231 // move it from the unresolved list to the resolved list.
232 for (redir = unresolved_redirs; redir != NULL; redir = next) {
sewardjcbdddcf2005-03-10 23:23:45 +0000233 next = redir->next;
234
njnd9109c62005-06-26 04:49:25 +0000235 if (resolve_redir_with_seginfo(redir, si)) {
sewardjcbdddcf2005-03-10 23:23:45 +0000236 *prevp = next;
237 redir->next = NULL;
sewardjf9a82d12005-07-23 09:52:21 +0000238 add_redir_to_resolved_list(redir, False);
sewardjcbdddcf2005-03-10 23:23:45 +0000239 } else
240 prevp = &redir->next;
241 }
sewardjcbdddcf2005-03-10 23:23:45 +0000242
njnd9109c62005-06-26 04:49:25 +0000243 TRACE_REDIR(" Finished resolving");
sewardjcbdddcf2005-03-10 23:23:45 +0000244}
245
tom748a1312005-04-02 15:53:01 +0000246/* Redirect a function at from_addr to a function at to_addr */
njn16eeb4e2005-06-16 03:56:58 +0000247__attribute__((unused)) // It is used, but not on all platforms...
njnd9109c62005-06-26 04:49:25 +0000248static void add_redirect_addr_to_addr( Addr from_addr, Addr to_addr )
tom748a1312005-04-02 15:53:01 +0000249{
njn8a96ec52005-10-15 15:48:52 +0000250 CodeRedirect* redir = VG_(OSet_AllocNode)(resolved_redirs,
251 sizeof(CodeRedirect));
njnd9109c62005-06-26 04:49:25 +0000252 vg_assert(0 != from_addr && 0 != to_addr);
253
254 redir->type = R_REDIRECT;
255
256 redir->from_lib = NULL;
257 redir->from_sym = NULL;
258 redir->from_addr = from_addr;
259
260 redir->to_addr = to_addr;
261 redir->wrapper = 0;
262
263 TRACE_REDIR("REDIRECT addr to addr: %p to %p", from_addr, to_addr);
264
265 // This redirection is already resolved, put it straight in the list.
sewardjf9a82d12005-07-23 09:52:21 +0000266 add_redir_to_resolved_list(redir, True);
njnd9109c62005-06-26 04:49:25 +0000267}
268
269/* Redirect a lib/symbol reference to a function at addr */
270static void add_redirect_sym_to_addr(
271 const Char *from_lib, const Char *from_sym, Addr to_addr
272)
273{
njn8a96ec52005-10-15 15:48:52 +0000274 CodeRedirect* redir = VG_(OSet_AllocNode)(resolved_redirs,
275 sizeof(CodeRedirect));
njnd9109c62005-06-26 04:49:25 +0000276 vg_assert(from_lib && from_sym && 0 != to_addr);
277
278 redir->type = R_REDIRECT;
279 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
280 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
281 redir->from_addr = 0;
282 redir->to_addr = to_addr;
283 redir->wrapper = 0;
284
285 TRACE_REDIR("REDIR sym to addr: %s:%s to %p", from_lib, from_sym, to_addr);
286
287 // Check against all existing segments to see if this redirection
njn2025cf92005-06-26 20:44:48 +0000288 // can be resolved immediately (as will be the case when the replacement
289 // function is loaded after the replacee). Then add it to the
290 // appropriate list.
njnd9109c62005-06-26 04:49:25 +0000291 if (resolve_redir_with_existing_seginfos(redir)) {
sewardjf9a82d12005-07-23 09:52:21 +0000292 add_redir_to_resolved_list(redir, True);
njnd9109c62005-06-26 04:49:25 +0000293 } else {
294 add_redir_to_unresolved_list(redir);
295 }
tom748a1312005-04-02 15:53:01 +0000296}
297
sewardjcbdddcf2005-03-10 23:23:45 +0000298CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
299 const FuncWrapper *wrapper)
300{
njn8a96ec52005-10-15 15:48:52 +0000301 CodeRedirect* redir = VG_(OSet_AllocNode)(resolved_redirs,
302 sizeof(CodeRedirect));
njnd9109c62005-06-26 04:49:25 +0000303 redir->type = R_WRAPPER;
njn136b83b2005-06-19 05:14:03 +0000304 redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
305 redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
sewardjcbdddcf2005-03-10 23:23:45 +0000306 redir->from_addr = 0;
njn136b83b2005-06-19 05:14:03 +0000307 redir->to_addr = 0;
308 redir->wrapper = wrapper;
sewardjcbdddcf2005-03-10 23:23:45 +0000309
njnd9109c62005-06-26 04:49:25 +0000310 TRACE_REDIR("REDIR sym to wrapper: %s:%s to (%p,%p)",
311 from_lib, from_sym, wrapper->before, wrapper->after);
312
313 // Check against all existing segments to see if this redirection
314 // can be resolved immediately. Then add it to the appropriate list.
315 if (resolve_redir_with_existing_seginfos(redir)) {
sewardjf9a82d12005-07-23 09:52:21 +0000316 add_redir_to_resolved_list(redir, True);
njnd9109c62005-06-26 04:49:25 +0000317 } else {
318 add_redir_to_unresolved_list(redir);
sewardjcbdddcf2005-03-10 23:23:45 +0000319 }
320
321 return redir;
322}
323
sewardjcbdddcf2005-03-10 23:23:45 +0000324/* If address 'a' is being redirected, return the redirected-to
325 address. */
326Addr VG_(code_redirect)(Addr a)
327{
njn8a96ec52005-10-15 15:48:52 +0000328 CodeRedirect* r = VG_(OSet_Lookup)(resolved_redirs, &a);
sewardjcbdddcf2005-03-10 23:23:45 +0000329 if (r == NULL)
330 return a;
331
332 vg_assert(r->to_addr != 0);
333
334 return r->to_addr;
335}
336
njn8a96ec52005-10-15 15:48:52 +0000337static void* symtab_alloc(SizeT n)
338{
339 return VG_(arena_malloc)(VG_AR_SYMTAB, n);
340}
341
342static void symtab_free(void* p)
343{
344 return VG_(arena_free)(VG_AR_SYMTAB, p);
345}
346
sewardjcbdddcf2005-03-10 23:23:45 +0000347void VG_(setup_code_redirect_table) ( void )
348{
njn8a96ec52005-10-15 15:48:52 +0000349 // Initialise resolved_redirs list.
350 resolved_redirs = VG_(OSet_Create)(offsetof(CodeRedirect, from_addr),
351 NULL, // Use fast comparison
352 symtab_alloc,
353 symtab_free);
354
njnd1af0032005-05-29 17:01:48 +0000355#if defined(VGP_x86_linux)
356 /* Redirect _dl_sysinfo_int80, which is glibc's default system call
sewardjb9bce632005-06-21 01:41:34 +0000357 routine, to our copy so that the special sysinfo unwind hack in
358 m_stacktrace.c will kick in. */
359 add_redirect_sym_to_addr(
360 "soname:ld-linux.so.2", "_dl_sysinfo_int80",
361 (Addr)&VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80)
362 );
363
njnd1af0032005-05-29 17:01:48 +0000364#elif defined(VGP_amd64_linux)
sewardjb9bce632005-06-21 01:41:34 +0000365
njnd1af0032005-05-29 17:01:48 +0000366 /* Redirect vsyscalls to local versions */
sewardjb9bce632005-06-21 01:41:34 +0000367 add_redirect_addr_to_addr(
368 0xFFFFFFFFFF600000ULL,
369 (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)
370 );
sewardjb9bce632005-06-21 01:41:34 +0000371 add_redirect_addr_to_addr(
tomf5db3b62005-06-21 13:26:17 +0000372 0xFFFFFFFFFF600400ULL,
sewardjb9bce632005-06-21 01:41:34 +0000373 (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)
374 );
375
cerion85665ca2005-06-20 15:51:07 +0000376#elif defined(VGP_ppc32_linux)
sewardjb9bce632005-06-21 01:41:34 +0000377
sewardjad50be32005-08-18 11:54:30 +0000378 add_redirect_sym_to_addr(
379 "soname:ld.so.1", "strlen",
380 (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen)
381 );
sewardj5e7b2302005-10-01 19:12:08 +0000382 add_redirect_sym_to_addr(
383 "soname:ld.so.1", "strcmp",
384 (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp)
385 );
sewardjb9bce632005-06-21 01:41:34 +0000386
njnd1af0032005-05-29 17:01:48 +0000387#else
388# error Unknown platform
389#endif
390}
sewardjcbdddcf2005-03-10 23:23:45 +0000391
njn16eeb4e2005-06-16 03:56:58 +0000392/* Z-decode a symbol into library:func form, eg
393
394 _vgi_libcZdsoZd6__ZdlPv --> libc.so.6:_ZdlPv
395
396 Uses the Z-encoding scheme described in pub_core_redir.h.
397 Returns True if demangle OK, False otherwise.
398*/
399static Bool Z_decode(const Char* symbol, Char* result, Int nbytes)
400{
401# define EMIT(ch) \
402 do { \
403 if (j >= nbytes) \
404 result[j-1] = 0; \
405 else \
406 result[j++] = ch; \
407 } while (0)
408
409 Bool error = False;
410 Int i, j = 0;
411 Int len = VG_(strlen)(symbol);
412 if (0) VG_(printf)("idm: %s\n", symbol);
413
414 i = VG_REPLACE_FUNCTION_PREFIX_LEN;
415
416 /* Chew though the Z-encoded soname part. */
417 while (True) {
418
419 if (i >= len)
420 break;
421
422 if (symbol[i] == '_')
423 /* We found the underscore following the Z-encoded soname.
424 Just copy the rest literally. */
425 break;
426
427 if (symbol[i] != 'Z') {
428 EMIT(symbol[i]);
429 i++;
430 continue;
431 }
432
433 /* We've got a Z-escape. Act accordingly. */
434 i++;
435 if (i >= len) {
436 /* Hmm, Z right at the end. Something's wrong. */
437 error = True;
438 EMIT('Z');
439 break;
440 }
441 switch (symbol[i]) {
442 case 'a': EMIT('*'); break;
443 case 'p': EMIT('+'); break;
444 case 'c': EMIT(':'); break;
445 case 'd': EMIT('.'); break;
446 case 'u': EMIT('_'); break;
447 case 'h': EMIT('-'); break;
448 case 's': EMIT(' '); break;
449 case 'Z': EMIT('Z'); break;
450 default: error = True; EMIT('Z'); EMIT(symbol[i]); break;
451 }
452 i++;
453 }
454
455 if (error || i >= len || symbol[i] != '_') {
456 /* Something's wrong. Give up. */
457 VG_(message)(Vg_UserMsg, "intercept: error demangling: %s", symbol);
458 EMIT(0);
459 return False;
460 }
461
462 /* Copy the rest of the string verbatim. */
463 i++;
464 EMIT(':');
465 while (True) {
466 if (i >= len)
467 break;
468 EMIT(symbol[i]);
469 i++;
470 }
471
472 EMIT(0);
473 if (0) VG_(printf)("%s\n", result);
474 return True;
475
476# undef EMIT
477}
478
479// Nb: this can change the string pointed to by 'symbol'.
480static void handle_replacement_function( Char* symbol, Addr addr )
481{
482 Bool ok;
483 Int len = VG_(strlen)(symbol) + 1 - VG_REPLACE_FUNCTION_PREFIX_LEN;
484 Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len+8);
485 Char *func;
486
487 // Put "soname:" at the start of lib
488 VG_(strcpy)(lib, "soname:");
489
490 ok = Z_decode(symbol, lib+7, len);
491 if (ok) {
492 // lib is "soname:<libname>:<fnname>". Split the string at the 2nd ':'.
493 func = lib + VG_(strlen)(lib)-1;
494 while(*func != ':') func--;
495 *func = '\0';
496 func++; // Move past the '\0'
497
498 // Now lib is "soname:<libname>" and func is "<fnname>".
499 if (0) VG_(printf)("lib A%sZ, func A%sZ\n", lib, func);
500 add_redirect_sym_to_addr(lib, func, addr);
501
502 // Overwrite the given Z-encoded name with just the fnname.
503 VG_(strcpy)(symbol, func);
504 }
505
506 VG_(arena_free)(VG_AR_SYMTAB, lib);
507}
508
njnbc6d84d2005-06-19 18:58:03 +0000509static Addr __libc_freeres_wrapper = 0;
510
511Addr VG_(get_libc_freeres_wrapper)(void)
512{
513 return __libc_freeres_wrapper;
514}
515
njn16eeb4e2005-06-16 03:56:58 +0000516// This is specifically for stringifying VG_(x) function names. We
517// need to do two macroexpansions to get the VG_ macro expanded before
518// stringifying.
519#define _STR(x) #x
520#define STR(x) _STR(x)
521
522static void handle_load_notifier( Char* symbol, Addr addr )
523{
524 if (VG_(strcmp)(symbol, STR(VG_NOTIFY_ON_LOAD(freeres))) == 0)
njnbc6d84d2005-06-19 18:58:03 +0000525 __libc_freeres_wrapper = addr;
njn16eeb4e2005-06-16 03:56:58 +0000526// else if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) == 0)
527// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value));
528 else
529 vg_assert2(0, "unrecognised load notification function: %s", symbol);
530}
531
532static Bool is_replacement_function(Char* s)
533{
534 return (0 == VG_(strncmp)(s,
535 VG_REPLACE_FUNCTION_PREFIX,
536 VG_REPLACE_FUNCTION_PREFIX_LEN));
537}
538
539static Bool is_load_notifier(Char* s)
540{
541 return (0 == VG_(strncmp)(s,
542 VG_NOTIFY_ON_LOAD_PREFIX,
543 VG_NOTIFY_ON_LOAD_PREFIX_LEN));
544}
545
546// Call this for each symbol loaded. It determines if we need to do
547// anything special with it. It can modify 'symbol' in-place.
548void VG_(maybe_redir_or_notify) ( Char* symbol, Addr addr )
549{
550 if (is_replacement_function(symbol))
551 handle_replacement_function(symbol, addr);
552 else
553 if (is_load_notifier(symbol))
554 handle_load_notifier(symbol, addr);
555}
556
557
sewardjcbdddcf2005-03-10 23:23:45 +0000558//:: /*------------------------------------------------------------*/
559//:: /*--- General function wrapping. ---*/
560//:: /*------------------------------------------------------------*/
561//::
562//:: /*
563//:: TODO:
564//:: - hook into the symtab machinery
565//:: - client-side wrappers?
566//:: - better interfaces for before() functions to get to arguments
567//:: - handle munmap of code (dlclose())
568//:: - handle thread exit
569//:: - handle longjmp
570//:: */
571//:: struct callkey {
572//:: ThreadId tid; /* calling thread */
573//:: Addr esp; /* address of args on stack */
574//:: Addr eip; /* return address */
575//:: };
576//::
577//:: struct call_instance {
578//:: struct callkey key;
579//::
580//:: const FuncWrapper *wrapper;
581//:: void *nonce;
582//:: };
583//::
584//:: static inline Addr addrcmp(Addr a, Addr b)
585//:: {
586//:: if (a < b)
587//:: return -1;
588//:: else if (a > b)
589//:: return 1;
590//:: else
591//:: return 0;
592//:: }
593//::
594//:: static inline Int cmp(UInt a, UInt b)
595//:: {
596//:: if (a < b)
597//:: return -1;
598//:: else if (a > b)
599//:: return 1;
600//:: else
601//:: return 0;
602//:: }
603//::
604//:: static Int keycmp(const void *pa, const void *pb)
605//:: {
606//:: const struct callkey *a = (const struct callkey *)pa;
607//:: const struct callkey *b = (const struct callkey *)pb;
608//:: Int ret;
609//::
610//:: if ((ret = cmp(a->tid, b->tid)))
611//:: return ret;
612//::
613//:: if ((ret = addrcmp(a->esp, b->esp)))
614//:: return ret;
615//::
616//:: return addrcmp(a->eip, b->eip);
617//:: }
618//::
619//:: /* List of wrapped call invocations which are currently active */
njnbe91aae2005-03-27 01:42:41 +0000620//:: static SkipList wrapped_frames = VG_SKIPLIST_INIT(struct call_instance, key, keycmp,
sewardjcbdddcf2005-03-10 23:23:45 +0000621//:: NULL, VG_AR_SYMTAB);
622//::
623//:: static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
624//:: {
625//:: struct callkey key = { tid, argsp, retaddr };
626//::
627//:: return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
628//:: }
629//::
630//:: static void wrapper_return(Addr retaddr);
631//::
632//:: /* Called from generated code via helper */
633//:: void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
634//:: {
njnaf839f52005-06-23 03:27:57 +0000635//:: Addr retaddr = VG_RETADDR(tst->arch);
636//:: Addr argp = (Addr)&VG_FUNC_ARG(tst->arch, 0);
sewardjcbdddcf2005-03-10 23:23:45 +0000637//:: void *nonce = NULL;
638//:: Bool mf = VG_(my_fault);
639//:: VG_(my_fault) = True;
640//::
641//:: if (wrapper->before) {
njnaf839f52005-06-23 03:27:57 +0000642//:: va_list args = VG_VA_LIST(tst->arch);
sewardjcbdddcf2005-03-10 23:23:45 +0000643//:: nonce = (*wrapper->before)(args);
644//:: }
645//::
646//:: if (wrapper->after) {
647//:: /* If there's an after function, make sure it gets called */
648//:: struct call_instance *call;
649//::
650//:: call = find_call(retaddr, argp, tst->tid);
651//::
652//:: if (call != NULL) {
653//:: /* Found a stale outstanding call; clean it up and recycle
654//:: the structure */
655//:: if (call->wrapper->after)
656//:: (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
657//:: } else {
658//:: call = VG_(SkipNode_Alloc)(&wrapped_frames);
659//::
660//:: call->key.tid = tst->tid;
661//:: call->key.esp = argp;
662//:: call->key.eip = retaddr;
663//::
664//:: VG_(SkipList_Insert)(&wrapped_frames, call);
665//::
666//:: wrapper_return(retaddr);
667//:: }
668//::
669//:: call->wrapper = wrapper;
670//:: call->nonce = nonce;
671//:: } else
672//:: vg_assert(nonce == NULL);
673//::
674//:: VG_(my_fault) = mf;
675//:: }
676//::
677//:: /* Called from generated code via helper */
678//:: void VG_(wrap_after)(ThreadState *tst)
679//:: {
njnaf839f52005-06-23 03:27:57 +0000680//:: Addr EIP = VG_INSTR_PTR(tst->arch); /* instruction after call */
681//:: Addr ESP = VG_STACK_PTR(tst->arch); /* pointer to args */
682//:: Word ret = VG_RETVAL(tst->arch); /* return value */
sewardjcbdddcf2005-03-10 23:23:45 +0000683//:: struct call_instance *call;
684//:: Bool mf = VG_(my_fault);
685//::
686//:: VG_(my_fault) = True;
687//:: call = find_call(EIP, ESP, tst->tid);
688//::
689//:: if (0)
690//:: VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
691//::
692//:: if (call != NULL) {
693//:: if (call->wrapper->after)
694//:: (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
695//::
696//:: VG_(SkipList_Remove)(&wrapped_frames, &call->key);
697//:: VG_(SkipNode_Free)(&wrapped_frames, call);
698//:: }
699//:: VG_(my_fault) = mf;
700//:: }
701//::
702//::
703//:: struct wrapped_function {
704//:: Addr eip; /* eip of function entrypoint */
705//:: const FuncWrapper *wrapper;
706//:: };
707//::
708//:: struct wrapper_return {
709//:: Addr eip; /* return address */
710//:: };
711//::
712//:: /* A mapping from eip of wrapped function entrypoints to actual wrappers */
njnbe91aae2005-03-27 01:42:41 +0000713//:: static SkipList wrapped_functions = VG_SKIPLIST_INIT(struct wrapped_function, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000714//:: NULL, VG_AR_SYMTAB);
715//::
716//:: /* A set of EIPs which are return addresses for wrapped functions */
njnbe91aae2005-03-27 01:42:41 +0000717//:: static SkipList wrapper_returns = VG_SKIPLIST_INIT(struct wrapper_return, eip, VG_(cmp_Addr),
sewardjcbdddcf2005-03-10 23:23:45 +0000718//:: NULL, VG_AR_SYMTAB);
719//::
720//:: /* Wrap function starting at eip */
721//:: void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
722//:: {
723//:: struct wrapped_function *func;
724//::
725//:: if (0)
726//:: VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
727//::
728//:: func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
729//::
730//:: if (func == NULL) {
731//:: func = VG_(SkipNode_Alloc)(&wrapped_functions);
732//:: VG_(invalidate_translations)(eip, 1, True);
733//::
734//:: func->eip = eip;
735//:: VG_(SkipList_Insert)(&wrapped_functions, func);
736//:: }
737//::
738//:: func->wrapper = wrapper;
739//:: }
740//::
741//:: const FuncWrapper *VG_(is_wrapped)(Addr eip)
742//:: {
743//:: struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
744//::
745//:: if (func)
746//:: return func->wrapper;
747//:: return NULL;
748//:: }
749//::
750//:: Bool VG_(is_wrapper_return)(Addr eip)
751//:: {
752//:: struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
753//::
754//:: return ret != NULL;
755//:: }
756//::
757//:: /* Mark eip as being the return address of a wrapper, so that the
758//:: codegen will generate the appropriate call. */
759//:: void wrapper_return(Addr eip)
760//:: {
761//:: struct wrapper_return *ret;
762//::
763//:: if (VG_(is_wrapper_return)(eip))
764//:: return;
765//::
766//:: VG_(invalidate_translations)(eip, 1, True);
767//::
768//:: ret = VG_(SkipNode_Alloc)(&wrapper_returns);
769//:: ret->eip = eip;
770//::
771//:: VG_(SkipList_Insert)(&wrapper_returns, ret);
772//:: }
njnc0ae7052005-08-25 22:55:19 +0000773
774/*--------------------------------------------------------------------*/
775/*--- end ---*/
776/*--------------------------------------------------------------------*/