1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Function replacement and wrapping.                 m_redir.c ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Copyright (C) 2000-2010 Julian Seward
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jseward@acm.org
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Copyright (C) 2003-2010 Jeremy Fitzhardinge
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jeremy@goop.org
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h"
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuglog.h"
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuginfo.h"
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h"
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h"
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h"
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_seqmatch.h"
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_mallocfree.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_options.h"
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_oset.h"
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_redir.h"
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_trampoline.h"
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_transtab.h"
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_tooliface.h"    // VG_(needs).malloc_replacement
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_machine.h"      // VG_(fnptr_to_fnentry)
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_aspacemgr.h"    // VG_(am_find_nsegment)
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_xarray.h"
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_clientstate.h"  // VG_(client___libc_freeres_wrapper)
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_demangle.h"     // VG_(maybe_Z_demangle)
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "config.h" /* GLIBC_2_* */
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This module is a critical part of the redirection/intercept system.
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   It keeps track of the current intercept state, cleans up the
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translation caches when that state changes, and finally, answers
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   queries about the whether an address is currently redirected or
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   not.  It doesn't do any of the control-flow trickery needed to put
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the redirections into practice.  That is the job of m_translate,
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which calls here to find out which translations need to be
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   redirected.
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The interface is simple.  VG_(redir_initialise) initialises and
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   loads some hardwired redirects which never disappear; this is
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   platform-specific.
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The module is notified of redirection state changes by m_debuginfo.
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   That calls VG_(redir_notify_new_DebugInfo) when a new DebugInfo
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (shared object symbol table, basically) appears.  Appearance of new
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   symbols can cause new (active) redirections to appear for two
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   reasons: the symbols in the new table may match existing
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   redirection specifications (see comments below), and because the
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   symbols in the new table may themselves supply new redirect
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   specifications which match existing symbols (or ones in the new
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   table).
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Redirect specifications are really symbols with "funny" prefixes
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (_vgrZU_ and _vgrZZ_).  These names tell m_redir that the
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   associated code should replace the standard entry point for some
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   set of functions.  The set of functions is specified by a (soname
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pattern, function name pattern) pair which is encoded in the symbol
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   name following the prefix.  The names use a Z-encoding scheme so
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that they may contain punctuation characters and wildcards (*).
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The encoding scheme is described in pub_tool_redir.h and is decoded
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   by VG_(maybe_Z_demangle).
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   When a shared object is unloaded, this module learns of it via a
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call to VG_(redir_notify_delete_DebugInfo).  It then removes from
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   its tables all active redirections in any way associated with that
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   object, and tidies up the translation caches accordingly.
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   That takes care of tracking the redirection state.  When a
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translation is actually to be made, m_translate calls to
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(redir_do_lookup) in this module to find out if the
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translation's address should be redirected.
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Semantics                                            ---*/
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The redirector holds two pieces of state:
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Specs  - a set of   (soname pattern, fnname pattern) -> redir addr
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Active - a set of   orig addr -> (bool, redir addr)
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Active is the currently active set of bindings that the translator
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   consults.  Specs is the current set of specifications as harvested
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from reading symbol tables of the currently loaded objects.
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Active is a pure function of Specs and the current symbol table
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   state (maintained by m_debuginfo).  Call the latter SyminfoState.
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Therefore whenever either Specs or SyminfoState changes, Active
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   must be recomputed.  [Inefficient if done naively, but this is a
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spec].
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Active is computed as follows:
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Active = empty
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for spec in Specs {
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sopatt = spec.soname pattern
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fnpatt = spec.fnname pattern
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         redir  = spec.redir addr
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for so matching sopatt in SyminfoState {
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for fn matching fnpatt in fnnames_of(so) {
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               &fn -> redir is added to Active
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [as an implementation detail, when a binding (orig -> redir) is
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   deleted from Active as a result of recomputing it, then all
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translations intersecting redir must be deleted.  However, this is
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   not part of the spec].
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [Active also depends on where the aspacemgr has decided to put all
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the pieces of code -- that affects the "orig addr" and "redir addr"
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   values.]
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ---------------------
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   That completes the spec, apart from one difficult issue: duplicates.
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Clearly we must impose the requirement that domain(Active) contains
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   no duplicates.  The difficulty is how to constrain Specs enough to
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   avoid getting into that situation.  It's easy to write specs which
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   could cause conflicting bindings in Active, eg:
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (libpthread.so, pthread_mutex_lock) ->    a1
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (libpthread.so, pthread_*)          ->    a2
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for a1 != a2.  Or even hairier:
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (libpthread.so, pthread_mutex_*) ->    a1
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (libpthread.so, pthread_*_lock)  ->    a2
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   I can't think of any sane way of detecting when an addition to
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Specs would generate conflicts.  However, considering we don't
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   actually want to have a system that allows this, I propose this:
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   all changes to Specs are acceptable.  But, when recomputing Active
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   following the change, if the same orig is bound to more than one
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   redir, then the first binding for orig is retained, and all the
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   rest ignored.
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ===========================================================
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ===========================================================
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Incremental implementation:
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   When a new DebugInfo appears:
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - it may be the source of new specs
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - it may be the source of new matches for existing specs
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Therefore:
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - (new Specs x existing DebugInfos): scan all symbols in the new
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     DebugInfo to find new specs.  Each of these needs to be compared
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     against all symbols in all the existing DebugInfos to generate
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     new actives.
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - (existing Specs x new DebugInfo): scan all symbols in the
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     DebugInfo, trying to match them to any existing specs, also
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     generating new actives.
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - (new Specs x new DebugInfo): scan all symbols in the new
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     DebugInfo, trying to match them against the new specs, to
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     generate new actives.
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - Finally, add new new specs to the current set of specs.
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   When adding a new active (s,d) to the Actives:
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     lookup s in Actives
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if already bound to d, ignore
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if already bound to something other than d, complain loudly and ignore
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else add (s,d) to Actives
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             and discard (s,1) and (d,1)  (maybe overly conservative)
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   When a DebugInfo disappears:
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - delete all specs acquired from the seginfo
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - delete all actives derived from the just-deleted specs
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - if each active (s,d) deleted, discard (s,1) and (d,1)
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- REDIRECTION SPECIFICATIONS                           ---*/
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A specification of a redirection we want to do.  Note that because
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   both the "from" soname and function name may contain wildcards, the
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spec can match an arbitrary number of times.
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   16 Nov 2007: Comments re .mandatory field: The initial motivation
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for this is making Memcheck work sanely on glibc-2.6.X ppc32-linux.
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   We really need to intercept 'strlen' in ld.so right from startup.
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If ld.so does not have a visible 'strlen' symbol, Memcheck
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   generates an impossible number of errors resulting from highly
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tuned strlen implementation in ld.so, and is completely unusable
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   -- the resulting undefinedness eventually seeps everywhere. */
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct _Spec {
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct _Spec* next;  /* linked list */
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* FIXED PARTS -- set when created and not changed */
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* from_sopatt;  /* from soname pattern  */
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* from_fnpatt;  /* from fnname pattern  */
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr   to_addr;      /* where redirecting to */
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isWrap;       /* wrap or replacement? */
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      const HChar** mandatory; /* non-NULL ==> abort V and print the
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  strings if from_sopatt is loaded but
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  from_fnpatt cannot be found */
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* VARIABLE PARTS -- used transiently whilst processing redirections */
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   mark; /* set if spec requires further processing */
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   done; /* set if spec was successfully matched */
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Spec;
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Top-level data structure.  It contains a pointer to a DebugInfo and
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   also a list of the specs harvested from that DebugInfo.  Note that
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   seginfo is allowed to be NULL, meaning that the specs are
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pre-loaded ones at startup and are not associated with any
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   particular seginfo. */
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct _TopSpec {
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct _TopSpec* next; /* linked list */
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DebugInfo* seginfo;    /* symbols etc */
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Spec*      specs;      /* specs pulled out of seginfo */
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool       mark; /* transient temporary used during deletion */
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TopSpec;
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the top level list of redirections.  m_debuginfo maintains
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a list of DebugInfos, and the idea here is to maintain a list with
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the same number of elements (in fact, with one more element, so as
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to record abovementioned preloaded specifications.) */
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic TopSpec* topSpecs = NULL;
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- CURRENTLY ACTIVE REDIRECTIONS                        ---*/
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Represents a currently active binding.  If either parent_spec or
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   parent_sym is NULL, then this binding was hardwired at startup and
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   should not be deleted.  Same is true if either parent's seginfo
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   field is NULL. */
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr     from_addr;   /* old addr -- MUST BE THE FIRST WORD! */
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr     to_addr;     /* where redirecting to */
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      TopSpec* parent_spec; /* the TopSpec which supplied the Spec */
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      TopSpec* parent_sym;  /* the TopSpec which supplied the symbol */
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool     isWrap;      /* wrap or replacement? */
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool     isIFunc;     /* indirect function? */
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Active;
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The active set is a fast lookup table */
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic OSet* activeSet = NULL;
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Wrapper routine for indirect functions */
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr iFuncWrapper;
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- FWDses                                               ---*/
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void maybe_add_active ( Active /*by value; callee copies*/ );
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void*  dinfo_zalloc(HChar* ec, SizeT);
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void   dinfo_free(void*);
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* dinfo_strdup(HChar* ec, HChar*);
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool   is_plausible_guest_addr(Addr);
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool   is_aix5_glink_idiom(Addr);
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void   show_redir_state ( HChar* who );
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void   show_active ( HChar* left, Active* act );
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void   handle_maybe_load_notifier( const UChar* soname,
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                HChar* symbol, Addr addr );
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void   handle_require_text_symbols ( DebugInfo* );
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- NOTIFICATIONS                                        ---*/
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid generate_and_add_actives (
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* spec list and the owning TopSpec */
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        Spec*    specs,
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        TopSpec* parent_spec,
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/* debuginfo and the owning TopSpec */
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DebugInfo* di,
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        TopSpec* parent_sym
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Notify m_redir of the arrival of a new DebugInfo.  This is fairly
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   complex, but the net effect is to (1) add a new entry to the
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   topspecs list, and (2) figure out what new binding are now active,
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and, as a result, add them to the actives mapping. */
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define N_DEMANGLED 256
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(redir_notify_new_DebugInfo)( DebugInfo* newsi )
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool         ok, isWrap;
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int          i, nsyms;
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Spec*        specList;
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Spec*        spec;
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TopSpec*     ts;
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TopSpec*     newts;
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar*       sym_name;
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr         sym_addr, sym_toc;
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar        demangled_sopatt[N_DEMANGLED];
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar        demangled_fnpatt[N_DEMANGLED];
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool         check_ppcTOCs = False;
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool         isText;
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const UChar* newsi_soname;
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_PLAT_USES_PPCTOC)
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   check_ppcTOCs = True;
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(newsi);
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newsi_soname = VG_(DebugInfo_get_soname)(newsi);
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(newsi_soname != NULL);
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* stay sane: we don't already have this. */
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (ts = topSpecs; ts; ts = ts->next)
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(ts->seginfo != newsi);
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* scan this DebugInfo's symbol table, pulling out and demangling
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      any specs found */
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   specList = NULL; /* the spec list we're building up */
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nsyms = VG_(DebugInfo_syms_howmany)( newsi );
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < nsyms; i++) {
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(DebugInfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc,
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  NULL, &sym_name, &isText, NULL );
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ok = VG_(maybe_Z_demangle)( sym_name, demangled_sopatt, N_DEMANGLED,
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  demangled_fnpatt, N_DEMANGLED, &isWrap );
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ignore data symbols */
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isText)
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!ok) {
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* It's not a full-scale redirect, but perhaps it is a load-notify
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fn?  Let the load-notify department see it. */
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         handle_maybe_load_notifier( newsi_soname, sym_name, sym_addr );
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (check_ppcTOCs && sym_toc == 0) {
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* This platform uses toc pointers, but none could be found
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for this symbol, so we can't safely redirect/wrap to it.
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Just skip it; we'll make a second pass over the symbols in
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            the following loop, and complain at that point. */
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      spec = dinfo_zalloc("redir.rnnD.1", sizeof(Spec));
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(spec);
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      spec->from_sopatt = dinfo_strdup("redir.rnnD.2", demangled_sopatt);
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      spec->from_fnpatt = dinfo_strdup("redir.rnnD.3", demangled_fnpatt);
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(spec->from_sopatt);
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(spec->from_fnpatt);
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      spec->to_addr = sym_addr;
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      spec->isWrap = isWrap;
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* check we're not adding manifestly stupid destinations */
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(is_plausible_guest_addr(sym_addr));
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      spec->next = specList;
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      spec->mark = False; /* not significant */
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      spec->done = False; /* not significant */
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      specList = spec;
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (check_ppcTOCs) {
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < nsyms; i++) {
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(DebugInfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc,
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     NULL, &sym_name, &isText, NULL );
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ok = isText
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              && VG_(maybe_Z_demangle)(
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sym_name, demangled_sopatt, N_DEMANGLED,
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    demangled_fnpatt, N_DEMANGLED, &isWrap );
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!ok)
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* not a redirect.  Ignore. */
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            continue;
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sym_toc != 0)
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* has a valid toc pointer.  Ignore. */
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            continue;
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (spec = specList; spec; spec = spec->next)
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (0 == VG_(strcmp)(spec->from_sopatt, demangled_sopatt)
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && 0 == VG_(strcmp)(spec->from_fnpatt, demangled_fnpatt))
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (spec)
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* a redirect to some other copy of that symbol, which
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               does have a TOC value, already exists */
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            continue;
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Complain */
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "WARNING: no TOC ptr for redir/wrap to %s %s\n",
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      demangled_sopatt, demangled_fnpatt);
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Ok.  Now specList holds the list of specs from the DebugInfo.
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Build a new TopSpec, but don't add it to topSpecs yet. */
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newts = dinfo_zalloc("redir.rnnD.4", sizeof(TopSpec));
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(newts);
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newts->next    = NULL; /* not significant */
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newts->seginfo = newsi;
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newts->specs   = specList;
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newts->mark    = False; /* not significant */
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We now need to augment the active set with the following partial
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cross product:
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (1) actives formed by matching the new specs in specList against
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          all symbols currently listed in topSpecs
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (2) actives formed by matching the new symbols in newsi against
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          all specs currently listed in topSpecs
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (3) actives formed by matching the new symbols in newsi against
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          the new specs in specList
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      This is necessary in order to maintain the invariant that
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Actives contains all bindings generated by matching ALL specs in
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      topSpecs against ALL symbols in topSpecs (that is, a cross
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      product of ALL known specs against ALL known symbols).
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Case (1) */
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (ts = topSpecs; ts; ts = ts->next) {
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ts->seginfo)
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         generate_and_add_actives( specList,    newts,
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ts->seginfo, ts );
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Case (2) */
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (ts = topSpecs; ts; ts = ts->next) {
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      generate_and_add_actives( ts->specs, ts,
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                newsi,     newts );
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Case (3) */
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   generate_and_add_actives( specList, newts,
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             newsi,    newts );
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Finally, add the new TopSpec. */
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newts->next = topSpecs;
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   topSpecs = newts;
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_redir))
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      show_redir_state("after VG_(redir_notify_new_DebugInfo)");
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Really finally (quite unrelated to all the above) check the
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      names in the module against any --require-text-symbol=
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      specifications we might have. */
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   handle_require_text_symbols(newsi);
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef N_DEMANGLED
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add a new target for an indirect function. Adds a new redirection
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for the indirection function with address old_from that redirects
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the ordinary function with address new_from to the target address
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of the original redirection. */
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(redir_add_ifunc_target)( Addr old_from, Addr new_from )
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    Active *old, new;
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    old = VG_(OSetGen_Lookup)(activeSet, &old_from);
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    vg_assert(old);
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    vg_assert(old->isIFunc);
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    new = *old;
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    new.from_addr = new_from;
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    new.isIFunc = False;
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    maybe_add_active (new);
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (VG_(clo_trace_redir)) {
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       VG_(message)( Vg_DebugMsg,
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     "Adding redirect for indirect function 0x%llx from 0x%llx -> 0x%llx\n",
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)old_from, (ULong)new_from, (ULong)new.to_addr );
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Do one element of the basic cross product: add to the active set,
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   all matches resulting from comparing all the given specs against
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   all the symbols in the given seginfo.  If a conflicting binding
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   would thereby arise, don't add it, but do complain. */
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid generate_and_add_actives (
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* spec list and the owning TopSpec */
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        Spec*    specs,
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        TopSpec* parent_spec,
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/* seginfo and the owning TopSpec */
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DebugInfo* di,
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        TopSpec* parent_sym
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     )
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Spec*  sp;
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   anyMark, isText, isIFunc;
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Active act;
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    nsyms, i;
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr   sym_addr;
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar* sym_name;
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First figure out which of the specs match the seginfo's soname.
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Also clear the 'done' bits, so that after the main loop below
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tell which of the Specs really did get done. */
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   anyMark = False;
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (sp = specs; sp; sp = sp->next) {
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sp->done = False;
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sp->mark = VG_(string_match)( sp->from_sopatt,
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    VG_(DebugInfo_get_soname)(di) );
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      anyMark = anyMark || sp->mark;
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* shortcut: if none of the sonames match, there will be no bindings. */
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!anyMark)
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Iterate outermost over the symbols in the seginfo, in the hope
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of trashing the caches less. */
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nsyms = VG_(DebugInfo_syms_howmany)( di );
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < nsyms; i++) {
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(DebugInfo_syms_getidx)( di, i, &sym_addr, NULL, NULL,
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  &sym_name, &isText, &isIFunc );
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ignore data symbols */
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isText)
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* On AIX, we cannot redirect calls to a so-called glink
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         function for reasons which are not obvious - something to do
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         with saving r2 across the call.  Not a problem, as we don't
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         want to anyway; presumably it is the target of the glink we
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         need to redirect.  Hence just spot them and ignore them.
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         They are always of a very specific (more or less
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ABI-mandated) form. */
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (is_aix5_glink_idiom(sym_addr))
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (sp = specs; sp; sp = sp->next) {
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!sp->mark)
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            continue; /* soname doesn't match */
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(string_match)( sp->from_fnpatt, sym_name )) {
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* got a new binding.  Add to collection. */
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            act.from_addr   = sym_addr;
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            act.to_addr     = sp->to_addr;
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            act.parent_spec = parent_spec;
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            act.parent_sym  = parent_sym;
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            act.isWrap      = sp->isWrap;
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            act.isIFunc     = isIFunc;
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sp->done = True;
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            maybe_add_active( act );
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } /* for (sp = specs; sp; sp = sp->next) */
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* for (i = 0; i < nsyms; i++)  */
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now, finally, look for Specs which were marked to be done, but
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      didn't get matched.  If any such are mandatory we must abort the
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      system at this point. */
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (sp = specs; sp; sp = sp->next) {
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!sp->mark)
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sp->mark && (!sp->done) && sp->mandatory)
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sp) {
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      const HChar** strp;
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* v = "valgrind:  ";
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(sp->mark);
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(!sp->done);
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(sp->mandatory);
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%sFatal error at startup: a function redirection\n", v);
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%swhich is mandatory for this platform-tool combination\n", v);
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%scannot be set up.  Details of the redirection are:\n", v);
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%s\n", v);
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%sA must-be-redirected function\n", v);
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%swhose name matches the pattern:      %s\n", v, sp->from_fnpatt);
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%sin an object with soname matching:   %s\n", v, sp->from_sopatt);
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%swas not found whilst processing\n", v);
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%ssymbols from the object with soname: %s\n",
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      v, VG_(DebugInfo_get_soname)(di));
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%s\n", v);
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (strp = sp->mandatory; *strp; strp++)
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)(
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%s%s\n", v, *strp);
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%s\n", v);
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "%sCannot continue -- exiting now.  Sorry.\n", v);
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(exit)(1);
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add an act (passed by value; is copied here) and deal with
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   conflicting bindings. */
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void maybe_add_active ( Active act )
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar*  what = NULL;
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Active* old;
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Complain and ignore manifestly bogus 'from' addresses.
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Kludge: because this can get called befor the trampoline area (a
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bunch of magic 'to' addresses) has its ownership changed from V
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to C, we can't check the 'to' address similarly.  Sigh.
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      amd64-linux hack: the vsysinfo pages appear to have no
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      permissions
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      so skip the check for them.  */
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!is_plausible_guest_addr(act.from_addr)
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#      if defined(VGP_amd64_linux)
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && act.from_addr != 0xFFFFFFFFFF600000ULL
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && act.from_addr != 0xFFFFFFFFFF600400ULL
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#      endif
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ) {
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      what = "redirection from-address is in non-executable area";
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto bad;
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old = VG_(OSetGen_Lookup)( activeSet, &act.from_addr );
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (old) {
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Dodgy.  Conflicting binding. */
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(old->from_addr == act.from_addr);
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (old->to_addr != act.to_addr) {
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* we have to ignore it -- otherwise activeSet would contain
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            conflicting bindings. */
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         what = "new redirection conflicts with existing -- ignoring it";
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto bad;
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* This appears to be a duplicate of an existing binding.
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Safe(ish) -- ignore. */
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* XXXXXXXXXXX COMPLAIN if new and old parents differ */
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Active* a = VG_(OSetGen_AllocNode)(activeSet, sizeof(Active));
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(a);
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *a = act;
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(OSetGen_Insert)(activeSet, a);
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Now that a new from->to redirection is in force, we need to
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         get rid of any translations intersecting 'from' in order that
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         they get redirected to 'to'.  So discard them.  Just for
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         paranoia (but, I believe, unnecessarily), discard 'to' as
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         well. */
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(discard_translations)( (Addr64)act.from_addr, 1,
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "redir_new_DebugInfo(from_addr)");
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(discard_translations)( (Addr64)act.to_addr, 1,
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "redir_new_DebugInfo(to_addr)");
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return;
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  bad:
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(what);
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 1) {
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "WARNING: %s\n", what);
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      show_active(             "    new: ", &act);
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Notify m_redir of the deletion of a DebugInfo.  This is relatively
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   simple -- just get rid of all actives derived from it, and free up
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the associated list elements. */
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(redir_notify_delete_DebugInfo)( DebugInfo* delsi )
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TopSpec* ts;
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TopSpec* tsPrev;
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Spec*    sp;
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Spec*    sp_next;
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   OSet*    tmpSet;
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Active*  act;
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool     delMe;
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr     addr;
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(delsi);
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Search for it, and make tsPrev point to the previous entry, if
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      any. */
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tsPrev = NULL;
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ts     = topSpecs;
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (ts == NULL) break;
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (ts->seginfo == delsi) break;
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     tsPrev = ts;
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     ts = ts->next;
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ts); /* else we don't have the deleted DebugInfo */
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ts->seginfo == delsi);
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Traverse the actives, copying the addresses of those we intend
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to delete into tmpSet. */
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tmpSet = VG_(OSetWord_Create)(dinfo_zalloc, "redir.rndD.1", dinfo_free);
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ts->mark = True;
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(OSetGen_ResetIter)( activeSet );
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while ( (act = VG_(OSetGen_Next)(activeSet)) ) {
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delMe = act->parent_spec != NULL
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              && act->parent_sym != NULL
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              && act->parent_spec->seginfo != NULL
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              && act->parent_sym->seginfo != NULL
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              && (act->parent_spec->mark || act->parent_sym->mark);
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* While we're at it, a bit of paranoia: delete any actives
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         which don't have both feet in valid client executable areas.
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         But don't delete hardwired-at-startup ones; these are denoted
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         by having parent_spec or parent_sym being NULL.  */
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( (!delMe)
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           && act->parent_spec != NULL
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           && act->parent_sym  != NULL ) {
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!is_plausible_guest_addr(act->from_addr))
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delMe = True;
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!is_plausible_guest_addr(act->to_addr))
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delMe = True;
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (delMe) {
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(OSetWord_Insert)( tmpSet, act->from_addr );
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* While we have our hands on both the 'from' and 'to'
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            of this Active, do paranoid stuff with tt/tc. */
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(discard_translations)( (Addr64)act->from_addr, 1,
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    "redir_del_DebugInfo(from_addr)");
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(discard_translations)( (Addr64)act->to_addr, 1,
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    "redir_del_DebugInfo(to_addr)");
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now traverse tmpSet, deleting corresponding elements in activeSet. */
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(OSetWord_ResetIter)( tmpSet );
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while ( VG_(OSetWord_Next)(tmpSet, &addr) ) {
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      act = VG_(OSetGen_Remove)( activeSet, &addr );
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(act);
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(OSetGen_FreeNode)( activeSet, act );
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(OSetWord_Destroy)( tmpSet );
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The Actives set is now cleaned up.  Free up this TopSpec and
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      everything hanging off it. */
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (sp = ts->specs; sp; sp = sp_next) {
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sp->from_sopatt) dinfo_free(sp->from_sopatt);
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sp->from_fnpatt) dinfo_free(sp->from_fnpatt);
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sp_next = sp->next;
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dinfo_free(sp);
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (tsPrev == NULL) {
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* first in list */
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      topSpecs = ts->next;
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tsPrev->next = ts->next;
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dinfo_free(ts);
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_redir))
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      show_redir_state("after VG_(redir_notify_delete_DebugInfo)");
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- QUERIES (really the whole point of this module)      ---*/
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the crucial redirection function.  It answers the question:
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   should this code address be redirected somewhere else?  It's used
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   just before translating a basic block. */
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAddr VG_(redir_do_lookup) ( Addr orig, Bool* isWrap )
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Active* r = VG_(OSetGen_Lookup)(activeSet, &orig);
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (r == NULL)
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return orig;
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(r->to_addr != 0);
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isWrap)
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *isWrap = r->isWrap || r->isIFunc;
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (r->isIFunc) {
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(iFuncWrapper);
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return iFuncWrapper;
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return r->to_addr;
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- INITIALISATION                                       ---*/
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add a never-delete-me Active. */
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((unused)) /* only used on amd64 */
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_hardwired_active ( Addr from, Addr to )
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Active act;
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   act.from_addr   = from;
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   act.to_addr     = to;
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   act.parent_spec = NULL;
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   act.parent_sym  = NULL;
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   act.isWrap      = False;
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   act.isIFunc     = False;
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   maybe_add_active( act );
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add a never-delete-me Spec.  This is a bit of a kludge.  On the
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assumption that this is called only at startup, only handle the
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case where topSpecs is completely empty, or if it isn't, it has
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   just one entry and that is the one with NULL seginfo -- that is the
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   entry that holds these initial specs. */
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((unused)) /* not used on all platforms */
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_hardwired_spec ( HChar* sopatt, HChar* fnpatt,
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Addr   to_addr,
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 const HChar** mandatory )
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Spec* spec = dinfo_zalloc("redir.ahs.1", sizeof(Spec));
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(spec);
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (topSpecs == NULL) {
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      topSpecs = dinfo_zalloc("redir.ahs.2", sizeof(TopSpec));
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(topSpecs);
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* symtab_zalloc sets all fields to zero */
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(topSpecs != NULL);
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(topSpecs->next == NULL);
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(topSpecs->seginfo == NULL);
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* FIXED PARTS */
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spec->from_sopatt = sopatt;
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spec->from_fnpatt = fnpatt;
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spec->to_addr     = to_addr;
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spec->isWrap      = False;
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spec->mandatory   = mandatory;
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* VARIABLE PARTS */
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spec->mark        = False; /* not significant */
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spec->done        = False; /* not significant */
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spec->next = topSpecs->specs;
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   topSpecs->specs = spec;
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((unused)) /* not used on all platforms */
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic const HChar* complain_about_stripped_glibc_ldso[]
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown= { "Possible fixes: (1, short term): install glibc's debuginfo",
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "package on this machine.  (2, longer term): ask the packagers",
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "for your Linux distribution to please in future ship a non-",
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "stripped ld.so (or whatever the dynamic linker .so is called)",
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "that exports the above-named function using the standard",
894f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root    "calling conventions for this platform.  The package you need",
895f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root    "to install for fix (1) is called",
896f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root    "",
897f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root    "  On Debian, Ubuntu:                 libc6-dbg",
898f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root    "  On SuSE, openSuSE, Fedora, RHEL:   glibc-debuginfo",
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    NULL
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  };
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Initialise the redir system, and create the initial Spec list and
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for amd64-linux a couple of permanent active mappings.  The initial
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Specs are not converted into Actives yet, on the (checked)
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assumption that no DebugInfos have so far been created, and so when
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   they are created, that will happen. */
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(redir_initialise) ( void )
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Assert that there are no DebugInfos so far
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert( VG_(next_DebugInfo)(NULL) == NULL );
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Initialise active mapping.
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   activeSet = VG_(OSetGen_Create)(offsetof(Active, from_addr),
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   NULL,     // Use fast comparison
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dinfo_zalloc,
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   "redir.ri.1",
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dinfo_free);
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // The rest of this function just adds initial Specs.
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux)
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If we're using memcheck, use this intercept right from the
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      start, otherwise ld.so (glibc-2.3.5) makes a lot of noise. */
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec(
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "ld-linux.so.2", "index",
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (Addr)&VG_(x86_linux_REDIR_FOR_index),
930f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root#        if defined(GLIBC_2_2) || defined(GLIBC_2_3) || defined(GLIBC_2_4) \
931f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            || defined(GLIBC_2_5) || defined(GLIBC_2_6) || defined(GLIBC_2_7) \
932f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            || defined(GLIBC_2_8) || defined(GLIBC_2_9) \
933f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            || defined(GLIBC_2_10) || defined(GLIBC_2_11)
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         NULL
935f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root#        else
936f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         /* for glibc-2.12 and later, this is mandatory - can't sanely
937f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            continue without it */
938f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         complain_about_stripped_glibc_ldso
939f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root#        endif
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux)
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Redirect vsyscalls to local versions */
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   add_hardwired_active(
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      0xFFFFFFFFFF600000ULL,
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   add_hardwired_active(
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      0xFFFFFFFFFF600400ULL,
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If we're using memcheck, use these intercepts right from
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the start, otherwise ld.so makes a lot of noise. */
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec(
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "ld-linux-x86-64.so.2", "strlen",
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (Addr)&VG_(amd64_linux_REDIR_FOR_strlen),
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        if defined(GLIBC_2_2) || defined(GLIBC_2_3) || defined(GLIBC_2_4) \
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            || defined(GLIBC_2_5) || defined(GLIBC_2_6) || defined(GLIBC_2_7) \
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            || defined(GLIBC_2_8) || defined(GLIBC_2_9)
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         NULL
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        else
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* for glibc-2.10 and later, this is mandatory - can't sanely
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            continue without it */
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         complain_about_stripped_glibc_ldso
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        endif
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc32_linux)
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If we're using memcheck, use these intercepts right from
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the start, otherwise ld.so makes a lot of noise. */
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* this is mandatory - can't sanely continue without it */
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec(
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "ld.so.1", "strlen",
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen),
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         complain_about_stripped_glibc_ldso
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec(
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "ld.so.1", "strcmp",
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp),
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         NULL /* not mandatory - so why bother at all? */
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec(
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "ld.so.1", "index",
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (Addr)&VG_(ppc32_linux_REDIR_FOR_strchr),
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         NULL /* not mandatory - so why bother at all? */
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc64_linux)
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If we're using memcheck, use these intercepts right from
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the start, otherwise ld.so makes a lot of noise. */
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* this is mandatory - can't sanely continue without it */
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec(
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "ld64.so.1", "strlen",
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strlen) ),
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         complain_about_stripped_glibc_ldso
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec(
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "ld64.so.1", "index",
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strchr) ),
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         NULL /* not mandatory - so why bother at all? */
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* glibc-2.5 (FC6, ppc64) seems fine without it */
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_arm_linux)
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If we're using memcheck, use these intercepts right from
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the start, otherwise ld.so makes a lot of noise. */
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec(
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "ld-linux.so.3", "strlen",
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (Addr)&VG_(arm_linux_REDIR_FOR_strlen),
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         complain_about_stripped_glibc_ldso
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //add_hardwired_spec(
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   "ld-linux.so.3", "index",
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   (Addr)&VG_(arm_linux_REDIR_FOR_index),
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   NULL
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //);
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec(
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "ld-linux.so.3", "memcpy",
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (Addr)&VG_(arm_linux_REDIR_FOR_memcpy),
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         complain_about_stripped_glibc_ldso
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* nothing so far */
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc32_aix5)
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* nothing so far */
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc64_aix5)
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* nothing so far */
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_x86_darwin)
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If we're using memcheck, use these intercepts right from
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the start, otherwise dyld makes a lot of noise. */
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "strcmp",
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(x86_darwin_REDIR_FOR_strcmp), NULL);
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "strlen",
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(x86_darwin_REDIR_FOR_strlen), NULL);
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "strcat",
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(x86_darwin_REDIR_FOR_strcat), NULL);
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "strcpy",
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(x86_darwin_REDIR_FOR_strcpy), NULL);
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "strlcat",
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(x86_darwin_REDIR_FOR_strlcat), NULL);
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_darwin)
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If we're using memcheck, use these intercepts right from
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the start, otherwise dyld makes a lot of noise. */
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "strcmp",
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(amd64_darwin_REDIR_FOR_strcmp), NULL);
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "strlen",
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(amd64_darwin_REDIR_FOR_strlen), NULL);
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "strcat",
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(amd64_darwin_REDIR_FOR_strcat), NULL);
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "strcpy",
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(amd64_darwin_REDIR_FOR_strcpy), NULL);
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "strlcat",
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(amd64_darwin_REDIR_FOR_strlcat), NULL);
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // DDD: #warning fixme rdar://6166275
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_hardwired_spec("dyld", "arc4random",
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Addr)&VG_(amd64_darwin_REDIR_FOR_arc4random), NULL);
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown platform
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_redir))
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      show_redir_state("after VG_(redir_initialise)");
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- MISC HELPERS                                         ---*/
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* dinfo_zalloc(HChar* ec, SizeT n) {
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void* p;
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n > 0);
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = VG_(arena_malloc)(VG_AR_DINFO, ec, n);
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(p);
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(p, 0, n);
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return p;
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void dinfo_free(void* p) {
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(p);
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return VG_(arena_free)(VG_AR_DINFO, p);
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* dinfo_strdup(HChar* ec, HChar* str)
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return VG_(arena_strdup)(VG_AR_DINFO, ec, str);
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Really this should be merged with translations_allowable_from_seg
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in m_translate. */
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool is_plausible_guest_addr(Addr a)
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NSegment const* seg = VG_(am_find_nsegment)(a);
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return seg != NULL
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (seg->kind == SkAnonC || seg->kind == SkFileC)
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (seg->hasX || seg->hasR); /* crude x86-specific hack */
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A function which spots AIX 'glink' functions.  A 'glink' function
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is a stub function which has something to do with AIX-style dynamic
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   linking, and jumps to the real target (with which it typically
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shares the same name).  See also comment where this function is
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   used (above). */
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool is_aix5_glink_idiom ( Addr sym_addr )
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_ppc32_aix5)
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt* w = (UInt*)sym_addr;
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_IS_4_ALIGNED(w)
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && is_plausible_guest_addr((Addr)(w+0))
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && is_plausible_guest_addr((Addr)(w+6))
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (w[0] & 0xFFFF0000) == 0x81820000 /* lwz r12,func@toc(r2) */
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[1] == 0x90410014                /* stw r2,20(r1) */
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[2] == 0x800c0000                /* lwz r0,0(r12) */
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[3] == 0x804c0004                /* lwz r2,4(r12) */
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[4] == 0x7c0903a6                /* mtctr r0 */
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[5] == 0x4e800420                /* bctr */
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[6] == 0x00000000                /* illegal */)
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc64_aix5)
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt* w = (UInt*)sym_addr;
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_IS_4_ALIGNED(w)
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && is_plausible_guest_addr((Addr)(w+0))
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && is_plausible_guest_addr((Addr)(w+6))
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (w[0] & 0xFFFF0000) == 0xE9820000 /* ld  r12,func@toc(r2) */
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[1] == 0xF8410028                /* std r2,40(r1) */
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[2] == 0xE80C0000                /* ld  r0,0(r12) */
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[3] == 0xE84C0008                /* ld  r2,8(r12) */
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[4] == 0x7c0903a6                /* mtctr r0 */
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[5] == 0x4e800420                /* bctr */
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && w[6] == 0x00000000                /* illegal */)
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- NOTIFY-ON-LOAD FUNCTIONS                             ---*/
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid handle_maybe_load_notifier( const UChar* soname,
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       HChar* symbol, Addr addr )
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux)
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* x86-linux only: if we see _dl_sysinfo_int80, note its address.
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      See comment on declaration of VG_(client__dl_sysinfo_int80) for
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the reason.  As far as I can tell, the relevant symbol is always
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      in object with soname "ld-linux.so.2". */
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (symbol && symbol[0] == '_'
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              && 0 == VG_(strcmp)(symbol, "_dl_sysinfo_int80")
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              && 0 == VG_(strcmp)(soname, "ld-linux.so.2")) {
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(client__dl_sysinfo_int80) == 0)
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(client__dl_sysinfo_int80) = addr;
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Normal load-notifier handling after here.  First, ignore all
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      symbols lacking the right prefix. */
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 != VG_(strncmp)(symbol, VG_NOTIFY_ON_LOAD_PREFIX,
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 VG_NOTIFY_ON_LOAD_PREFIX_LEN))
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Doesn't have the right prefix */
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(freeres))) == 0)
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(client___libc_freeres_wrapper) = addr;
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(ifunc_wrapper))) == 0)
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      iFuncWrapper = addr;
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert2(0, "unrecognised load notification function: %s", symbol);
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- REQUIRE-TEXT-SYMBOL HANDLING                         ---*/
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* In short: check that the currently-being-loaded object has text
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   symbols that satisfy any --require-text-symbol= specifications that
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   apply to it, and abort the run with an error message if not.
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void handle_require_text_symbols ( DebugInfo* di )
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First thing to do is figure out which, if any,
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      --require-text-symbol specification strings apply to this
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      object.  Most likely none do, since it is not expected to
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      frequently be used.  Work through the list of specs and
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      accumulate in fnpatts[] the fn patterns that pertain to this
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      object. */
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar* fnpatts[VG_CLO_MAX_REQ_TSYMS];
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    fnpatts_used = 0;
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    i, j;
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const HChar* di_soname = VG_(DebugInfo_get_soname)(di);
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(di_soname); // must be present
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&fnpatts, 0, sizeof(fnpatts));
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(clo_n_req_tsyms) >= 0);
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(clo_n_req_tsyms) <= VG_CLO_MAX_REQ_TSYMS);
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < VG_(clo_n_req_tsyms); i++) {
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* spec = VG_(clo_req_tsyms)[i];
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(spec && VG_(strlen)(spec) >= 4);
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // clone the spec, so we can stick a zero at the end of the sopatt
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      spec = VG_(strdup)("m_redir.hrts.1", spec);
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar sep = spec[0];
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* sopatt = &spec[1];
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* fnpatt = VG_(strchr)(sopatt, sep);
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // the initial check at clo processing in time in m_main
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // should ensure this.
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(fnpatt && *fnpatt == sep);
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *fnpatt = 0;
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fnpatt++;
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(string_match)(sopatt, di_soname))
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fnpatts[fnpatts_used++]
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = VG_(strdup)("m_redir.hrts.2", fnpatt);
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(free)(spec);
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (fnpatts_used == 0)
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;  /* no applicable spec strings */
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So finally, fnpatts[0 .. fnpatts_used - 1] contains the set of
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (patterns for) text symbol names that must be found in this
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      object, in order to continue.  That is, we must find at least
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      one text symbol name that matches each pattern, else we must
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abort the run. */
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("for %s\n", di_soname);
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < fnpatts_used; i++)
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0) VG_(printf)("   fnpatt: %s\n", fnpatts[i]);
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* For each spec, look through the syms to find one that matches.
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      This isn't terribly efficient but it happens rarely, so no big
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      deal. */
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < fnpatts_used; i++) {
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   found = False;
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* fnpatt = fnpatts[i];
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    nsyms = VG_(DebugInfo_syms_howmany)(di);
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (j = 0; j < nsyms; j++) {
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   isText   = False;
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* sym_name = NULL;
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(DebugInfo_syms_getidx)( di, j, NULL, NULL,
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     NULL, &sym_name, &isText, NULL );
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* ignore data symbols */
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0) VG_(printf)("QQQ %s\n", sym_name);
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(sym_name);
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!isText)
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            continue;
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(string_match)(fnpatt, sym_name)) {
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            found = True;
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!found) {
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* v = "valgrind:  ";
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("\n");
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)(
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%sFatal error at when loading library with soname\n", v);
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)(
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%s   %s\n", v, di_soname);
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)(
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%sCannot find any text symbol with a name "
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "that matches the pattern\n", v);
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("%s   %s\n", v, fnpatt);
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("%sas required by a --require-text-symbol= "
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "specification.\n", v);
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("\n");
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)(
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%sCannot continue -- exiting now.\n", v);
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("\n");
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(exit)(1);
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All required specs were found.  Just free memory and return. */
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < fnpatts_used; i++)
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(free)(fnpatts[i]);
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- SANITY/DEBUG                                         ---*/
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void show_spec ( HChar* left, Spec* spec )
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)( Vg_DebugMsg,
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 "%s%25s %30s %s-> 0x%08llx\n",
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 left,
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 spec->from_sopatt, spec->from_fnpatt,
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 spec->isWrap ? "W" : "R",
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 (ULong)spec->to_addr );
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void show_active ( HChar* left, Active* act )
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool ok;
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar name1[64] = "";
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar name2[64] = "";
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   name1[0] = name2[0] = 0;
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ok = VG_(get_fnname_w_offset)(act->from_addr, name1, 64);
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!ok) VG_(strcpy)(name1, "???");
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ok = VG_(get_fnname_w_offset)(act->to_addr, name2, 64);
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!ok) VG_(strcpy)(name2, "???");
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg, "%s0x%08llx (%20s) %s-> 0x%08llx %s\n",
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             left,
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             (ULong)act->from_addr, name1,
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             act->isWrap ? "W" : "R",
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             (ULong)act->to_addr, name2 );
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void show_redir_state ( HChar* who )
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TopSpec* ts;
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Spec*    sp;
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Active*  act;
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg, "<<\n");
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg, "   ------ REDIR STATE %s ------\n", who);
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (ts = topSpecs; ts; ts = ts->next) {
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_DebugMsg,
1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "   TOPSPECS of soname %s\n",
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ts->seginfo
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      ? (HChar*)VG_(DebugInfo_get_soname)(ts->seginfo)
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      : "(hardwired)" );
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (sp = ts->specs; sp; sp = sp->next)
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         show_spec("     ", sp);
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg, "   ------ ACTIVE ------\n");
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(OSetGen_ResetIter)( activeSet );
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while ( (act = VG_(OSetGen_Next)(activeSet)) ) {
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      show_active("    ", act);
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg, ">>\n");
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1366