Home | History | Annotate | Download | only in coregrind
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Function replacement and wrapping.                 m_redir.c ---*/
      4 /*--------------------------------------------------------------------*/
      5 
      6 /*
      7    This file is part of Valgrind, a dynamic binary instrumentation
      8    framework.
      9 
     10    Copyright (C) 2000-2015 Julian Seward
     11       jseward (at) acm.org
     12    Copyright (C) 2003-2015 Jeremy Fitzhardinge
     13       jeremy (at) 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 */
     32 
     33 #include "pub_core_basics.h"
     34 #include "pub_core_debuglog.h"
     35 #include "pub_core_debuginfo.h"
     36 #include "pub_core_libcbase.h"
     37 #include "pub_core_libcassert.h"
     38 #include "pub_core_libcprint.h"
     39 #include "pub_core_vki.h"
     40 #include "pub_core_libcfile.h"
     41 #include "pub_core_seqmatch.h"
     42 #include "pub_core_mallocfree.h"
     43 #include "pub_core_options.h"
     44 #include "pub_core_oset.h"
     45 #include "pub_core_redir.h"
     46 #include "pub_core_trampoline.h"
     47 #include "pub_core_transtab.h"
     48 #include "pub_core_tooliface.h"    // VG_(needs).malloc_replacement
     49 #include "pub_core_machine.h"      // VG_(fnptr_to_fnentry)
     50 #include "pub_core_aspacemgr.h"    // VG_(am_find_nsegment)
     51 #include "pub_core_xarray.h"
     52 #include "pub_core_clientstate.h"  // VG_(client___libc_freeres_wrapper)
     53 #include "pub_core_demangle.h"     // VG_(maybe_Z_demangle)
     54 #include "pub_core_libcproc.h"     // VG_(libdir)
     55 
     56 #include "config.h" /* GLIBC_MANDATORY_*_REDIRECT */
     57 
     58 
     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.
     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).
     81 
     82    Redirect specifications are really symbols with "funny" prefixes
     83    (_vgrNNNNZU_ and _vgrNNNNZZ_).  These names tell m_redir that the
     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
     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.
     95 
     96    When a shared object is unloaded, this module learns of it via a
     97    call to VG_(redir_notify_delete_DebugInfo).  It then removes from
     98    its tables all active redirections in any way associated with that
     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 
    107 /*------------------------------------------------------------*/
    108 /*--- Semantics                                            ---*/
    109 /*------------------------------------------------------------*/
    110 
    111 /* The redirector holds two pieces of state:
    112 
    113      Specs  - a set of   (soname pattern, fnname pattern) -> redir addr
    114      Active - a set of   orig addr -> (bool, redir addr)
    115 
    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.
    119 
    120    Active is a pure function of Specs and the current symbol table
    121    state (maintained by m_debuginfo).  Call the latter SyminfoState.
    122 
    123    Therefore whenever either Specs or SyminfoState changes, Active
    124    must be recomputed.  [Inefficient if done naively, but this is a
    125    spec].
    126 
    127    Active is computed as follows:
    128 
    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          }
    139       }
    140 
    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 
    179    When a new DebugInfo appears:
    180    - it may be the source of new specs
    181    - it may be the source of new matches for existing specs
    182    Therefore:
    183 
    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
    187      new actives.
    188 
    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.
    192 
    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.
    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 
    206    When a DebugInfo disappears:
    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
    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. */
    228 typedef
    229    struct _Spec {
    230       struct _Spec* next;  /* linked list */
    231       /* FIXED PARTS -- set when created and not changed */
    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? */
    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. */
    239       Int    becPrio; /* 0 through 9.  Behavioural equivalence class prio.
    240                          Used to choose between competing wrappers with
    241                          the same (non-zero) tag. */
    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 */
    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 */
    248    }
    249    Spec;
    250 
    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
    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 */
    259       const DebugInfo* seginfo;    /* symbols etc */
    260       Spec*      specs;      /* specs pulled out of seginfo */
    261       Bool       mark; /* transient temporary used during deletion */
    262    }
    263    TopSpec;
    264 
    265 /* This is the top level list of redirections.  m_debuginfo maintains
    266    a list of DebugInfos, and the idea here is to maintain a list with
    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 */
    286       Int      becTag;      /* behavioural eclass tag for ::to_addr */
    287       Int      becPrio;     /* and its priority */
    288       Bool     isWrap;      /* wrap or replacement? */
    289       Bool     isIFunc;     /* indirect function? */
    290    }
    291    Active;
    292 
    293 /* The active set is a fast lookup table */
    294 static OSet* activeSet = NULL;
    295 
    296 /* Wrapper routine for indirect functions */
    297 static Addr iFuncWrapper;
    298 
    299 /*------------------------------------------------------------*/
    300 /*--- FWDses                                               ---*/
    301 /*------------------------------------------------------------*/
    302 
    303 static void maybe_add_active ( Active /*by value; callee copies*/ );
    304 
    305 static void*  dinfo_zalloc(const HChar* ec, SizeT);
    306 static void   dinfo_free(void*);
    307 static HChar* dinfo_strdup(const HChar* ec, const HChar*);
    308 static Bool   is_plausible_guest_addr(Addr);
    309 
    310 static void   show_redir_state ( const HChar* who );
    311 static void   show_active ( const HChar* left, const Active* act );
    312 
    313 static void   handle_maybe_load_notifier( const HChar* soname,
    314                                           const HChar* symbol, Addr addr );
    315 
    316 static void   handle_require_text_symbols ( const DebugInfo* );
    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,
    327 	/* debuginfo and the owning TopSpec */
    328         const DebugInfo* di,
    329         TopSpec* parent_sym
    330      );
    331 
    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. */
    337 static const HChar** alloc_symname_array ( const HChar* pri_name,
    338                                            const HChar** sec_names,
    339                                            const HChar** twoslots )
    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;
    350    const HChar** pp = sec_names;
    351    while (*pp) { n_req++; pp++; }
    352    /* .. allocate and copy in. */
    353    const HChar** arr = dinfo_zalloc("redir.asa.1", (n_req+1) * sizeof(HChar*));
    354    Word    i   = 0;
    355    arr[i++] = pri_name;
    356    pp = sec_names;
    357    while (*pp) { arr[i++] = *pp; pp++; }
    358    vg_assert(i == n_req);
    359    vg_assert(arr[n_req] == NULL);
    360    return arr;
    361 }
    362 
    363 
    364 /* Free the array allocated by alloc_symname_array, if any. */
    365 static void free_symname_array ( const HChar** names, const HChar** twoslots )
    366 {
    367    if (names != twoslots)
    368       dinfo_free(names);
    369 }
    370 
    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 }
    383 
    384 /* Notify m_redir of the arrival of a new DebugInfo.  This is fairly
    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 
    389 void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi )
    390 {
    391    Bool         ok, isWrap;
    392    Int          i, nsyms, becTag, becPrio;
    393    Spec*        specList;
    394    Spec*        spec;
    395    TopSpec*     ts;
    396    TopSpec*     newts;
    397    const HChar*  sym_name_pri;
    398    const HChar** sym_names_sec;
    399    SymAVMAs     sym_avmas;
    400    const HChar* demangled_sopatt;
    401    const HChar* demangled_fnpatt;
    402    Bool         check_ppcTOCs = False;
    403    Bool         isText;
    404    const HChar* newdi_soname;
    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";
    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
    414 
    415 #  if defined(VG_PLAT_USES_PPCTOC)
    416    check_ppcTOCs = True;
    417 #  endif
    418 
    419    vg_assert(newdi);
    420    newdi_soname = VG_(DebugInfo_get_soname)(newdi);
    421    vg_assert(newdi_soname != NULL);
    422 
    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       */
    448       const HChar* newdi_filename = VG_(DebugInfo_get_filename)(newdi);
    449       const HChar* newdi_basename = VG_(basename) (newdi_filename);
    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;
    458          struct vg_stat in_vglib_stat;
    459          SysRes in_vglib_res;
    460 
    461          newdi_res = VG_(stat)(newdi_filename, &newdi_stat);
    462 
    463          HChar in_vglib_filename[VG_(strlen)(VG_(libdir)) + 1 +
    464                                  VG_(strlen)(newdi_basename) + 1];
    465          VG_(sprintf)(in_vglib_filename, "%s/%s", VG_(libdir), newdi_basename);
    466 
    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 
    499    /* stay sane: we don't already have this. */
    500    for (ts = topSpecs; ts; ts = ts->next)
    501       vg_assert(ts->seginfo != newdi);
    502 
    503    /* scan this DebugInfo's symbol table, pulling out and demangling
    504       any specs found */
    505 
    506    specList = NULL; /* the spec list we're building up */
    507 
    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 
    512 #if defined(VGO_solaris)
    513    vg_vfork_fildes_var_search =
    514       0 == VG_(strcmp)(newdi_soname, vg_preload_core_soname);
    515 #endif
    516 
    517    nsyms = VG_(DebugInfo_syms_howmany)( newdi );
    518    for (i = 0; i < nsyms; i++) {
    519       VG_(DebugInfo_syms_getidx)( newdi, i, &sym_avmas,
    520                                   NULL, &sym_name_pri, &sym_names_sec,
    521                                   &isText, NULL );
    522       /* Set up to conveniently iterate over all names for this symbol. */
    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;
    527       for (names = names_init; *names; names++) {
    528          ok = VG_(maybe_Z_demangle)( *names,
    529                                      &demangled_sopatt,
    530                                      &demangled_fnpatt,
    531                                      &isWrap, &becTag, &becPrio );
    532          /* ignore data symbols */
    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             }
    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
    559             continue;
    560          }
    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. */
    564             handle_maybe_load_notifier( newdi_soname, *names, sym_avmas.main );
    565             continue;
    566          }
    567          if (check_ppcTOCs && GET_TOCPTR_AVMA(sym_avmas) == 0) {
    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          }
    574 
    575          HChar *replaced_sopatt = NULL;
    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);
    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;
    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.
    615             if (replaced_sopatt == NULL)
    616                continue;
    617          }
    618 
    619          spec = dinfo_zalloc("redir.rnnD.1", sizeof(Spec));
    620          spec->from_sopatt = dinfo_strdup("redir.rnnD.2", demangled_sopatt);
    621          spec->from_fnpatt = dinfo_strdup("redir.rnnD.3", demangled_fnpatt);
    622          spec->to_addr = sym_avmas.main;
    623          spec->isWrap = isWrap;
    624          spec->becTag = becTag;
    625          spec->becPrio = becPrio;
    626          /* check we're not adding manifestly stupid destinations */
    627          vg_assert(is_plausible_guest_addr(sym_avmas.main));
    628          spec->next = specList;
    629          spec->mark = False; /* not significant */
    630          spec->done = False; /* not significant */
    631          specList = spec;
    632       }
    633       free_symname_array(names_init, &twoslots[0]);
    634    }
    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    }
    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
    651 
    652    if (check_ppcTOCs) {
    653       for (i = 0; i < nsyms; i++) {
    654          VG_(DebugInfo_syms_getidx)( newdi, i, &sym_avmas,
    655                                      NULL, &sym_name_pri, &sym_names_sec,
    656                                      &isText, NULL );
    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;
    661          for (names = names_init; *names; names++) {
    662             ok = isText
    663                  && VG_(maybe_Z_demangle)(
    664                        *names, &demangled_sopatt,
    665                        &demangled_fnpatt, &isWrap, NULL, NULL );
    666             if (!ok)
    667                /* not a redirect.  Ignore. */
    668                continue;
    669             if (GET_TOCPTR_AVMA(sym_avmas) != 0)
    670                /* has a valid toc pointer.  Ignore. */
    671                continue;
    672 
    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;
    681 
    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]);
    688       }
    689    }
    690 
    691    /* Ok.  Now specList holds the list of specs from the DebugInfo.
    692       Build a new TopSpec, but don't add it to topSpecs yet. */
    693    newts = dinfo_zalloc("redir.rnnD.4", sizeof(TopSpec));
    694    newts->next    = NULL; /* not significant */
    695    newts->seginfo = newdi;
    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 
    705       (2) actives formed by matching the new symbols in newdi against
    706           all specs currently listed in topSpecs
    707 
    708       (3) actives formed by matching the new symbols in newdi against
    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    }
    722 
    723    /* Case (2) */
    724    for (ts = topSpecs; ts; ts = ts->next) {
    725       generate_and_add_actives( ts->specs, ts,
    726                                 newdi,     newts );
    727    }
    728 
    729    /* Case (3) */
    730    generate_and_add_actives( specList, newts,
    731                              newdi,    newts );
    732 
    733    /* Finally, add the new TopSpec. */
    734    newts->next = topSpecs;
    735    topSpecs = newts;
    736 
    737    if (VG_(clo_trace_redir))
    738       show_redir_state("after VG_(redir_notify_new_DebugInfo)");
    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. */
    743    handle_require_text_symbols(newdi);
    744 }
    745 
    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,
    766                      "Adding redirect for indirect function "
    767                      "0x%lx from 0x%lx -> 0x%lx\n",
    768                      old_from, new_from, new.to_addr );
    769     }
    770 }
    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 */
    783         const DebugInfo* di,
    784         TopSpec* parent_sym
    785      )
    786 {
    787    Spec*   sp;
    788    Bool    anyMark, isText, isIFunc;
    789    Active  act;
    790    Int     nsyms, i;
    791    SymAVMAs  sym_avmas;
    792    const HChar*  sym_name_pri;
    793    const HChar** sym_names_sec;
    794 
    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. */
    798    anyMark = False;
    799    for (sp = specs; sp; sp = sp->next) {
    800       sp->done = False;
    801       sp->mark = VG_(string_match)( sp->from_sopatt,
    802                                     VG_(DebugInfo_get_soname)(di) );
    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. */
    812    nsyms = VG_(DebugInfo_syms_howmany)( di );
    813    for (i = 0; i < nsyms; i++) {
    814       VG_(DebugInfo_syms_getidx)( di, i, &sym_avmas,
    815                                   NULL, &sym_name_pri, &sym_names_sec,
    816                                   &isText, &isIFunc );
    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;
    821       for (names = names_init; *names; names++) {
    822 
    823          /* ignore data symbols */
    824          if (!isText)
    825             continue;
    826 
    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. */
    832                act.from_addr   = sym_avmas.main;
    833                act.to_addr     = sp->to_addr;
    834                act.parent_spec = parent_spec;
    835                act.parent_sym  = parent_sym;
    836                act.becTag      = sp->becTag;
    837                act.becPrio     = sp->becPrio;
    838                act.isWrap      = sp->isWrap;
    839                act.isIFunc     = isIFunc;
    840                sp->done = True;
    841                maybe_add_active( act );
    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
    847                 * in PPC64 Little Endian.
    848                 */
    849                if (GET_LOCAL_EP_AVMA(sym_avmas) != 0) {
    850                   act.from_addr = GET_LOCAL_EP_AVMA(sym_avmas);
    851                   maybe_add_active( act );
    852                }
    853 
    854             }
    855          } /* for (sp = specs; sp; sp = sp->next) */
    856 
    857       } /* iterating over names[] */
    858       free_symname_array(names_init, &twoslots[0]);
    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) {
    871       const HChar** strp;
    872       const HChar* v = "valgrind:  ";
    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)(
    894       "%ssymbols from the object with soname: %s\n",
    895       v, VG_(DebugInfo_get_soname)(di));
    896       VG_(printf)(
    897       "%s\n", v);
    898 
    899       for (strp = sp->mandatory; *strp; strp++)
    900          VG_(printf)(
    901          "%s%s\n", v, *strp);
    902 
    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);
    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 {
    917    const HChar*  what = NULL;
    918    Active* old     = NULL;
    919    Bool    add_act = False;
    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
    935        && act.from_addr != 0xFFFFFFFFFF600800ULL
    936 #      endif
    937       ) {
    938       what = "redirection from-address is in non-executable area";
    939       goto bad;
    940    }
    941 
    942    old = VG_(OSetGen_Lookup)( activeSet, &act.from_addr );
    943    if (old) {
    944       /* Dodgy.  Conflicting binding. */
    945       vg_assert(old->from_addr == act.from_addr);
    946       if (old->to_addr != act.to_addr) {
    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. */
    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. */
    976             if (VG_(clo_verbosity) > 2) {
    977                VG_(message)(Vg_UserMsg, "Ignoring %s redirection:\n",
    978                             act.becPrio < old->becPrio ? "lower priority"
    979                                                        : "duplicate");
    980                show_active(             "    old: ", old);
    981                show_active(             "    new: ", &act);
    982             }
    983          } else {
    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;
    998          }
    999       } else {
   1000          /* This appears to be a duplicate of an existing binding.
   1001             Safe(ish) -- ignore. */
   1002          /* XXXXXXXXXXX COMPLAIN if new and old parents differ */
   1003       }
   1004 
   1005    } else {
   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) {
   1013       Active* a = VG_(OSetGen_AllocNode)(activeSet, sizeof(Active));
   1014       vg_assert(a);
   1015       *a = act;
   1016       VG_(OSetGen_Insert)(activeSet, a);
   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. */
   1022       VG_(discard_translations)( act.from_addr, 1,
   1023                                  "redir_new_DebugInfo(from_addr)");
   1024       VG_(discard_translations)( act.to_addr, 1,
   1025                                  "redir_new_DebugInfo(to_addr)");
   1026       if (VG_(clo_verbosity) > 2) {
   1027          VG_(message)(Vg_UserMsg, "Adding active redirection:\n");
   1028          show_active(             "    new: ", &act);
   1029       }
   1030    }
   1031    return;
   1032 
   1033   bad:
   1034    vg_assert(what);
   1035    vg_assert(!add_act);
   1036    if (VG_(clo_verbosity) > 1) {
   1037       VG_(message)(Vg_UserMsg, "WARNING: %s\n", what);
   1038       if (old) {
   1039          show_active(             "    old: ", old);
   1040       }
   1041       show_active(             "    new: ", &act);
   1042    }
   1043 }
   1044 
   1045 
   1046 /* Notify m_redir of the deletion of a DebugInfo.  This is relatively
   1047    simple -- just get rid of all actives derived from it, and free up
   1048    the associated list elements. */
   1049 
   1050 void VG_(redir_notify_delete_DebugInfo)( const DebugInfo* delsi )
   1051 {
   1052    TopSpec* ts;
   1053    TopSpec* tsPrev;
   1054    Spec*    sp;
   1055    Spec*    sp_next;
   1056    OSet*    tmpSet;
   1057    Active*  act;
   1058    Bool     delMe;
   1059    Addr     addr;
   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 
   1074    vg_assert(ts); /* else we don't have the deleted DebugInfo */
   1075    vg_assert(ts->seginfo == delsi);
   1076 
   1077    /* Traverse the actives, copying the addresses of those we intend
   1078       to delete into tmpSet. */
   1079    tmpSet = VG_(OSetWord_Create)(dinfo_zalloc, "redir.rndD.1", dinfo_free);
   1080 
   1081    ts->mark = True;
   1082 
   1083    VG_(OSetGen_ResetIter)( activeSet );
   1084    while ( (act = VG_(OSetGen_Next)(activeSet)) ) {
   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
   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;
   1102       }
   1103 
   1104       if (delMe) {
   1105          VG_(OSetWord_Insert)( tmpSet, act->from_addr );
   1106          /* While we have our hands on both the 'from' and 'to'
   1107             of this Active, do paranoid stuff with tt/tc. */
   1108          VG_(discard_translations)( act->from_addr, 1,
   1109                                     "redir_del_DebugInfo(from_addr)");
   1110          VG_(discard_translations)( act->to_addr, 1,
   1111                                     "redir_del_DebugInfo(to_addr)");
   1112       }
   1113    }
   1114 
   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 );
   1119       vg_assert(act);
   1120       VG_(OSetGen_FreeNode)( activeSet, act );
   1121    }
   1122 
   1123    VG_(OSetWord_Destroy)( tmpSet );
   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) {
   1128       if (sp->from_sopatt) dinfo_free(sp->from_sopatt);
   1129       if (sp->from_fnpatt) dinfo_free(sp->from_fnpatt);
   1130       sp_next = sp->next;
   1131       dinfo_free(sp);
   1132    }
   1133 
   1134    if (tsPrev == NULL) {
   1135       /* first in list */
   1136       topSpecs = ts->next;
   1137    } else {
   1138       tsPrev->next = ts->next;
   1139    }
   1140    dinfo_free(ts);
   1141 
   1142    if (VG_(clo_trace_redir))
   1143       show_redir_state("after VG_(redir_notify_delete_DebugInfo)");
   1144 }
   1145 
   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 )
   1155 {
   1156    Active* r = VG_(OSetGen_Lookup)(activeSet, &orig);
   1157    if (r == NULL)
   1158       return orig;
   1159 
   1160    vg_assert(r->to_addr != 0);
   1161    if (isWrap)
   1162       *isWrap = r->isWrap || r->isIFunc;
   1163    if (r->isIFunc) {
   1164       vg_assert(iFuncWrapper);
   1165       return iFuncWrapper;
   1166    }
   1167    return r->to_addr;
   1168 }
   1169 
   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 )
   1179 {
   1180    Active act;
   1181    act.from_addr   = from;
   1182    act.to_addr     = to;
   1183    act.parent_spec = NULL;
   1184    act.parent_sym  = NULL;
   1185    act.becTag      = 0; /* "not equivalent to any other fn" */
   1186    act.becPrio     = 0; /* mandatory when becTag == 0 */
   1187    act.isWrap      = False;
   1188    act.isIFunc     = False;
   1189    maybe_add_active( act );
   1190 }
   1191 
   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 */
   1200 static void add_hardwired_spec (const  HChar* sopatt, const HChar* fnpatt,
   1201                                 Addr   to_addr,
   1202                                 const HChar** mandatory )
   1203 {
   1204    Spec* spec = dinfo_zalloc("redir.ahs.1", sizeof(Spec));
   1205 
   1206    if (topSpecs == NULL) {
   1207       topSpecs = dinfo_zalloc("redir.ahs.2", sizeof(TopSpec));
   1208       /* symtab_zalloc sets all fields to zero */
   1209    }
   1210 
   1211    vg_assert(topSpecs != NULL);
   1212    vg_assert(topSpecs->next == NULL);
   1213    vg_assert(topSpecs->seginfo == NULL);
   1214    /* FIXED PARTS */
   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. */
   1219    spec->from_sopatt = CONST_CAST(HChar *,sopatt);
   1220    spec->from_fnpatt = CONST_CAST(HChar *,fnpatt);
   1221    spec->to_addr     = to_addr;
   1222    spec->isWrap      = False;
   1223    spec->mandatory   = mandatory;
   1224    /* VARIABLE PARTS */
   1225    spec->mark        = False; /* not significant */
   1226    spec->done        = False; /* not significant */
   1227 
   1228    spec->next = topSpecs->specs;
   1229    topSpecs->specs = spec;
   1230 }
   1231 
   1232 
   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",
   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",
   1245     NULL
   1246   };
   1247 
   1248 
   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)
   1252    assumption that no DebugInfos have so far been created, and so when
   1253    they are created, that will happen. */
   1254 
   1255 void VG_(redir_initialise) ( void )
   1256 {
   1257    // Assert that there are no DebugInfos so far
   1258    vg_assert( VG_(next_DebugInfo)(NULL) == NULL );
   1259 
   1260    // Initialise active mapping.
   1261    activeSet = VG_(OSetGen_Create)(offsetof(Active, from_addr),
   1262                                    NULL,     // Use fast comparison
   1263                                    dinfo_zalloc,
   1264                                    "redir.ri.1",
   1265                                    dinfo_free);
   1266 
   1267    // The rest of this function just adds initial Specs.
   1268 
   1269 #  if defined(VGP_x86_linux)
   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)) {
   1273       const HChar** mandatory;
   1274 #     ifndef GLIBC_MANDATORY_INDEX_AND_STRLEN_REDIRECT
   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
   1281       add_hardwired_spec(
   1282          "ld-linux.so.2", "index",
   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);
   1287    }
   1288 
   1289 #  elif defined(VGP_amd64_linux)
   1290    /* Redirect vsyscalls to local versions */
   1291    add_hardwired_active(
   1292       0xFFFFFFFFFF600000ULL,
   1293       (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)
   1294    );
   1295    add_hardwired_active(
   1296       0xFFFFFFFFFF600400ULL,
   1297       (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)
   1298    );
   1299    add_hardwired_active(
   1300       0xFFFFFFFFFF600800ULL,
   1301       (Addr)&VG_(amd64_linux_REDIR_FOR_vgetcpu)
   1302    );
   1303 
   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)) {
   1307 
   1308       add_hardwired_spec(
   1309          "ld-linux-x86-64.so.2", "strlen",
   1310          (Addr)&VG_(amd64_linux_REDIR_FOR_strlen),
   1311 #        ifndef GLIBC_MANDATORY_STRLEN_REDIRECT
   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)
   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)) {
   1325 
   1326       /* this is mandatory - can't sanely continue without it */
   1327       add_hardwired_spec(
   1328          "ld.so.1", "strlen",
   1329          (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen),
   1330          complain_about_stripped_glibc_ldso
   1331       );
   1332       add_hardwired_spec(
   1333          "ld.so.1", "strcmp",
   1334          (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp),
   1335          NULL /* not mandatory - so why bother at all? */
   1336          /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */
   1337       );
   1338       add_hardwired_spec(
   1339          "ld.so.1", "index",
   1340          (Addr)&VG_(ppc32_linux_REDIR_FOR_strchr),
   1341          NULL /* not mandatory - so why bother at all? */
   1342          /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */
   1343       );
   1344    }
   1345 
   1346 #  elif defined(VGP_ppc64be_linux)
   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 
   1351       /* this is mandatory - can't sanely continue without it */
   1352       add_hardwired_spec(
   1353          "ld64.so.1", "strlen",
   1354          (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strlen) ),
   1355          complain_about_stripped_glibc_ldso
   1356       );
   1357 
   1358       add_hardwired_spec(
   1359          "ld64.so.1", "index",
   1360          (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strchr) ),
   1361          NULL /* not mandatory - so why bother at all? */
   1362          /* glibc-2.5 (FC6, ppc64) seems fine without it */
   1363       );
   1364    }
   1365 
   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 
   1387 #  elif defined(VGP_arm_linux)
   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. */
   1392    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1393       /* strlen */
   1394       add_hardwired_spec(
   1395          "ld-linux.so.3", "strlen",
   1396          (Addr)&VG_(arm_linux_REDIR_FOR_strlen),
   1397          complain_about_stripped_glibc_ldso
   1398       );
   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 */
   1405       add_hardwired_spec(
   1406          "ld-linux.so.3", "memcpy",
   1407          (Addr)&VG_(arm_linux_REDIR_FOR_memcpy),
   1408          complain_about_stripped_glibc_ldso
   1409       );
   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       );
   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       );
   1426    }
   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)) {
   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       );
   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
   1454    }
   1455 
   1456 #  elif defined(VGP_x86_darwin)
   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",
   1461                          (Addr)&VG_(x86_darwin_REDIR_FOR_strcmp), NULL);
   1462       add_hardwired_spec("dyld", "strlen",
   1463                          (Addr)&VG_(x86_darwin_REDIR_FOR_strlen), NULL);
   1464       add_hardwired_spec("dyld", "strcat",
   1465                          (Addr)&VG_(x86_darwin_REDIR_FOR_strcat), NULL);
   1466       add_hardwired_spec("dyld", "strcpy",
   1467                          (Addr)&VG_(x86_darwin_REDIR_FOR_strcpy), NULL);
   1468       add_hardwired_spec("dyld", "strlcat",
   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);
   1486       // DDD: #warning fixme rdar://6166275
   1487       add_hardwired_spec("dyld", "arc4random",
   1488                          (Addr)&VG_(amd64_darwin_REDIR_FOR_arc4random), NULL);
   1489 #     if DARWIN_VERS == DARWIN_10_9
   1490       add_hardwired_spec("dyld", "strchr",
   1491                          (Addr)&VG_(amd64_darwin_REDIR_FOR_strchr), NULL);
   1492 #     endif
   1493    }
   1494 
   1495 #  elif defined(VGP_s390x_linux)
   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    }
   1502 
   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 
   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 
   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 
   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 
   1568 #  else
   1569 #    error Unknown platform
   1570 #  endif
   1571 
   1572    if (VG_(clo_trace_redir))
   1573       show_redir_state("after VG_(redir_initialise)");
   1574 }
   1575 
   1576 
   1577 /*------------------------------------------------------------*/
   1578 /*--- MISC HELPERS                                         ---*/
   1579 /*------------------------------------------------------------*/
   1580 
   1581 static void* dinfo_zalloc(const HChar* ec, SizeT n) {
   1582    void* p;
   1583    vg_assert(n > 0);
   1584    p = VG_(arena_malloc)(VG_AR_DINFO, ec, n);
   1585    VG_(memset)(p, 0, n);
   1586    return p;
   1587 }
   1588 
   1589 static void dinfo_free(void* p) {
   1590    vg_assert(p);
   1591    return VG_(arena_free)(VG_AR_DINFO, p);
   1592 }
   1593 
   1594 static HChar* dinfo_strdup(const HChar* ec, const HChar* str)
   1595 {
   1596    return VG_(arena_strdup)(VG_AR_DINFO, ec, str);
   1597 }
   1598 
   1599 /* Really this should be merged with translations_allowable_from_seg
   1600    in m_translate. */
   1601 static Bool is_plausible_guest_addr(Addr a)
   1602 {
   1603    NSegment const* seg = VG_(am_find_nsegment)(a);
   1604    return seg != NULL
   1605           && (seg->kind == SkAnonC || seg->kind == SkFileC ||
   1606               seg->kind == SkShmC)
   1607           && (seg->hasX || seg->hasR); /* crude x86-specific hack */
   1608 }
   1609 
   1610 
   1611 /*------------------------------------------------------------*/
   1612 /*--- NOTIFY-ON-LOAD FUNCTIONS                             ---*/
   1613 /*------------------------------------------------------------*/
   1614 
   1615 static
   1616 void handle_maybe_load_notifier( const HChar* soname,
   1617                                  const HChar* symbol, Addr addr )
   1618 {
   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. */
   1634    vg_assert(symbol); // assert rather than segfault if it is NULL
   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;
   1642    else
   1643    if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(ifunc_wrapper))) == 0)
   1644       iFuncWrapper = addr;
   1645    else
   1646       vg_assert2(0, "unrecognised load notification function: %s", symbol);
   1647 }
   1648 
   1649 
   1650 /*------------------------------------------------------------*/
   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 */
   1658 static void handle_require_text_symbols ( const DebugInfo* di )
   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. */
   1666    XArray *fnpatts = VG_(newXA)( VG_(malloc), "m_redir.hrts.5",
   1667                                  VG_(free), sizeof(HChar*) );
   1668 
   1669    Int    i, j;
   1670    const HChar* di_soname = VG_(DebugInfo_get_soname)(di);
   1671    vg_assert(di_soname); // must be present
   1672 
   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);
   1675       vg_assert(clo_spec && VG_(strlen)(clo_spec) >= 4);
   1676       // clone the spec, so we can stick a zero at the end of the sopatt
   1677       HChar *spec = VG_(strdup)("m_redir.hrts.1", clo_spec);
   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++;
   1686       if (VG_(string_match)(sopatt, di_soname)) {
   1687          HChar *pattern = VG_(strdup)("m_redir.hrts.2", fnpatt);
   1688          VG_(addToXA)(fnpatts, &pattern);
   1689       }
   1690       VG_(free)(spec);
   1691    }
   1692 
   1693    if (VG_(sizeXA)(fnpatts) == 0) {
   1694       VG_(deleteXA)(fnpatts);
   1695       return;  /* no applicable spec strings */
   1696    }
   1697 
   1698    /* So finally, fnpatts contains the set of
   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);
   1705    for (i = 0; i < VG_(sizeXA)(fnpatts); i++)
   1706       if (0) VG_(printf)("   fnpatt: %s\n",
   1707                          *(HChar**) VG_(indexXA)(fnpatts, i));
   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. */
   1712    for (i = 0; i < VG_(sizeXA)(fnpatts); i++) {
   1713       Bool   found  = False;
   1714       const HChar* fnpatt = *(HChar**) VG_(indexXA)(fnpatts, i);
   1715       Int    nsyms  = VG_(DebugInfo_syms_howmany)(di);
   1716       for (j = 0; j < nsyms; j++) {
   1717          Bool    isText        = False;
   1718          const HChar*  sym_name_pri  = NULL;
   1719          const HChar** sym_names_sec = NULL;
   1720          VG_(DebugInfo_syms_getidx)( di, j, NULL,
   1721                                      NULL, &sym_name_pri, &sym_names_sec,
   1722                                      &isText, NULL );
   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;
   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             }
   1737          }
   1738          free_symname_array(names_init, &twoslots[0]);
   1739          if (found)
   1740             break;
   1741       }
   1742 
   1743       if (!found) {
   1744          const HChar* v = "valgrind:  ";
   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. */
   1765    VG_(deleteXA)(fnpatts);
   1766 }
   1767 
   1768 
   1769 /*------------------------------------------------------------*/
   1770 /*--- SANITY/DEBUG                                         ---*/
   1771 /*------------------------------------------------------------*/
   1772 
   1773 static void show_spec ( const HChar* left, const Spec* spec )
   1774 {
   1775    VG_(message)( Vg_DebugMsg,
   1776                  "%s%-25s %-30s %s-> (%04d.%d) 0x%08lx\n",
   1777                  left,
   1778                  spec->from_sopatt, spec->from_fnpatt,
   1779                  spec->isWrap ? "W" : "R",
   1780                  spec->becTag, spec->becPrio,
   1781                  spec->to_addr );
   1782 }
   1783 
   1784 static void show_active ( const HChar* left, const Active* act )
   1785 {
   1786    Bool ok;
   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 = "???";
   1798 
   1799    VG_(message)(Vg_DebugMsg, "%s0x%08lx (%-20s) %s-> (%04d.%d) 0x%08lx %s\n",
   1800                              left,
   1801                              act->from_addr, name1,
   1802                              act->isWrap ? "W" : "R",
   1803                              act->becTag, act->becPrio,
   1804                              act->to_addr, name2 );
   1805 }
   1806 
   1807 static void show_redir_state ( const HChar* who )
   1808 {
   1809    TopSpec* ts;
   1810    Spec*    sp;
   1811    Active*  act;
   1812    VG_(message)(Vg_DebugMsg, "<<\n");
   1813    VG_(message)(Vg_DebugMsg, "   ------ REDIR STATE %s ------\n", who);
   1814    for (ts = topSpecs; ts; ts = ts->next) {
   1815       if (ts->seginfo)
   1816          VG_(message)(Vg_DebugMsg,
   1817                       "   TOPSPECS of soname %s filename %s\n",
   1818                       VG_(DebugInfo_get_soname)(ts->seginfo),
   1819                       VG_(DebugInfo_get_filename)(ts->seginfo));
   1820       else
   1821          VG_(message)(Vg_DebugMsg,
   1822                       "   TOPSPECS of soname (hardwired)\n");
   1823 
   1824       for (sp = ts->specs; sp; sp = sp->next)
   1825          show_spec("     ", sp);
   1826    }
   1827    VG_(message)(Vg_DebugMsg, "   ------ ACTIVE ------\n");
   1828    VG_(OSetGen_ResetIter)( activeSet );
   1829    while ( (act = VG_(OSetGen_Next)(activeSet)) ) {
   1830       show_active("    ", act);
   1831    }
   1832 
   1833    VG_(message)(Vg_DebugMsg, ">>\n");
   1834 }
   1835 
   1836 /*--------------------------------------------------------------------*/
   1837 /*--- end                                                          ---*/
   1838 /*--------------------------------------------------------------------*/
   1839