njn | c0ae705 | 2005-08-25 22:55:19 +0000 | [diff] [blame] | 1 | |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 2 | /*--------------------------------------------------------------------*/ |
njn | c0ae705 | 2005-08-25 22:55:19 +0000 | [diff] [blame] | 3 | /*--- Function replacement and wrapping. m_redir.c ---*/ |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 4 | /*--------------------------------------------------------------------*/ |
| 5 | |
| 6 | /* |
njn | c0ae705 | 2005-08-25 22:55:19 +0000 | [diff] [blame] | 7 | This file is part of Valgrind, a dynamic binary instrumentation |
| 8 | framework. |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 9 | |
sewardj | b3a1e4b | 2015-08-21 11:32:26 +0000 | [diff] [blame] | 10 | Copyright (C) 2000-2015 Julian Seward |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 11 | jseward@acm.org |
sewardj | b3a1e4b | 2015-08-21 11:32:26 +0000 | [diff] [blame] | 12 | Copyright (C) 2003-2015 Jeremy Fitzhardinge |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 13 | jeremy@goop.org |
| 14 | |
| 15 | This program is free software; you can redistribute it and/or |
| 16 | modify it under the terms of the GNU General Public License as |
| 17 | published by the Free Software Foundation; either version 2 of the |
| 18 | License, or (at your option) any later version. |
| 19 | |
| 20 | This program is distributed in the hope that it will be useful, but |
| 21 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 23 | General Public License for more details. |
| 24 | |
| 25 | You should have received a copy of the GNU General Public License |
| 26 | along with this program; if not, write to the Free Software |
| 27 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 28 | 02111-1307, USA. |
| 29 | |
| 30 | The GNU General Public License is contained in the file COPYING. |
| 31 | */ |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 32 | |
njn | c7561b9 | 2005-06-19 01:24:32 +0000 | [diff] [blame] | 33 | #include "pub_core_basics.h" |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 34 | #include "pub_core_debuglog.h" |
njn | 88c5148 | 2005-06-25 20:49:33 +0000 | [diff] [blame] | 35 | #include "pub_core_debuginfo.h" |
njn | 97405b2 | 2005-06-02 03:39:33 +0000 | [diff] [blame] | 36 | #include "pub_core_libcbase.h" |
njn | 132bfcc | 2005-06-04 19:16:06 +0000 | [diff] [blame] | 37 | #include "pub_core_libcassert.h" |
njn | 36a20fa | 2005-06-03 03:08:39 +0000 | [diff] [blame] | 38 | #include "pub_core_libcprint.h" |
philippe | 277eaff | 2012-03-03 12:01:48 +0000 | [diff] [blame] | 39 | #include "pub_core_vki.h" |
| 40 | #include "pub_core_libcfile.h" |
sewardj | d7a02db | 2008-12-12 08:07:49 +0000 | [diff] [blame] | 41 | #include "pub_core_seqmatch.h" |
njn | af1d7df | 2005-06-11 01:31:52 +0000 | [diff] [blame] | 42 | #include "pub_core_mallocfree.h" |
njn | 2024234 | 2005-05-16 23:31:24 +0000 | [diff] [blame] | 43 | #include "pub_core_options.h" |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 44 | #include "pub_core_oset.h" |
njn | d1af003 | 2005-05-29 17:01:48 +0000 | [diff] [blame] | 45 | #include "pub_core_redir.h" |
njn | a7598f6 | 2005-06-18 03:27:58 +0000 | [diff] [blame] | 46 | #include "pub_core_trampoline.h" |
njn | 8bddf58 | 2005-05-13 23:40:55 +0000 | [diff] [blame] | 47 | #include "pub_core_transtab.h" |
sewardj | 461c69d | 2005-11-17 20:15:04 +0000 | [diff] [blame] | 48 | #include "pub_core_tooliface.h" // VG_(needs).malloc_replacement |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 49 | #include "pub_core_machine.h" // VG_(fnptr_to_fnentry) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 50 | #include "pub_core_aspacemgr.h" // VG_(am_find_nsegment) |
sewardj | 14c7cc5 | 2007-02-25 15:08:24 +0000 | [diff] [blame] | 51 | #include "pub_core_xarray.h" |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 52 | #include "pub_core_clientstate.h" // VG_(client___libc_freeres_wrapper) |
| 53 | #include "pub_core_demangle.h" // VG_(maybe_Z_demangle) |
philippe | 277eaff | 2012-03-03 12:01:48 +0000 | [diff] [blame] | 54 | #include "pub_core_libcproc.h" // VG_(libdir) |
sewardj | 461c69d | 2005-11-17 20:15:04 +0000 | [diff] [blame] | 55 | |
bart | 8219bff | 2014-09-13 10:53:00 +0000 | [diff] [blame] | 56 | #include "config.h" /* GLIBC_MANDATORY_*_REDIRECT */ |
bart | 257b91b | 2009-12-31 13:31:11 +0000 | [diff] [blame] | 57 | |
sewardj | 55f9d1a | 2005-04-25 11:11:44 +0000 | [diff] [blame] | 58 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 59 | /* This module is a critical part of the redirection/intercept system. |
| 60 | It keeps track of the current intercept state, cleans up the |
| 61 | translation caches when that state changes, and finally, answers |
| 62 | queries about the whether an address is currently redirected or |
| 63 | not. It doesn't do any of the control-flow trickery needed to put |
| 64 | the redirections into practice. That is the job of m_translate, |
| 65 | which calls here to find out which translations need to be |
| 66 | redirected. |
| 67 | |
| 68 | The interface is simple. VG_(redir_initialise) initialises and |
| 69 | loads some hardwired redirects which never disappear; this is |
| 70 | platform-specific. |
| 71 | |
| 72 | The module is notified of redirection state changes by m_debuginfo. |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 73 | That calls VG_(redir_notify_new_DebugInfo) when a new DebugInfo |
| 74 | (shared object symbol table, basically) appears. Appearance of new |
| 75 | symbols can cause new (active) redirections to appear for two |
| 76 | reasons: the symbols in the new table may match existing |
| 77 | redirection specifications (see comments below), and because the |
| 78 | symbols in the new table may themselves supply new redirect |
| 79 | specifications which match existing symbols (or ones in the new |
| 80 | table). |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 81 | |
| 82 | Redirect specifications are really symbols with "funny" prefixes |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 83 | (_vgrNNNNZU_ and _vgrNNNNZZ_). These names tell m_redir that the |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 84 | associated code should replace the standard entry point for some |
| 85 | set of functions. The set of functions is specified by a (soname |
| 86 | pattern, function name pattern) pair which is encoded in the symbol |
| 87 | name following the prefix. The names use a Z-encoding scheme so |
| 88 | that they may contain punctuation characters and wildcards (*). |
| 89 | The encoding scheme is described in pub_tool_redir.h and is decoded |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 90 | by VG_(maybe_Z_demangle). The NNNN are behavioural equivalence |
| 91 | class tags, and are used to by code in this module to resolve |
| 92 | situations where one address appears to be redirected to more than |
| 93 | one replacement/wrapper. This is also described in |
| 94 | pub_tool_redir.h. |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 95 | |
| 96 | When a shared object is unloaded, this module learns of it via a |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 97 | call to VG_(redir_notify_delete_DebugInfo). It then removes from |
| 98 | its tables all active redirections in any way associated with that |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 99 | object, and tidies up the translation caches accordingly. |
| 100 | |
| 101 | That takes care of tracking the redirection state. When a |
| 102 | translation is actually to be made, m_translate calls to |
| 103 | VG_(redir_do_lookup) in this module to find out if the |
| 104 | translation's address should be redirected. |
| 105 | */ |
| 106 | |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 107 | /*------------------------------------------------------------*/ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 108 | /*--- Semantics ---*/ |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 109 | /*------------------------------------------------------------*/ |
| 110 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 111 | /* The redirector holds two pieces of state: |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 112 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 113 | Specs - a set of (soname pattern, fnname pattern) -> redir addr |
| 114 | Active - a set of orig addr -> (bool, redir addr) |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 115 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 116 | Active is the currently active set of bindings that the translator |
| 117 | consults. Specs is the current set of specifications as harvested |
| 118 | from reading symbol tables of the currently loaded objects. |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 119 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 120 | Active is a pure function of Specs and the current symbol table |
| 121 | state (maintained by m_debuginfo). Call the latter SyminfoState. |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 122 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 123 | Therefore whenever either Specs or SyminfoState changes, Active |
| 124 | must be recomputed. [Inefficient if done naively, but this is a |
| 125 | spec]. |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 126 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 127 | Active is computed as follows: |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 128 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 129 | Active = empty |
| 130 | for spec in Specs { |
| 131 | sopatt = spec.soname pattern |
| 132 | fnpatt = spec.fnname pattern |
| 133 | redir = spec.redir addr |
| 134 | for so matching sopatt in SyminfoState { |
| 135 | for fn matching fnpatt in fnnames_of(so) { |
| 136 | &fn -> redir is added to Active |
| 137 | } |
| 138 | } |
tom | 748a131 | 2005-04-02 15:53:01 +0000 | [diff] [blame] | 139 | } |
| 140 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 141 | [as an implementation detail, when a binding (orig -> redir) is |
| 142 | deleted from Active as a result of recomputing it, then all |
| 143 | translations intersecting redir must be deleted. However, this is |
| 144 | not part of the spec]. |
| 145 | |
| 146 | [Active also depends on where the aspacemgr has decided to put all |
| 147 | the pieces of code -- that affects the "orig addr" and "redir addr" |
| 148 | values.] |
| 149 | |
| 150 | --------------------- |
| 151 | |
| 152 | That completes the spec, apart from one difficult issue: duplicates. |
| 153 | |
| 154 | Clearly we must impose the requirement that domain(Active) contains |
| 155 | no duplicates. The difficulty is how to constrain Specs enough to |
| 156 | avoid getting into that situation. It's easy to write specs which |
| 157 | could cause conflicting bindings in Active, eg: |
| 158 | |
| 159 | (libpthread.so, pthread_mutex_lock) -> a1 |
| 160 | (libpthread.so, pthread_*) -> a2 |
| 161 | |
| 162 | for a1 != a2. Or even hairier: |
| 163 | |
| 164 | (libpthread.so, pthread_mutex_*) -> a1 |
| 165 | (libpthread.so, pthread_*_lock) -> a2 |
| 166 | |
| 167 | I can't think of any sane way of detecting when an addition to |
| 168 | Specs would generate conflicts. However, considering we don't |
| 169 | actually want to have a system that allows this, I propose this: |
| 170 | all changes to Specs are acceptable. But, when recomputing Active |
| 171 | following the change, if the same orig is bound to more than one |
| 172 | redir, then the first binding for orig is retained, and all the |
| 173 | rest ignored. |
| 174 | |
| 175 | =========================================================== |
| 176 | =========================================================== |
| 177 | Incremental implementation: |
| 178 | |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 179 | When a new DebugInfo appears: |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 180 | - it may be the source of new specs |
| 181 | - it may be the source of new matches for existing specs |
| 182 | Therefore: |
| 183 | |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 184 | - (new Specs x existing DebugInfos): scan all symbols in the new |
| 185 | DebugInfo to find new specs. Each of these needs to be compared |
| 186 | against all symbols in all the existing DebugInfos to generate |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 187 | new actives. |
| 188 | |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 189 | - (existing Specs x new DebugInfo): scan all symbols in the |
| 190 | DebugInfo, trying to match them to any existing specs, also |
| 191 | generating new actives. |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 192 | |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 193 | - (new Specs x new DebugInfo): scan all symbols in the new |
| 194 | DebugInfo, trying to match them against the new specs, to |
| 195 | generate new actives. |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 196 | |
| 197 | - Finally, add new new specs to the current set of specs. |
| 198 | |
| 199 | When adding a new active (s,d) to the Actives: |
| 200 | lookup s in Actives |
| 201 | if already bound to d, ignore |
| 202 | if already bound to something other than d, complain loudly and ignore |
| 203 | else add (s,d) to Actives |
| 204 | and discard (s,1) and (d,1) (maybe overly conservative) |
| 205 | |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 206 | When a DebugInfo disappears: |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 207 | - delete all specs acquired from the seginfo |
| 208 | - delete all actives derived from the just-deleted specs |
| 209 | - if each active (s,d) deleted, discard (s,1) and (d,1) |
| 210 | */ |
| 211 | |
| 212 | |
| 213 | /*------------------------------------------------------------*/ |
| 214 | /*--- REDIRECTION SPECIFICATIONS ---*/ |
| 215 | /*------------------------------------------------------------*/ |
| 216 | |
| 217 | /* A specification of a redirection we want to do. Note that because |
| 218 | both the "from" soname and function name may contain wildcards, the |
sewardj | 5092a97 | 2007-11-16 18:45:40 +0000 | [diff] [blame] | 219 | spec can match an arbitrary number of times. |
| 220 | |
| 221 | 16 Nov 2007: Comments re .mandatory field: The initial motivation |
| 222 | for this is making Memcheck work sanely on glibc-2.6.X ppc32-linux. |
| 223 | We really need to intercept 'strlen' in ld.so right from startup. |
| 224 | If ld.so does not have a visible 'strlen' symbol, Memcheck |
| 225 | generates an impossible number of errors resulting from highly |
| 226 | tuned strlen implementation in ld.so, and is completely unusable |
| 227 | -- the resulting undefinedness eventually seeps everywhere. */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 228 | typedef |
| 229 | struct _Spec { |
| 230 | struct _Spec* next; /* linked list */ |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 231 | /* FIXED PARTS -- set when created and not changed */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 232 | HChar* from_sopatt; /* from soname pattern */ |
| 233 | HChar* from_fnpatt; /* from fnname pattern */ |
| 234 | Addr to_addr; /* where redirecting to */ |
| 235 | Bool isWrap; /* wrap or replacement? */ |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 236 | Int becTag; /* 0 through 9999. Behavioural equivalance class tag. |
| 237 | If two wrappers have the same (non-zero) tag, they |
| 238 | are promising that they behave identically. */ |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 239 | Int becPrio; /* 0 through 9. Behavioural equivalence class prio. |
| 240 | Used to choose between competing wrappers with |
| 241 | the same (non-zero) tag. */ |
sewardj | f499c7d | 2009-08-10 19:39:02 +0000 | [diff] [blame] | 242 | const HChar** mandatory; /* non-NULL ==> abort V and print the |
| 243 | strings if from_sopatt is loaded but |
| 244 | from_fnpatt cannot be found */ |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 245 | /* VARIABLE PARTS -- used transiently whilst processing redirections */ |
| 246 | Bool mark; /* set if spec requires further processing */ |
| 247 | Bool done; /* set if spec was successfully matched */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 248 | } |
| 249 | Spec; |
| 250 | |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 251 | /* Top-level data structure. It contains a pointer to a DebugInfo and |
| 252 | also a list of the specs harvested from that DebugInfo. Note that |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 253 | seginfo is allowed to be NULL, meaning that the specs are |
| 254 | pre-loaded ones at startup and are not associated with any |
| 255 | particular seginfo. */ |
| 256 | typedef |
| 257 | struct _TopSpec { |
| 258 | struct _TopSpec* next; /* linked list */ |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 259 | const DebugInfo* seginfo; /* symbols etc */ |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 260 | Spec* specs; /* specs pulled out of seginfo */ |
| 261 | Bool mark; /* transient temporary used during deletion */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 262 | } |
| 263 | TopSpec; |
| 264 | |
| 265 | /* This is the top level list of redirections. m_debuginfo maintains |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 266 | a list of DebugInfos, and the idea here is to maintain a list with |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 267 | the same number of elements (in fact, with one more element, so as |
| 268 | to record abovementioned preloaded specifications.) */ |
| 269 | static TopSpec* topSpecs = NULL; |
| 270 | |
| 271 | |
| 272 | /*------------------------------------------------------------*/ |
| 273 | /*--- CURRENTLY ACTIVE REDIRECTIONS ---*/ |
| 274 | /*------------------------------------------------------------*/ |
| 275 | |
| 276 | /* Represents a currently active binding. If either parent_spec or |
| 277 | parent_sym is NULL, then this binding was hardwired at startup and |
| 278 | should not be deleted. Same is true if either parent's seginfo |
| 279 | field is NULL. */ |
| 280 | typedef |
| 281 | struct { |
| 282 | Addr from_addr; /* old addr -- MUST BE THE FIRST WORD! */ |
| 283 | Addr to_addr; /* where redirecting to */ |
| 284 | TopSpec* parent_spec; /* the TopSpec which supplied the Spec */ |
| 285 | TopSpec* parent_sym; /* the TopSpec which supplied the symbol */ |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 286 | Int becTag; /* behavioural eclass tag for ::to_addr */ |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 287 | Int becPrio; /* and its priority */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 288 | Bool isWrap; /* wrap or replacement? */ |
tom | d264514 | 2009-10-29 09:27:11 +0000 | [diff] [blame] | 289 | Bool isIFunc; /* indirect function? */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 290 | } |
| 291 | Active; |
| 292 | |
| 293 | /* The active set is a fast lookup table */ |
| 294 | static OSet* activeSet = NULL; |
| 295 | |
tom | d264514 | 2009-10-29 09:27:11 +0000 | [diff] [blame] | 296 | /* Wrapper routine for indirect functions */ |
| 297 | static Addr iFuncWrapper; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 298 | |
| 299 | /*------------------------------------------------------------*/ |
| 300 | /*--- FWDses ---*/ |
| 301 | /*------------------------------------------------------------*/ |
| 302 | |
| 303 | static void maybe_add_active ( Active /*by value; callee copies*/ ); |
| 304 | |
florian | 54fe202 | 2012-10-27 23:07:42 +0000 | [diff] [blame] | 305 | static void* dinfo_zalloc(const HChar* ec, SizeT); |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 306 | static void dinfo_free(void*); |
florian | 54fe202 | 2012-10-27 23:07:42 +0000 | [diff] [blame] | 307 | static HChar* dinfo_strdup(const HChar* ec, const HChar*); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 308 | static Bool is_plausible_guest_addr(Addr); |
| 309 | |
florian | 54fe202 | 2012-10-27 23:07:42 +0000 | [diff] [blame] | 310 | static void show_redir_state ( const HChar* who ); |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 311 | static void show_active ( const HChar* left, const Active* act ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 312 | |
florian | 19f91bb | 2012-11-10 22:29:54 +0000 | [diff] [blame] | 313 | static void handle_maybe_load_notifier( const HChar* soname, |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 314 | const HChar* symbol, Addr addr ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 315 | |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 316 | static void handle_require_text_symbols ( const DebugInfo* ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 317 | |
| 318 | /*------------------------------------------------------------*/ |
| 319 | /*--- NOTIFICATIONS ---*/ |
| 320 | /*------------------------------------------------------------*/ |
| 321 | |
| 322 | static |
| 323 | void generate_and_add_actives ( |
| 324 | /* spec list and the owning TopSpec */ |
| 325 | Spec* specs, |
| 326 | TopSpec* parent_spec, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 327 | /* debuginfo and the owning TopSpec */ |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 328 | const DebugInfo* di, |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 329 | TopSpec* parent_sym |
| 330 | ); |
| 331 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 332 | |
| 333 | /* Copy all the names from a given symbol into an AR_DINFO allocated, |
| 334 | NULL terminated array, for easy iteration. Caller must pass also |
| 335 | the address of a 2-entry array which can be used in the common case |
| 336 | to avoid dynamic allocation. */ |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 337 | static const HChar** alloc_symname_array ( const HChar* pri_name, |
| 338 | const HChar** sec_names, |
| 339 | const HChar** twoslots ) |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 340 | { |
| 341 | /* Special-case the common case: only one name. We expect the |
| 342 | caller to supply a stack-allocated 2-entry array for this. */ |
| 343 | if (sec_names == NULL) { |
| 344 | twoslots[0] = pri_name; |
| 345 | twoslots[1] = NULL; |
| 346 | return twoslots; |
| 347 | } |
| 348 | /* Else must use dynamic allocation. Figure out size .. */ |
| 349 | Word n_req = 1; |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 350 | const HChar** pp = sec_names; |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 351 | while (*pp) { n_req++; pp++; } |
| 352 | /* .. allocate and copy in. */ |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 353 | const HChar** arr = dinfo_zalloc("redir.asa.1", (n_req+1) * sizeof(HChar*)); |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 354 | Word i = 0; |
| 355 | arr[i++] = pri_name; |
| 356 | pp = sec_names; |
| 357 | while (*pp) { arr[i++] = *pp; pp++; } |
florian | e2800c9 | 2014-09-15 20:57:45 +0000 | [diff] [blame] | 358 | vg_assert(i == n_req); |
| 359 | vg_assert(arr[n_req] == NULL); |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 360 | return arr; |
| 361 | } |
| 362 | |
| 363 | |
| 364 | /* Free the array allocated by alloc_symname_array, if any. */ |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 365 | static void free_symname_array ( const HChar** names, const HChar** twoslots ) |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 366 | { |
| 367 | if (names != twoslots) |
| 368 | dinfo_free(names); |
| 369 | } |
| 370 | |
philippe | 1e470b5 | 2012-05-11 19:33:46 +0000 | [diff] [blame] | 371 | static HChar const* advance_to_equal ( HChar const* c ) { |
| 372 | while (*c && *c != '=') { |
| 373 | ++c; |
| 374 | } |
| 375 | return c; |
| 376 | } |
| 377 | static HChar const* advance_to_comma ( HChar const* c ) { |
| 378 | while (*c && *c != ',') { |
| 379 | ++c; |
| 380 | } |
| 381 | return c; |
| 382 | } |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 383 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 384 | /* Notify m_redir of the arrival of a new DebugInfo. This is fairly |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 385 | complex, but the net effect is to (1) add a new entry to the |
| 386 | topspecs list, and (2) figure out what new binding are now active, |
| 387 | and, as a result, add them to the actives mapping. */ |
| 388 | |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 389 | void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi ) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 390 | { |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 391 | Bool ok, isWrap; |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 392 | Int i, nsyms, becTag, becPrio; |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 393 | Spec* specList; |
| 394 | Spec* spec; |
| 395 | TopSpec* ts; |
| 396 | TopSpec* newts; |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 397 | const HChar* sym_name_pri; |
| 398 | const HChar** sym_names_sec; |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 399 | SymAVMAs sym_avmas; |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 400 | const HChar* demangled_sopatt; |
| 401 | const HChar* demangled_fnpatt; |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 402 | Bool check_ppcTOCs = False; |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 403 | Bool isText; |
florian | 19f91bb | 2012-11-10 22:29:54 +0000 | [diff] [blame] | 404 | const HChar* newdi_soname; |
philippe | 9848690 | 2014-08-19 22:46:44 +0000 | [diff] [blame] | 405 | Bool dehacktivate_pthread_stack_cache_var_search = False; |
| 406 | const HChar* const pthread_soname = "libpthread.so.0"; |
| 407 | const HChar* const pthread_stack_cache_actsize_varname |
| 408 | = "stack_cache_actsize"; |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 409 | #if defined(VGO_solaris) |
| 410 | Bool vg_vfork_fildes_var_search = False; |
| 411 | const HChar* const vg_preload_core_soname = "vgpreload_core.so.0"; |
| 412 | const HChar* const vg_vfork_fildes_varname = "vg_vfork_fildes"; |
| 413 | #endif |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 414 | |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 415 | # if defined(VG_PLAT_USES_PPCTOC) |
| 416 | check_ppcTOCs = True; |
| 417 | # endif |
| 418 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 419 | vg_assert(newdi); |
| 420 | newdi_soname = VG_(DebugInfo_get_soname)(newdi); |
| 421 | vg_assert(newdi_soname != NULL); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 422 | |
philippe | 277eaff | 2012-03-03 12:01:48 +0000 | [diff] [blame] | 423 | #ifdef ENABLE_INNER |
| 424 | { |
| 425 | /* When an outer Valgrind is executing an inner Valgrind, the |
| 426 | inner "sees" in its address space the mmap-ed vgpreload files |
| 427 | of the outer. The inner must avoid interpreting the |
| 428 | redirections given in the outer vgpreload mmap-ed files. |
| 429 | Otherwise, some tool combinations badly fail. |
| 430 | |
| 431 | Example: outer memcheck tool executing an inner none tool. |
| 432 | |
| 433 | If inner none interprets the outer malloc redirection, the |
| 434 | inner will redirect malloc to a memcheck function it does not |
| 435 | have (as the redirection target is from the outer). With |
| 436 | such a failed redirection, a call to malloc inside the inner |
| 437 | will then result in a "no-operation" (and so no memory will |
| 438 | be allocated). |
| 439 | |
| 440 | When running as an inner, no redirection will be done |
| 441 | for a vgpreload file if this file is not located in the |
| 442 | inner VALGRIND_LIB directory. |
| 443 | |
| 444 | Recognising a vgpreload file based on a filename pattern |
| 445 | is a kludge. An alternate solution would be to change |
| 446 | the _vgr prefix according to outer/inner/client. |
| 447 | */ |
florian | 19f91bb | 2012-11-10 22:29:54 +0000 | [diff] [blame] | 448 | const HChar* newdi_filename = VG_(DebugInfo_get_filename)(newdi); |
| 449 | const HChar* newdi_basename = VG_(basename) (newdi_filename); |
philippe | 277eaff | 2012-03-03 12:01:48 +0000 | [diff] [blame] | 450 | if (VG_(strncmp) (newdi_basename, "vgpreload_", 10) == 0) { |
| 451 | /* This looks like a vgpreload file => check if this file |
| 452 | is from the inner VALGRIND_LIB. |
| 453 | We do this check using VG_(stat) + dev/inode comparison |
| 454 | as vg-in-place defines a VALGRIND_LIB with symlinks |
| 455 | pointing to files inside the valgrind build directories. */ |
| 456 | struct vg_stat newdi_stat; |
| 457 | SysRes newdi_res; |
philippe | 277eaff | 2012-03-03 12:01:48 +0000 | [diff] [blame] | 458 | struct vg_stat in_vglib_stat; |
| 459 | SysRes in_vglib_res; |
| 460 | |
| 461 | newdi_res = VG_(stat)(newdi_filename, &newdi_stat); |
florian | 606afa9 | 2014-09-27 18:47:07 +0000 | [diff] [blame] | 462 | |
| 463 | HChar in_vglib_filename[VG_(strlen)(VG_(libdir)) + 1 + |
| 464 | VG_(strlen)(newdi_basename) + 1]; |
philippe | ed596b8 | 2014-09-28 16:13:09 +0000 | [diff] [blame] | 465 | VG_(sprintf)(in_vglib_filename, "%s/%s", VG_(libdir), newdi_basename); |
florian | 606afa9 | 2014-09-27 18:47:07 +0000 | [diff] [blame] | 466 | |
philippe | 277eaff | 2012-03-03 12:01:48 +0000 | [diff] [blame] | 467 | in_vglib_res = VG_(stat)(in_vglib_filename, &in_vglib_stat); |
| 468 | |
| 469 | /* If we find newdi_basename in inner VALGRIND_LIB |
| 470 | but newdi_filename is not the same file, then we do |
| 471 | not execute the redirection. */ |
| 472 | if (!sr_isError(in_vglib_res) |
| 473 | && !sr_isError(newdi_res) |
| 474 | && (newdi_stat.dev != in_vglib_stat.dev |
| 475 | || newdi_stat.ino != in_vglib_stat.ino)) { |
| 476 | /* <inner VALGRIND_LIB>/newdi_basename is an existing file |
| 477 | and is different of newdi_filename. |
| 478 | So, we do not execute newdi_filename redirection. */ |
| 479 | if ( VG_(clo_verbosity) > 1 ) { |
| 480 | VG_(message)( Vg_DebugMsg, |
| 481 | "Skipping vgpreload redir in %s" |
| 482 | " (not from VALGRIND_LIB_INNER)\n", |
| 483 | newdi_filename); |
| 484 | } |
| 485 | return; |
| 486 | } else { |
| 487 | if ( VG_(clo_verbosity) > 1 ) { |
| 488 | VG_(message)( Vg_DebugMsg, |
| 489 | "Executing vgpreload redir in %s" |
| 490 | " (from VALGRIND_LIB_INNER)\n", |
| 491 | newdi_filename); |
| 492 | } |
| 493 | } |
| 494 | } |
| 495 | } |
| 496 | #endif |
| 497 | |
| 498 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 499 | /* stay sane: we don't already have this. */ |
| 500 | for (ts = topSpecs; ts; ts = ts->next) |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 501 | vg_assert(ts->seginfo != newdi); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 502 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 503 | /* scan this DebugInfo's symbol table, pulling out and demangling |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 504 | any specs found */ |
| 505 | |
| 506 | specList = NULL; /* the spec list we're building up */ |
| 507 | |
philippe | 9848690 | 2014-08-19 22:46:44 +0000 | [diff] [blame] | 508 | dehacktivate_pthread_stack_cache_var_search = |
| 509 | SimHintiS(SimHint_no_nptl_pthread_stackcache, VG_(clo_sim_hints)) |
| 510 | && 0 == VG_(strcmp)(newdi_soname, pthread_soname); |
| 511 | |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 512 | #if defined(VGO_solaris) |
| 513 | vg_vfork_fildes_var_search = |
| 514 | 0 == VG_(strcmp)(newdi_soname, vg_preload_core_soname); |
| 515 | #endif |
| 516 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 517 | nsyms = VG_(DebugInfo_syms_howmany)( newdi ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 518 | for (i = 0; i < nsyms; i++) { |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 519 | VG_(DebugInfo_syms_getidx)( newdi, i, &sym_avmas, |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 520 | NULL, &sym_name_pri, &sym_names_sec, |
| 521 | &isText, NULL ); |
| 522 | /* Set up to conveniently iterate over all names for this symbol. */ |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 523 | const HChar* twoslots[2]; |
| 524 | const HChar** names_init = |
| 525 | alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]); |
| 526 | const HChar** names; |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 527 | for (names = names_init; *names; names++) { |
| 528 | ok = VG_(maybe_Z_demangle)( *names, |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 529 | &demangled_sopatt, |
| 530 | &demangled_fnpatt, |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 531 | &isWrap, &becTag, &becPrio ); |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 532 | /* ignore data symbols */ |
philippe | 9848690 | 2014-08-19 22:46:44 +0000 | [diff] [blame] | 533 | if (!isText) { |
| 534 | /* But search for dehacktivate stack cache var if needed. */ |
| 535 | if (dehacktivate_pthread_stack_cache_var_search |
| 536 | && 0 == VG_(strcmp)(*names, |
| 537 | pthread_stack_cache_actsize_varname)) { |
| 538 | if ( VG_(clo_verbosity) > 1 ) { |
| 539 | VG_(message)( Vg_DebugMsg, |
| 540 | "deactivate nptl pthread stackcache via kludge:" |
| 541 | " found symbol %s at addr %p\n", |
| 542 | *names, (void*) sym_avmas.main); |
| 543 | } |
| 544 | VG_(client__stack_cache_actsize__addr) = (SizeT*) sym_avmas.main; |
| 545 | dehacktivate_pthread_stack_cache_var_search = False; |
| 546 | } |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 547 | #if defined(VGO_solaris) |
| 548 | if (vg_vfork_fildes_var_search |
| 549 | && 0 == VG_(strcmp)(*names, vg_vfork_fildes_varname)) { |
| 550 | if ( VG_(clo_verbosity) > 1 ) { |
| 551 | VG_(message)( Vg_DebugMsg, |
| 552 | "vfork kludge: found symbol %s at addr %p\n", |
| 553 | *names, (void*) sym_avmas.main); |
| 554 | } |
| 555 | VG_(vfork_fildes_addr) = (Int*) sym_avmas.main; |
| 556 | vg_vfork_fildes_var_search = False; |
| 557 | } |
| 558 | #endif |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 559 | continue; |
philippe | 9848690 | 2014-08-19 22:46:44 +0000 | [diff] [blame] | 560 | } |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 561 | if (!ok) { |
| 562 | /* It's not a full-scale redirect, but perhaps it is a load-notify |
| 563 | fn? Let the load-notify department see it. */ |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 564 | handle_maybe_load_notifier( newdi_soname, *names, sym_avmas.main ); |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 565 | continue; |
| 566 | } |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 567 | if (check_ppcTOCs && GET_TOCPTR_AVMA(sym_avmas) == 0) { |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 568 | /* This platform uses toc pointers, but none could be found |
| 569 | for this symbol, so we can't safely redirect/wrap to it. |
| 570 | Just skip it; we'll make a second pass over the symbols in |
| 571 | the following loop, and complain at that point. */ |
| 572 | continue; |
| 573 | } |
philippe | 1e470b5 | 2012-05-11 19:33:46 +0000 | [diff] [blame] | 574 | |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 575 | HChar *replaced_sopatt = NULL; |
philippe | 1e470b5 | 2012-05-11 19:33:46 +0000 | [diff] [blame] | 576 | if (0 == VG_(strncmp) (demangled_sopatt, |
| 577 | VG_SO_SYN_PREFIX, VG_SO_SYN_PREFIX_LEN)) { |
| 578 | /* This is a redirection for handling lib so synonyms. If we |
| 579 | have a matching lib synonym, then replace the sopatt. |
| 580 | Otherwise, just ignore this redirection spec. */ |
| 581 | |
| 582 | if (!VG_(clo_soname_synonyms)) |
| 583 | continue; // No synonyms => skip the redir. |
| 584 | |
| 585 | /* Search for a matching synonym=newname*/ |
| 586 | SizeT const sopatt_syn_len |
| 587 | = VG_(strlen)(demangled_sopatt+VG_SO_SYN_PREFIX_LEN); |
| 588 | HChar const* last = VG_(clo_soname_synonyms); |
| 589 | |
| 590 | while (*last) { |
| 591 | HChar const* first = last; |
| 592 | last = advance_to_equal(first); |
| 593 | |
| 594 | if ((last - first) == sopatt_syn_len |
| 595 | && 0 == VG_(strncmp)(demangled_sopatt+VG_SO_SYN_PREFIX_LEN, |
| 596 | first, |
| 597 | sopatt_syn_len)) { |
| 598 | // Found the demangle_sopatt synonym => replace it |
| 599 | first = last + 1; |
| 600 | last = advance_to_comma(first); |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 601 | replaced_sopatt = dinfo_zalloc("redir.rnnD.5", |
| 602 | last - first + 1); |
| 603 | VG_(strncpy)(replaced_sopatt, first, last - first); |
| 604 | replaced_sopatt[last - first] = '\0'; |
| 605 | demangled_sopatt = replaced_sopatt; |
philippe | 1e470b5 | 2012-05-11 19:33:46 +0000 | [diff] [blame] | 606 | break; |
| 607 | } |
| 608 | |
| 609 | last = advance_to_comma(last); |
| 610 | if (*last == ',') |
| 611 | last++; |
| 612 | } |
| 613 | |
| 614 | // If we have not replaced the sopatt, then skip the redir. |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 615 | if (replaced_sopatt == NULL) |
philippe | 1e470b5 | 2012-05-11 19:33:46 +0000 | [diff] [blame] | 616 | continue; |
| 617 | } |
| 618 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 619 | spec = dinfo_zalloc("redir.rnnD.1", sizeof(Spec)); |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 620 | spec->from_sopatt = dinfo_strdup("redir.rnnD.2", demangled_sopatt); |
| 621 | spec->from_fnpatt = dinfo_strdup("redir.rnnD.3", demangled_fnpatt); |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 622 | spec->to_addr = sym_avmas.main; |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 623 | spec->isWrap = isWrap; |
| 624 | spec->becTag = becTag; |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 625 | spec->becPrio = becPrio; |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 626 | /* check we're not adding manifestly stupid destinations */ |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 627 | vg_assert(is_plausible_guest_addr(sym_avmas.main)); |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 628 | spec->next = specList; |
| 629 | spec->mark = False; /* not significant */ |
| 630 | spec->done = False; /* not significant */ |
| 631 | specList = spec; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 632 | } |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 633 | free_symname_array(names_init, &twoslots[0]); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 634 | } |
philippe | 9848690 | 2014-08-19 22:46:44 +0000 | [diff] [blame] | 635 | if (dehacktivate_pthread_stack_cache_var_search) { |
| 636 | VG_(message)(Vg_DebugMsg, |
| 637 | "WARNING: could not find symbol for var %s in %s\n", |
| 638 | pthread_stack_cache_actsize_varname, pthread_soname); |
| 639 | VG_(message)(Vg_DebugMsg, |
| 640 | "=> pthread stack cache cannot be disabled!\n"); |
| 641 | } |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 642 | #if defined(VGO_solaris) |
| 643 | if (vg_vfork_fildes_var_search) { |
| 644 | VG_(message)(Vg_DebugMsg, |
| 645 | "WARNING: could not find symbol for var %s in %s\n", |
| 646 | vg_vfork_fildes_varname, vg_preload_core_soname); |
| 647 | VG_(message)(Vg_DebugMsg, |
| 648 | "=> posix_spawn() will not work correctly!\n"); |
| 649 | } |
| 650 | #endif |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 651 | |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 652 | if (check_ppcTOCs) { |
| 653 | for (i = 0; i < nsyms; i++) { |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 654 | VG_(DebugInfo_syms_getidx)( newdi, i, &sym_avmas, |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 655 | NULL, &sym_name_pri, &sym_names_sec, |
sewardj | a5cace0 | 2011-08-15 09:42:34 +0000 | [diff] [blame] | 656 | &isText, NULL ); |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 657 | const HChar* twoslots[2]; |
| 658 | const HChar** names_init = |
| 659 | alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]); |
| 660 | const HChar** names; |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 661 | for (names = names_init; *names; names++) { |
| 662 | ok = isText |
| 663 | && VG_(maybe_Z_demangle)( |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 664 | *names, &demangled_sopatt, |
| 665 | &demangled_fnpatt, &isWrap, NULL, NULL ); |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 666 | if (!ok) |
| 667 | /* not a redirect. Ignore. */ |
| 668 | continue; |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 669 | if (GET_TOCPTR_AVMA(sym_avmas) != 0) |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 670 | /* has a valid toc pointer. Ignore. */ |
| 671 | continue; |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 672 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 673 | for (spec = specList; spec; spec = spec->next) |
| 674 | if (0 == VG_(strcmp)(spec->from_sopatt, demangled_sopatt) |
| 675 | && 0 == VG_(strcmp)(spec->from_fnpatt, demangled_fnpatt)) |
| 676 | break; |
| 677 | if (spec) |
| 678 | /* a redirect to some other copy of that symbol, which |
| 679 | does have a TOC value, already exists */ |
| 680 | continue; |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 681 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 682 | /* Complain */ |
| 683 | VG_(message)(Vg_DebugMsg, |
| 684 | "WARNING: no TOC ptr for redir/wrap to %s %s\n", |
| 685 | demangled_sopatt, demangled_fnpatt); |
| 686 | } |
| 687 | free_symname_array(names_init, &twoslots[0]); |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 688 | } |
| 689 | } |
| 690 | |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 691 | /* Ok. Now specList holds the list of specs from the DebugInfo. |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 692 | Build a new TopSpec, but don't add it to topSpecs yet. */ |
sewardj | 9c606bd | 2008-09-18 18:12:50 +0000 | [diff] [blame] | 693 | newts = dinfo_zalloc("redir.rnnD.4", sizeof(TopSpec)); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 694 | newts->next = NULL; /* not significant */ |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 695 | newts->seginfo = newdi; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 696 | newts->specs = specList; |
| 697 | newts->mark = False; /* not significant */ |
| 698 | |
| 699 | /* We now need to augment the active set with the following partial |
| 700 | cross product: |
| 701 | |
| 702 | (1) actives formed by matching the new specs in specList against |
| 703 | all symbols currently listed in topSpecs |
| 704 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 705 | (2) actives formed by matching the new symbols in newdi against |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 706 | all specs currently listed in topSpecs |
| 707 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 708 | (3) actives formed by matching the new symbols in newdi against |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 709 | the new specs in specList |
| 710 | |
| 711 | This is necessary in order to maintain the invariant that |
| 712 | Actives contains all bindings generated by matching ALL specs in |
| 713 | topSpecs against ALL symbols in topSpecs (that is, a cross |
| 714 | product of ALL known specs against ALL known symbols). |
| 715 | */ |
| 716 | /* Case (1) */ |
| 717 | for (ts = topSpecs; ts; ts = ts->next) { |
| 718 | if (ts->seginfo) |
| 719 | generate_and_add_actives( specList, newts, |
| 720 | ts->seginfo, ts ); |
| 721 | } |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 722 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 723 | /* Case (2) */ |
| 724 | for (ts = topSpecs; ts; ts = ts->next) { |
| 725 | generate_and_add_actives( ts->specs, ts, |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 726 | newdi, newts ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 727 | } |
| 728 | |
| 729 | /* Case (3) */ |
| 730 | generate_and_add_actives( specList, newts, |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 731 | newdi, newts ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 732 | |
| 733 | /* Finally, add the new TopSpec. */ |
| 734 | newts->next = topSpecs; |
| 735 | topSpecs = newts; |
| 736 | |
| 737 | if (VG_(clo_trace_redir)) |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 738 | show_redir_state("after VG_(redir_notify_new_DebugInfo)"); |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 739 | |
| 740 | /* Really finally (quite unrelated to all the above) check the |
| 741 | names in the module against any --require-text-symbol= |
| 742 | specifications we might have. */ |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 743 | handle_require_text_symbols(newdi); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 744 | } |
| 745 | |
tom | d264514 | 2009-10-29 09:27:11 +0000 | [diff] [blame] | 746 | /* Add a new target for an indirect function. Adds a new redirection |
| 747 | for the indirection function with address old_from that redirects |
| 748 | the ordinary function with address new_from to the target address |
| 749 | of the original redirection. */ |
| 750 | |
| 751 | void VG_(redir_add_ifunc_target)( Addr old_from, Addr new_from ) |
| 752 | { |
| 753 | Active *old, new; |
| 754 | |
| 755 | old = VG_(OSetGen_Lookup)(activeSet, &old_from); |
| 756 | vg_assert(old); |
| 757 | vg_assert(old->isIFunc); |
| 758 | |
| 759 | new = *old; |
| 760 | new.from_addr = new_from; |
| 761 | new.isIFunc = False; |
| 762 | maybe_add_active (new); |
| 763 | |
| 764 | if (VG_(clo_trace_redir)) { |
| 765 | VG_(message)( Vg_DebugMsg, |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 766 | "Adding redirect for indirect function " |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 767 | "0x%lx from 0x%lx -> 0x%lx\n", |
| 768 | old_from, new_from, new.to_addr ); |
tom | d264514 | 2009-10-29 09:27:11 +0000 | [diff] [blame] | 769 | } |
| 770 | } |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 771 | |
| 772 | /* Do one element of the basic cross product: add to the active set, |
| 773 | all matches resulting from comparing all the given specs against |
| 774 | all the symbols in the given seginfo. If a conflicting binding |
| 775 | would thereby arise, don't add it, but do complain. */ |
| 776 | |
| 777 | static |
| 778 | void generate_and_add_actives ( |
| 779 | /* spec list and the owning TopSpec */ |
| 780 | Spec* specs, |
| 781 | TopSpec* parent_spec, |
| 782 | /* seginfo and the owning TopSpec */ |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 783 | const DebugInfo* di, |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 784 | TopSpec* parent_sym |
| 785 | ) |
| 786 | { |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 787 | Spec* sp; |
| 788 | Bool anyMark, isText, isIFunc; |
| 789 | Active act; |
| 790 | Int nsyms, i; |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 791 | SymAVMAs sym_avmas; |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 792 | const HChar* sym_name_pri; |
| 793 | const HChar** sym_names_sec; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 794 | |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 795 | /* First figure out which of the specs match the seginfo's soname. |
| 796 | Also clear the 'done' bits, so that after the main loop below |
| 797 | tell which of the Specs really did get done. */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 798 | anyMark = False; |
| 799 | for (sp = specs; sp; sp = sp->next) { |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 800 | sp->done = False; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 801 | sp->mark = VG_(string_match)( sp->from_sopatt, |
sewardj | e3f1e59 | 2009-07-31 09:41:29 +0000 | [diff] [blame] | 802 | VG_(DebugInfo_get_soname)(di) ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 803 | anyMark = anyMark || sp->mark; |
| 804 | } |
| 805 | |
| 806 | /* shortcut: if none of the sonames match, there will be no bindings. */ |
| 807 | if (!anyMark) |
| 808 | return; |
| 809 | |
| 810 | /* Iterate outermost over the symbols in the seginfo, in the hope |
| 811 | of trashing the caches less. */ |
sewardj | e3f1e59 | 2009-07-31 09:41:29 +0000 | [diff] [blame] | 812 | nsyms = VG_(DebugInfo_syms_howmany)( di ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 813 | for (i = 0; i < nsyms; i++) { |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 814 | VG_(DebugInfo_syms_getidx)( di, i, &sym_avmas, |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 815 | NULL, &sym_name_pri, &sym_names_sec, |
| 816 | &isText, &isIFunc ); |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 817 | const HChar* twoslots[2]; |
| 818 | const HChar** names_init = |
| 819 | alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]); |
| 820 | const HChar** names; |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 821 | for (names = names_init; *names; names++) { |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 822 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 823 | /* ignore data symbols */ |
| 824 | if (!isText) |
| 825 | continue; |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 826 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 827 | for (sp = specs; sp; sp = sp->next) { |
| 828 | if (!sp->mark) |
| 829 | continue; /* soname doesn't match */ |
| 830 | if (VG_(string_match)( sp->from_fnpatt, *names )) { |
| 831 | /* got a new binding. Add to collection. */ |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 832 | act.from_addr = sym_avmas.main; |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 833 | act.to_addr = sp->to_addr; |
| 834 | act.parent_spec = parent_spec; |
| 835 | act.parent_sym = parent_sym; |
| 836 | act.becTag = sp->becTag; |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 837 | act.becPrio = sp->becPrio; |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 838 | act.isWrap = sp->isWrap; |
| 839 | act.isIFunc = isIFunc; |
| 840 | sp->done = True; |
| 841 | maybe_add_active( act ); |
carll | 582d582 | 2014-08-07 23:35:54 +0000 | [diff] [blame] | 842 | |
| 843 | /* If the function being wrapped has a local entry point |
| 844 | * redirect it to the global entry point. The redirection |
| 845 | * must save and setup r2 then setup r12 for the new function. |
| 846 | * On return, r2 must be restored. Local entry points used |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 847 | * in PPC64 Little Endian. |
carll | 582d582 | 2014-08-07 23:35:54 +0000 | [diff] [blame] | 848 | */ |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 849 | if (GET_LOCAL_EP_AVMA(sym_avmas) != 0) { |
| 850 | act.from_addr = GET_LOCAL_EP_AVMA(sym_avmas); |
carll | 582d582 | 2014-08-07 23:35:54 +0000 | [diff] [blame] | 851 | maybe_add_active( act ); |
| 852 | } |
| 853 | |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 854 | } |
| 855 | } /* for (sp = specs; sp; sp = sp->next) */ |
| 856 | |
| 857 | } /* iterating over names[] */ |
| 858 | free_symname_array(names_init, &twoslots[0]); |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 859 | } /* for (i = 0; i < nsyms; i++) */ |
| 860 | |
| 861 | /* Now, finally, look for Specs which were marked to be done, but |
| 862 | didn't get matched. If any such are mandatory we must abort the |
| 863 | system at this point. */ |
| 864 | for (sp = specs; sp; sp = sp->next) { |
| 865 | if (!sp->mark) |
| 866 | continue; |
| 867 | if (sp->mark && (!sp->done) && sp->mandatory) |
| 868 | break; |
| 869 | } |
| 870 | if (sp) { |
sewardj | f499c7d | 2009-08-10 19:39:02 +0000 | [diff] [blame] | 871 | const HChar** strp; |
florian | 6bd9dc1 | 2012-11-23 16:17:43 +0000 | [diff] [blame] | 872 | const HChar* v = "valgrind: "; |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 873 | vg_assert(sp->mark); |
| 874 | vg_assert(!sp->done); |
| 875 | vg_assert(sp->mandatory); |
| 876 | VG_(printf)("\n"); |
| 877 | VG_(printf)( |
| 878 | "%sFatal error at startup: a function redirection\n", v); |
| 879 | VG_(printf)( |
| 880 | "%swhich is mandatory for this platform-tool combination\n", v); |
| 881 | VG_(printf)( |
| 882 | "%scannot be set up. Details of the redirection are:\n", v); |
| 883 | VG_(printf)( |
| 884 | "%s\n", v); |
| 885 | VG_(printf)( |
| 886 | "%sA must-be-redirected function\n", v); |
| 887 | VG_(printf)( |
| 888 | "%swhose name matches the pattern: %s\n", v, sp->from_fnpatt); |
| 889 | VG_(printf)( |
| 890 | "%sin an object with soname matching: %s\n", v, sp->from_sopatt); |
| 891 | VG_(printf)( |
| 892 | "%swas not found whilst processing\n", v); |
| 893 | VG_(printf)( |
sewardj | e3f1e59 | 2009-07-31 09:41:29 +0000 | [diff] [blame] | 894 | "%ssymbols from the object with soname: %s\n", |
| 895 | v, VG_(DebugInfo_get_soname)(di)); |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 896 | VG_(printf)( |
| 897 | "%s\n", v); |
sewardj | b57e693 | 2009-08-02 12:21:31 +0000 | [diff] [blame] | 898 | |
| 899 | for (strp = sp->mandatory; *strp; strp++) |
| 900 | VG_(printf)( |
| 901 | "%s%s\n", v, *strp); |
| 902 | |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 903 | VG_(printf)( |
| 904 | "%s\n", v); |
| 905 | VG_(printf)( |
| 906 | "%sCannot continue -- exiting now. Sorry.\n", v); |
| 907 | VG_(printf)("\n"); |
| 908 | VG_(exit)(1); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 909 | } |
| 910 | } |
| 911 | |
| 912 | |
| 913 | /* Add an act (passed by value; is copied here) and deal with |
| 914 | conflicting bindings. */ |
| 915 | static void maybe_add_active ( Active act ) |
| 916 | { |
florian | 6bd9dc1 | 2012-11-23 16:17:43 +0000 | [diff] [blame] | 917 | const HChar* what = NULL; |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 918 | Active* old = NULL; |
| 919 | Bool add_act = False; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 920 | |
| 921 | /* Complain and ignore manifestly bogus 'from' addresses. |
| 922 | |
| 923 | Kludge: because this can get called befor the trampoline area (a |
| 924 | bunch of magic 'to' addresses) has its ownership changed from V |
| 925 | to C, we can't check the 'to' address similarly. Sigh. |
| 926 | |
| 927 | amd64-linux hack: the vsysinfo pages appear to have no |
| 928 | permissions |
| 929 | ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0 |
| 930 | so skip the check for them. */ |
| 931 | if (!is_plausible_guest_addr(act.from_addr) |
| 932 | # if defined(VGP_amd64_linux) |
| 933 | && act.from_addr != 0xFFFFFFFFFF600000ULL |
| 934 | && act.from_addr != 0xFFFFFFFFFF600400ULL |
tom | d6ae9e6 | 2012-02-09 11:54:16 +0000 | [diff] [blame] | 935 | && act.from_addr != 0xFFFFFFFFFF600800ULL |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 936 | # endif |
| 937 | ) { |
| 938 | what = "redirection from-address is in non-executable area"; |
| 939 | goto bad; |
| 940 | } |
| 941 | |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 942 | old = VG_(OSetGen_Lookup)( activeSet, &act.from_addr ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 943 | if (old) { |
| 944 | /* Dodgy. Conflicting binding. */ |
| 945 | vg_assert(old->from_addr == act.from_addr); |
| 946 | if (old->to_addr != act.to_addr) { |
sewardj | bd2cff2 | 2011-08-16 21:45:28 +0000 | [diff] [blame] | 947 | /* We've got a conflicting binding -- that is, from_addr is |
| 948 | specified to redirect to two different destinations, |
| 949 | old->to_addr and act.to_addr. If we can prove that they |
| 950 | are behaviourally equivalent then that's no problem. So |
| 951 | we can look at the behavioural eclass tags for both |
| 952 | functions to see if that's so. If they are equal, and |
| 953 | nonzero, then that's fine. But if not, we can't show they |
| 954 | are equivalent, so we have to complain, and ignore the new |
| 955 | binding. */ |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 956 | vg_assert(old->becTag >= 0 && old->becTag <= 9999); |
| 957 | vg_assert(old->becPrio >= 0 && old->becPrio <= 9); |
| 958 | vg_assert(act.becTag >= 0 && act.becTag <= 9999); |
| 959 | vg_assert(act.becPrio >= 0 && act.becPrio <= 9); |
| 960 | if (old->becTag == 0) |
| 961 | vg_assert(old->becPrio == 0); |
| 962 | if (act.becTag == 0) |
| 963 | vg_assert(act.becPrio == 0); |
| 964 | |
| 965 | if (old->becTag == 0 || act.becTag == 0 || old->becTag != act.becTag) { |
| 966 | /* We can't show that they are equivalent. Complain and |
| 967 | ignore. */ |
| 968 | what = "new redirection conflicts with existing -- ignoring it"; |
| 969 | goto bad; |
| 970 | } |
| 971 | /* They have the same eclass tag. Use the priorities to |
| 972 | resolve the ambiguity. */ |
| 973 | if (act.becPrio <= old->becPrio) { |
| 974 | /* The new one doesn't have a higher priority, so just |
| 975 | ignore it. */ |
sewardj | 14127d6 | 2011-08-17 21:23:21 +0000 | [diff] [blame] | 976 | if (VG_(clo_verbosity) > 2) { |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 977 | VG_(message)(Vg_UserMsg, "Ignoring %s redirection:\n", |
| 978 | act.becPrio < old->becPrio ? "lower priority" |
| 979 | : "duplicate"); |
sewardj | 14127d6 | 2011-08-17 21:23:21 +0000 | [diff] [blame] | 980 | show_active( " old: ", old); |
| 981 | show_active( " new: ", &act); |
| 982 | } |
sewardj | bd2cff2 | 2011-08-16 21:45:28 +0000 | [diff] [blame] | 983 | } else { |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 984 | /* The tricky case. The new one has a higher priority, so |
| 985 | we need to get the old one out of the OSet and install |
| 986 | this one in its place. */ |
| 987 | if (VG_(clo_verbosity) > 1) { |
| 988 | VG_(message)(Vg_UserMsg, |
| 989 | "Preferring higher priority redirection:\n"); |
| 990 | show_active( " old: ", old); |
| 991 | show_active( " new: ", &act); |
| 992 | } |
| 993 | add_act = True; |
| 994 | void* oldNd = VG_(OSetGen_Remove)( activeSet, &act.from_addr ); |
| 995 | vg_assert(oldNd == old); |
| 996 | VG_(OSetGen_FreeNode)( activeSet, old ); |
| 997 | old = NULL; |
sewardj | bd2cff2 | 2011-08-16 21:45:28 +0000 | [diff] [blame] | 998 | } |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 999 | } else { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1000 | /* This appears to be a duplicate of an existing binding. |
| 1001 | Safe(ish) -- ignore. */ |
| 1002 | /* XXXXXXXXXXX COMPLAIN if new and old parents differ */ |
tom | 748a131 | 2005-04-02 15:53:01 +0000 | [diff] [blame] | 1003 | } |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 1004 | |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 1005 | } else { |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 1006 | /* There's no previous binding for this from_addr, so we must |
| 1007 | add 'act' to the active set. */ |
| 1008 | add_act = True; |
| 1009 | } |
| 1010 | |
| 1011 | /* So, finally, actually add it. */ |
| 1012 | if (add_act) { |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1013 | Active* a = VG_(OSetGen_AllocNode)(activeSet, sizeof(Active)); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1014 | vg_assert(a); |
| 1015 | *a = act; |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1016 | VG_(OSetGen_Insert)(activeSet, a); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1017 | /* Now that a new from->to redirection is in force, we need to |
| 1018 | get rid of any translations intersecting 'from' in order that |
| 1019 | they get redirected to 'to'. So discard them. Just for |
| 1020 | paranoia (but, I believe, unnecessarily), discard 'to' as |
| 1021 | well. */ |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 1022 | VG_(discard_translations)( act.from_addr, 1, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1023 | "redir_new_DebugInfo(from_addr)"); |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 1024 | VG_(discard_translations)( act.to_addr, 1, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1025 | "redir_new_DebugInfo(to_addr)"); |
sewardj | 14127d6 | 2011-08-17 21:23:21 +0000 | [diff] [blame] | 1026 | if (VG_(clo_verbosity) > 2) { |
| 1027 | VG_(message)(Vg_UserMsg, "Adding active redirection:\n"); |
| 1028 | show_active( " new: ", &act); |
| 1029 | } |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1030 | } |
| 1031 | return; |
| 1032 | |
| 1033 | bad: |
| 1034 | vg_assert(what); |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 1035 | vg_assert(!add_act); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1036 | if (VG_(clo_verbosity) > 1) { |
sewardj | 738856f | 2009-07-15 14:48:32 +0000 | [diff] [blame] | 1037 | VG_(message)(Vg_UserMsg, "WARNING: %s\n", what); |
sewardj | bd2cff2 | 2011-08-16 21:45:28 +0000 | [diff] [blame] | 1038 | if (old) { |
| 1039 | show_active( " old: ", old); |
| 1040 | } |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1041 | show_active( " new: ", &act); |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 1042 | } |
tom | 748a131 | 2005-04-02 15:53:01 +0000 | [diff] [blame] | 1043 | } |
| 1044 | |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 1045 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1046 | /* Notify m_redir of the deletion of a DebugInfo. This is relatively |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1047 | simple -- just get rid of all actives derived from it, and free up |
| 1048 | the associated list elements. */ |
| 1049 | |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 1050 | void VG_(redir_notify_delete_DebugInfo)( const DebugInfo* delsi ) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1051 | { |
| 1052 | TopSpec* ts; |
| 1053 | TopSpec* tsPrev; |
| 1054 | Spec* sp; |
| 1055 | Spec* sp_next; |
| 1056 | OSet* tmpSet; |
| 1057 | Active* act; |
| 1058 | Bool delMe; |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1059 | Addr addr; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1060 | |
| 1061 | vg_assert(delsi); |
| 1062 | |
| 1063 | /* Search for it, and make tsPrev point to the previous entry, if |
| 1064 | any. */ |
| 1065 | tsPrev = NULL; |
| 1066 | ts = topSpecs; |
| 1067 | while (True) { |
| 1068 | if (ts == NULL) break; |
| 1069 | if (ts->seginfo == delsi) break; |
| 1070 | tsPrev = ts; |
| 1071 | ts = ts->next; |
| 1072 | } |
| 1073 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1074 | vg_assert(ts); /* else we don't have the deleted DebugInfo */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1075 | vg_assert(ts->seginfo == delsi); |
| 1076 | |
| 1077 | /* Traverse the actives, copying the addresses of those we intend |
| 1078 | to delete into tmpSet. */ |
sewardj | 9c606bd | 2008-09-18 18:12:50 +0000 | [diff] [blame] | 1079 | tmpSet = VG_(OSetWord_Create)(dinfo_zalloc, "redir.rndD.1", dinfo_free); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1080 | |
| 1081 | ts->mark = True; |
| 1082 | |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1083 | VG_(OSetGen_ResetIter)( activeSet ); |
| 1084 | while ( (act = VG_(OSetGen_Next)(activeSet)) ) { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1085 | delMe = act->parent_spec != NULL |
| 1086 | && act->parent_sym != NULL |
| 1087 | && act->parent_spec->seginfo != NULL |
| 1088 | && act->parent_sym->seginfo != NULL |
| 1089 | && (act->parent_spec->mark || act->parent_sym->mark); |
| 1090 | |
| 1091 | /* While we're at it, a bit of paranoia: delete any actives |
sewardj | e6647f4 | 2006-03-12 00:39:19 +0000 | [diff] [blame] | 1092 | which don't have both feet in valid client executable areas. |
| 1093 | But don't delete hardwired-at-startup ones; these are denoted |
| 1094 | by having parent_spec or parent_sym being NULL. */ |
| 1095 | if ( (!delMe) |
| 1096 | && act->parent_spec != NULL |
| 1097 | && act->parent_sym != NULL ) { |
| 1098 | if (!is_plausible_guest_addr(act->from_addr)) |
| 1099 | delMe = True; |
| 1100 | if (!is_plausible_guest_addr(act->to_addr)) |
| 1101 | delMe = True; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1102 | } |
| 1103 | |
| 1104 | if (delMe) { |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1105 | VG_(OSetWord_Insert)( tmpSet, act->from_addr ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1106 | /* While we have our hands on both the 'from' and 'to' |
| 1107 | of this Active, do paranoid stuff with tt/tc. */ |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 1108 | VG_(discard_translations)( act->from_addr, 1, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1109 | "redir_del_DebugInfo(from_addr)"); |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 1110 | VG_(discard_translations)( act->to_addr, 1, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1111 | "redir_del_DebugInfo(to_addr)"); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1112 | } |
| 1113 | } |
| 1114 | |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1115 | /* Now traverse tmpSet, deleting corresponding elements in activeSet. */ |
| 1116 | VG_(OSetWord_ResetIter)( tmpSet ); |
| 1117 | while ( VG_(OSetWord_Next)(tmpSet, &addr) ) { |
| 1118 | act = VG_(OSetGen_Remove)( activeSet, &addr ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1119 | vg_assert(act); |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1120 | VG_(OSetGen_FreeNode)( activeSet, act ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1121 | } |
| 1122 | |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1123 | VG_(OSetWord_Destroy)( tmpSet ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1124 | |
| 1125 | /* The Actives set is now cleaned up. Free up this TopSpec and |
| 1126 | everything hanging off it. */ |
| 1127 | for (sp = ts->specs; sp; sp = sp_next) { |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1128 | if (sp->from_sopatt) dinfo_free(sp->from_sopatt); |
| 1129 | if (sp->from_fnpatt) dinfo_free(sp->from_fnpatt); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1130 | sp_next = sp->next; |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1131 | dinfo_free(sp); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1132 | } |
| 1133 | |
| 1134 | if (tsPrev == NULL) { |
| 1135 | /* first in list */ |
| 1136 | topSpecs = ts->next; |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 1137 | } else { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1138 | tsPrev->next = ts->next; |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 1139 | } |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1140 | dinfo_free(ts); |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 1141 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1142 | if (VG_(clo_trace_redir)) |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1143 | show_redir_state("after VG_(redir_notify_delete_DebugInfo)"); |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 1144 | } |
| 1145 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1146 | |
| 1147 | /*------------------------------------------------------------*/ |
| 1148 | /*--- QUERIES (really the whole point of this module) ---*/ |
| 1149 | /*------------------------------------------------------------*/ |
| 1150 | |
| 1151 | /* This is the crucial redirection function. It answers the question: |
| 1152 | should this code address be redirected somewhere else? It's used |
| 1153 | just before translating a basic block. */ |
| 1154 | Addr VG_(redir_do_lookup) ( Addr orig, Bool* isWrap ) |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 1155 | { |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1156 | Active* r = VG_(OSetGen_Lookup)(activeSet, &orig); |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 1157 | if (r == NULL) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1158 | return orig; |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 1159 | |
| 1160 | vg_assert(r->to_addr != 0); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1161 | if (isWrap) |
tom | d264514 | 2009-10-29 09:27:11 +0000 | [diff] [blame] | 1162 | *isWrap = r->isWrap || r->isIFunc; |
tom | 3b42e16 | 2009-11-16 09:06:09 +0000 | [diff] [blame] | 1163 | if (r->isIFunc) { |
| 1164 | vg_assert(iFuncWrapper); |
tom | d264514 | 2009-10-29 09:27:11 +0000 | [diff] [blame] | 1165 | return iFuncWrapper; |
tom | 3b42e16 | 2009-11-16 09:06:09 +0000 | [diff] [blame] | 1166 | } |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 1167 | return r->to_addr; |
| 1168 | } |
| 1169 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1170 | |
| 1171 | /*------------------------------------------------------------*/ |
| 1172 | /*--- INITIALISATION ---*/ |
| 1173 | /*------------------------------------------------------------*/ |
| 1174 | |
| 1175 | /* Add a never-delete-me Active. */ |
| 1176 | |
| 1177 | __attribute__((unused)) /* only used on amd64 */ |
| 1178 | static void add_hardwired_active ( Addr from, Addr to ) |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 1179 | { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1180 | Active act; |
| 1181 | act.from_addr = from; |
| 1182 | act.to_addr = to; |
| 1183 | act.parent_spec = NULL; |
| 1184 | act.parent_sym = NULL; |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 1185 | act.becTag = 0; /* "not equivalent to any other fn" */ |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 1186 | act.becPrio = 0; /* mandatory when becTag == 0 */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1187 | act.isWrap = False; |
tom | b6fd365 | 2009-11-01 16:37:33 +0000 | [diff] [blame] | 1188 | act.isIFunc = False; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1189 | maybe_add_active( act ); |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 1190 | } |
| 1191 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1192 | |
| 1193 | /* Add a never-delete-me Spec. This is a bit of a kludge. On the |
| 1194 | assumption that this is called only at startup, only handle the |
| 1195 | case where topSpecs is completely empty, or if it isn't, it has |
| 1196 | just one entry and that is the one with NULL seginfo -- that is the |
| 1197 | entry that holds these initial specs. */ |
| 1198 | |
| 1199 | __attribute__((unused)) /* not used on all platforms */ |
florian | 6bd9dc1 | 2012-11-23 16:17:43 +0000 | [diff] [blame] | 1200 | static void add_hardwired_spec (const HChar* sopatt, const HChar* fnpatt, |
| 1201 | Addr to_addr, |
| 1202 | const HChar** mandatory ) |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 1203 | { |
sewardj | 9c606bd | 2008-09-18 18:12:50 +0000 | [diff] [blame] | 1204 | Spec* spec = dinfo_zalloc("redir.ahs.1", sizeof(Spec)); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1205 | |
| 1206 | if (topSpecs == NULL) { |
sewardj | 9c606bd | 2008-09-18 18:12:50 +0000 | [diff] [blame] | 1207 | topSpecs = dinfo_zalloc("redir.ahs.2", sizeof(TopSpec)); |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1208 | /* symtab_zalloc sets all fields to zero */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1209 | } |
| 1210 | |
| 1211 | vg_assert(topSpecs != NULL); |
| 1212 | vg_assert(topSpecs->next == NULL); |
| 1213 | vg_assert(topSpecs->seginfo == NULL); |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1214 | /* FIXED PARTS */ |
florian | 0e68012 | 2014-12-16 12:04:03 +0000 | [diff] [blame] | 1215 | /* Note, that these CONST_CAST will not cause a problem, in the sense |
| 1216 | that VG_(redir_notify_delete_DebugInfo) will delete them. The reason |
| 1217 | is that the TopSpec here has seginfo == NULL and such a TopSpec will |
| 1218 | never be freed. See the asserts at the beginning of said function. */ |
florian | 70a5de1 | 2014-10-22 12:53:16 +0000 | [diff] [blame] | 1219 | spec->from_sopatt = CONST_CAST(HChar *,sopatt); |
| 1220 | spec->from_fnpatt = CONST_CAST(HChar *,fnpatt); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1221 | spec->to_addr = to_addr; |
| 1222 | spec->isWrap = False; |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1223 | spec->mandatory = mandatory; |
| 1224 | /* VARIABLE PARTS */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1225 | spec->mark = False; /* not significant */ |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1226 | spec->done = False; /* not significant */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1227 | |
| 1228 | spec->next = topSpecs->specs; |
| 1229 | topSpecs->specs = spec; |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 1230 | } |
| 1231 | |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 1232 | |
sewardj | b57e693 | 2009-08-02 12:21:31 +0000 | [diff] [blame] | 1233 | __attribute__((unused)) /* not used on all platforms */ |
| 1234 | static const HChar* complain_about_stripped_glibc_ldso[] |
| 1235 | = { "Possible fixes: (1, short term): install glibc's debuginfo", |
| 1236 | "package on this machine. (2, longer term): ask the packagers", |
| 1237 | "for your Linux distribution to please in future ship a non-", |
| 1238 | "stripped ld.so (or whatever the dynamic linker .so is called)", |
| 1239 | "that exports the above-named function using the standard", |
sewardj | d85ee0c | 2011-02-11 16:47:03 +0000 | [diff] [blame] | 1240 | "calling conventions for this platform. The package you need", |
| 1241 | "to install for fix (1) is called", |
| 1242 | "", |
| 1243 | " On Debian, Ubuntu: libc6-dbg", |
| 1244 | " On SuSE, openSuSE, Fedora, RHEL: glibc-debuginfo", |
sewardj | b57e693 | 2009-08-02 12:21:31 +0000 | [diff] [blame] | 1245 | NULL |
| 1246 | }; |
| 1247 | |
| 1248 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1249 | /* Initialise the redir system, and create the initial Spec list and |
| 1250 | for amd64-linux a couple of permanent active mappings. The initial |
| 1251 | Specs are not converted into Actives yet, on the (checked) |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1252 | assumption that no DebugInfos have so far been created, and so when |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1253 | they are created, that will happen. */ |
| 1254 | |
| 1255 | void VG_(redir_initialise) ( void ) |
| 1256 | { |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1257 | // Assert that there are no DebugInfos so far |
sewardj | e3f1e59 | 2009-07-31 09:41:29 +0000 | [diff] [blame] | 1258 | vg_assert( VG_(next_DebugInfo)(NULL) == NULL ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1259 | |
| 1260 | // Initialise active mapping. |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1261 | activeSet = VG_(OSetGen_Create)(offsetof(Active, from_addr), |
| 1262 | NULL, // Use fast comparison |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1263 | dinfo_zalloc, |
sewardj | 9c606bd | 2008-09-18 18:12:50 +0000 | [diff] [blame] | 1264 | "redir.ri.1", |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1265 | dinfo_free); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1266 | |
| 1267 | // The rest of this function just adds initial Specs. |
| 1268 | |
| 1269 | # if defined(VGP_x86_linux) |
sewardj | 6a443b2 | 2005-11-20 19:37:54 +0000 | [diff] [blame] | 1270 | /* If we're using memcheck, use this intercept right from the |
| 1271 | start, otherwise ld.so (glibc-2.3.5) makes a lot of noise. */ |
| 1272 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
sewardj | d28cc96 | 2011-03-28 08:22:55 +0000 | [diff] [blame] | 1273 | const HChar** mandatory; |
bart | 8219bff | 2014-09-13 10:53:00 +0000 | [diff] [blame] | 1274 | # ifndef GLIBC_MANDATORY_INDEX_AND_STRLEN_REDIRECT |
sewardj | d28cc96 | 2011-03-28 08:22:55 +0000 | [diff] [blame] | 1275 | mandatory = NULL; |
| 1276 | # else |
| 1277 | /* for glibc-2.12 and later, this is mandatory - can't sanely |
| 1278 | continue without it */ |
| 1279 | mandatory = complain_about_stripped_glibc_ldso; |
| 1280 | # endif |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1281 | add_hardwired_spec( |
| 1282 | "ld-linux.so.2", "index", |
sewardj | d28cc96 | 2011-03-28 08:22:55 +0000 | [diff] [blame] | 1283 | (Addr)&VG_(x86_linux_REDIR_FOR_index), mandatory); |
| 1284 | add_hardwired_spec( |
| 1285 | "ld-linux.so.2", "strlen", |
| 1286 | (Addr)&VG_(x86_linux_REDIR_FOR_strlen), mandatory); |
sewardj | 6a443b2 | 2005-11-20 19:37:54 +0000 | [diff] [blame] | 1287 | } |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 1288 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1289 | # elif defined(VGP_amd64_linux) |
njn | d1af003 | 2005-05-29 17:01:48 +0000 | [diff] [blame] | 1290 | /* Redirect vsyscalls to local versions */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1291 | add_hardwired_active( |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 1292 | 0xFFFFFFFFFF600000ULL, |
tom | d6ae9e6 | 2012-02-09 11:54:16 +0000 | [diff] [blame] | 1293 | (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday) |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 1294 | ); |
tom | d6ae9e6 | 2012-02-09 11:54:16 +0000 | [diff] [blame] | 1295 | add_hardwired_active( |
tom | f5db3b6 | 2005-06-21 13:26:17 +0000 | [diff] [blame] | 1296 | 0xFFFFFFFFFF600400ULL, |
tom | d6ae9e6 | 2012-02-09 11:54:16 +0000 | [diff] [blame] | 1297 | (Addr)&VG_(amd64_linux_REDIR_FOR_vtime) |
| 1298 | ); |
| 1299 | add_hardwired_active( |
| 1300 | 0xFFFFFFFFFF600800ULL, |
| 1301 | (Addr)&VG_(amd64_linux_REDIR_FOR_vgetcpu) |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 1302 | ); |
| 1303 | |
sewardj | b57e693 | 2009-08-02 12:21:31 +0000 | [diff] [blame] | 1304 | /* If we're using memcheck, use these intercepts right from |
| 1305 | the start, otherwise ld.so makes a lot of noise. */ |
| 1306 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
bart | 2ebe411 | 2008-06-01 16:33:37 +0000 | [diff] [blame] | 1307 | |
sewardj | b57e693 | 2009-08-02 12:21:31 +0000 | [diff] [blame] | 1308 | add_hardwired_spec( |
| 1309 | "ld-linux-x86-64.so.2", "strlen", |
| 1310 | (Addr)&VG_(amd64_linux_REDIR_FOR_strlen), |
bart | 8219bff | 2014-09-13 10:53:00 +0000 | [diff] [blame] | 1311 | # ifndef GLIBC_MANDATORY_STRLEN_REDIRECT |
sewardj | b57e693 | 2009-08-02 12:21:31 +0000 | [diff] [blame] | 1312 | NULL |
| 1313 | # else |
| 1314 | /* for glibc-2.10 and later, this is mandatory - can't sanely |
| 1315 | continue without it */ |
| 1316 | complain_about_stripped_glibc_ldso |
| 1317 | # endif |
| 1318 | ); |
| 1319 | } |
| 1320 | |
| 1321 | # elif defined(VGP_ppc32_linux) |
sewardj | 96fcfc8 | 2005-11-18 21:12:52 +0000 | [diff] [blame] | 1322 | /* If we're using memcheck, use these intercepts right from |
| 1323 | the start, otherwise ld.so makes a lot of noise. */ |
| 1324 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
sewardj | 0fd3049 | 2007-11-16 19:39:49 +0000 | [diff] [blame] | 1325 | |
sewardj | 5092a97 | 2007-11-16 18:45:40 +0000 | [diff] [blame] | 1326 | /* this is mandatory - can't sanely continue without it */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1327 | add_hardwired_spec( |
| 1328 | "ld.so.1", "strlen", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1329 | (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen), |
sewardj | b57e693 | 2009-08-02 12:21:31 +0000 | [diff] [blame] | 1330 | complain_about_stripped_glibc_ldso |
sewardj | 96fcfc8 | 2005-11-18 21:12:52 +0000 | [diff] [blame] | 1331 | ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1332 | add_hardwired_spec( |
sewardj | d5a30a4 | 2006-02-09 10:29:43 +0000 | [diff] [blame] | 1333 | "ld.so.1", "strcmp", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1334 | (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp), |
sewardj | 5092a97 | 2007-11-16 18:45:40 +0000 | [diff] [blame] | 1335 | NULL /* not mandatory - so why bother at all? */ |
| 1336 | /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */ |
sewardj | 96fcfc8 | 2005-11-18 21:12:52 +0000 | [diff] [blame] | 1337 | ); |
sewardj | cd8c95a | 2006-08-25 11:48:38 +0000 | [diff] [blame] | 1338 | add_hardwired_spec( |
| 1339 | "ld.so.1", "index", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1340 | (Addr)&VG_(ppc32_linux_REDIR_FOR_strchr), |
sewardj | 5092a97 | 2007-11-16 18:45:40 +0000 | [diff] [blame] | 1341 | NULL /* not mandatory - so why bother at all? */ |
| 1342 | /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */ |
sewardj | cd8c95a | 2006-08-25 11:48:38 +0000 | [diff] [blame] | 1343 | ); |
bart | 2ebe411 | 2008-06-01 16:33:37 +0000 | [diff] [blame] | 1344 | } |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 1345 | |
carll | cae0cc2 | 2014-08-07 23:17:29 +0000 | [diff] [blame] | 1346 | # elif defined(VGP_ppc64be_linux) |
sewardj | f0915fc | 2006-01-05 14:07:04 +0000 | [diff] [blame] | 1347 | /* If we're using memcheck, use these intercepts right from |
| 1348 | the start, otherwise ld.so makes a lot of noise. */ |
| 1349 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1350 | |
sewardj | 0fd3049 | 2007-11-16 19:39:49 +0000 | [diff] [blame] | 1351 | /* this is mandatory - can't sanely continue without it */ |
sewardj | 1a85f4f | 2006-01-12 21:15:35 +0000 | [diff] [blame] | 1352 | add_hardwired_spec( |
| 1353 | "ld64.so.1", "strlen", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1354 | (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strlen) ), |
sewardj | b57e693 | 2009-08-02 12:21:31 +0000 | [diff] [blame] | 1355 | complain_about_stripped_glibc_ldso |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1356 | ); |
sewardj | f0915fc | 2006-01-05 14:07:04 +0000 | [diff] [blame] | 1357 | |
sewardj | 1a85f4f | 2006-01-12 21:15:35 +0000 | [diff] [blame] | 1358 | add_hardwired_spec( |
| 1359 | "ld64.so.1", "index", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1360 | (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strchr) ), |
sewardj | 0fd3049 | 2007-11-16 19:39:49 +0000 | [diff] [blame] | 1361 | NULL /* not mandatory - so why bother at all? */ |
| 1362 | /* glibc-2.5 (FC6, ppc64) seems fine without it */ |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1363 | ); |
bart | 2ebe411 | 2008-06-01 16:33:37 +0000 | [diff] [blame] | 1364 | } |
sewardj | 2c48c7b | 2005-11-29 13:05:56 +0000 | [diff] [blame] | 1365 | |
carll | 582d582 | 2014-08-07 23:35:54 +0000 | [diff] [blame] | 1366 | # elif defined(VGP_ppc64le_linux) |
| 1367 | /* If we're using memcheck, use these intercepts right from |
| 1368 | * the start, otherwise ld.so makes a lot of noise. |
| 1369 | */ |
| 1370 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1371 | |
| 1372 | /* this is mandatory - can't sanely continue without it */ |
| 1373 | add_hardwired_spec( |
| 1374 | "ld64.so.2", "strlen", |
| 1375 | (Addr)&VG_(ppc64_linux_REDIR_FOR_strlen), |
| 1376 | complain_about_stripped_glibc_ldso |
| 1377 | ); |
| 1378 | |
| 1379 | add_hardwired_spec( |
| 1380 | "ld64.so.2", "index", |
| 1381 | (Addr)&VG_(ppc64_linux_REDIR_FOR_strchr), |
| 1382 | NULL /* not mandatory - so why bother at all? */ |
| 1383 | /* glibc-2.5 (FC6, ppc64) seems fine without it */ |
| 1384 | ); |
| 1385 | } |
| 1386 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1387 | # elif defined(VGP_arm_linux) |
sewardj | 808584b | 2014-04-24 23:47:16 +0000 | [diff] [blame] | 1388 | /* If we're using memcheck, use these intercepts right from the |
| 1389 | start, otherwise ld.so makes a lot of noise. In most ARM-linux |
| 1390 | distros, ld.so's soname is ld-linux.so.3, but Ubuntu 14.04 on |
| 1391 | Odroid uses ld-linux-armhf.so.3 for some reason. */ |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1392 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
sewardj | 808584b | 2014-04-24 23:47:16 +0000 | [diff] [blame] | 1393 | /* strlen */ |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1394 | add_hardwired_spec( |
| 1395 | "ld-linux.so.3", "strlen", |
| 1396 | (Addr)&VG_(arm_linux_REDIR_FOR_strlen), |
sewardj | d69cee8 | 2010-08-22 12:13:35 +0000 | [diff] [blame] | 1397 | complain_about_stripped_glibc_ldso |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1398 | ); |
sewardj | 808584b | 2014-04-24 23:47:16 +0000 | [diff] [blame] | 1399 | add_hardwired_spec( |
| 1400 | "ld-linux-armhf.so.3", "strlen", |
| 1401 | (Addr)&VG_(arm_linux_REDIR_FOR_strlen), |
| 1402 | complain_about_stripped_glibc_ldso |
| 1403 | ); |
| 1404 | /* memcpy */ |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1405 | add_hardwired_spec( |
| 1406 | "ld-linux.so.3", "memcpy", |
| 1407 | (Addr)&VG_(arm_linux_REDIR_FOR_memcpy), |
sewardj | d69cee8 | 2010-08-22 12:13:35 +0000 | [diff] [blame] | 1408 | complain_about_stripped_glibc_ldso |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1409 | ); |
sewardj | 808584b | 2014-04-24 23:47:16 +0000 | [diff] [blame] | 1410 | add_hardwired_spec( |
| 1411 | "ld-linux-armhf.so.3", "memcpy", |
| 1412 | (Addr)&VG_(arm_linux_REDIR_FOR_memcpy), |
| 1413 | complain_about_stripped_glibc_ldso |
| 1414 | ); |
mjw | 1cd2378 | 2014-08-28 14:59:04 +0000 | [diff] [blame] | 1415 | /* strcmp */ |
| 1416 | add_hardwired_spec( |
| 1417 | "ld-linux.so.3", "strcmp", |
| 1418 | (Addr)&VG_(arm_linux_REDIR_FOR_strcmp), |
| 1419 | complain_about_stripped_glibc_ldso |
| 1420 | ); |
| 1421 | add_hardwired_spec( |
| 1422 | "ld-linux-armhf.so.3", "strcmp", |
| 1423 | (Addr)&VG_(arm_linux_REDIR_FOR_strcmp), |
| 1424 | complain_about_stripped_glibc_ldso |
| 1425 | ); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1426 | } |
sewardj | f0c1250 | 2014-01-12 12:54:00 +0000 | [diff] [blame] | 1427 | |
| 1428 | # elif defined(VGP_arm64_linux) |
| 1429 | /* If we're using memcheck, use these intercepts right from |
| 1430 | the start, otherwise ld.so makes a lot of noise. */ |
| 1431 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
sewardj | 7aa6651 | 2014-03-09 09:44:32 +0000 | [diff] [blame] | 1432 | add_hardwired_spec( |
| 1433 | "ld-linux-aarch64.so.1", "strlen", |
| 1434 | (Addr)&VG_(arm64_linux_REDIR_FOR_strlen), |
| 1435 | complain_about_stripped_glibc_ldso |
| 1436 | ); |
| 1437 | add_hardwired_spec( |
| 1438 | "ld-linux-aarch64.so.1", "index", |
| 1439 | (Addr)&VG_(arm64_linux_REDIR_FOR_index), |
| 1440 | NULL |
| 1441 | ); |
| 1442 | add_hardwired_spec( |
| 1443 | "ld-linux-aarch64.so.1", "strcmp", |
| 1444 | (Addr)&VG_(arm64_linux_REDIR_FOR_strcmp), |
| 1445 | NULL |
| 1446 | ); |
sewardj | 26ed419 | 2014-11-04 17:44:21 +0000 | [diff] [blame] | 1447 | # if defined(VGPV_arm64_linux_android) |
| 1448 | add_hardwired_spec( |
| 1449 | "NONE", "__dl_strlen", // in /system/bin/linker64 |
| 1450 | (Addr)&VG_(arm64_linux_REDIR_FOR_strlen), |
| 1451 | NULL |
| 1452 | ); |
| 1453 | # endif |
sewardj | f0c1250 | 2014-01-12 12:54:00 +0000 | [diff] [blame] | 1454 | } |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1455 | |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 1456 | # elif defined(VGP_x86_darwin) |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 1457 | /* If we're using memcheck, use these intercepts right from |
| 1458 | the start, otherwise dyld makes a lot of noise. */ |
| 1459 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1460 | add_hardwired_spec("dyld", "strcmp", |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 1461 | (Addr)&VG_(x86_darwin_REDIR_FOR_strcmp), NULL); |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 1462 | add_hardwired_spec("dyld", "strlen", |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 1463 | (Addr)&VG_(x86_darwin_REDIR_FOR_strlen), NULL); |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 1464 | add_hardwired_spec("dyld", "strcat", |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 1465 | (Addr)&VG_(x86_darwin_REDIR_FOR_strcat), NULL); |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 1466 | add_hardwired_spec("dyld", "strcpy", |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 1467 | (Addr)&VG_(x86_darwin_REDIR_FOR_strcpy), NULL); |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 1468 | add_hardwired_spec("dyld", "strlcat", |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 1469 | (Addr)&VG_(x86_darwin_REDIR_FOR_strlcat), NULL); |
| 1470 | } |
| 1471 | |
| 1472 | # elif defined(VGP_amd64_darwin) |
| 1473 | /* If we're using memcheck, use these intercepts right from |
| 1474 | the start, otherwise dyld makes a lot of noise. */ |
| 1475 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1476 | add_hardwired_spec("dyld", "strcmp", |
| 1477 | (Addr)&VG_(amd64_darwin_REDIR_FOR_strcmp), NULL); |
| 1478 | add_hardwired_spec("dyld", "strlen", |
| 1479 | (Addr)&VG_(amd64_darwin_REDIR_FOR_strlen), NULL); |
| 1480 | add_hardwired_spec("dyld", "strcat", |
| 1481 | (Addr)&VG_(amd64_darwin_REDIR_FOR_strcat), NULL); |
| 1482 | add_hardwired_spec("dyld", "strcpy", |
| 1483 | (Addr)&VG_(amd64_darwin_REDIR_FOR_strcpy), NULL); |
| 1484 | add_hardwired_spec("dyld", "strlcat", |
| 1485 | (Addr)&VG_(amd64_darwin_REDIR_FOR_strlcat), NULL); |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 1486 | // DDD: #warning fixme rdar://6166275 |
| 1487 | add_hardwired_spec("dyld", "arc4random", |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 1488 | (Addr)&VG_(amd64_darwin_REDIR_FOR_arc4random), NULL); |
sewardj | 704bf0e | 2014-06-21 09:34:22 +0000 | [diff] [blame] | 1489 | # if DARWIN_VERS == DARWIN_10_9 |
| 1490 | add_hardwired_spec("dyld", "strchr", |
| 1491 | (Addr)&VG_(amd64_darwin_REDIR_FOR_strchr), NULL); |
| 1492 | # endif |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 1493 | } |
| 1494 | |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1495 | # elif defined(VGP_s390x_linux) |
florian | ae6e3ac | 2014-09-03 16:01:10 +0000 | [diff] [blame] | 1496 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1497 | // added in rsponse to BZ 327943 |
| 1498 | add_hardwired_spec("ld64.so.1", "index", |
| 1499 | (Addr)&VG_(s390x_linux_REDIR_FOR_index), |
| 1500 | complain_about_stripped_glibc_ldso); |
| 1501 | } |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1502 | |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1503 | # elif defined(VGP_mips32_linux) |
| 1504 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1505 | |
| 1506 | /* this is mandatory - can't sanely continue without it */ |
| 1507 | add_hardwired_spec( |
| 1508 | "ld.so.3", "strlen", |
| 1509 | (Addr)&VG_(mips32_linux_REDIR_FOR_strlen), |
| 1510 | complain_about_stripped_glibc_ldso |
| 1511 | ); |
| 1512 | } |
| 1513 | |
petarj | 4df0bfc | 2013-02-27 23:17:33 +0000 | [diff] [blame] | 1514 | # elif defined(VGP_mips64_linux) |
| 1515 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1516 | |
| 1517 | /* this is mandatory - can't sanely continue without it */ |
| 1518 | add_hardwired_spec( |
| 1519 | "ld.so.3", "strlen", |
| 1520 | (Addr)&VG_(mips64_linux_REDIR_FOR_strlen), |
| 1521 | complain_about_stripped_glibc_ldso |
| 1522 | ); |
| 1523 | } |
| 1524 | |
sewardj | 112711a | 2015-04-10 12:30:09 +0000 | [diff] [blame] | 1525 | # elif defined(VGP_tilegx_linux) |
| 1526 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1527 | |
| 1528 | add_hardwired_spec( |
| 1529 | "ld.so.1", "strlen", |
| 1530 | (Addr)&VG_(tilegx_linux_REDIR_FOR_strlen), NULL |
| 1531 | ); |
| 1532 | } |
| 1533 | |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 1534 | # elif defined(VGP_x86_solaris) |
| 1535 | /* If we're using memcheck, use these intercepts right from |
| 1536 | the start, otherwise ld.so makes a lot of noise. */ |
| 1537 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1538 | add_hardwired_spec("/lib/ld.so.1", "strcmp", |
| 1539 | (Addr)&VG_(x86_solaris_REDIR_FOR_strcmp), NULL); |
| 1540 | } |
| 1541 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1542 | add_hardwired_spec("/lib/ld.so.1", "strlen", |
| 1543 | (Addr)&VG_(x86_solaris_REDIR_FOR_strlen), NULL); |
| 1544 | } |
| 1545 | |
| 1546 | # elif defined(VGP_amd64_solaris) |
| 1547 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1548 | add_hardwired_spec("/lib/amd64/ld.so.1", "strcpy", |
| 1549 | (Addr)&VG_(amd64_solaris_REDIR_FOR_strcpy), NULL); |
| 1550 | } |
| 1551 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1552 | add_hardwired_spec("/lib/amd64/ld.so.1", "strncpy", |
| 1553 | (Addr)&VG_(amd64_solaris_REDIR_FOR_strncpy), NULL); |
| 1554 | } |
| 1555 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1556 | add_hardwired_spec("/lib/amd64/ld.so.1", "strcmp", |
| 1557 | (Addr)&VG_(amd64_solaris_REDIR_FOR_strcmp), NULL); |
| 1558 | } |
| 1559 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1560 | add_hardwired_spec("/lib/amd64/ld.so.1", "strcat", |
| 1561 | (Addr)&VG_(amd64_solaris_REDIR_FOR_strcat), NULL); |
| 1562 | } |
| 1563 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 1564 | add_hardwired_spec("/lib/amd64/ld.so.1", "strlen", |
| 1565 | (Addr)&VG_(amd64_solaris_REDIR_FOR_strlen), NULL); |
| 1566 | } |
| 1567 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1568 | # else |
| 1569 | # error Unknown platform |
| 1570 | # endif |
| 1571 | |
| 1572 | if (VG_(clo_trace_redir)) |
| 1573 | show_redir_state("after VG_(redir_initialise)"); |
njn | d1af003 | 2005-05-29 17:01:48 +0000 | [diff] [blame] | 1574 | } |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 1575 | |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1576 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1577 | /*------------------------------------------------------------*/ |
| 1578 | /*--- MISC HELPERS ---*/ |
| 1579 | /*------------------------------------------------------------*/ |
| 1580 | |
florian | 54fe202 | 2012-10-27 23:07:42 +0000 | [diff] [blame] | 1581 | static void* dinfo_zalloc(const HChar* ec, SizeT n) { |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1582 | void* p; |
| 1583 | vg_assert(n > 0); |
sewardj | 9c606bd | 2008-09-18 18:12:50 +0000 | [diff] [blame] | 1584 | p = VG_(arena_malloc)(VG_AR_DINFO, ec, n); |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 1585 | VG_(memset)(p, 0, n); |
| 1586 | return p; |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1587 | } |
| 1588 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1589 | static void dinfo_free(void* p) { |
florian | e2800c9 | 2014-09-15 20:57:45 +0000 | [diff] [blame] | 1590 | vg_assert(p); |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1591 | return VG_(arena_free)(VG_AR_DINFO, p); |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1592 | } |
| 1593 | |
florian | 54fe202 | 2012-10-27 23:07:42 +0000 | [diff] [blame] | 1594 | static HChar* dinfo_strdup(const HChar* ec, const HChar* str) |
njn | bc6d84d | 2005-06-19 18:58:03 +0000 | [diff] [blame] | 1595 | { |
sewardj | 9c606bd | 2008-09-18 18:12:50 +0000 | [diff] [blame] | 1596 | return VG_(arena_strdup)(VG_AR_DINFO, ec, str); |
njn | bc6d84d | 2005-06-19 18:58:03 +0000 | [diff] [blame] | 1597 | } |
| 1598 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1599 | /* Really this should be merged with translations_allowable_from_seg |
| 1600 | in m_translate. */ |
| 1601 | static Bool is_plausible_guest_addr(Addr a) |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1602 | { |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 1603 | NSegment const* seg = VG_(am_find_nsegment)(a); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1604 | return seg != NULL |
florian | acf521c | 2015-05-13 08:11:56 +0000 | [diff] [blame] | 1605 | && (seg->kind == SkAnonC || seg->kind == SkFileC || |
| 1606 | seg->kind == SkShmC) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1607 | && (seg->hasX || seg->hasR); /* crude x86-specific hack */ |
| 1608 | } |
| 1609 | |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1610 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1611 | /*------------------------------------------------------------*/ |
| 1612 | /*--- NOTIFY-ON-LOAD FUNCTIONS ---*/ |
| 1613 | /*------------------------------------------------------------*/ |
| 1614 | |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 1615 | static |
florian | 19f91bb | 2012-11-10 22:29:54 +0000 | [diff] [blame] | 1616 | void handle_maybe_load_notifier( const HChar* soname, |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 1617 | const HChar* symbol, Addr addr ) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1618 | { |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 1619 | # if defined(VGP_x86_linux) |
| 1620 | /* x86-linux only: if we see _dl_sysinfo_int80, note its address. |
| 1621 | See comment on declaration of VG_(client__dl_sysinfo_int80) for |
| 1622 | the reason. As far as I can tell, the relevant symbol is always |
| 1623 | in object with soname "ld-linux.so.2". */ |
| 1624 | if (symbol && symbol[0] == '_' |
| 1625 | && 0 == VG_(strcmp)(symbol, "_dl_sysinfo_int80") |
| 1626 | && 0 == VG_(strcmp)(soname, "ld-linux.so.2")) { |
| 1627 | if (VG_(client__dl_sysinfo_int80) == 0) |
| 1628 | VG_(client__dl_sysinfo_int80) = addr; |
| 1629 | } |
| 1630 | # endif |
| 1631 | |
| 1632 | /* Normal load-notifier handling after here. First, ignore all |
| 1633 | symbols lacking the right prefix. */ |
sewardj | dd9508c | 2011-05-04 09:03:41 +0000 | [diff] [blame] | 1634 | vg_assert(symbol); // assert rather than segfault if it is NULL |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1635 | if (0 != VG_(strncmp)(symbol, VG_NOTIFY_ON_LOAD_PREFIX, |
| 1636 | VG_NOTIFY_ON_LOAD_PREFIX_LEN)) |
| 1637 | /* Doesn't have the right prefix */ |
| 1638 | return; |
| 1639 | |
| 1640 | if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(freeres))) == 0) |
| 1641 | VG_(client___libc_freeres_wrapper) = addr; |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 1642 | else |
| 1643 | if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(ifunc_wrapper))) == 0) |
tom | d264514 | 2009-10-29 09:27:11 +0000 | [diff] [blame] | 1644 | iFuncWrapper = addr; |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1645 | else |
| 1646 | vg_assert2(0, "unrecognised load notification function: %s", symbol); |
| 1647 | } |
| 1648 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1649 | |
| 1650 | /*------------------------------------------------------------*/ |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1651 | /*--- REQUIRE-TEXT-SYMBOL HANDLING ---*/ |
| 1652 | /*------------------------------------------------------------*/ |
| 1653 | |
| 1654 | /* In short: check that the currently-being-loaded object has text |
| 1655 | symbols that satisfy any --require-text-symbol= specifications that |
| 1656 | apply to it, and abort the run with an error message if not. |
| 1657 | */ |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 1658 | static void handle_require_text_symbols ( const DebugInfo* di ) |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1659 | { |
| 1660 | /* First thing to do is figure out which, if any, |
| 1661 | --require-text-symbol specification strings apply to this |
| 1662 | object. Most likely none do, since it is not expected to |
| 1663 | frequently be used. Work through the list of specs and |
| 1664 | accumulate in fnpatts[] the fn patterns that pertain to this |
| 1665 | object. */ |
florian | 7931627 | 2014-10-07 18:36:28 +0000 | [diff] [blame] | 1666 | XArray *fnpatts = VG_(newXA)( VG_(malloc), "m_redir.hrts.5", |
| 1667 | VG_(free), sizeof(HChar*) ); |
| 1668 | |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1669 | Int i, j; |
| 1670 | const HChar* di_soname = VG_(DebugInfo_get_soname)(di); |
| 1671 | vg_assert(di_soname); // must be present |
| 1672 | |
florian | 7931627 | 2014-10-07 18:36:28 +0000 | [diff] [blame] | 1673 | for (i = 0; i < VG_(sizeXA)(VG_(clo_req_tsyms)); i++) { |
| 1674 | const HChar* clo_spec = *(HChar**) VG_(indexXA)(VG_(clo_req_tsyms), i); |
florian | 19f91bb | 2012-11-10 22:29:54 +0000 | [diff] [blame] | 1675 | vg_assert(clo_spec && VG_(strlen)(clo_spec) >= 4); |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1676 | // clone the spec, so we can stick a zero at the end of the sopatt |
florian | 19f91bb | 2012-11-10 22:29:54 +0000 | [diff] [blame] | 1677 | HChar *spec = VG_(strdup)("m_redir.hrts.1", clo_spec); |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1678 | HChar sep = spec[0]; |
| 1679 | HChar* sopatt = &spec[1]; |
| 1680 | HChar* fnpatt = VG_(strchr)(sopatt, sep); |
| 1681 | // the initial check at clo processing in time in m_main |
| 1682 | // should ensure this. |
| 1683 | vg_assert(fnpatt && *fnpatt == sep); |
| 1684 | *fnpatt = 0; |
| 1685 | fnpatt++; |
florian | 7931627 | 2014-10-07 18:36:28 +0000 | [diff] [blame] | 1686 | if (VG_(string_match)(sopatt, di_soname)) { |
| 1687 | HChar *pattern = VG_(strdup)("m_redir.hrts.2", fnpatt); |
| 1688 | VG_(addToXA)(fnpatts, &pattern); |
| 1689 | } |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1690 | VG_(free)(spec); |
| 1691 | } |
| 1692 | |
florian | 7931627 | 2014-10-07 18:36:28 +0000 | [diff] [blame] | 1693 | if (VG_(sizeXA)(fnpatts) == 0) { |
| 1694 | VG_(deleteXA)(fnpatts); |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1695 | return; /* no applicable spec strings */ |
florian | 7931627 | 2014-10-07 18:36:28 +0000 | [diff] [blame] | 1696 | } |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1697 | |
florian | 7931627 | 2014-10-07 18:36:28 +0000 | [diff] [blame] | 1698 | /* So finally, fnpatts contains the set of |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1699 | (patterns for) text symbol names that must be found in this |
| 1700 | object, in order to continue. That is, we must find at least |
| 1701 | one text symbol name that matches each pattern, else we must |
| 1702 | abort the run. */ |
| 1703 | |
| 1704 | if (0) VG_(printf)("for %s\n", di_soname); |
florian | 7931627 | 2014-10-07 18:36:28 +0000 | [diff] [blame] | 1705 | for (i = 0; i < VG_(sizeXA)(fnpatts); i++) |
| 1706 | if (0) VG_(printf)(" fnpatt: %s\n", |
| 1707 | *(HChar**) VG_(indexXA)(fnpatts, i)); |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1708 | |
| 1709 | /* For each spec, look through the syms to find one that matches. |
| 1710 | This isn't terribly efficient but it happens rarely, so no big |
| 1711 | deal. */ |
florian | 7931627 | 2014-10-07 18:36:28 +0000 | [diff] [blame] | 1712 | for (i = 0; i < VG_(sizeXA)(fnpatts); i++) { |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 1713 | Bool found = False; |
florian | 7931627 | 2014-10-07 18:36:28 +0000 | [diff] [blame] | 1714 | const HChar* fnpatt = *(HChar**) VG_(indexXA)(fnpatts, i); |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 1715 | Int nsyms = VG_(DebugInfo_syms_howmany)(di); |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1716 | for (j = 0; j < nsyms; j++) { |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 1717 | Bool isText = False; |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 1718 | const HChar* sym_name_pri = NULL; |
| 1719 | const HChar** sym_names_sec = NULL; |
philippe | 4cace66 | 2014-08-13 21:25:45 +0000 | [diff] [blame] | 1720 | VG_(DebugInfo_syms_getidx)( di, j, NULL, |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 1721 | NULL, &sym_name_pri, &sym_names_sec, |
sewardj | a5cace0 | 2011-08-15 09:42:34 +0000 | [diff] [blame] | 1722 | &isText, NULL ); |
florian | 1ef70c6 | 2014-10-22 17:42:37 +0000 | [diff] [blame] | 1723 | const HChar* twoslots[2]; |
| 1724 | const HChar** names_init = |
| 1725 | alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]); |
| 1726 | const HChar** names; |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 1727 | for (names = names_init; *names; names++) { |
| 1728 | /* ignore data symbols */ |
| 1729 | if (0) VG_(printf)("QQQ %s\n", *names); |
| 1730 | vg_assert(sym_name_pri); |
| 1731 | if (!isText) |
| 1732 | continue; |
| 1733 | if (VG_(string_match)(fnpatt, *names)) { |
| 1734 | found = True; |
| 1735 | break; |
| 1736 | } |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1737 | } |
sewardj | 85cf900 | 2011-08-16 09:54:00 +0000 | [diff] [blame] | 1738 | free_symname_array(names_init, &twoslots[0]); |
| 1739 | if (found) |
| 1740 | break; |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1741 | } |
| 1742 | |
| 1743 | if (!found) { |
florian | 6bd9dc1 | 2012-11-23 16:17:43 +0000 | [diff] [blame] | 1744 | const HChar* v = "valgrind: "; |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1745 | VG_(printf)("\n"); |
| 1746 | VG_(printf)( |
| 1747 | "%sFatal error at when loading library with soname\n", v); |
| 1748 | VG_(printf)( |
| 1749 | "%s %s\n", v, di_soname); |
| 1750 | VG_(printf)( |
| 1751 | "%sCannot find any text symbol with a name " |
| 1752 | "that matches the pattern\n", v); |
| 1753 | VG_(printf)("%s %s\n", v, fnpatt); |
| 1754 | VG_(printf)("%sas required by a --require-text-symbol= " |
| 1755 | "specification.\n", v); |
| 1756 | VG_(printf)("\n"); |
| 1757 | VG_(printf)( |
| 1758 | "%sCannot continue -- exiting now.\n", v); |
| 1759 | VG_(printf)("\n"); |
| 1760 | VG_(exit)(1); |
| 1761 | } |
| 1762 | } |
| 1763 | |
| 1764 | /* All required specs were found. Just free memory and return. */ |
florian | 7931627 | 2014-10-07 18:36:28 +0000 | [diff] [blame] | 1765 | VG_(deleteXA)(fnpatts); |
sewardj | f9ebc39 | 2010-05-09 22:30:43 +0000 | [diff] [blame] | 1766 | } |
| 1767 | |
| 1768 | |
| 1769 | /*------------------------------------------------------------*/ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1770 | /*--- SANITY/DEBUG ---*/ |
| 1771 | /*------------------------------------------------------------*/ |
| 1772 | |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 1773 | static void show_spec ( const HChar* left, const Spec* spec ) |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1774 | { |
sewardj | 738856f | 2009-07-15 14:48:32 +0000 | [diff] [blame] | 1775 | VG_(message)( Vg_DebugMsg, |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 1776 | "%s%-25s %-30s %s-> (%04d.%d) 0x%08lx\n", |
sewardj | 738856f | 2009-07-15 14:48:32 +0000 | [diff] [blame] | 1777 | left, |
| 1778 | spec->from_sopatt, spec->from_fnpatt, |
| 1779 | spec->isWrap ? "W" : "R", |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 1780 | spec->becTag, spec->becPrio, |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 1781 | spec->to_addr ); |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1782 | } |
| 1783 | |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 1784 | static void show_active ( const HChar* left, const Active* act ) |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1785 | { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1786 | Bool ok; |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 1787 | const HChar *buf; |
| 1788 | |
| 1789 | ok = VG_(get_fnname_w_offset)(act->from_addr, &buf); |
| 1790 | if (!ok) buf = "???"; |
| 1791 | // Stash away name1 |
| 1792 | HChar name1[VG_(strlen)(buf) + 1]; |
| 1793 | VG_(strcpy)(name1, buf); |
| 1794 | |
| 1795 | const HChar *name2; |
| 1796 | ok = VG_(get_fnname_w_offset)(act->to_addr, &name2); |
| 1797 | if (!ok) name2 = "???"; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1798 | |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 1799 | VG_(message)(Vg_DebugMsg, "%s0x%08lx (%-20s) %s-> (%04d.%d) 0x%08lx %s\n", |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1800 | left, |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 1801 | act->from_addr, name1, |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1802 | act->isWrap ? "W" : "R", |
sewardj | 9604484 | 2011-08-18 13:09:55 +0000 | [diff] [blame] | 1803 | act->becTag, act->becPrio, |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 1804 | act->to_addr, name2 ); |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1805 | } |
| 1806 | |
florian | 54fe202 | 2012-10-27 23:07:42 +0000 | [diff] [blame] | 1807 | static void show_redir_state ( const HChar* who ) |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1808 | { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1809 | TopSpec* ts; |
| 1810 | Spec* sp; |
| 1811 | Active* act; |
sewardj | 738856f | 2009-07-15 14:48:32 +0000 | [diff] [blame] | 1812 | VG_(message)(Vg_DebugMsg, "<<\n"); |
| 1813 | VG_(message)(Vg_DebugMsg, " ------ REDIR STATE %s ------\n", who); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1814 | for (ts = topSpecs; ts; ts = ts->next) { |
philippe | 80beb24 | 2012-05-03 21:09:51 +0000 | [diff] [blame] | 1815 | if (ts->seginfo) |
| 1816 | VG_(message)(Vg_DebugMsg, |
| 1817 | " TOPSPECS of soname %s filename %s\n", |
florian | 3e79863 | 2012-11-24 19:41:54 +0000 | [diff] [blame] | 1818 | VG_(DebugInfo_get_soname)(ts->seginfo), |
| 1819 | VG_(DebugInfo_get_filename)(ts->seginfo)); |
philippe | 80beb24 | 2012-05-03 21:09:51 +0000 | [diff] [blame] | 1820 | else |
| 1821 | VG_(message)(Vg_DebugMsg, |
| 1822 | " TOPSPECS of soname (hardwired)\n"); |
| 1823 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1824 | for (sp = ts->specs; sp; sp = sp->next) |
| 1825 | show_spec(" ", sp); |
| 1826 | } |
sewardj | 738856f | 2009-07-15 14:48:32 +0000 | [diff] [blame] | 1827 | VG_(message)(Vg_DebugMsg, " ------ ACTIVE ------\n"); |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1828 | VG_(OSetGen_ResetIter)( activeSet ); |
| 1829 | while ( (act = VG_(OSetGen_Next)(activeSet)) ) { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1830 | show_active(" ", act); |
| 1831 | } |
| 1832 | |
sewardj | 738856f | 2009-07-15 14:48:32 +0000 | [diff] [blame] | 1833 | VG_(message)(Vg_DebugMsg, ">>\n"); |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1834 | } |
| 1835 | |
njn | c0ae705 | 2005-08-25 22:55:19 +0000 | [diff] [blame] | 1836 | /*--------------------------------------------------------------------*/ |
| 1837 | /*--- end ---*/ |
| 1838 | /*--------------------------------------------------------------------*/ |