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 | 4d474d0 | 2008-02-11 11:34:59 +0000 | [diff] [blame] | 10 | Copyright (C) 2000-2008 Julian Seward |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 11 | jseward@acm.org |
sewardj | 4d474d0 | 2008-02-11 11:34:59 +0000 | [diff] [blame] | 12 | Copyright (C) 2003-2008 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" |
njn | af1d7df | 2005-06-11 01:31:52 +0000 | [diff] [blame] | 39 | #include "pub_core_mallocfree.h" |
njn | 2024234 | 2005-05-16 23:31:24 +0000 | [diff] [blame] | 40 | #include "pub_core_options.h" |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 41 | #include "pub_core_oset.h" |
njn | d1af003 | 2005-05-29 17:01:48 +0000 | [diff] [blame] | 42 | #include "pub_core_redir.h" |
njn | a7598f6 | 2005-06-18 03:27:58 +0000 | [diff] [blame] | 43 | #include "pub_core_trampoline.h" |
njn | 8bddf58 | 2005-05-13 23:40:55 +0000 | [diff] [blame] | 44 | #include "pub_core_transtab.h" |
sewardj | 461c69d | 2005-11-17 20:15:04 +0000 | [diff] [blame] | 45 | #include "pub_core_tooliface.h" // VG_(needs).malloc_replacement |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 46 | #include "pub_core_machine.h" // VG_(fnptr_to_fnentry) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 47 | #include "pub_core_aspacemgr.h" // VG_(am_find_nsegment) |
sewardj | 14c7cc5 | 2007-02-25 15:08:24 +0000 | [diff] [blame] | 48 | #include "pub_core_xarray.h" |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 49 | #include "pub_core_clientstate.h" // VG_(client___libc_freeres_wrapper) |
| 50 | #include "pub_core_demangle.h" // VG_(maybe_Z_demangle) |
sewardj | 461c69d | 2005-11-17 20:15:04 +0000 | [diff] [blame] | 51 | |
sewardj | 55f9d1a | 2005-04-25 11:11:44 +0000 | [diff] [blame] | 52 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 53 | /* This module is a critical part of the redirection/intercept system. |
| 54 | It keeps track of the current intercept state, cleans up the |
| 55 | translation caches when that state changes, and finally, answers |
| 56 | queries about the whether an address is currently redirected or |
| 57 | not. It doesn't do any of the control-flow trickery needed to put |
| 58 | the redirections into practice. That is the job of m_translate, |
| 59 | which calls here to find out which translations need to be |
| 60 | redirected. |
| 61 | |
| 62 | The interface is simple. VG_(redir_initialise) initialises and |
| 63 | loads some hardwired redirects which never disappear; this is |
| 64 | platform-specific. |
| 65 | |
| 66 | The module is notified of redirection state changes by m_debuginfo. |
| 67 | That calls VG_(redir_notify_new_SegInfo) when a new SegInfo (shared |
| 68 | object symbol table, basically) appears. Appearance of new symbols |
| 69 | can cause new (active) redirections to appear for two reasons: the |
| 70 | symbols in the new table may match existing redirection |
| 71 | specifications (see comments below), and because the symbols in the |
| 72 | new table may themselves supply new redirect specifications which |
| 73 | match existing symbols (or ones in the new table). |
| 74 | |
| 75 | Redirect specifications are really symbols with "funny" prefixes |
| 76 | (_vgrZU_ and _vgrZZ_). These names tell m_redir that the |
| 77 | associated code should replace the standard entry point for some |
| 78 | set of functions. The set of functions is specified by a (soname |
| 79 | pattern, function name pattern) pair which is encoded in the symbol |
| 80 | name following the prefix. The names use a Z-encoding scheme so |
| 81 | that they may contain punctuation characters and wildcards (*). |
| 82 | The encoding scheme is described in pub_tool_redir.h and is decoded |
| 83 | by VG_(maybe_Z_demangle). |
| 84 | |
| 85 | When a shared object is unloaded, this module learns of it via a |
| 86 | call to VG_(redir_notify_delete_SegInfo). It then removes from its |
| 87 | tables all active redirections in any way associated with that |
| 88 | object, and tidies up the translation caches accordingly. |
| 89 | |
| 90 | That takes care of tracking the redirection state. When a |
| 91 | translation is actually to be made, m_translate calls to |
| 92 | VG_(redir_do_lookup) in this module to find out if the |
| 93 | translation's address should be redirected. |
| 94 | */ |
| 95 | |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 96 | /*------------------------------------------------------------*/ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 97 | /*--- Semantics ---*/ |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 98 | /*------------------------------------------------------------*/ |
| 99 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 100 | /* The redirector holds two pieces of state: |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 101 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 102 | Specs - a set of (soname pattern, fnname pattern) -> redir addr |
| 103 | Active - a set of orig addr -> (bool, redir addr) |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 104 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 105 | Active is the currently active set of bindings that the translator |
| 106 | consults. Specs is the current set of specifications as harvested |
| 107 | from reading symbol tables of the currently loaded objects. |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 108 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 109 | Active is a pure function of Specs and the current symbol table |
| 110 | state (maintained by m_debuginfo). Call the latter SyminfoState. |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 111 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 112 | Therefore whenever either Specs or SyminfoState changes, Active |
| 113 | must be recomputed. [Inefficient if done naively, but this is a |
| 114 | spec]. |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 115 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 116 | Active is computed as follows: |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 117 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 118 | Active = empty |
| 119 | for spec in Specs { |
| 120 | sopatt = spec.soname pattern |
| 121 | fnpatt = spec.fnname pattern |
| 122 | redir = spec.redir addr |
| 123 | for so matching sopatt in SyminfoState { |
| 124 | for fn matching fnpatt in fnnames_of(so) { |
| 125 | &fn -> redir is added to Active |
| 126 | } |
| 127 | } |
tom | 748a131 | 2005-04-02 15:53:01 +0000 | [diff] [blame] | 128 | } |
| 129 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 130 | [as an implementation detail, when a binding (orig -> redir) is |
| 131 | deleted from Active as a result of recomputing it, then all |
| 132 | translations intersecting redir must be deleted. However, this is |
| 133 | not part of the spec]. |
| 134 | |
| 135 | [Active also depends on where the aspacemgr has decided to put all |
| 136 | the pieces of code -- that affects the "orig addr" and "redir addr" |
| 137 | values.] |
| 138 | |
| 139 | --------------------- |
| 140 | |
| 141 | That completes the spec, apart from one difficult issue: duplicates. |
| 142 | |
| 143 | Clearly we must impose the requirement that domain(Active) contains |
| 144 | no duplicates. The difficulty is how to constrain Specs enough to |
| 145 | avoid getting into that situation. It's easy to write specs which |
| 146 | could cause conflicting bindings in Active, eg: |
| 147 | |
| 148 | (libpthread.so, pthread_mutex_lock) -> a1 |
| 149 | (libpthread.so, pthread_*) -> a2 |
| 150 | |
| 151 | for a1 != a2. Or even hairier: |
| 152 | |
| 153 | (libpthread.so, pthread_mutex_*) -> a1 |
| 154 | (libpthread.so, pthread_*_lock) -> a2 |
| 155 | |
| 156 | I can't think of any sane way of detecting when an addition to |
| 157 | Specs would generate conflicts. However, considering we don't |
| 158 | actually want to have a system that allows this, I propose this: |
| 159 | all changes to Specs are acceptable. But, when recomputing Active |
| 160 | following the change, if the same orig is bound to more than one |
| 161 | redir, then the first binding for orig is retained, and all the |
| 162 | rest ignored. |
| 163 | |
| 164 | =========================================================== |
| 165 | =========================================================== |
| 166 | Incremental implementation: |
| 167 | |
| 168 | When a new SegInfo appears: |
| 169 | - it may be the source of new specs |
| 170 | - it may be the source of new matches for existing specs |
| 171 | Therefore: |
| 172 | |
| 173 | - (new Specs x existing SegInfos): scan all symbols in the new |
| 174 | SegInfo to find new specs. Each of these needs to be compared |
| 175 | against all symbols in all the existing SegInfos to generate |
| 176 | new actives. |
| 177 | |
| 178 | - (existing Specs x new SegInfo): scan all symbols in the SegInfo, |
| 179 | trying to match them to any existing specs, also generating |
| 180 | new actives. |
| 181 | |
| 182 | - (new Specs x new SegInfo): scan all symbols in the new SegInfo, |
| 183 | trying to match them against the new specs, to generate new |
| 184 | actives. |
| 185 | |
| 186 | - Finally, add new new specs to the current set of specs. |
| 187 | |
| 188 | When adding a new active (s,d) to the Actives: |
| 189 | lookup s in Actives |
| 190 | if already bound to d, ignore |
| 191 | if already bound to something other than d, complain loudly and ignore |
| 192 | else add (s,d) to Actives |
| 193 | and discard (s,1) and (d,1) (maybe overly conservative) |
| 194 | |
| 195 | When a SegInfo disappears: |
| 196 | - delete all specs acquired from the seginfo |
| 197 | - delete all actives derived from the just-deleted specs |
| 198 | - if each active (s,d) deleted, discard (s,1) and (d,1) |
| 199 | */ |
| 200 | |
| 201 | |
| 202 | /*------------------------------------------------------------*/ |
| 203 | /*--- REDIRECTION SPECIFICATIONS ---*/ |
| 204 | /*------------------------------------------------------------*/ |
| 205 | |
| 206 | /* A specification of a redirection we want to do. Note that because |
| 207 | both the "from" soname and function name may contain wildcards, the |
sewardj | 5092a97 | 2007-11-16 18:45:40 +0000 | [diff] [blame] | 208 | spec can match an arbitrary number of times. |
| 209 | |
| 210 | 16 Nov 2007: Comments re .mandatory field: The initial motivation |
| 211 | for this is making Memcheck work sanely on glibc-2.6.X ppc32-linux. |
| 212 | We really need to intercept 'strlen' in ld.so right from startup. |
| 213 | If ld.so does not have a visible 'strlen' symbol, Memcheck |
| 214 | generates an impossible number of errors resulting from highly |
| 215 | tuned strlen implementation in ld.so, and is completely unusable |
| 216 | -- the resulting undefinedness eventually seeps everywhere. */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 217 | typedef |
| 218 | struct _Spec { |
| 219 | struct _Spec* next; /* linked list */ |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 220 | /* FIXED PARTS -- set when created and not changed */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 221 | HChar* from_sopatt; /* from soname pattern */ |
| 222 | HChar* from_fnpatt; /* from fnname pattern */ |
| 223 | Addr to_addr; /* where redirecting to */ |
| 224 | Bool isWrap; /* wrap or replacement? */ |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 225 | HChar* mandatory; /* non-NULL ==> abort V and print the |
| 226 | string if from_sopatt is loaded but |
| 227 | from_fnpatt cannot be found */ |
| 228 | /* VARIABLE PARTS -- used transiently whilst processing redirections */ |
| 229 | Bool mark; /* set if spec requires further processing */ |
| 230 | Bool done; /* set if spec was successfully matched */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 231 | } |
| 232 | Spec; |
| 233 | |
| 234 | /* Top-level data structure. It contains a pointer to a SegInfo and |
| 235 | also a list of the specs harvested from that SegInfo. Note that |
| 236 | seginfo is allowed to be NULL, meaning that the specs are |
| 237 | pre-loaded ones at startup and are not associated with any |
| 238 | particular seginfo. */ |
| 239 | typedef |
| 240 | struct _TopSpec { |
| 241 | struct _TopSpec* next; /* linked list */ |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 242 | DebugInfo* seginfo; /* symbols etc */ |
| 243 | Spec* specs; /* specs pulled out of seginfo */ |
| 244 | Bool mark; /* transient temporary used during deletion */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 245 | } |
| 246 | TopSpec; |
| 247 | |
| 248 | /* This is the top level list of redirections. m_debuginfo maintains |
| 249 | a list of SegInfos, and the idea here is to maintain a list with |
| 250 | the same number of elements (in fact, with one more element, so as |
| 251 | to record abovementioned preloaded specifications.) */ |
| 252 | static TopSpec* topSpecs = NULL; |
| 253 | |
| 254 | |
| 255 | /*------------------------------------------------------------*/ |
| 256 | /*--- CURRENTLY ACTIVE REDIRECTIONS ---*/ |
| 257 | /*------------------------------------------------------------*/ |
| 258 | |
| 259 | /* Represents a currently active binding. If either parent_spec or |
| 260 | parent_sym is NULL, then this binding was hardwired at startup and |
| 261 | should not be deleted. Same is true if either parent's seginfo |
| 262 | field is NULL. */ |
| 263 | typedef |
| 264 | struct { |
| 265 | Addr from_addr; /* old addr -- MUST BE THE FIRST WORD! */ |
| 266 | Addr to_addr; /* where redirecting to */ |
| 267 | TopSpec* parent_spec; /* the TopSpec which supplied the Spec */ |
| 268 | TopSpec* parent_sym; /* the TopSpec which supplied the symbol */ |
| 269 | Bool isWrap; /* wrap or replacement? */ |
| 270 | } |
| 271 | Active; |
| 272 | |
| 273 | /* The active set is a fast lookup table */ |
| 274 | static OSet* activeSet = NULL; |
| 275 | |
| 276 | |
| 277 | /*------------------------------------------------------------*/ |
| 278 | /*--- FWDses ---*/ |
| 279 | /*------------------------------------------------------------*/ |
| 280 | |
| 281 | static void maybe_add_active ( Active /*by value; callee copies*/ ); |
| 282 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 283 | static void* dinfo_zalloc(SizeT); |
| 284 | static void dinfo_free(void*); |
| 285 | static HChar* dinfo_strdup(HChar*); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 286 | static Bool is_plausible_guest_addr(Addr); |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 287 | static Bool is_aix5_glink_idiom(Addr); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 288 | |
| 289 | static void show_redir_state ( HChar* who ); |
| 290 | static void show_active ( HChar* left, Active* act ); |
| 291 | |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 292 | static void handle_maybe_load_notifier( const UChar* soname, |
| 293 | HChar* symbol, Addr addr ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 294 | |
| 295 | |
| 296 | /*------------------------------------------------------------*/ |
| 297 | /*--- NOTIFICATIONS ---*/ |
| 298 | /*------------------------------------------------------------*/ |
| 299 | |
| 300 | static |
| 301 | void generate_and_add_actives ( |
| 302 | /* spec list and the owning TopSpec */ |
| 303 | Spec* specs, |
| 304 | TopSpec* parent_spec, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 305 | /* debuginfo and the owning TopSpec */ |
| 306 | DebugInfo* di, |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 307 | TopSpec* parent_sym |
| 308 | ); |
| 309 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 310 | /* Notify m_redir of the arrival of a new DebugInfo. This is fairly |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 311 | complex, but the net effect is to (1) add a new entry to the |
| 312 | topspecs list, and (2) figure out what new binding are now active, |
| 313 | and, as a result, add them to the actives mapping. */ |
| 314 | |
| 315 | #define N_DEMANGLED 256 |
| 316 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 317 | void VG_(redir_notify_new_DebugInfo)( DebugInfo* newsi ) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 318 | { |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 319 | Bool ok, isWrap; |
| 320 | Int i, nsyms; |
| 321 | Spec* specList; |
| 322 | Spec* spec; |
| 323 | TopSpec* ts; |
| 324 | TopSpec* newts; |
| 325 | HChar* sym_name; |
| 326 | Addr sym_addr, sym_toc; |
| 327 | HChar demangled_sopatt[N_DEMANGLED]; |
| 328 | HChar demangled_fnpatt[N_DEMANGLED]; |
| 329 | Bool check_ppcTOCs = False; |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 330 | Bool isText; |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 331 | const UChar* newsi_soname; |
| 332 | |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 333 | # if defined(VG_PLAT_USES_PPCTOC) |
| 334 | check_ppcTOCs = True; |
| 335 | # endif |
| 336 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 337 | vg_assert(newsi); |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 338 | newsi_soname = VG_(seginfo_soname)(newsi); |
| 339 | vg_assert(newsi_soname != NULL); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 340 | |
| 341 | /* stay sane: we don't already have this. */ |
| 342 | for (ts = topSpecs; ts; ts = ts->next) |
| 343 | vg_assert(ts->seginfo != newsi); |
| 344 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 345 | /* scan this DebugInfo's symbol table, pulling out and demangling |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 346 | any specs found */ |
| 347 | |
| 348 | specList = NULL; /* the spec list we're building up */ |
| 349 | |
| 350 | nsyms = VG_(seginfo_syms_howmany)( newsi ); |
| 351 | for (i = 0; i < nsyms; i++) { |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 352 | VG_(seginfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 353 | NULL, &sym_name, &isText ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 354 | ok = VG_(maybe_Z_demangle)( sym_name, demangled_sopatt, N_DEMANGLED, |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 355 | demangled_fnpatt, N_DEMANGLED, &isWrap ); |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 356 | /* ignore data symbols */ |
| 357 | if (!isText) |
| 358 | continue; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 359 | if (!ok) { |
| 360 | /* It's not a full-scale redirect, but perhaps it is a load-notify |
| 361 | fn? Let the load-notify department see it. */ |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 362 | handle_maybe_load_notifier( newsi_soname, sym_name, sym_addr ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 363 | continue; |
| 364 | } |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 365 | if (check_ppcTOCs && sym_toc == 0) { |
| 366 | /* This platform uses toc pointers, but none could be found |
| 367 | for this symbol, so we can't safely redirect/wrap to it. |
| 368 | Just skip it; we'll make a second pass over the symbols in |
| 369 | the following loop, and complain at that point. */ |
| 370 | continue; |
| 371 | } |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 372 | spec = dinfo_zalloc(sizeof(Spec)); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 373 | vg_assert(spec); |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 374 | spec->from_sopatt = dinfo_strdup(demangled_sopatt); |
| 375 | spec->from_fnpatt = dinfo_strdup(demangled_fnpatt); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 376 | vg_assert(spec->from_sopatt); |
| 377 | vg_assert(spec->from_fnpatt); |
| 378 | spec->to_addr = sym_addr; |
| 379 | spec->isWrap = isWrap; |
| 380 | /* check we're not adding manifestly stupid destinations */ |
| 381 | vg_assert(is_plausible_guest_addr(sym_addr)); |
| 382 | spec->next = specList; |
| 383 | spec->mark = False; /* not significant */ |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 384 | spec->done = False; /* not significant */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 385 | specList = spec; |
| 386 | } |
| 387 | |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 388 | if (check_ppcTOCs) { |
| 389 | for (i = 0; i < nsyms; i++) { |
| 390 | VG_(seginfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 391 | NULL, &sym_name, &isText ); |
| 392 | ok = isText |
| 393 | && VG_(maybe_Z_demangle)( |
| 394 | sym_name, demangled_sopatt, N_DEMANGLED, |
| 395 | demangled_fnpatt, N_DEMANGLED, &isWrap ); |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 396 | if (!ok) |
| 397 | /* not a redirect. Ignore. */ |
| 398 | continue; |
| 399 | if (sym_toc != 0) |
| 400 | /* has a valid toc pointer. Ignore. */ |
| 401 | continue; |
| 402 | |
| 403 | for (spec = specList; spec; spec = spec->next) |
| 404 | if (0 == VG_(strcmp)(spec->from_sopatt, demangled_sopatt) |
| 405 | && 0 == VG_(strcmp)(spec->from_fnpatt, demangled_fnpatt)) |
| 406 | break; |
| 407 | if (spec) |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 408 | /* a redirect to some other copy of that symbol, which |
| 409 | does have a TOC value, already exists */ |
| 410 | continue; |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 411 | |
| 412 | /* Complain */ |
| 413 | VG_(message)(Vg_DebugMsg, |
| 414 | "WARNING: no TOC ptr for redir/wrap to %s %s", |
| 415 | demangled_sopatt, demangled_fnpatt); |
| 416 | } |
| 417 | } |
| 418 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 419 | /* Ok. Now specList holds the list of specs from the DebugInfo. |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 420 | Build a new TopSpec, but don't add it to topSpecs yet. */ |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 421 | newts = dinfo_zalloc(sizeof(TopSpec)); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 422 | vg_assert(newts); |
| 423 | newts->next = NULL; /* not significant */ |
| 424 | newts->seginfo = newsi; |
| 425 | newts->specs = specList; |
| 426 | newts->mark = False; /* not significant */ |
| 427 | |
| 428 | /* We now need to augment the active set with the following partial |
| 429 | cross product: |
| 430 | |
| 431 | (1) actives formed by matching the new specs in specList against |
| 432 | all symbols currently listed in topSpecs |
| 433 | |
| 434 | (2) actives formed by matching the new symbols in newsi against |
| 435 | all specs currently listed in topSpecs |
| 436 | |
| 437 | (3) actives formed by matching the new symbols in newsi against |
| 438 | the new specs in specList |
| 439 | |
| 440 | This is necessary in order to maintain the invariant that |
| 441 | Actives contains all bindings generated by matching ALL specs in |
| 442 | topSpecs against ALL symbols in topSpecs (that is, a cross |
| 443 | product of ALL known specs against ALL known symbols). |
| 444 | */ |
| 445 | /* Case (1) */ |
| 446 | for (ts = topSpecs; ts; ts = ts->next) { |
| 447 | if (ts->seginfo) |
| 448 | generate_and_add_actives( specList, newts, |
| 449 | ts->seginfo, ts ); |
| 450 | } |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 451 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 452 | /* Case (2) */ |
| 453 | for (ts = topSpecs; ts; ts = ts->next) { |
| 454 | generate_and_add_actives( ts->specs, ts, |
| 455 | newsi, newts ); |
| 456 | } |
| 457 | |
| 458 | /* Case (3) */ |
| 459 | generate_and_add_actives( specList, newts, |
| 460 | newsi, newts ); |
| 461 | |
| 462 | /* Finally, add the new TopSpec. */ |
| 463 | newts->next = topSpecs; |
| 464 | topSpecs = newts; |
| 465 | |
| 466 | if (VG_(clo_trace_redir)) |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 467 | show_redir_state("after VG_(redir_notify_new_DebugInfo)"); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 468 | } |
| 469 | |
| 470 | #undef N_DEMANGLED |
| 471 | |
| 472 | |
| 473 | /* Do one element of the basic cross product: add to the active set, |
| 474 | all matches resulting from comparing all the given specs against |
| 475 | all the symbols in the given seginfo. If a conflicting binding |
| 476 | would thereby arise, don't add it, but do complain. */ |
| 477 | |
| 478 | static |
| 479 | void generate_and_add_actives ( |
| 480 | /* spec list and the owning TopSpec */ |
| 481 | Spec* specs, |
| 482 | TopSpec* parent_spec, |
| 483 | /* seginfo and the owning TopSpec */ |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 484 | DebugInfo* di, |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 485 | TopSpec* parent_sym |
| 486 | ) |
| 487 | { |
| 488 | Spec* sp; |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 489 | Bool anyMark, isText; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 490 | Active act; |
| 491 | Int nsyms, i; |
| 492 | Addr sym_addr; |
| 493 | HChar* sym_name; |
| 494 | |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 495 | /* First figure out which of the specs match the seginfo's soname. |
| 496 | Also clear the 'done' bits, so that after the main loop below |
| 497 | tell which of the Specs really did get done. */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 498 | anyMark = False; |
| 499 | for (sp = specs; sp; sp = sp->next) { |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 500 | sp->done = False; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 501 | sp->mark = VG_(string_match)( sp->from_sopatt, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 502 | VG_(seginfo_soname)(di) ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 503 | anyMark = anyMark || sp->mark; |
| 504 | } |
| 505 | |
| 506 | /* shortcut: if none of the sonames match, there will be no bindings. */ |
| 507 | if (!anyMark) |
| 508 | return; |
| 509 | |
| 510 | /* Iterate outermost over the symbols in the seginfo, in the hope |
| 511 | of trashing the caches less. */ |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 512 | nsyms = VG_(seginfo_syms_howmany)( di ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 513 | for (i = 0; i < nsyms; i++) { |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 514 | VG_(seginfo_syms_getidx)( di, i, |
| 515 | &sym_addr, NULL, NULL, &sym_name, &isText ); |
| 516 | |
| 517 | /* ignore data symbols */ |
| 518 | if (!isText) |
| 519 | continue; |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 520 | |
| 521 | /* On AIX, we cannot redirect calls to a so-called glink |
| 522 | function for reasons which are not obvious - something to do |
| 523 | with saving r2 across the call. Not a problem, as we don't |
| 524 | want to anyway; presumably it is the target of the glink we |
| 525 | need to redirect. Hence just spot them and ignore them. |
| 526 | They are always of a very specific (more or less |
| 527 | ABI-mandated) form. */ |
| 528 | if (is_aix5_glink_idiom(sym_addr)) |
| 529 | continue; |
| 530 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 531 | for (sp = specs; sp; sp = sp->next) { |
| 532 | if (!sp->mark) |
| 533 | continue; /* soname doesn't match */ |
| 534 | if (VG_(string_match)( sp->from_fnpatt, sym_name )) { |
| 535 | /* got a new binding. Add to collection. */ |
| 536 | act.from_addr = sym_addr; |
| 537 | act.to_addr = sp->to_addr; |
| 538 | act.parent_spec = parent_spec; |
| 539 | act.parent_sym = parent_sym; |
| 540 | act.isWrap = sp->isWrap; |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 541 | sp->done = True; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 542 | maybe_add_active( act ); |
| 543 | } |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 544 | } /* for (sp = specs; sp; sp = sp->next) */ |
| 545 | } /* for (i = 0; i < nsyms; i++) */ |
| 546 | |
| 547 | /* Now, finally, look for Specs which were marked to be done, but |
| 548 | didn't get matched. If any such are mandatory we must abort the |
| 549 | system at this point. */ |
| 550 | for (sp = specs; sp; sp = sp->next) { |
| 551 | if (!sp->mark) |
| 552 | continue; |
| 553 | if (sp->mark && (!sp->done) && sp->mandatory) |
| 554 | break; |
| 555 | } |
| 556 | if (sp) { |
| 557 | HChar* v = "valgrind: "; |
| 558 | vg_assert(sp->mark); |
| 559 | vg_assert(!sp->done); |
| 560 | vg_assert(sp->mandatory); |
| 561 | VG_(printf)("\n"); |
| 562 | VG_(printf)( |
| 563 | "%sFatal error at startup: a function redirection\n", v); |
| 564 | VG_(printf)( |
| 565 | "%swhich is mandatory for this platform-tool combination\n", v); |
| 566 | VG_(printf)( |
| 567 | "%scannot be set up. Details of the redirection are:\n", v); |
| 568 | VG_(printf)( |
| 569 | "%s\n", v); |
| 570 | VG_(printf)( |
| 571 | "%sA must-be-redirected function\n", v); |
| 572 | VG_(printf)( |
| 573 | "%swhose name matches the pattern: %s\n", v, sp->from_fnpatt); |
| 574 | VG_(printf)( |
| 575 | "%sin an object with soname matching: %s\n", v, sp->from_sopatt); |
| 576 | VG_(printf)( |
| 577 | "%swas not found whilst processing\n", v); |
| 578 | VG_(printf)( |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 579 | "%ssymbols from the object with soname: %s\n", v, VG_(seginfo_soname)(di)); |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 580 | VG_(printf)( |
| 581 | "%s\n", v); |
| 582 | VG_(printf)( |
| 583 | "%s%s\n", v, sp->mandatory); |
| 584 | VG_(printf)( |
| 585 | "%s\n", v); |
| 586 | VG_(printf)( |
| 587 | "%sCannot continue -- exiting now. Sorry.\n", v); |
| 588 | VG_(printf)("\n"); |
| 589 | VG_(exit)(1); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 590 | } |
| 591 | } |
| 592 | |
| 593 | |
| 594 | /* Add an act (passed by value; is copied here) and deal with |
| 595 | conflicting bindings. */ |
| 596 | static void maybe_add_active ( Active act ) |
| 597 | { |
| 598 | HChar* what = NULL; |
| 599 | Active* old; |
| 600 | |
| 601 | /* Complain and ignore manifestly bogus 'from' addresses. |
| 602 | |
| 603 | Kludge: because this can get called befor the trampoline area (a |
| 604 | bunch of magic 'to' addresses) has its ownership changed from V |
| 605 | to C, we can't check the 'to' address similarly. Sigh. |
| 606 | |
| 607 | amd64-linux hack: the vsysinfo pages appear to have no |
| 608 | permissions |
| 609 | ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0 |
| 610 | so skip the check for them. */ |
| 611 | if (!is_plausible_guest_addr(act.from_addr) |
| 612 | # if defined(VGP_amd64_linux) |
| 613 | && act.from_addr != 0xFFFFFFFFFF600000ULL |
| 614 | && act.from_addr != 0xFFFFFFFFFF600400ULL |
| 615 | # endif |
| 616 | ) { |
| 617 | what = "redirection from-address is in non-executable area"; |
| 618 | goto bad; |
| 619 | } |
| 620 | |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 621 | old = VG_(OSetGen_Lookup)( activeSet, &act.from_addr ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 622 | if (old) { |
| 623 | /* Dodgy. Conflicting binding. */ |
| 624 | vg_assert(old->from_addr == act.from_addr); |
| 625 | if (old->to_addr != act.to_addr) { |
| 626 | /* we have to ignore it -- otherwise activeSet would contain |
| 627 | conflicting bindings. */ |
| 628 | what = "new redirection conflicts with existing -- ignoring it"; |
| 629 | goto bad; |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 630 | } else { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 631 | /* This appears to be a duplicate of an existing binding. |
| 632 | Safe(ish) -- ignore. */ |
| 633 | /* XXXXXXXXXXX COMPLAIN if new and old parents differ */ |
tom | 748a131 | 2005-04-02 15:53:01 +0000 | [diff] [blame] | 634 | } |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 635 | } else { |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 636 | Active* a = VG_(OSetGen_AllocNode)(activeSet, sizeof(Active)); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 637 | vg_assert(a); |
| 638 | *a = act; |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 639 | VG_(OSetGen_Insert)(activeSet, a); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 640 | /* Now that a new from->to redirection is in force, we need to |
| 641 | get rid of any translations intersecting 'from' in order that |
| 642 | they get redirected to 'to'. So discard them. Just for |
| 643 | paranoia (but, I believe, unnecessarily), discard 'to' as |
| 644 | well. */ |
| 645 | VG_(discard_translations)( (Addr64)act.from_addr, 1, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 646 | "redir_new_DebugInfo(from_addr)"); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 647 | VG_(discard_translations)( (Addr64)act.to_addr, 1, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 648 | "redir_new_DebugInfo(to_addr)"); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 649 | } |
| 650 | return; |
| 651 | |
| 652 | bad: |
| 653 | vg_assert(what); |
| 654 | if (VG_(clo_verbosity) > 1) { |
| 655 | VG_(message)(Vg_UserMsg, "WARNING: %s", what); |
| 656 | show_active( " new: ", &act); |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 657 | } |
tom | 748a131 | 2005-04-02 15:53:01 +0000 | [diff] [blame] | 658 | } |
| 659 | |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 660 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 661 | /* Notify m_redir of the deletion of a DebugInfo. This is relatively |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 662 | simple -- just get rid of all actives derived from it, and free up |
| 663 | the associated list elements. */ |
| 664 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 665 | void VG_(redir_notify_delete_DebugInfo)( DebugInfo* delsi ) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 666 | { |
| 667 | TopSpec* ts; |
| 668 | TopSpec* tsPrev; |
| 669 | Spec* sp; |
| 670 | Spec* sp_next; |
| 671 | OSet* tmpSet; |
| 672 | Active* act; |
| 673 | Bool delMe; |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 674 | Addr addr; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 675 | |
| 676 | vg_assert(delsi); |
| 677 | |
| 678 | /* Search for it, and make tsPrev point to the previous entry, if |
| 679 | any. */ |
| 680 | tsPrev = NULL; |
| 681 | ts = topSpecs; |
| 682 | while (True) { |
| 683 | if (ts == NULL) break; |
| 684 | if (ts->seginfo == delsi) break; |
| 685 | tsPrev = ts; |
| 686 | ts = ts->next; |
| 687 | } |
| 688 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 689 | vg_assert(ts); /* else we don't have the deleted DebugInfo */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 690 | vg_assert(ts->seginfo == delsi); |
| 691 | |
| 692 | /* Traverse the actives, copying the addresses of those we intend |
| 693 | to delete into tmpSet. */ |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 694 | tmpSet = VG_(OSetWord_Create)(dinfo_zalloc, dinfo_free); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 695 | |
| 696 | ts->mark = True; |
| 697 | |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 698 | VG_(OSetGen_ResetIter)( activeSet ); |
| 699 | while ( (act = VG_(OSetGen_Next)(activeSet)) ) { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 700 | delMe = act->parent_spec != NULL |
| 701 | && act->parent_sym != NULL |
| 702 | && act->parent_spec->seginfo != NULL |
| 703 | && act->parent_sym->seginfo != NULL |
| 704 | && (act->parent_spec->mark || act->parent_sym->mark); |
| 705 | |
| 706 | /* While we're at it, a bit of paranoia: delete any actives |
sewardj | e6647f4 | 2006-03-12 00:39:19 +0000 | [diff] [blame] | 707 | which don't have both feet in valid client executable areas. |
| 708 | But don't delete hardwired-at-startup ones; these are denoted |
| 709 | by having parent_spec or parent_sym being NULL. */ |
| 710 | if ( (!delMe) |
| 711 | && act->parent_spec != NULL |
| 712 | && act->parent_sym != NULL ) { |
| 713 | if (!is_plausible_guest_addr(act->from_addr)) |
| 714 | delMe = True; |
| 715 | if (!is_plausible_guest_addr(act->to_addr)) |
| 716 | delMe = True; |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 717 | } |
| 718 | |
| 719 | if (delMe) { |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 720 | VG_(OSetWord_Insert)( tmpSet, act->from_addr ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 721 | /* While we have our hands on both the 'from' and 'to' |
| 722 | of this Active, do paranoid stuff with tt/tc. */ |
| 723 | VG_(discard_translations)( (Addr64)act->from_addr, 1, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 724 | "redir_del_DebugInfo(from_addr)"); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 725 | VG_(discard_translations)( (Addr64)act->to_addr, 1, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 726 | "redir_del_DebugInfo(to_addr)"); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 727 | } |
| 728 | } |
| 729 | |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 730 | /* Now traverse tmpSet, deleting corresponding elements in activeSet. */ |
| 731 | VG_(OSetWord_ResetIter)( tmpSet ); |
| 732 | while ( VG_(OSetWord_Next)(tmpSet, &addr) ) { |
| 733 | act = VG_(OSetGen_Remove)( activeSet, &addr ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 734 | vg_assert(act); |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 735 | VG_(OSetGen_FreeNode)( activeSet, act ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 736 | } |
| 737 | |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 738 | VG_(OSetWord_Destroy)( tmpSet ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 739 | |
| 740 | /* The Actives set is now cleaned up. Free up this TopSpec and |
| 741 | everything hanging off it. */ |
| 742 | for (sp = ts->specs; sp; sp = sp_next) { |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 743 | if (sp->from_sopatt) dinfo_free(sp->from_sopatt); |
| 744 | if (sp->from_fnpatt) dinfo_free(sp->from_fnpatt); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 745 | sp_next = sp->next; |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 746 | dinfo_free(sp); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 747 | } |
| 748 | |
| 749 | if (tsPrev == NULL) { |
| 750 | /* first in list */ |
| 751 | topSpecs = ts->next; |
njn | d9109c6 | 2005-06-26 04:49:25 +0000 | [diff] [blame] | 752 | } else { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 753 | tsPrev->next = ts->next; |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 754 | } |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 755 | dinfo_free(ts); |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 756 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 757 | if (VG_(clo_trace_redir)) |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 758 | show_redir_state("after VG_(redir_notify_delete_DebugInfo)"); |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 759 | } |
| 760 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 761 | |
| 762 | /*------------------------------------------------------------*/ |
| 763 | /*--- QUERIES (really the whole point of this module) ---*/ |
| 764 | /*------------------------------------------------------------*/ |
| 765 | |
| 766 | /* This is the crucial redirection function. It answers the question: |
| 767 | should this code address be redirected somewhere else? It's used |
| 768 | just before translating a basic block. */ |
| 769 | Addr VG_(redir_do_lookup) ( Addr orig, Bool* isWrap ) |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 770 | { |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 771 | Active* r = VG_(OSetGen_Lookup)(activeSet, &orig); |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 772 | if (r == NULL) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 773 | return orig; |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 774 | |
| 775 | vg_assert(r->to_addr != 0); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 776 | if (isWrap) |
| 777 | *isWrap = r->isWrap; |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 778 | return r->to_addr; |
| 779 | } |
| 780 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 781 | |
| 782 | /*------------------------------------------------------------*/ |
| 783 | /*--- INITIALISATION ---*/ |
| 784 | /*------------------------------------------------------------*/ |
| 785 | |
| 786 | /* Add a never-delete-me Active. */ |
| 787 | |
| 788 | __attribute__((unused)) /* only used on amd64 */ |
| 789 | static void add_hardwired_active ( Addr from, Addr to ) |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 790 | { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 791 | Active act; |
| 792 | act.from_addr = from; |
| 793 | act.to_addr = to; |
| 794 | act.parent_spec = NULL; |
| 795 | act.parent_sym = NULL; |
| 796 | act.isWrap = False; |
| 797 | maybe_add_active( act ); |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 798 | } |
| 799 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 800 | |
| 801 | /* Add a never-delete-me Spec. This is a bit of a kludge. On the |
| 802 | assumption that this is called only at startup, only handle the |
| 803 | case where topSpecs is completely empty, or if it isn't, it has |
| 804 | just one entry and that is the one with NULL seginfo -- that is the |
| 805 | entry that holds these initial specs. */ |
| 806 | |
| 807 | __attribute__((unused)) /* not used on all platforms */ |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 808 | static void add_hardwired_spec ( HChar* sopatt, HChar* fnpatt, |
| 809 | Addr to_addr, |
| 810 | HChar* mandatory ) |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 811 | { |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 812 | Spec* spec = dinfo_zalloc(sizeof(Spec)); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 813 | vg_assert(spec); |
| 814 | |
| 815 | if (topSpecs == NULL) { |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 816 | topSpecs = dinfo_zalloc(sizeof(TopSpec)); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 817 | vg_assert(topSpecs); |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 818 | /* symtab_zalloc sets all fields to zero */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 819 | } |
| 820 | |
| 821 | vg_assert(topSpecs != NULL); |
| 822 | vg_assert(topSpecs->next == NULL); |
| 823 | vg_assert(topSpecs->seginfo == NULL); |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 824 | /* FIXED PARTS */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 825 | spec->from_sopatt = sopatt; |
| 826 | spec->from_fnpatt = fnpatt; |
| 827 | spec->to_addr = to_addr; |
| 828 | spec->isWrap = False; |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 829 | spec->mandatory = mandatory; |
| 830 | /* VARIABLE PARTS */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 831 | spec->mark = False; /* not significant */ |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 832 | spec->done = False; /* not significant */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 833 | |
| 834 | spec->next = topSpecs->specs; |
| 835 | topSpecs->specs = spec; |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 836 | } |
| 837 | |
njn | 8a96ec5 | 2005-10-15 15:48:52 +0000 | [diff] [blame] | 838 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 839 | /* Initialise the redir system, and create the initial Spec list and |
| 840 | for amd64-linux a couple of permanent active mappings. The initial |
| 841 | Specs are not converted into Actives yet, on the (checked) |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 842 | assumption that no DebugInfos have so far been created, and so when |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 843 | they are created, that will happen. */ |
| 844 | |
| 845 | void VG_(redir_initialise) ( void ) |
| 846 | { |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 847 | // Assert that there are no DebugInfos so far |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 848 | vg_assert( VG_(next_seginfo)(NULL) == NULL ); |
| 849 | |
| 850 | // Initialise active mapping. |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 851 | activeSet = VG_(OSetGen_Create)(offsetof(Active, from_addr), |
| 852 | NULL, // Use fast comparison |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 853 | dinfo_zalloc, |
| 854 | dinfo_free); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 855 | |
| 856 | // The rest of this function just adds initial Specs. |
| 857 | |
| 858 | # if defined(VGP_x86_linux) |
sewardj | 6a443b2 | 2005-11-20 19:37:54 +0000 | [diff] [blame] | 859 | /* If we're using memcheck, use this intercept right from the |
| 860 | start, otherwise ld.so (glibc-2.3.5) makes a lot of noise. */ |
| 861 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 862 | add_hardwired_spec( |
| 863 | "ld-linux.so.2", "index", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 864 | (Addr)&VG_(x86_linux_REDIR_FOR_index), |
| 865 | NULL |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 866 | ); |
sewardj | 6a443b2 | 2005-11-20 19:37:54 +0000 | [diff] [blame] | 867 | } |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 868 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 869 | # elif defined(VGP_amd64_linux) |
njn | d1af003 | 2005-05-29 17:01:48 +0000 | [diff] [blame] | 870 | /* Redirect vsyscalls to local versions */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 871 | add_hardwired_active( |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 872 | 0xFFFFFFFFFF600000ULL, |
| 873 | (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday) |
| 874 | ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 875 | add_hardwired_active( |
tom | f5db3b6 | 2005-06-21 13:26:17 +0000 | [diff] [blame] | 876 | 0xFFFFFFFFFF600400ULL, |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 877 | (Addr)&VG_(amd64_linux_REDIR_FOR_vtime) |
| 878 | ); |
| 879 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 880 | # elif defined(VGP_ppc32_linux) |
sewardj | 96fcfc8 | 2005-11-18 21:12:52 +0000 | [diff] [blame] | 881 | /* If we're using memcheck, use these intercepts right from |
| 882 | the start, otherwise ld.so makes a lot of noise. */ |
| 883 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
sewardj | 0fd3049 | 2007-11-16 19:39:49 +0000 | [diff] [blame] | 884 | |
| 885 | static HChar* croakage = "Possible fix: install glibc's debuginfo " |
| 886 | "package on this machine."; |
| 887 | |
sewardj | 5092a97 | 2007-11-16 18:45:40 +0000 | [diff] [blame] | 888 | /* this is mandatory - can't sanely continue without it */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 889 | add_hardwired_spec( |
| 890 | "ld.so.1", "strlen", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 891 | (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen), |
sewardj | 5092a97 | 2007-11-16 18:45:40 +0000 | [diff] [blame] | 892 | croakage |
sewardj | 96fcfc8 | 2005-11-18 21:12:52 +0000 | [diff] [blame] | 893 | ); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 894 | add_hardwired_spec( |
sewardj | d5a30a4 | 2006-02-09 10:29:43 +0000 | [diff] [blame] | 895 | "ld.so.1", "strcmp", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 896 | (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp), |
sewardj | 5092a97 | 2007-11-16 18:45:40 +0000 | [diff] [blame] | 897 | NULL /* not mandatory - so why bother at all? */ |
| 898 | /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */ |
sewardj | 96fcfc8 | 2005-11-18 21:12:52 +0000 | [diff] [blame] | 899 | ); |
sewardj | cd8c95a | 2006-08-25 11:48:38 +0000 | [diff] [blame] | 900 | add_hardwired_spec( |
| 901 | "ld.so.1", "index", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 902 | (Addr)&VG_(ppc32_linux_REDIR_FOR_strchr), |
sewardj | 5092a97 | 2007-11-16 18:45:40 +0000 | [diff] [blame] | 903 | NULL /* not mandatory - so why bother at all? */ |
| 904 | /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */ |
sewardj | cd8c95a | 2006-08-25 11:48:38 +0000 | [diff] [blame] | 905 | ); |
sewardj | 96fcfc8 | 2005-11-18 21:12:52 +0000 | [diff] [blame] | 906 | } |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 907 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 908 | # elif defined(VGP_ppc64_linux) |
sewardj | f0915fc | 2006-01-05 14:07:04 +0000 | [diff] [blame] | 909 | /* If we're using memcheck, use these intercepts right from |
| 910 | the start, otherwise ld.so makes a lot of noise. */ |
| 911 | if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { |
| 912 | |
sewardj | 0fd3049 | 2007-11-16 19:39:49 +0000 | [diff] [blame] | 913 | static HChar* croakage = "Possible fix: install glibc's debuginfo " |
| 914 | "package on this machine."; |
| 915 | |
| 916 | /* this is mandatory - can't sanely continue without it */ |
sewardj | 1a85f4f | 2006-01-12 21:15:35 +0000 | [diff] [blame] | 917 | add_hardwired_spec( |
| 918 | "ld64.so.1", "strlen", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 919 | (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strlen) ), |
sewardj | 0fd3049 | 2007-11-16 19:39:49 +0000 | [diff] [blame] | 920 | croakage |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 921 | ); |
sewardj | f0915fc | 2006-01-05 14:07:04 +0000 | [diff] [blame] | 922 | |
sewardj | 1a85f4f | 2006-01-12 21:15:35 +0000 | [diff] [blame] | 923 | add_hardwired_spec( |
| 924 | "ld64.so.1", "index", |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 925 | (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strchr) ), |
sewardj | 0fd3049 | 2007-11-16 19:39:49 +0000 | [diff] [blame] | 926 | NULL /* not mandatory - so why bother at all? */ |
| 927 | /* glibc-2.5 (FC6, ppc64) seems fine without it */ |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 928 | ); |
sewardj | 1a85f4f | 2006-01-12 21:15:35 +0000 | [diff] [blame] | 929 | |
sewardj | f0915fc | 2006-01-05 14:07:04 +0000 | [diff] [blame] | 930 | } |
sewardj | 2c48c7b | 2005-11-29 13:05:56 +0000 | [diff] [blame] | 931 | |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 932 | # elif defined(VGP_ppc32_aix5) |
| 933 | /* nothing so far */ |
| 934 | |
| 935 | # elif defined(VGP_ppc64_aix5) |
| 936 | /* nothing so far */ |
| 937 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 938 | # else |
| 939 | # error Unknown platform |
| 940 | # endif |
| 941 | |
| 942 | if (VG_(clo_trace_redir)) |
| 943 | show_redir_state("after VG_(redir_initialise)"); |
njn | d1af003 | 2005-05-29 17:01:48 +0000 | [diff] [blame] | 944 | } |
sewardj | cbdddcf | 2005-03-10 23:23:45 +0000 | [diff] [blame] | 945 | |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 946 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 947 | /*------------------------------------------------------------*/ |
| 948 | /*--- MISC HELPERS ---*/ |
| 949 | /*------------------------------------------------------------*/ |
| 950 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 951 | static void* dinfo_zalloc(SizeT n) { |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 952 | void* p; |
| 953 | vg_assert(n > 0); |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 954 | p = VG_(arena_malloc)(VG_AR_DINFO, n); |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 955 | tl_assert(p); |
| 956 | VG_(memset)(p, 0, n); |
| 957 | return p; |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 958 | } |
| 959 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 960 | static void dinfo_free(void* p) { |
sewardj | df24cf1 | 2007-11-16 18:32:40 +0000 | [diff] [blame] | 961 | tl_assert(p); |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 962 | return VG_(arena_free)(VG_AR_DINFO, p); |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 963 | } |
| 964 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 965 | static HChar* dinfo_strdup(HChar* str) |
njn | bc6d84d | 2005-06-19 18:58:03 +0000 | [diff] [blame] | 966 | { |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 967 | return VG_(arena_strdup)(VG_AR_DINFO, str); |
njn | bc6d84d | 2005-06-19 18:58:03 +0000 | [diff] [blame] | 968 | } |
| 969 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 970 | /* Really this should be merged with translations_allowable_from_seg |
| 971 | in m_translate. */ |
| 972 | static Bool is_plausible_guest_addr(Addr a) |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 973 | { |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 974 | NSegment const* seg = VG_(am_find_nsegment)(a); |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 975 | return seg != NULL |
| 976 | && (seg->kind == SkAnonC || seg->kind == SkFileC) |
| 977 | && (seg->hasX || seg->hasR); /* crude x86-specific hack */ |
| 978 | } |
| 979 | |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 980 | /* A function which spots AIX 'glink' functions. A 'glink' function |
| 981 | is a stub function which has something to do with AIX-style dynamic |
| 982 | linking, and jumps to the real target (with which it typically |
| 983 | shares the same name). See also comment where this function is |
| 984 | used (above). */ |
| 985 | static Bool is_aix5_glink_idiom ( Addr sym_addr ) |
| 986 | { |
| 987 | # if defined(VGP_ppc32_aix5) |
| 988 | UInt* w = (UInt*)sym_addr; |
| 989 | if (VG_IS_4_ALIGNED(w) |
| 990 | && is_plausible_guest_addr((Addr)(w+0)) |
| 991 | && is_plausible_guest_addr((Addr)(w+6)) |
| 992 | && (w[0] & 0xFFFF0000) == 0x81820000 /* lwz r12,func@toc(r2) */ |
| 993 | && w[1] == 0x90410014 /* stw r2,20(r1) */ |
| 994 | && w[2] == 0x800c0000 /* lwz r0,0(r12) */ |
| 995 | && w[3] == 0x804c0004 /* lwz r2,4(r12) */ |
| 996 | && w[4] == 0x7c0903a6 /* mtctr r0 */ |
| 997 | && w[5] == 0x4e800420 /* bctr */ |
| 998 | && w[6] == 0x00000000 /* illegal */) |
| 999 | return True; |
| 1000 | # elif defined(VGP_ppc64_aix5) |
| 1001 | UInt* w = (UInt*)sym_addr; |
| 1002 | if (VG_IS_4_ALIGNED(w) |
| 1003 | && is_plausible_guest_addr((Addr)(w+0)) |
| 1004 | && is_plausible_guest_addr((Addr)(w+6)) |
| 1005 | && (w[0] & 0xFFFF0000) == 0xE9820000 /* ld r12,func@toc(r2) */ |
| 1006 | && w[1] == 0xF8410028 /* std r2,40(r1) */ |
| 1007 | && w[2] == 0xE80C0000 /* ld r0,0(r12) */ |
| 1008 | && w[3] == 0xE84C0008 /* ld r2,8(r12) */ |
| 1009 | && w[4] == 0x7c0903a6 /* mtctr r0 */ |
| 1010 | && w[5] == 0x4e800420 /* bctr */ |
| 1011 | && w[6] == 0x00000000 /* illegal */) |
| 1012 | return True; |
| 1013 | # endif |
| 1014 | return False; |
| 1015 | } |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1016 | |
| 1017 | /*------------------------------------------------------------*/ |
| 1018 | /*--- NOTIFY-ON-LOAD FUNCTIONS ---*/ |
| 1019 | /*------------------------------------------------------------*/ |
| 1020 | |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 1021 | static |
| 1022 | void handle_maybe_load_notifier( const UChar* soname, |
| 1023 | HChar* symbol, Addr addr ) |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1024 | { |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 1025 | # if defined(VGP_x86_linux) |
| 1026 | /* x86-linux only: if we see _dl_sysinfo_int80, note its address. |
| 1027 | See comment on declaration of VG_(client__dl_sysinfo_int80) for |
| 1028 | the reason. As far as I can tell, the relevant symbol is always |
| 1029 | in object with soname "ld-linux.so.2". */ |
| 1030 | if (symbol && symbol[0] == '_' |
| 1031 | && 0 == VG_(strcmp)(symbol, "_dl_sysinfo_int80") |
| 1032 | && 0 == VG_(strcmp)(soname, "ld-linux.so.2")) { |
| 1033 | if (VG_(client__dl_sysinfo_int80) == 0) |
| 1034 | VG_(client__dl_sysinfo_int80) = addr; |
| 1035 | } |
| 1036 | # endif |
| 1037 | |
| 1038 | /* Normal load-notifier handling after here. First, ignore all |
| 1039 | symbols lacking the right prefix. */ |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1040 | if (0 != VG_(strncmp)(symbol, VG_NOTIFY_ON_LOAD_PREFIX, |
| 1041 | VG_NOTIFY_ON_LOAD_PREFIX_LEN)) |
| 1042 | /* Doesn't have the right prefix */ |
| 1043 | return; |
| 1044 | |
| 1045 | if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(freeres))) == 0) |
| 1046 | VG_(client___libc_freeres_wrapper) = addr; |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1047 | else |
| 1048 | vg_assert2(0, "unrecognised load notification function: %s", symbol); |
| 1049 | } |
| 1050 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1051 | |
| 1052 | /*------------------------------------------------------------*/ |
| 1053 | /*--- SANITY/DEBUG ---*/ |
| 1054 | /*------------------------------------------------------------*/ |
| 1055 | |
| 1056 | static void show_spec ( HChar* left, Spec* spec ) |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1057 | { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1058 | VG_(message)(Vg_DebugMsg, |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 1059 | "%s%25s %30s %s-> 0x%08llx", |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1060 | left, |
| 1061 | spec->from_sopatt, spec->from_fnpatt, |
| 1062 | spec->isWrap ? "W" : "R", |
| 1063 | (ULong)spec->to_addr ); |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1064 | } |
| 1065 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1066 | static void show_active ( HChar* left, Active* act ) |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1067 | { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1068 | Bool ok; |
| 1069 | HChar name1[64] = ""; |
| 1070 | HChar name2[64] = ""; |
| 1071 | name1[0] = name2[0] = 0; |
| 1072 | ok = VG_(get_fnname_w_offset)(act->from_addr, name1, 64); |
| 1073 | if (!ok) VG_(strcpy)(name1, "???"); |
| 1074 | ok = VG_(get_fnname_w_offset)(act->to_addr, name2, 64); |
| 1075 | if (!ok) VG_(strcpy)(name2, "???"); |
| 1076 | |
sewardj | 6b9cc87 | 2006-10-17 01:39:30 +0000 | [diff] [blame] | 1077 | VG_(message)(Vg_DebugMsg, "%s0x%08llx (%20s) %s-> 0x%08llx %s", |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1078 | left, |
| 1079 | (ULong)act->from_addr, name1, |
| 1080 | act->isWrap ? "W" : "R", |
| 1081 | (ULong)act->to_addr, name2 ); |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1082 | } |
| 1083 | |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1084 | static void show_redir_state ( HChar* who ) |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1085 | { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1086 | TopSpec* ts; |
| 1087 | Spec* sp; |
| 1088 | Active* act; |
| 1089 | VG_(message)(Vg_DebugMsg, "<<"); |
| 1090 | VG_(message)(Vg_DebugMsg, " ------ REDIR STATE %s ------", who); |
| 1091 | for (ts = topSpecs; ts; ts = ts->next) { |
| 1092 | VG_(message)(Vg_DebugMsg, |
| 1093 | " TOPSPECS of soname %s", |
| 1094 | ts->seginfo ? (HChar*)VG_(seginfo_soname)(ts->seginfo) |
| 1095 | : "(hardwired)" ); |
| 1096 | for (sp = ts->specs; sp; sp = sp->next) |
| 1097 | show_spec(" ", sp); |
| 1098 | } |
| 1099 | VG_(message)(Vg_DebugMsg, " ------ ACTIVE ------"); |
njn | e2a9ad3 | 2007-09-17 05:30:48 +0000 | [diff] [blame] | 1100 | VG_(OSetGen_ResetIter)( activeSet ); |
| 1101 | while ( (act = VG_(OSetGen_Next)(activeSet)) ) { |
sewardj | 0ec07f3 | 2006-01-12 12:32:32 +0000 | [diff] [blame] | 1102 | show_active(" ", act); |
| 1103 | } |
| 1104 | |
| 1105 | VG_(message)(Vg_DebugMsg, ">>"); |
njn | 16eeb4e | 2005-06-16 03:56:58 +0000 | [diff] [blame] | 1106 | } |
| 1107 | |
njn | c0ae705 | 2005-08-25 22:55:19 +0000 | [diff] [blame] | 1108 | /*--------------------------------------------------------------------*/ |
| 1109 | /*--- end ---*/ |
| 1110 | /*--------------------------------------------------------------------*/ |