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-2013 Julian Seward
     11       jseward (at) acm.org
     12    Copyright (C) 2003-2013 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_2_* */
     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       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, Active* act );
    312 
    313 static void   handle_maybe_load_notifier( const HChar* soname,
    314                                                 HChar* symbol, Addr addr );
    315 
    316 static void   handle_require_text_symbols ( 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         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 HChar** alloc_symname_array ( HChar* pri_name, HChar** sec_names,
    338                                      HChar** twoslots )
    339 {
    340    /* Special-case the common case: only one name.  We expect the
    341       caller to supply a stack-allocated 2-entry array for this. */
    342    if (sec_names == NULL) {
    343       twoslots[0] = pri_name;
    344       twoslots[1] = NULL;
    345       return twoslots;
    346    }
    347    /* Else must use dynamic allocation.  Figure out size .. */
    348    Word    n_req = 1;
    349    HChar** pp    = sec_names;
    350    while (*pp) { n_req++; pp++; }
    351    /* .. allocate and copy in. */
    352    HChar** arr = dinfo_zalloc( "redir.asa.1", (n_req+1) * sizeof(HChar*) );
    353    Word    i   = 0;
    354    arr[i++] = pri_name;
    355    pp = sec_names;
    356    while (*pp) { arr[i++] = *pp; pp++; }
    357    tl_assert(i == n_req);
    358    tl_assert(arr[n_req] == NULL);
    359    return arr;
    360 }
    361 
    362 
    363 /* Free the array allocated by alloc_symname_array, if any. */
    364 static void free_symname_array ( HChar** names, HChar** twoslots )
    365 {
    366    if (names != twoslots)
    367       dinfo_free(names);
    368 }
    369 
    370 static HChar const* advance_to_equal ( HChar const* c ) {
    371    while (*c && *c != '=') {
    372       ++c;
    373    }
    374    return c;
    375 }
    376 static HChar const* advance_to_comma ( HChar const* c ) {
    377    while (*c && *c != ',') {
    378       ++c;
    379    }
    380    return c;
    381 }
    382 
    383 /* Notify m_redir of the arrival of a new DebugInfo.  This is fairly
    384    complex, but the net effect is to (1) add a new entry to the
    385    topspecs list, and (2) figure out what new binding are now active,
    386    and, as a result, add them to the actives mapping. */
    387 
    388 #define N_DEMANGLED 256
    389 
    390 void VG_(redir_notify_new_DebugInfo)( DebugInfo* newdi )
    391 {
    392    Bool         ok, isWrap;
    393    Int          i, nsyms, becTag, becPrio;
    394    Spec*        specList;
    395    Spec*        spec;
    396    TopSpec*     ts;
    397    TopSpec*     newts;
    398    HChar*       sym_name_pri;
    399    HChar**      sym_names_sec;
    400    Addr         sym_addr, sym_toc;
    401    HChar        demangled_sopatt[N_DEMANGLED];
    402    HChar        demangled_fnpatt[N_DEMANGLED];
    403    Bool         check_ppcTOCs = False;
    404    Bool         isText;
    405    const HChar* newdi_soname;
    406 
    407 #  if defined(VG_PLAT_USES_PPCTOC)
    408    check_ppcTOCs = True;
    409 #  endif
    410 
    411    vg_assert(newdi);
    412    newdi_soname = VG_(DebugInfo_get_soname)(newdi);
    413    vg_assert(newdi_soname != NULL);
    414 
    415 #ifdef ENABLE_INNER
    416    {
    417       /* When an outer Valgrind is executing an inner Valgrind, the
    418          inner "sees" in its address space the mmap-ed vgpreload files
    419          of the outer.  The inner must avoid interpreting the
    420          redirections given in the outer vgpreload mmap-ed files.
    421          Otherwise, some tool combinations badly fail.
    422 
    423          Example: outer memcheck tool executing an inner none tool.
    424 
    425          If inner none interprets the outer malloc redirection, the
    426          inner will redirect malloc to a memcheck function it does not
    427          have (as the redirection target is from the outer).  With
    428          such a failed redirection, a call to malloc inside the inner
    429          will then result in a "no-operation" (and so no memory will
    430          be allocated).
    431 
    432          When running as an inner, no redirection will be done
    433          for a vgpreload file if this file is not located in the
    434          inner VALGRIND_LIB directory.
    435 
    436          Recognising a vgpreload file based on a filename pattern
    437          is a kludge. An alternate solution would be to change
    438          the _vgr prefix according to outer/inner/client.
    439       */
    440       const HChar* newdi_filename = VG_(DebugInfo_get_filename)(newdi);
    441       const HChar* newdi_basename = VG_(basename) (newdi_filename);
    442       if (VG_(strncmp) (newdi_basename, "vgpreload_", 10) == 0) {
    443          /* This looks like a vgpreload file => check if this file
    444             is from the inner VALGRIND_LIB.
    445             We do this check using VG_(stat) + dev/inode comparison
    446             as vg-in-place defines a VALGRIND_LIB with symlinks
    447             pointing to files inside the valgrind build directories. */
    448          struct vg_stat newdi_stat;
    449          SysRes newdi_res;
    450          HChar in_vglib_filename[VKI_PATH_MAX];
    451          struct vg_stat in_vglib_stat;
    452          SysRes in_vglib_res;
    453 
    454          newdi_res = VG_(stat)(newdi_filename, &newdi_stat);
    455 
    456          VG_(strncpy) (in_vglib_filename, VG_(libdir), VKI_PATH_MAX);
    457          VG_(strncat) (in_vglib_filename, "/", VKI_PATH_MAX);
    458          VG_(strncat) (in_vglib_filename, newdi_basename, VKI_PATH_MAX);
    459          in_vglib_res = VG_(stat)(in_vglib_filename, &in_vglib_stat);
    460 
    461          /* If we find newdi_basename in inner VALGRIND_LIB
    462             but newdi_filename is not the same file, then we do
    463             not execute the redirection. */
    464          if (!sr_isError(in_vglib_res)
    465              && !sr_isError(newdi_res)
    466              && (newdi_stat.dev != in_vglib_stat.dev
    467                  || newdi_stat.ino != in_vglib_stat.ino)) {
    468             /* <inner VALGRIND_LIB>/newdi_basename is an existing file
    469                and is different of newdi_filename.
    470                So, we do not execute newdi_filename redirection. */
    471             if ( VG_(clo_verbosity) > 1 ) {
    472                VG_(message)( Vg_DebugMsg,
    473                              "Skipping vgpreload redir in %s"
    474                              " (not from VALGRIND_LIB_INNER)\n",
    475                              newdi_filename);
    476             }
    477             return;
    478          } else {
    479             if ( VG_(clo_verbosity) > 1 ) {
    480                VG_(message)( Vg_DebugMsg,
    481                              "Executing vgpreload redir in %s"
    482                              " (from VALGRIND_LIB_INNER)\n",
    483                              newdi_filename);
    484             }
    485          }
    486       }
    487    }
    488 #endif
    489 
    490 
    491    /* stay sane: we don't already have this. */
    492    for (ts = topSpecs; ts; ts = ts->next)
    493       vg_assert(ts->seginfo != newdi);
    494 
    495    /* scan this DebugInfo's symbol table, pulling out and demangling
    496       any specs found */
    497 
    498    specList = NULL; /* the spec list we're building up */
    499 
    500    nsyms = VG_(DebugInfo_syms_howmany)( newdi );
    501    for (i = 0; i < nsyms; i++) {
    502       VG_(DebugInfo_syms_getidx)( newdi, i, &sym_addr, &sym_toc,
    503                                   NULL, &sym_name_pri, &sym_names_sec,
    504                                   &isText, NULL );
    505       /* Set up to conveniently iterate over all names for this symbol. */
    506       HChar*  twoslots[2];
    507       HChar** names_init = alloc_symname_array(sym_name_pri, sym_names_sec,
    508                                                &twoslots[0]);
    509       HChar** names;
    510       for (names = names_init; *names; names++) {
    511          ok = VG_(maybe_Z_demangle)( *names,
    512                                      demangled_sopatt, N_DEMANGLED,
    513                                      demangled_fnpatt, N_DEMANGLED,
    514                                      &isWrap, &becTag, &becPrio );
    515          /* ignore data symbols */
    516          if (!isText)
    517             continue;
    518          if (!ok) {
    519             /* It's not a full-scale redirect, but perhaps it is a load-notify
    520                fn?  Let the load-notify department see it. */
    521             handle_maybe_load_notifier( newdi_soname, *names, sym_addr );
    522             continue;
    523          }
    524          if (check_ppcTOCs && sym_toc == 0) {
    525             /* This platform uses toc pointers, but none could be found
    526                for this symbol, so we can't safely redirect/wrap to it.
    527                Just skip it; we'll make a second pass over the symbols in
    528                the following loop, and complain at that point. */
    529             continue;
    530          }
    531 
    532          if (0 == VG_(strncmp) (demangled_sopatt,
    533                                 VG_SO_SYN_PREFIX, VG_SO_SYN_PREFIX_LEN)) {
    534             /* This is a redirection for handling lib so synonyms. If we
    535                have a matching lib synonym, then replace the sopatt.
    536                Otherwise, just ignore this redirection spec. */
    537 
    538             if (!VG_(clo_soname_synonyms))
    539                continue; // No synonyms => skip the redir.
    540 
    541             /* Search for a matching synonym=newname*/
    542             SizeT const sopatt_syn_len
    543                = VG_(strlen)(demangled_sopatt+VG_SO_SYN_PREFIX_LEN);
    544             HChar const* last = VG_(clo_soname_synonyms);
    545 
    546             while (*last) {
    547                HChar const* first = last;
    548                last = advance_to_equal(first);
    549 
    550                if ((last - first) == sopatt_syn_len
    551                    && 0 == VG_(strncmp)(demangled_sopatt+VG_SO_SYN_PREFIX_LEN,
    552                                         first,
    553                                         sopatt_syn_len)) {
    554                   // Found the demangle_sopatt synonym => replace it
    555                   first = last + 1;
    556                   last = advance_to_comma(first);
    557                   VG_(strncpy)(demangled_sopatt, first, last - first);
    558                   demangled_sopatt[last - first] = '\0';
    559                   break;
    560                }
    561 
    562                last = advance_to_comma(last);
    563                if (*last == ',')
    564                   last++;
    565             }
    566 
    567             // If we have not replaced the sopatt, then skip the redir.
    568             if (0 == VG_(strncmp) (demangled_sopatt,
    569                                    VG_SO_SYN_PREFIX, VG_SO_SYN_PREFIX_LEN))
    570                continue;
    571          }
    572 
    573          spec = dinfo_zalloc("redir.rnnD.1", sizeof(Spec));
    574          vg_assert(spec);
    575          spec->from_sopatt = dinfo_strdup("redir.rnnD.2", demangled_sopatt);
    576          spec->from_fnpatt = dinfo_strdup("redir.rnnD.3", demangled_fnpatt);
    577          vg_assert(spec->from_sopatt);
    578          vg_assert(spec->from_fnpatt);
    579          spec->to_addr = sym_addr;
    580          spec->isWrap = isWrap;
    581          spec->becTag = becTag;
    582          spec->becPrio = becPrio;
    583          /* check we're not adding manifestly stupid destinations */
    584          vg_assert(is_plausible_guest_addr(sym_addr));
    585          spec->next = specList;
    586          spec->mark = False; /* not significant */
    587          spec->done = False; /* not significant */
    588          specList = spec;
    589       }
    590       free_symname_array(names_init, &twoslots[0]);
    591    }
    592 
    593    if (check_ppcTOCs) {
    594       for (i = 0; i < nsyms; i++) {
    595          VG_(DebugInfo_syms_getidx)( newdi, i, &sym_addr, &sym_toc,
    596                                      NULL, &sym_name_pri, &sym_names_sec,
    597                                      &isText, NULL );
    598          HChar*  twoslots[2];
    599          HChar** names_init = alloc_symname_array(sym_name_pri, sym_names_sec,
    600                                                   &twoslots[0]);
    601          HChar** names;
    602          for (names = names_init; *names; names++) {
    603             ok = isText
    604                  && VG_(maybe_Z_demangle)(
    605                        *names, demangled_sopatt, N_DEMANGLED,
    606                        demangled_fnpatt, N_DEMANGLED, &isWrap, NULL, NULL );
    607             if (!ok)
    608                /* not a redirect.  Ignore. */
    609                continue;
    610             if (sym_toc != 0)
    611                /* has a valid toc pointer.  Ignore. */
    612                continue;
    613 
    614             for (spec = specList; spec; spec = spec->next)
    615                if (0 == VG_(strcmp)(spec->from_sopatt, demangled_sopatt)
    616                    && 0 == VG_(strcmp)(spec->from_fnpatt, demangled_fnpatt))
    617                   break;
    618             if (spec)
    619                /* a redirect to some other copy of that symbol, which
    620                   does have a TOC value, already exists */
    621                continue;
    622 
    623             /* Complain */
    624             VG_(message)(Vg_DebugMsg,
    625                          "WARNING: no TOC ptr for redir/wrap to %s %s\n",
    626                          demangled_sopatt, demangled_fnpatt);
    627          }
    628          free_symname_array(names_init, &twoslots[0]);
    629       }
    630    }
    631 
    632    /* Ok.  Now specList holds the list of specs from the DebugInfo.
    633       Build a new TopSpec, but don't add it to topSpecs yet. */
    634    newts = dinfo_zalloc("redir.rnnD.4", sizeof(TopSpec));
    635    vg_assert(newts);
    636    newts->next    = NULL; /* not significant */
    637    newts->seginfo = newdi;
    638    newts->specs   = specList;
    639    newts->mark    = False; /* not significant */
    640 
    641    /* We now need to augment the active set with the following partial
    642       cross product:
    643 
    644       (1) actives formed by matching the new specs in specList against
    645           all symbols currently listed in topSpecs
    646 
    647       (2) actives formed by matching the new symbols in newdi against
    648           all specs currently listed in topSpecs
    649 
    650       (3) actives formed by matching the new symbols in newdi against
    651           the new specs in specList
    652 
    653       This is necessary in order to maintain the invariant that
    654       Actives contains all bindings generated by matching ALL specs in
    655       topSpecs against ALL symbols in topSpecs (that is, a cross
    656       product of ALL known specs against ALL known symbols).
    657    */
    658    /* Case (1) */
    659    for (ts = topSpecs; ts; ts = ts->next) {
    660       if (ts->seginfo)
    661          generate_and_add_actives( specList,    newts,
    662                                    ts->seginfo, ts );
    663    }
    664 
    665    /* Case (2) */
    666    for (ts = topSpecs; ts; ts = ts->next) {
    667       generate_and_add_actives( ts->specs, ts,
    668                                 newdi,     newts );
    669    }
    670 
    671    /* Case (3) */
    672    generate_and_add_actives( specList, newts,
    673                              newdi,    newts );
    674 
    675    /* Finally, add the new TopSpec. */
    676    newts->next = topSpecs;
    677    topSpecs = newts;
    678 
    679    if (VG_(clo_trace_redir))
    680       show_redir_state("after VG_(redir_notify_new_DebugInfo)");
    681 
    682    /* Really finally (quite unrelated to all the above) check the
    683       names in the module against any --require-text-symbol=
    684       specifications we might have. */
    685    handle_require_text_symbols(newdi);
    686 }
    687 
    688 #undef N_DEMANGLED
    689 
    690 /* Add a new target for an indirect function. Adds a new redirection
    691    for the indirection function with address old_from that redirects
    692    the ordinary function with address new_from to the target address
    693    of the original redirection. */
    694 
    695 void VG_(redir_add_ifunc_target)( Addr old_from, Addr new_from )
    696 {
    697     Active *old, new;
    698 
    699     old = VG_(OSetGen_Lookup)(activeSet, &old_from);
    700     vg_assert(old);
    701     vg_assert(old->isIFunc);
    702 
    703     new = *old;
    704     new.from_addr = new_from;
    705     new.isIFunc = False;
    706     maybe_add_active (new);
    707 
    708     if (VG_(clo_trace_redir)) {
    709        VG_(message)( Vg_DebugMsg,
    710                      "Adding redirect for indirect function "
    711                      "0x%llx from 0x%llx -> 0x%llx\n",
    712                      (ULong)old_from, (ULong)new_from, (ULong)new.to_addr );
    713     }
    714 }
    715 
    716 /* Do one element of the basic cross product: add to the active set,
    717    all matches resulting from comparing all the given specs against
    718    all the symbols in the given seginfo.  If a conflicting binding
    719    would thereby arise, don't add it, but do complain. */
    720 
    721 static
    722 void generate_and_add_actives (
    723         /* spec list and the owning TopSpec */
    724         Spec*    specs,
    725         TopSpec* parent_spec,
    726 	/* seginfo and the owning TopSpec */
    727         DebugInfo* di,
    728         TopSpec* parent_sym
    729      )
    730 {
    731    Spec*   sp;
    732    Bool    anyMark, isText, isIFunc;
    733    Active  act;
    734    Int     nsyms, i;
    735    Addr    sym_addr;
    736    HChar*  sym_name_pri;
    737    HChar** sym_names_sec;
    738 
    739    /* First figure out which of the specs match the seginfo's soname.
    740       Also clear the 'done' bits, so that after the main loop below
    741       tell which of the Specs really did get done. */
    742    anyMark = False;
    743    for (sp = specs; sp; sp = sp->next) {
    744       sp->done = False;
    745       sp->mark = VG_(string_match)( sp->from_sopatt,
    746                                     VG_(DebugInfo_get_soname)(di) );
    747       anyMark = anyMark || sp->mark;
    748    }
    749 
    750    /* shortcut: if none of the sonames match, there will be no bindings. */
    751    if (!anyMark)
    752       return;
    753 
    754    /* Iterate outermost over the symbols in the seginfo, in the hope
    755       of trashing the caches less. */
    756    nsyms = VG_(DebugInfo_syms_howmany)( di );
    757    for (i = 0; i < nsyms; i++) {
    758       VG_(DebugInfo_syms_getidx)( di, i, &sym_addr, NULL,
    759                                   NULL, &sym_name_pri, &sym_names_sec,
    760                                   &isText, &isIFunc );
    761       HChar*  twoslots[2];
    762       HChar** names_init = alloc_symname_array(sym_name_pri, sym_names_sec,
    763                                                &twoslots[0]);
    764       HChar** names;
    765       for (names = names_init; *names; names++) {
    766 
    767          /* ignore data symbols */
    768          if (!isText)
    769             continue;
    770 
    771          for (sp = specs; sp; sp = sp->next) {
    772             if (!sp->mark)
    773                continue; /* soname doesn't match */
    774             if (VG_(string_match)( sp->from_fnpatt, *names )) {
    775                /* got a new binding.  Add to collection. */
    776                act.from_addr   = sym_addr;
    777                act.to_addr     = sp->to_addr;
    778                act.parent_spec = parent_spec;
    779                act.parent_sym  = parent_sym;
    780                act.becTag      = sp->becTag;
    781                act.becPrio     = sp->becPrio;
    782                act.isWrap      = sp->isWrap;
    783                act.isIFunc     = isIFunc;
    784                sp->done = True;
    785                maybe_add_active( act );
    786             }
    787          } /* for (sp = specs; sp; sp = sp->next) */
    788 
    789       } /* iterating over names[] */
    790       free_symname_array(names_init, &twoslots[0]);
    791    } /* for (i = 0; i < nsyms; i++)  */
    792 
    793    /* Now, finally, look for Specs which were marked to be done, but
    794       didn't get matched.  If any such are mandatory we must abort the
    795       system at this point. */
    796    for (sp = specs; sp; sp = sp->next) {
    797       if (!sp->mark)
    798          continue;
    799       if (sp->mark && (!sp->done) && sp->mandatory)
    800          break;
    801    }
    802    if (sp) {
    803       const HChar** strp;
    804       const HChar* v = "valgrind:  ";
    805       vg_assert(sp->mark);
    806       vg_assert(!sp->done);
    807       vg_assert(sp->mandatory);
    808       VG_(printf)("\n");
    809       VG_(printf)(
    810       "%sFatal error at startup: a function redirection\n", v);
    811       VG_(printf)(
    812       "%swhich is mandatory for this platform-tool combination\n", v);
    813       VG_(printf)(
    814       "%scannot be set up.  Details of the redirection are:\n", v);
    815       VG_(printf)(
    816       "%s\n", v);
    817       VG_(printf)(
    818       "%sA must-be-redirected function\n", v);
    819       VG_(printf)(
    820       "%swhose name matches the pattern:      %s\n", v, sp->from_fnpatt);
    821       VG_(printf)(
    822       "%sin an object with soname matching:   %s\n", v, sp->from_sopatt);
    823       VG_(printf)(
    824       "%swas not found whilst processing\n", v);
    825       VG_(printf)(
    826       "%ssymbols from the object with soname: %s\n",
    827       v, VG_(DebugInfo_get_soname)(di));
    828       VG_(printf)(
    829       "%s\n", v);
    830 
    831       for (strp = sp->mandatory; *strp; strp++)
    832          VG_(printf)(
    833          "%s%s\n", v, *strp);
    834 
    835       VG_(printf)(
    836       "%s\n", v);
    837       VG_(printf)(
    838       "%sCannot continue -- exiting now.  Sorry.\n", v);
    839       VG_(printf)("\n");
    840       VG_(exit)(1);
    841    }
    842 }
    843 
    844 
    845 /* Add an act (passed by value; is copied here) and deal with
    846    conflicting bindings. */
    847 static void maybe_add_active ( Active act )
    848 {
    849    const HChar*  what = NULL;
    850    Active* old     = NULL;
    851    Bool    add_act = False;
    852 
    853    /* Complain and ignore manifestly bogus 'from' addresses.
    854 
    855       Kludge: because this can get called befor the trampoline area (a
    856       bunch of magic 'to' addresses) has its ownership changed from V
    857       to C, we can't check the 'to' address similarly.  Sigh.
    858 
    859       amd64-linux hack: the vsysinfo pages appear to have no
    860       permissions
    861          ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0
    862       so skip the check for them.  */
    863    if (!is_plausible_guest_addr(act.from_addr)
    864 #      if defined(VGP_amd64_linux)
    865        && act.from_addr != 0xFFFFFFFFFF600000ULL
    866        && act.from_addr != 0xFFFFFFFFFF600400ULL
    867        && act.from_addr != 0xFFFFFFFFFF600800ULL
    868 #      endif
    869       ) {
    870       what = "redirection from-address is in non-executable area";
    871       goto bad;
    872    }
    873 
    874    old = VG_(OSetGen_Lookup)( activeSet, &act.from_addr );
    875    if (old) {
    876       /* Dodgy.  Conflicting binding. */
    877       vg_assert(old->from_addr == act.from_addr);
    878       if (old->to_addr != act.to_addr) {
    879          /* We've got a conflicting binding -- that is, from_addr is
    880             specified to redirect to two different destinations,
    881             old->to_addr and act.to_addr.  If we can prove that they
    882             are behaviourally equivalent then that's no problem.  So
    883             we can look at the behavioural eclass tags for both
    884             functions to see if that's so.  If they are equal, and
    885             nonzero, then that's fine.  But if not, we can't show they
    886             are equivalent, so we have to complain, and ignore the new
    887             binding. */
    888          vg_assert(old->becTag  >= 0 && old->becTag  <= 9999);
    889          vg_assert(old->becPrio >= 0 && old->becPrio <= 9);
    890          vg_assert(act.becTag   >= 0 && act.becTag   <= 9999);
    891          vg_assert(act.becPrio  >= 0 && act.becPrio  <= 9);
    892          if (old->becTag == 0)
    893             vg_assert(old->becPrio == 0);
    894          if (act.becTag == 0)
    895             vg_assert(act.becPrio == 0);
    896 
    897          if (old->becTag == 0 || act.becTag == 0 || old->becTag != act.becTag) {
    898             /* We can't show that they are equivalent.  Complain and
    899                ignore. */
    900             what = "new redirection conflicts with existing -- ignoring it";
    901             goto bad;
    902          }
    903          /* They have the same eclass tag.  Use the priorities to
    904             resolve the ambiguity. */
    905          if (act.becPrio <= old->becPrio) {
    906             /* The new one doesn't have a higher priority, so just
    907                ignore it. */
    908             if (VG_(clo_verbosity) > 2) {
    909                VG_(message)(Vg_UserMsg, "Ignoring %s redirection:\n",
    910                             act.becPrio < old->becPrio ? "lower priority"
    911                                                        : "duplicate");
    912                show_active(             "    old: ", old);
    913                show_active(             "    new: ", &act);
    914             }
    915          } else {
    916             /* The tricky case.  The new one has a higher priority, so
    917                we need to get the old one out of the OSet and install
    918                this one in its place. */
    919             if (VG_(clo_verbosity) > 1) {
    920                VG_(message)(Vg_UserMsg,
    921                            "Preferring higher priority redirection:\n");
    922                show_active(             "    old: ", old);
    923                show_active(             "    new: ", &act);
    924             }
    925             add_act = True;
    926             void* oldNd = VG_(OSetGen_Remove)( activeSet, &act.from_addr );
    927             vg_assert(oldNd == old);
    928             VG_(OSetGen_FreeNode)( activeSet, old );
    929             old = NULL;
    930          }
    931       } else {
    932          /* This appears to be a duplicate of an existing binding.
    933             Safe(ish) -- ignore. */
    934          /* XXXXXXXXXXX COMPLAIN if new and old parents differ */
    935       }
    936 
    937    } else {
    938       /* There's no previous binding for this from_addr, so we must
    939          add 'act' to the active set. */
    940       add_act = True;
    941    }
    942 
    943    /* So, finally, actually add it. */
    944    if (add_act) {
    945       Active* a = VG_(OSetGen_AllocNode)(activeSet, sizeof(Active));
    946       vg_assert(a);
    947       *a = act;
    948       VG_(OSetGen_Insert)(activeSet, a);
    949       /* Now that a new from->to redirection is in force, we need to
    950          get rid of any translations intersecting 'from' in order that
    951          they get redirected to 'to'.  So discard them.  Just for
    952          paranoia (but, I believe, unnecessarily), discard 'to' as
    953          well. */
    954       VG_(discard_translations)( (Addr64)act.from_addr, 1,
    955                                  "redir_new_DebugInfo(from_addr)");
    956       VG_(discard_translations)( (Addr64)act.to_addr, 1,
    957                                  "redir_new_DebugInfo(to_addr)");
    958       if (VG_(clo_verbosity) > 2) {
    959          VG_(message)(Vg_UserMsg, "Adding active redirection:\n");
    960          show_active(             "    new: ", &act);
    961       }
    962    }
    963    return;
    964 
    965   bad:
    966    vg_assert(what);
    967    vg_assert(!add_act);
    968    if (VG_(clo_verbosity) > 1) {
    969       VG_(message)(Vg_UserMsg, "WARNING: %s\n", what);
    970       if (old) {
    971          show_active(             "    old: ", old);
    972       }
    973       show_active(             "    new: ", &act);
    974    }
    975 }
    976 
    977 
    978 /* Notify m_redir of the deletion of a DebugInfo.  This is relatively
    979    simple -- just get rid of all actives derived from it, and free up
    980    the associated list elements. */
    981 
    982 void VG_(redir_notify_delete_DebugInfo)( DebugInfo* delsi )
    983 {
    984    TopSpec* ts;
    985    TopSpec* tsPrev;
    986    Spec*    sp;
    987    Spec*    sp_next;
    988    OSet*    tmpSet;
    989    Active*  act;
    990    Bool     delMe;
    991    Addr     addr;
    992 
    993    vg_assert(delsi);
    994 
    995    /* Search for it, and make tsPrev point to the previous entry, if
    996       any. */
    997    tsPrev = NULL;
    998    ts     = topSpecs;
    999    while (True) {
   1000      if (ts == NULL) break;
   1001      if (ts->seginfo == delsi) break;
   1002      tsPrev = ts;
   1003      ts = ts->next;
   1004    }
   1005 
   1006    vg_assert(ts); /* else we don't have the deleted DebugInfo */
   1007    vg_assert(ts->seginfo == delsi);
   1008 
   1009    /* Traverse the actives, copying the addresses of those we intend
   1010       to delete into tmpSet. */
   1011    tmpSet = VG_(OSetWord_Create)(dinfo_zalloc, "redir.rndD.1", dinfo_free);
   1012 
   1013    ts->mark = True;
   1014 
   1015    VG_(OSetGen_ResetIter)( activeSet );
   1016    while ( (act = VG_(OSetGen_Next)(activeSet)) ) {
   1017       delMe = act->parent_spec != NULL
   1018               && act->parent_sym != NULL
   1019               && act->parent_spec->seginfo != NULL
   1020               && act->parent_sym->seginfo != NULL
   1021               && (act->parent_spec->mark || act->parent_sym->mark);
   1022 
   1023       /* While we're at it, a bit of paranoia: delete any actives
   1024          which don't have both feet in valid client executable areas.
   1025          But don't delete hardwired-at-startup ones; these are denoted
   1026          by having parent_spec or parent_sym being NULL.  */
   1027       if ( (!delMe)
   1028            && act->parent_spec != NULL
   1029            && act->parent_sym  != NULL ) {
   1030          if (!is_plausible_guest_addr(act->from_addr))
   1031             delMe = True;
   1032          if (!is_plausible_guest_addr(act->to_addr))
   1033             delMe = True;
   1034       }
   1035 
   1036       if (delMe) {
   1037          VG_(OSetWord_Insert)( tmpSet, act->from_addr );
   1038          /* While we have our hands on both the 'from' and 'to'
   1039             of this Active, do paranoid stuff with tt/tc. */
   1040          VG_(discard_translations)( (Addr64)act->from_addr, 1,
   1041                                     "redir_del_DebugInfo(from_addr)");
   1042          VG_(discard_translations)( (Addr64)act->to_addr, 1,
   1043                                     "redir_del_DebugInfo(to_addr)");
   1044       }
   1045    }
   1046 
   1047    /* Now traverse tmpSet, deleting corresponding elements in activeSet. */
   1048    VG_(OSetWord_ResetIter)( tmpSet );
   1049    while ( VG_(OSetWord_Next)(tmpSet, &addr) ) {
   1050       act = VG_(OSetGen_Remove)( activeSet, &addr );
   1051       vg_assert(act);
   1052       VG_(OSetGen_FreeNode)( activeSet, act );
   1053    }
   1054 
   1055    VG_(OSetWord_Destroy)( tmpSet );
   1056 
   1057    /* The Actives set is now cleaned up.  Free up this TopSpec and
   1058       everything hanging off it. */
   1059    for (sp = ts->specs; sp; sp = sp_next) {
   1060       if (sp->from_sopatt) dinfo_free(sp->from_sopatt);
   1061       if (sp->from_fnpatt) dinfo_free(sp->from_fnpatt);
   1062       sp_next = sp->next;
   1063       dinfo_free(sp);
   1064    }
   1065 
   1066    if (tsPrev == NULL) {
   1067       /* first in list */
   1068       topSpecs = ts->next;
   1069    } else {
   1070       tsPrev->next = ts->next;
   1071    }
   1072    dinfo_free(ts);
   1073 
   1074    if (VG_(clo_trace_redir))
   1075       show_redir_state("after VG_(redir_notify_delete_DebugInfo)");
   1076 }
   1077 
   1078 
   1079 /*------------------------------------------------------------*/
   1080 /*--- QUERIES (really the whole point of this module)      ---*/
   1081 /*------------------------------------------------------------*/
   1082 
   1083 /* This is the crucial redirection function.  It answers the question:
   1084    should this code address be redirected somewhere else?  It's used
   1085    just before translating a basic block. */
   1086 Addr VG_(redir_do_lookup) ( Addr orig, Bool* isWrap )
   1087 {
   1088    Active* r = VG_(OSetGen_Lookup)(activeSet, &orig);
   1089    if (r == NULL)
   1090       return orig;
   1091 
   1092    vg_assert(r->to_addr != 0);
   1093    if (isWrap)
   1094       *isWrap = r->isWrap || r->isIFunc;
   1095    if (r->isIFunc) {
   1096       vg_assert(iFuncWrapper);
   1097       return iFuncWrapper;
   1098    }
   1099    return r->to_addr;
   1100 }
   1101 
   1102 
   1103 /*------------------------------------------------------------*/
   1104 /*--- INITIALISATION                                       ---*/
   1105 /*------------------------------------------------------------*/
   1106 
   1107 /* Add a never-delete-me Active. */
   1108 
   1109 __attribute__((unused)) /* only used on amd64 */
   1110 static void add_hardwired_active ( Addr from, Addr to )
   1111 {
   1112    Active act;
   1113    act.from_addr   = from;
   1114    act.to_addr     = to;
   1115    act.parent_spec = NULL;
   1116    act.parent_sym  = NULL;
   1117    act.becTag      = 0; /* "not equivalent to any other fn" */
   1118    act.becPrio     = 0; /* mandatory when becTag == 0 */
   1119    act.isWrap      = False;
   1120    act.isIFunc     = False;
   1121    maybe_add_active( act );
   1122 }
   1123 
   1124 
   1125 /* Add a never-delete-me Spec.  This is a bit of a kludge.  On the
   1126    assumption that this is called only at startup, only handle the
   1127    case where topSpecs is completely empty, or if it isn't, it has
   1128    just one entry and that is the one with NULL seginfo -- that is the
   1129    entry that holds these initial specs. */
   1130 
   1131 __attribute__((unused)) /* not used on all platforms */
   1132 static void add_hardwired_spec (const  HChar* sopatt, const HChar* fnpatt,
   1133                                 Addr   to_addr,
   1134                                 const HChar** mandatory )
   1135 {
   1136    Spec* spec = dinfo_zalloc("redir.ahs.1", sizeof(Spec));
   1137    vg_assert(spec);
   1138 
   1139    if (topSpecs == NULL) {
   1140       topSpecs = dinfo_zalloc("redir.ahs.2", sizeof(TopSpec));
   1141       vg_assert(topSpecs);
   1142       /* symtab_zalloc sets all fields to zero */
   1143    }
   1144 
   1145    vg_assert(topSpecs != NULL);
   1146    vg_assert(topSpecs->next == NULL);
   1147    vg_assert(topSpecs->seginfo == NULL);
   1148    /* FIXED PARTS */
   1149    spec->from_sopatt = (HChar *)sopatt;
   1150    spec->from_fnpatt = (HChar *)fnpatt;
   1151    spec->to_addr     = to_addr;
   1152    spec->isWrap      = False;
   1153    spec->mandatory   = mandatory;
   1154    /* VARIABLE PARTS */
   1155    spec->mark        = False; /* not significant */
   1156    spec->done        = False; /* not significant */
   1157 
   1158    spec->next = topSpecs->specs;
   1159    topSpecs->specs = spec;
   1160 }
   1161 
   1162 
   1163 __attribute__((unused)) /* not used on all platforms */
   1164 static const HChar* complain_about_stripped_glibc_ldso[]
   1165 = { "Possible fixes: (1, short term): install glibc's debuginfo",
   1166     "package on this machine.  (2, longer term): ask the packagers",
   1167     "for your Linux distribution to please in future ship a non-",
   1168     "stripped ld.so (or whatever the dynamic linker .so is called)",
   1169     "that exports the above-named function using the standard",
   1170     "calling conventions for this platform.  The package you need",
   1171     "to install for fix (1) is called",
   1172     "",
   1173     "  On Debian, Ubuntu:                 libc6-dbg",
   1174     "  On SuSE, openSuSE, Fedora, RHEL:   glibc-debuginfo",
   1175     NULL
   1176   };
   1177 
   1178 
   1179 /* Initialise the redir system, and create the initial Spec list and
   1180    for amd64-linux a couple of permanent active mappings.  The initial
   1181    Specs are not converted into Actives yet, on the (checked)
   1182    assumption that no DebugInfos have so far been created, and so when
   1183    they are created, that will happen. */
   1184 
   1185 void VG_(redir_initialise) ( void )
   1186 {
   1187    // Assert that there are no DebugInfos so far
   1188    vg_assert( VG_(next_DebugInfo)(NULL) == NULL );
   1189 
   1190    // Initialise active mapping.
   1191    activeSet = VG_(OSetGen_Create)(offsetof(Active, from_addr),
   1192                                    NULL,     // Use fast comparison
   1193                                    dinfo_zalloc,
   1194                                    "redir.ri.1",
   1195                                    dinfo_free);
   1196 
   1197    // The rest of this function just adds initial Specs.
   1198 
   1199 #  if defined(VGP_x86_linux)
   1200    /* If we're using memcheck, use this intercept right from the
   1201       start, otherwise ld.so (glibc-2.3.5) makes a lot of noise. */
   1202    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1203       const HChar** mandatory;
   1204 #     if defined(GLIBC_2_2) || defined(GLIBC_2_3) || defined(GLIBC_2_4) \
   1205          || defined(GLIBC_2_5) || defined(GLIBC_2_6) || defined(GLIBC_2_7) \
   1206          || defined(GLIBC_2_8) || defined(GLIBC_2_9) \
   1207          || defined(GLIBC_2_10) || defined(GLIBC_2_11)
   1208       mandatory = NULL;
   1209 #     else
   1210       /* for glibc-2.12 and later, this is mandatory - can't sanely
   1211          continue without it */
   1212       mandatory = complain_about_stripped_glibc_ldso;
   1213 #     endif
   1214       add_hardwired_spec(
   1215          "ld-linux.so.2", "index",
   1216          (Addr)&VG_(x86_linux_REDIR_FOR_index), mandatory);
   1217       add_hardwired_spec(
   1218          "ld-linux.so.2", "strlen",
   1219          (Addr)&VG_(x86_linux_REDIR_FOR_strlen), mandatory);
   1220    }
   1221 
   1222 #  elif defined(VGP_amd64_linux)
   1223    /* Redirect vsyscalls to local versions */
   1224    add_hardwired_active(
   1225       0xFFFFFFFFFF600000ULL,
   1226       (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday)
   1227    );
   1228    add_hardwired_active(
   1229       0xFFFFFFFFFF600400ULL,
   1230       (Addr)&VG_(amd64_linux_REDIR_FOR_vtime)
   1231    );
   1232    add_hardwired_active(
   1233       0xFFFFFFFFFF600800ULL,
   1234       (Addr)&VG_(amd64_linux_REDIR_FOR_vgetcpu)
   1235    );
   1236 
   1237    /* If we're using memcheck, use these intercepts right from
   1238       the start, otherwise ld.so makes a lot of noise. */
   1239    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1240 
   1241       add_hardwired_spec(
   1242          "ld-linux-x86-64.so.2", "strlen",
   1243          (Addr)&VG_(amd64_linux_REDIR_FOR_strlen),
   1244 #        if defined(GLIBC_2_2) || defined(GLIBC_2_3) || defined(GLIBC_2_4) \
   1245             || defined(GLIBC_2_5) || defined(GLIBC_2_6) || defined(GLIBC_2_7) \
   1246             || defined(GLIBC_2_8) || defined(GLIBC_2_9)
   1247          NULL
   1248 #        else
   1249          /* for glibc-2.10 and later, this is mandatory - can't sanely
   1250             continue without it */
   1251          complain_about_stripped_glibc_ldso
   1252 #        endif
   1253       );
   1254    }
   1255 
   1256 #  elif defined(VGP_ppc32_linux)
   1257    /* If we're using memcheck, use these intercepts right from
   1258       the start, otherwise ld.so makes a lot of noise. */
   1259    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1260 
   1261       /* this is mandatory - can't sanely continue without it */
   1262       add_hardwired_spec(
   1263          "ld.so.1", "strlen",
   1264          (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen),
   1265          complain_about_stripped_glibc_ldso
   1266       );
   1267       add_hardwired_spec(
   1268          "ld.so.1", "strcmp",
   1269          (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp),
   1270          NULL /* not mandatory - so why bother at all? */
   1271          /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */
   1272       );
   1273       add_hardwired_spec(
   1274          "ld.so.1", "index",
   1275          (Addr)&VG_(ppc32_linux_REDIR_FOR_strchr),
   1276          NULL /* not mandatory - so why bother at all? */
   1277          /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */
   1278       );
   1279    }
   1280 
   1281 #  elif defined(VGP_ppc64_linux)
   1282    /* If we're using memcheck, use these intercepts right from
   1283       the start, otherwise ld.so makes a lot of noise. */
   1284    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1285 
   1286       /* this is mandatory - can't sanely continue without it */
   1287       add_hardwired_spec(
   1288          "ld64.so.1", "strlen",
   1289          (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strlen) ),
   1290          complain_about_stripped_glibc_ldso
   1291       );
   1292 
   1293       add_hardwired_spec(
   1294          "ld64.so.1", "index",
   1295          (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strchr) ),
   1296          NULL /* not mandatory - so why bother at all? */
   1297          /* glibc-2.5 (FC6, ppc64) seems fine without it */
   1298       );
   1299    }
   1300 
   1301 #  elif defined(VGP_arm_linux)
   1302    /* If we're using memcheck, use these intercepts right from the
   1303       start, otherwise ld.so makes a lot of noise.  In most ARM-linux
   1304       distros, ld.so's soname is ld-linux.so.3, but Ubuntu 14.04 on
   1305       Odroid uses ld-linux-armhf.so.3 for some reason. */
   1306    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1307       /* strlen */
   1308       add_hardwired_spec(
   1309          "ld-linux.so.3", "strlen",
   1310          (Addr)&VG_(arm_linux_REDIR_FOR_strlen),
   1311          complain_about_stripped_glibc_ldso
   1312       );
   1313       add_hardwired_spec(
   1314          "ld-linux-armhf.so.3", "strlen",
   1315          (Addr)&VG_(arm_linux_REDIR_FOR_strlen),
   1316          complain_about_stripped_glibc_ldso
   1317       );
   1318       /* memcpy */
   1319       add_hardwired_spec(
   1320          "ld-linux.so.3", "memcpy",
   1321          (Addr)&VG_(arm_linux_REDIR_FOR_memcpy),
   1322          complain_about_stripped_glibc_ldso
   1323       );
   1324       add_hardwired_spec(
   1325          "ld-linux-armhf.so.3", "memcpy",
   1326          (Addr)&VG_(arm_linux_REDIR_FOR_memcpy),
   1327          complain_about_stripped_glibc_ldso
   1328       );
   1329    }
   1330 
   1331 #  elif defined(VGP_arm64_linux)
   1332    /* If we're using memcheck, use these intercepts right from
   1333       the start, otherwise ld.so makes a lot of noise. */
   1334    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1335       add_hardwired_spec(
   1336          "ld-linux-aarch64.so.1", "strlen",
   1337          (Addr)&VG_(arm64_linux_REDIR_FOR_strlen),
   1338          complain_about_stripped_glibc_ldso
   1339       );
   1340       add_hardwired_spec(
   1341          "ld-linux-aarch64.so.1", "index",
   1342          (Addr)&VG_(arm64_linux_REDIR_FOR_index),
   1343          NULL
   1344       );
   1345       add_hardwired_spec(
   1346          "ld-linux-aarch64.so.1", "strcmp",
   1347          (Addr)&VG_(arm64_linux_REDIR_FOR_strcmp),
   1348          NULL
   1349       );
   1350       //add_hardwired_spec(
   1351       //   "ld-linux.so.3", "memcpy",
   1352       //   (Addr)&VG_(arm_linux_REDIR_FOR_memcpy),
   1353       //   complain_about_stripped_glibc_ldso
   1354       //);
   1355    }
   1356 
   1357 #  elif defined(VGP_x86_darwin)
   1358    /* If we're using memcheck, use these intercepts right from
   1359       the start, otherwise dyld makes a lot of noise. */
   1360    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1361       add_hardwired_spec("dyld", "strcmp",
   1362                          (Addr)&VG_(x86_darwin_REDIR_FOR_strcmp), NULL);
   1363       add_hardwired_spec("dyld", "strlen",
   1364                          (Addr)&VG_(x86_darwin_REDIR_FOR_strlen), NULL);
   1365       add_hardwired_spec("dyld", "strcat",
   1366                          (Addr)&VG_(x86_darwin_REDIR_FOR_strcat), NULL);
   1367       add_hardwired_spec("dyld", "strcpy",
   1368                          (Addr)&VG_(x86_darwin_REDIR_FOR_strcpy), NULL);
   1369       add_hardwired_spec("dyld", "strlcat",
   1370                          (Addr)&VG_(x86_darwin_REDIR_FOR_strlcat), NULL);
   1371    }
   1372 
   1373 #  elif defined(VGP_amd64_darwin)
   1374    /* If we're using memcheck, use these intercepts right from
   1375       the start, otherwise dyld makes a lot of noise. */
   1376    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1377       add_hardwired_spec("dyld", "strcmp",
   1378                          (Addr)&VG_(amd64_darwin_REDIR_FOR_strcmp), NULL);
   1379       add_hardwired_spec("dyld", "strlen",
   1380                          (Addr)&VG_(amd64_darwin_REDIR_FOR_strlen), NULL);
   1381       add_hardwired_spec("dyld", "strcat",
   1382                          (Addr)&VG_(amd64_darwin_REDIR_FOR_strcat), NULL);
   1383       add_hardwired_spec("dyld", "strcpy",
   1384                          (Addr)&VG_(amd64_darwin_REDIR_FOR_strcpy), NULL);
   1385       add_hardwired_spec("dyld", "strlcat",
   1386                          (Addr)&VG_(amd64_darwin_REDIR_FOR_strlcat), NULL);
   1387       // DDD: #warning fixme rdar://6166275
   1388       add_hardwired_spec("dyld", "arc4random",
   1389                          (Addr)&VG_(amd64_darwin_REDIR_FOR_arc4random), NULL);
   1390    }
   1391 
   1392 #  elif defined(VGP_s390x_linux)
   1393    /* nothing so far */
   1394 
   1395 #  elif defined(VGP_mips32_linux)
   1396    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1397 
   1398       /* this is mandatory - can't sanely continue without it */
   1399       add_hardwired_spec(
   1400          "ld.so.3", "strlen",
   1401          (Addr)&VG_(mips32_linux_REDIR_FOR_strlen),
   1402          complain_about_stripped_glibc_ldso
   1403       );
   1404    }
   1405 
   1406 #  elif defined(VGP_mips64_linux)
   1407    if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
   1408 
   1409       /* this is mandatory - can't sanely continue without it */
   1410       add_hardwired_spec(
   1411          "ld.so.3", "strlen",
   1412          (Addr)&VG_(mips64_linux_REDIR_FOR_strlen),
   1413          complain_about_stripped_glibc_ldso
   1414       );
   1415    }
   1416 
   1417 #  else
   1418 #    error Unknown platform
   1419 #  endif
   1420 
   1421    if (VG_(clo_trace_redir))
   1422       show_redir_state("after VG_(redir_initialise)");
   1423 }
   1424 
   1425 
   1426 /*------------------------------------------------------------*/
   1427 /*--- MISC HELPERS                                         ---*/
   1428 /*------------------------------------------------------------*/
   1429 
   1430 static void* dinfo_zalloc(const HChar* ec, SizeT n) {
   1431    void* p;
   1432    vg_assert(n > 0);
   1433    p = VG_(arena_malloc)(VG_AR_DINFO, ec, n);
   1434    tl_assert(p);
   1435    VG_(memset)(p, 0, n);
   1436    return p;
   1437 }
   1438 
   1439 static void dinfo_free(void* p) {
   1440    tl_assert(p);
   1441    return VG_(arena_free)(VG_AR_DINFO, p);
   1442 }
   1443 
   1444 static HChar* dinfo_strdup(const HChar* ec, const HChar* str)
   1445 {
   1446    return VG_(arena_strdup)(VG_AR_DINFO, ec, str);
   1447 }
   1448 
   1449 /* Really this should be merged with translations_allowable_from_seg
   1450    in m_translate. */
   1451 static Bool is_plausible_guest_addr(Addr a)
   1452 {
   1453    NSegment const* seg = VG_(am_find_nsegment)(a);
   1454    return seg != NULL
   1455           && (seg->kind == SkAnonC || seg->kind == SkFileC)
   1456           && (seg->hasX || seg->hasR); /* crude x86-specific hack */
   1457 }
   1458 
   1459 
   1460 /*------------------------------------------------------------*/
   1461 /*--- NOTIFY-ON-LOAD FUNCTIONS                             ---*/
   1462 /*------------------------------------------------------------*/
   1463 
   1464 static
   1465 void handle_maybe_load_notifier( const HChar* soname,
   1466                                        HChar* symbol, Addr addr )
   1467 {
   1468 #  if defined(VGP_x86_linux)
   1469    /* x86-linux only: if we see _dl_sysinfo_int80, note its address.
   1470       See comment on declaration of VG_(client__dl_sysinfo_int80) for
   1471       the reason.  As far as I can tell, the relevant symbol is always
   1472       in object with soname "ld-linux.so.2". */
   1473    if (symbol && symbol[0] == '_'
   1474               && 0 == VG_(strcmp)(symbol, "_dl_sysinfo_int80")
   1475               && 0 == VG_(strcmp)(soname, "ld-linux.so.2")) {
   1476       if (VG_(client__dl_sysinfo_int80) == 0)
   1477          VG_(client__dl_sysinfo_int80) = addr;
   1478    }
   1479 #  endif
   1480 
   1481    /* Normal load-notifier handling after here.  First, ignore all
   1482       symbols lacking the right prefix. */
   1483    vg_assert(symbol); // assert rather than segfault if it is NULL
   1484    if (0 != VG_(strncmp)(symbol, VG_NOTIFY_ON_LOAD_PREFIX,
   1485                                  VG_NOTIFY_ON_LOAD_PREFIX_LEN))
   1486       /* Doesn't have the right prefix */
   1487       return;
   1488 
   1489    if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(freeres))) == 0)
   1490       VG_(client___libc_freeres_wrapper) = addr;
   1491    else
   1492    if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(ifunc_wrapper))) == 0)
   1493       iFuncWrapper = addr;
   1494    else
   1495       vg_assert2(0, "unrecognised load notification function: %s", symbol);
   1496 }
   1497 
   1498 
   1499 /*------------------------------------------------------------*/
   1500 /*--- REQUIRE-TEXT-SYMBOL HANDLING                         ---*/
   1501 /*------------------------------------------------------------*/
   1502 
   1503 /* In short: check that the currently-being-loaded object has text
   1504    symbols that satisfy any --require-text-symbol= specifications that
   1505    apply to it, and abort the run with an error message if not.
   1506 */
   1507 static void handle_require_text_symbols ( DebugInfo* di )
   1508 {
   1509    /* First thing to do is figure out which, if any,
   1510       --require-text-symbol specification strings apply to this
   1511       object.  Most likely none do, since it is not expected to
   1512       frequently be used.  Work through the list of specs and
   1513       accumulate in fnpatts[] the fn patterns that pertain to this
   1514       object. */
   1515    HChar* fnpatts[VG_CLO_MAX_REQ_TSYMS];
   1516    Int    fnpatts_used = 0;
   1517    Int    i, j;
   1518    const HChar* di_soname = VG_(DebugInfo_get_soname)(di);
   1519    vg_assert(di_soname); // must be present
   1520 
   1521    VG_(memset)(&fnpatts, 0, sizeof(fnpatts));
   1522 
   1523    vg_assert(VG_(clo_n_req_tsyms) >= 0);
   1524    vg_assert(VG_(clo_n_req_tsyms) <= VG_CLO_MAX_REQ_TSYMS);
   1525    for (i = 0; i < VG_(clo_n_req_tsyms); i++) {
   1526       const HChar* clo_spec = VG_(clo_req_tsyms)[i];
   1527       vg_assert(clo_spec && VG_(strlen)(clo_spec) >= 4);
   1528       // clone the spec, so we can stick a zero at the end of the sopatt
   1529       HChar *spec = VG_(strdup)("m_redir.hrts.1", clo_spec);
   1530       HChar sep = spec[0];
   1531       HChar* sopatt = &spec[1];
   1532       HChar* fnpatt = VG_(strchr)(sopatt, sep);
   1533       // the initial check at clo processing in time in m_main
   1534       // should ensure this.
   1535       vg_assert(fnpatt && *fnpatt == sep);
   1536       *fnpatt = 0;
   1537       fnpatt++;
   1538       if (VG_(string_match)(sopatt, di_soname))
   1539          fnpatts[fnpatts_used++]
   1540             = VG_(strdup)("m_redir.hrts.2", fnpatt);
   1541       VG_(free)(spec);
   1542    }
   1543 
   1544    if (fnpatts_used == 0)
   1545       return;  /* no applicable spec strings */
   1546 
   1547    /* So finally, fnpatts[0 .. fnpatts_used - 1] contains the set of
   1548       (patterns for) text symbol names that must be found in this
   1549       object, in order to continue.  That is, we must find at least
   1550       one text symbol name that matches each pattern, else we must
   1551       abort the run. */
   1552 
   1553    if (0) VG_(printf)("for %s\n", di_soname);
   1554    for (i = 0; i < fnpatts_used; i++)
   1555       if (0) VG_(printf)("   fnpatt: %s\n", fnpatts[i]);
   1556 
   1557    /* For each spec, look through the syms to find one that matches.
   1558       This isn't terribly efficient but it happens rarely, so no big
   1559       deal. */
   1560    for (i = 0; i < fnpatts_used; i++) {
   1561       Bool   found  = False;
   1562       HChar* fnpatt = fnpatts[i];
   1563       Int    nsyms  = VG_(DebugInfo_syms_howmany)(di);
   1564       for (j = 0; j < nsyms; j++) {
   1565          Bool    isText        = False;
   1566          HChar*  sym_name_pri  = NULL;
   1567          HChar** sym_names_sec = NULL;
   1568          VG_(DebugInfo_syms_getidx)( di, j, NULL, NULL,
   1569                                      NULL, &sym_name_pri, &sym_names_sec,
   1570                                      &isText, NULL );
   1571          HChar*  twoslots[2];
   1572          HChar** names_init = alloc_symname_array(sym_name_pri, sym_names_sec,
   1573                                                   &twoslots[0]);
   1574          HChar** names;
   1575          for (names = names_init; *names; names++) {
   1576             /* ignore data symbols */
   1577             if (0) VG_(printf)("QQQ %s\n", *names);
   1578             vg_assert(sym_name_pri);
   1579             if (!isText)
   1580                continue;
   1581             if (VG_(string_match)(fnpatt, *names)) {
   1582                found = True;
   1583                break;
   1584             }
   1585          }
   1586          free_symname_array(names_init, &twoslots[0]);
   1587          if (found)
   1588             break;
   1589       }
   1590 
   1591       if (!found) {
   1592          const HChar* v = "valgrind:  ";
   1593          VG_(printf)("\n");
   1594          VG_(printf)(
   1595          "%sFatal error at when loading library with soname\n", v);
   1596          VG_(printf)(
   1597          "%s   %s\n", v, di_soname);
   1598          VG_(printf)(
   1599          "%sCannot find any text symbol with a name "
   1600          "that matches the pattern\n", v);
   1601          VG_(printf)("%s   %s\n", v, fnpatt);
   1602          VG_(printf)("%sas required by a --require-text-symbol= "
   1603          "specification.\n", v);
   1604          VG_(printf)("\n");
   1605          VG_(printf)(
   1606          "%sCannot continue -- exiting now.\n", v);
   1607          VG_(printf)("\n");
   1608          VG_(exit)(1);
   1609       }
   1610    }
   1611 
   1612    /* All required specs were found.  Just free memory and return. */
   1613    for (i = 0; i < fnpatts_used; i++)
   1614       VG_(free)(fnpatts[i]);
   1615 }
   1616 
   1617 
   1618 /*------------------------------------------------------------*/
   1619 /*--- SANITY/DEBUG                                         ---*/
   1620 /*------------------------------------------------------------*/
   1621 
   1622 static void show_spec ( const HChar* left, Spec* spec )
   1623 {
   1624    VG_(message)( Vg_DebugMsg,
   1625                  "%s%25s %30s %s-> (%04d.%d) 0x%08llx\n",
   1626                  left,
   1627                  spec->from_sopatt, spec->from_fnpatt,
   1628                  spec->isWrap ? "W" : "R",
   1629                  spec->becTag, spec->becPrio,
   1630                  (ULong)spec->to_addr );
   1631 }
   1632 
   1633 static void show_active ( const HChar* left, Active* act )
   1634 {
   1635    Bool ok;
   1636    HChar name1[64] = "";
   1637    HChar name2[64] = "";
   1638    name1[0] = name2[0] = 0;
   1639    ok = VG_(get_fnname_w_offset)(act->from_addr, name1, 64);
   1640    if (!ok) VG_(strcpy)(name1, "???");
   1641    ok = VG_(get_fnname_w_offset)(act->to_addr, name2, 64);
   1642    if (!ok) VG_(strcpy)(name2, "???");
   1643 
   1644    VG_(message)(Vg_DebugMsg, "%s0x%08llx (%20s) %s-> (%04d.%d) 0x%08llx %s\n",
   1645                              left,
   1646                              (ULong)act->from_addr, name1,
   1647                              act->isWrap ? "W" : "R",
   1648                              act->becTag, act->becPrio,
   1649                              (ULong)act->to_addr, name2 );
   1650 }
   1651 
   1652 static void show_redir_state ( const HChar* who )
   1653 {
   1654    TopSpec* ts;
   1655    Spec*    sp;
   1656    Active*  act;
   1657    VG_(message)(Vg_DebugMsg, "<<\n");
   1658    VG_(message)(Vg_DebugMsg, "   ------ REDIR STATE %s ------\n", who);
   1659    for (ts = topSpecs; ts; ts = ts->next) {
   1660       if (ts->seginfo)
   1661          VG_(message)(Vg_DebugMsg,
   1662                       "   TOPSPECS of soname %s filename %s\n",
   1663                       VG_(DebugInfo_get_soname)(ts->seginfo),
   1664                       VG_(DebugInfo_get_filename)(ts->seginfo));
   1665       else
   1666          VG_(message)(Vg_DebugMsg,
   1667                       "   TOPSPECS of soname (hardwired)\n");
   1668 
   1669       for (sp = ts->specs; sp; sp = sp->next)
   1670          show_spec("     ", sp);
   1671    }
   1672    VG_(message)(Vg_DebugMsg, "   ------ ACTIVE ------\n");
   1673    VG_(OSetGen_ResetIter)( activeSet );
   1674    while ( (act = VG_(OSetGen_Next)(activeSet)) ) {
   1675       show_active("    ", act);
   1676    }
   1677 
   1678    VG_(message)(Vg_DebugMsg, ">>\n");
   1679 }
   1680 
   1681 /*--------------------------------------------------------------------*/
   1682 /*--- end                                                          ---*/
   1683 /*--------------------------------------------------------------------*/
   1684