Home | History | Annotate | Download | only in m_aspacemgr
      1 /* -*- mode: C; c-basic-offset: 3; -*- */
      2 
      3 /*--------------------------------------------------------------------*/
      4 /*--- The address space manager: segment initialisation and        ---*/
      5 /*--- tracking, stack operations                                   ---*/
      6 /*---                                                              ---*/
      7 /*--- Implementation for Linux (and Darwin!)     aspacemgr-linux.c ---*/
      8 /*--------------------------------------------------------------------*/
      9 
     10 /*
     11    This file is part of Valgrind, a dynamic binary instrumentation
     12    framework.
     13 
     14    Copyright (C) 2000-2015 Julian Seward
     15       jseward (at) acm.org
     16 
     17    This program is free software; you can redistribute it and/or
     18    modify it under the terms of the GNU General Public License as
     19    published by the Free Software Foundation; either version 2 of the
     20    License, or (at your option) any later version.
     21 
     22    This program is distributed in the hope that it will be useful, but
     23    WITHOUT ANY WARRANTY; without even the implied warranty of
     24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     25    General Public License for more details.
     26 
     27    You should have received a copy of the GNU General Public License
     28    along with this program; if not, write to the Free Software
     29    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     30    02111-1307, USA.
     31 
     32    The GNU General Public License is contained in the file COPYING.
     33 */
     34 
     35 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
     36 
     37 /* *************************************************************
     38    DO NOT INCLUDE ANY OTHER FILES HERE.
     39    ADD NEW INCLUDES ONLY TO priv_aspacemgr.h
     40    AND THEN ONLY AFTER READING DIRE WARNINGS THERE TOO.
     41    ************************************************************* */
     42 
     43 #include "priv_aspacemgr.h"
     44 #include "config.h"
     45 
     46 
     47 /* Note: many of the exported functions implemented below are
     48    described more fully in comments in pub_core_aspacemgr.h.
     49 */
     50 
     51 
     52 /*-----------------------------------------------------------------*/
     53 /*---                                                           ---*/
     54 /*--- Overview.                                                 ---*/
     55 /*---                                                           ---*/
     56 /*-----------------------------------------------------------------*/
     57 
     58 /* Purpose
     59    ~~~~~~~
     60    The purpose of the address space manager (aspacem) is:
     61 
     62    (1) to record the disposition of all parts of the process' address
     63        space at all times.
     64 
     65    (2) to the extent that it can, influence layout in ways favourable
     66        to our purposes.
     67 
     68    It is important to appreciate that whilst it can and does attempt
     69    to influence layout, and usually succeeds, it isn't possible to
     70    impose absolute control: in the end, the kernel is the final
     71    arbiter, and can always bounce our requests.
     72 
     73    Strategy
     74    ~~~~~~~~
     75    The strategy is therefore as follows:
     76 
     77    * Track ownership of mappings.  Each one can belong either to
     78      Valgrind or to the client.
     79 
     80    * Try to place the client's fixed and hinted mappings at the
     81      requested addresses.  Fixed mappings are allowed anywhere except
     82      in areas reserved by Valgrind; the client can trash its own
     83      mappings if it wants.  Hinted mappings are allowed providing they
     84      fall entirely in free areas; if not, they will be placed by
     85      aspacem in a free area.
     86 
     87    * Anonymous mappings are allocated so as to keep Valgrind and
     88      client areas widely separated when possible.  If address space
     89      runs low, then they may become intermingled: aspacem will attempt
     90      to use all possible space.  But under most circumstances lack of
     91      address space is not a problem and so the areas will remain far
     92      apart.
     93 
     94      Searches for client space start at aspacem_cStart and will wrap
     95      around the end of the available space if needed.  Searches for
     96      Valgrind space start at aspacem_vStart and will also wrap around.
     97      Because aspacem_cStart is approximately at the start of the
     98      available space and aspacem_vStart is approximately in the
     99      middle, for the most part the client anonymous mappings will be
    100      clustered towards the start of available space, and Valgrind ones
    101      in the middle.
    102 
    103      On Solaris, searches for client space start at (aspacem_vStart - 1)
    104      and for Valgrind space start at (aspacem_maxAddr - 1) and go backwards.
    105      This simulates what kernel does - brk limit grows from bottom and mmap'ed
    106      objects from top. It is in contrary with Linux where data segment
    107      and mmap'ed objects grow from bottom (leading to early data segment
    108      exhaustion for tools which do not use m_replacemalloc). While Linux glibc
    109      can cope with this problem by employing mmap, Solaris libc treats inability
    110      to grow brk limit as a hard failure.
    111 
    112      The available space is delimited by aspacem_minAddr and
    113      aspacem_maxAddr.  aspacem is flexible and can operate with these
    114      at any (sane) setting.  For 32-bit Linux, aspacem_minAddr is set
    115      to some low-ish value at startup (64M) and aspacem_maxAddr is
    116      derived from the stack pointer at system startup.  This seems a
    117      reliable way to establish the initial boundaries.
    118      A command line option allows to change the value of aspacem_minAddr,
    119      so as to allow memory hungry applications to use the lowest
    120      part of the memory.
    121 
    122      64-bit Linux is similar except for the important detail that the
    123      upper boundary is set to 64G.  The reason is so that all
    124      anonymous mappings (basically all client data areas) are kept
    125      below 64G, since that is the maximum range that memcheck can
    126      track shadow memory using a fast 2-level sparse array.  It can go
    127      beyond that but runs much more slowly.  The 64G limit is
    128      arbitrary and is trivially changed.  So, with the current
    129      settings, programs on 64-bit Linux will appear to run out of
    130      address space and presumably fail at the 64G limit.  Given the
    131      considerable space overhead of Memcheck, that means you should be
    132      able to memcheckify programs that use up to about 32G natively.
    133 
    134    Note that the aspacem_minAddr/aspacem_maxAddr limits apply only to
    135    anonymous mappings.  The client can still do fixed and hinted maps
    136    at any addresses provided they do not overlap Valgrind's segments.
    137    This makes Valgrind able to load prelinked .so's at their requested
    138    addresses on 64-bit platforms, even if they are very high (eg,
    139    112TB).
    140 
    141    At startup, aspacem establishes the usable limits, and advises
    142    m_main to place the client stack at the top of the range, which on
    143    a 32-bit machine will be just below the real initial stack.  One
    144    effect of this is that self-hosting sort-of works, because an inner
    145    valgrind will then place its client's stack just below its own
    146    initial stack.
    147 
    148    The segment array and segment kinds
    149    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    150    The central data structure is the segment array (segments[0
    151    .. nsegments_used-1]).  This covers the entire address space in
    152    order, giving account of every byte of it.  Free spaces are
    153    represented explicitly as this makes many operations simpler.
    154    Mergeable adjacent segments are aggressively merged so as to create
    155    a "normalised" representation (preen_nsegments).
    156 
    157    There are 7 (mutually-exclusive) segment kinds, the meaning of
    158    which is important:
    159 
    160    SkFree: a free space, which may be allocated either to Valgrind (V)
    161       or the client (C).
    162 
    163    SkAnonC: an anonymous mapping belonging to C.  For these, aspacem
    164       tracks a boolean indicating whether or not is is part of the
    165       client's heap area (can't remember why).
    166 
    167    SkFileC: a file mapping belonging to C.
    168 
    169    SkShmC: a shared memory segment belonging to C.
    170 
    171    SkAnonV: an anonymous mapping belonging to V.  These cover all V's
    172       dynamic memory needs, including non-client malloc/free areas,
    173       shadow memory, and the translation cache.
    174 
    175    SkFileV: a file mapping belonging to V.  As far as I know these are
    176       only created transiently for the purposes of reading debug info.
    177 
    178    SkResvn: a reservation segment.
    179 
    180    These are mostly straightforward.  Reservation segments have some
    181    subtlety, however.
    182 
    183    A reservation segment is unmapped from the kernel's point of view,
    184    but is an area in which aspacem will not create anonymous maps
    185    (either Vs or Cs).  The idea is that we will try to keep it clear
    186    when the choice to do so is ours.  Reservation segments are
    187    'invisible' from the client's point of view: it may choose to park
    188    a fixed mapping in the middle of one, and that's just tough -- we
    189    can't do anything about that.  From the client's perspective
    190    reservations are semantically equivalent to (although
    191    distinguishable from, if it makes enquiries) free areas.
    192 
    193    Reservations are a primitive mechanism provided for whatever
    194    purposes the rest of the system wants.  Currently they are used to
    195    reserve the expansion space into which a growdown stack is
    196    expanded, and into which the data segment is extended.  Note,
    197    though, those uses are entirely external to this module, which only
    198    supplies the primitives.
    199 
    200    Reservations may be shrunk in order that an adjoining anonymous
    201    mapping may be extended.  This makes dataseg/stack expansion work.
    202    A reservation may not be shrunk below one page.
    203 
    204    The advise/notify concept
    205    ~~~~~~~~~~~~~~~~~~~~~~~~~
    206    All mmap-related calls must be routed via aspacem.  Calling
    207    sys_mmap directly from the rest of the system is very dangerous
    208    because aspacem's data structures will become out of date.
    209 
    210    The fundamental mode of operation of aspacem is to support client
    211    mmaps.  Here's what happens (in ML_(generic_PRE_sys_mmap)):
    212 
    213    * m_syswrap intercepts the mmap call.  It examines the parameters
    214      and identifies the requested placement constraints.  There are
    215      three possibilities: no constraint (MAny), hinted (MHint, "I
    216      prefer X but will accept anything"), and fixed (MFixed, "X or
    217      nothing").
    218 
    219    * This request is passed to VG_(am_get_advisory).  This decides on
    220      a placement as described in detail in Strategy above.  It may
    221      also indicate that the map should fail, because it would trash
    222      one of Valgrind's areas, which would probably kill the system.
    223 
    224    * Control returns to the wrapper.  If VG_(am_get_advisory) has
    225      declared that the map should fail, then it must be made to do so.
    226      Usually, though, the request is considered acceptable, in which
    227      case an "advised" address is supplied.  The advised address
    228      replaces the original address supplied by the client, and
    229      MAP_FIXED is set.
    230 
    231      Note at this point that although aspacem has been asked for
    232      advice on where to place the mapping, no commitment has yet been
    233      made by either it or the kernel.
    234 
    235    * The adjusted request is handed off to the kernel.
    236 
    237    * The kernel's result is examined.  If the map succeeded, aspacem
    238      is told of the outcome (VG_(am_notify_client_mmap)), so it can
    239      update its records accordingly.
    240 
    241   This then is the central advise-notify idiom for handling client
    242   mmap/munmap/mprotect/shmat:
    243 
    244   * ask aspacem for an advised placement (or a veto)
    245 
    246   * if not vetoed, hand request to kernel, using the advised placement
    247 
    248   * examine result, and if successful, notify aspacem of the result.
    249 
    250   There are also many convenience functions, eg
    251   VG_(am_mmap_anon_fixed_client), which do both phases entirely within
    252   aspacem.
    253 
    254   To debug all this, a sync-checker is provided.  It reads
    255   /proc/self/maps, compares what it sees with aspacem's records, and
    256   complains if there is a difference.  --sanity-level=3 runs it before
    257   and after each syscall, which is a powerful, if slow way of finding
    258   buggy syscall wrappers.
    259 
    260   Loss of pointercheck
    261   ~~~~~~~~~~~~~~~~~~~~
    262   Up to and including Valgrind 2.4.1, x86 segmentation was used to
    263   enforce seperation of V and C, so that wild writes by C could not
    264   trash V.  This got called "pointercheck".  Unfortunately, the new
    265   more flexible memory layout, plus the need to be portable across
    266   different architectures, means doing this in hardware is no longer
    267   viable, and doing it in software is expensive.  So at the moment we
    268   don't do it at all.
    269 */
    270 
    271 
    272 /*-----------------------------------------------------------------*/
    273 /*---                                                           ---*/
    274 /*--- The Address Space Manager's state.                        ---*/
    275 /*---                                                           ---*/
    276 /*-----------------------------------------------------------------*/
    277 
    278 /* ------ start of STATE for the address-space manager ------ */
    279 
    280 /* Max number of segments we can track.  On Android, virtual address
    281    space is limited, so keep a low limit -- 5000 x sizef(NSegment) is
    282    360KB. */
    283 #if defined(VGPV_arm_linux_android) \
    284     || defined(VGPV_x86_linux_android) \
    285     || defined(VGPV_mips32_linux_android) \
    286     || defined(VGPV_arm64_linux_android)
    287 # define VG_N_SEGMENTS 5000
    288 #else
    289 # define VG_N_SEGMENTS 30000
    290 #endif
    291 
    292 /* Array [0 .. nsegments_used-1] of all mappings. */
    293 /* Sorted by .addr field. */
    294 /* I: len may not be zero. */
    295 /* I: overlapping segments are not allowed. */
    296 /* I: the segments cover the entire address space precisely. */
    297 /* Each segment can optionally hold an index into the filename table. */
    298 
    299 static NSegment nsegments[VG_N_SEGMENTS];
    300 static Int      nsegments_used = 0;
    301 
    302 #define Addr_MIN ((Addr)0)
    303 #define Addr_MAX ((Addr)(-1ULL))
    304 
    305 /* Limits etc */
    306 
    307 
    308 Addr VG_(clo_aspacem_minAddr)
    309 #if defined(VGO_linux)
    310    = (Addr) 0x04000000; // 64M
    311 #elif defined(VGO_darwin)
    312 # if VG_WORDSIZE == 4
    313    = (Addr) 0x00001000;
    314 # else
    315    = (Addr) 0x100000000;  // 4GB page zero
    316 # endif
    317 #elif defined(VGO_solaris)
    318    = (Addr) 0x00100000; // 1MB
    319 #else
    320 #endif
    321 
    322 
    323 // The smallest address that aspacem will try to allocate
    324 static Addr aspacem_minAddr = 0;
    325 
    326 // The largest address that aspacem will try to allocate
    327 static Addr aspacem_maxAddr = 0;
    328 
    329 // Where aspacem will start looking for client space
    330 static Addr aspacem_cStart = 0;
    331 
    332 // Where aspacem will start looking for Valgrind space
    333 static Addr aspacem_vStart = 0;
    334 
    335 
    336 #define AM_SANITY_CHECK                                      \
    337    do {                                                      \
    338       if (VG_(clo_sanity_level >= 3))                        \
    339          aspacem_assert(VG_(am_do_sync_check)                \
    340             (__PRETTY_FUNCTION__,__FILE__,__LINE__));        \
    341    } while (0)
    342 
    343 /* ------ end of STATE for the address-space manager ------ */
    344 
    345 /* ------ Forwards decls ------ */
    346 inline
    347 static Int  find_nsegment_idx ( Addr a );
    348 
    349 static void parse_procselfmaps (
    350       void (*record_mapping)( Addr addr, SizeT len, UInt prot,
    351                               ULong dev, ULong ino, Off64T offset,
    352                               const HChar* filename ),
    353       void (*record_gap)( Addr addr, SizeT len )
    354    );
    355 
    356 /* ----- Hacks to do with the "commpage" on arm-linux ----- */
    357 /* Not that I have anything against the commpage per se.  It's just
    358    that it's not listed in /proc/self/maps, which is a royal PITA --
    359    we have to fake it up, in parse_procselfmaps.
    360 
    361    But note also bug 254556 comment #2: this is now fixed in newer
    362    kernels -- it is listed as a "[vectors]" entry.  Presumably the
    363    fake entry made here duplicates the [vectors] entry, and so, if at
    364    some point in the future, we can stop supporting buggy kernels,
    365    then this kludge can be removed entirely, since the procmap parser
    366    below will read that entry in the normal way. */
    367 #if defined(VGP_arm_linux)
    368 #  define ARM_LINUX_FAKE_COMMPAGE_START 0xFFFF0000
    369 #  define ARM_LINUX_FAKE_COMMPAGE_END1  0xFFFF1000
    370 #endif
    371 
    372 
    373 
    374 /*-----------------------------------------------------------------*/
    375 /*---                                                           ---*/
    376 /*--- Displaying the segment array.                             ---*/
    377 /*---                                                           ---*/
    378 /*-----------------------------------------------------------------*/
    379 
    380 static const HChar* show_SegKind ( SegKind sk )
    381 {
    382    switch (sk) {
    383       case SkFree:  return "    ";
    384       case SkAnonC: return "anon";
    385       case SkAnonV: return "ANON";
    386       case SkFileC: return "file";
    387       case SkFileV: return "FILE";
    388       case SkShmC:  return "shm ";
    389       case SkResvn: return "RSVN";
    390       default:      return "????";
    391    }
    392 }
    393 
    394 static const HChar* show_ShrinkMode ( ShrinkMode sm )
    395 {
    396    switch (sm) {
    397       case SmLower: return "SmLower";
    398       case SmUpper: return "SmUpper";
    399       case SmFixed: return "SmFixed";
    400       default: return "Sm?????";
    401    }
    402 }
    403 
    404 static void show_len_concisely ( /*OUT*/HChar* buf, Addr start, Addr end )
    405 {
    406    const HChar* fmt;
    407    ULong len = ((ULong)end) - ((ULong)start) + 1;
    408 
    409    if (len < 10*1000*1000ULL) {
    410       fmt = "%7llu";
    411    }
    412    else if (len < 999999ULL * (1ULL<<20)) {
    413       fmt = "%6llum";
    414       len >>= 20;
    415    }
    416    else if (len < 999999ULL * (1ULL<<30)) {
    417       fmt = "%6llug";
    418       len >>= 30;
    419    }
    420    else if (len < 999999ULL * (1ULL<<40)) {
    421       fmt = "%6llut";
    422       len >>= 40;
    423    }
    424    else {
    425       fmt = "%6llue";
    426       len >>= 50;
    427    }
    428    ML_(am_sprintf)(buf, fmt, len);
    429 }
    430 
    431 /* Show full details of an NSegment */
    432 
    433 static void show_nsegment_full ( Int logLevel, Int segNo, const NSegment* seg )
    434 {
    435    HChar len_buf[20];
    436    const HChar* name = ML_(am_get_segname)( seg->fnIdx );
    437 
    438    if (name == NULL)
    439       name = "(none)";
    440 
    441    show_len_concisely(len_buf, seg->start, seg->end);
    442 
    443    VG_(debugLog)(
    444       logLevel, "aspacem",
    445       "%3d: %s %010lx-%010lx %s %c%c%c%c%c %s "
    446       "d=0x%03llx i=%-7llu o=%-7lld (%d,%d) %s\n",
    447       segNo, show_SegKind(seg->kind),
    448       seg->start, seg->end, len_buf,
    449       seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
    450       seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
    451       seg->isCH ? 'H' : '-',
    452       show_ShrinkMode(seg->smode),
    453       seg->dev, seg->ino, seg->offset,
    454       ML_(am_segname_get_seqnr)(seg->fnIdx), seg->fnIdx,
    455       name
    456    );
    457 }
    458 
    459 
    460 /* Show an NSegment in a user-friendly-ish way. */
    461 
    462 static void show_nsegment ( Int logLevel, Int segNo, const NSegment* seg )
    463 {
    464    HChar len_buf[20];
    465    show_len_concisely(len_buf, seg->start, seg->end);
    466 
    467    switch (seg->kind) {
    468 
    469       case SkFree:
    470          VG_(debugLog)(
    471             logLevel, "aspacem",
    472             "%3d: %s %010lx-%010lx %s\n",
    473             segNo, show_SegKind(seg->kind),
    474             seg->start, seg->end, len_buf
    475          );
    476          break;
    477 
    478       case SkAnonC: case SkAnonV: case SkShmC:
    479          VG_(debugLog)(
    480             logLevel, "aspacem",
    481             "%3d: %s %010lx-%010lx %s %c%c%c%c%c\n",
    482             segNo, show_SegKind(seg->kind),
    483             seg->start, seg->end, len_buf,
    484             seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
    485             seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
    486             seg->isCH ? 'H' : '-'
    487          );
    488          break;
    489 
    490       case SkFileC: case SkFileV:
    491          VG_(debugLog)(
    492             logLevel, "aspacem",
    493             "%3d: %s %010lx-%010lx %s %c%c%c%c%c d=0x%03llx "
    494             "i=%-7llu o=%-7lld (%d,%d)\n",
    495             segNo, show_SegKind(seg->kind),
    496             seg->start, seg->end, len_buf,
    497             seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
    498             seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
    499             seg->isCH ? 'H' : '-',
    500             seg->dev, seg->ino, seg->offset,
    501             ML_(am_segname_get_seqnr)(seg->fnIdx), seg->fnIdx
    502          );
    503          break;
    504 
    505       case SkResvn:
    506          VG_(debugLog)(
    507             logLevel, "aspacem",
    508             "%3d: %s %010lx-%010lx %s %c%c%c%c%c %s\n",
    509             segNo, show_SegKind(seg->kind),
    510             seg->start, seg->end, len_buf,
    511             seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
    512             seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
    513             seg->isCH ? 'H' : '-',
    514             show_ShrinkMode(seg->smode)
    515          );
    516          break;
    517 
    518       default:
    519          VG_(debugLog)(
    520             logLevel, "aspacem",
    521             "%3d: ???? UNKNOWN SEGMENT KIND\n",
    522             segNo
    523          );
    524          break;
    525    }
    526 }
    527 
    528 /* Print out the segment array (debugging only!). */
    529 void VG_(am_show_nsegments) ( Int logLevel, const HChar* who )
    530 {
    531    Int i;
    532    VG_(debugLog)(logLevel, "aspacem",
    533                  "<<< SHOW_SEGMENTS: %s (%d segments)\n",
    534                  who, nsegments_used);
    535    ML_(am_show_segnames)( logLevel, who);
    536    for (i = 0; i < nsegments_used; i++)
    537      show_nsegment( logLevel, i, &nsegments[i] );
    538    VG_(debugLog)(logLevel, "aspacem",
    539                  ">>>\n");
    540 }
    541 
    542 
    543 /* Get the filename corresponding to this segment, if known and if it
    544    has one. */
    545 const HChar* VG_(am_get_filename)( NSegment const * seg )
    546 {
    547    aspacem_assert(seg);
    548    return ML_(am_get_segname)( seg->fnIdx );
    549 }
    550 
    551 /* Collect up the start addresses of segments whose kind matches one of
    552    the kinds specified in kind_mask.
    553    The interface is a bit strange in order to avoid potential
    554    segment-creation races caused by dynamic allocation of the result
    555    buffer *starts.
    556 
    557    The function first computes how many entries in the result
    558    buffer *starts will be needed.  If this number <= nStarts,
    559    they are placed in starts[0..], and the number is returned.
    560    If nStarts is not large enough, nothing is written to
    561    starts[0..], and the negation of the size is returned.
    562 
    563    Correct use of this function may mean calling it multiple times in
    564    order to establish a suitably-sized buffer. */
    565 
    566 Int VG_(am_get_segment_starts)( UInt kind_mask, Addr* starts, Int nStarts )
    567 {
    568    Int i, j, nSegs;
    569 
    570    /* don't pass dumbass arguments */
    571    aspacem_assert(nStarts > 0);
    572 
    573    nSegs = 0;
    574    for (i = 0; i < nsegments_used; i++) {
    575       if ((nsegments[i].kind & kind_mask) != 0)
    576          nSegs++;
    577    }
    578 
    579    if (nSegs > nStarts) {
    580       /* The buffer isn't big enough.  Tell the caller how big it needs
    581          to be. */
    582       return -nSegs;
    583    }
    584 
    585    /* There's enough space.  So write into the result buffer. */
    586    aspacem_assert(nSegs <= nStarts);
    587 
    588    j = 0;
    589    for (i = 0; i < nsegments_used; i++) {
    590       if ((nsegments[i].kind & kind_mask) != 0)
    591          starts[j++] = nsegments[i].start;
    592    }
    593 
    594    aspacem_assert(j == nSegs); /* this should not fail */
    595    return nSegs;
    596 }
    597 
    598 
    599 /*-----------------------------------------------------------------*/
    600 /*---                                                           ---*/
    601 /*--- Sanity checking and preening of the segment array.        ---*/
    602 /*---                                                           ---*/
    603 /*-----------------------------------------------------------------*/
    604 
    605 /* Check representational invariants for NSegments. */
    606 
    607 static Bool sane_NSegment ( const NSegment* s )
    608 {
    609    if (s == NULL) return False;
    610 
    611    /* No zero sized segments and no wraparounds. */
    612    if (s->start > s->end) return False;
    613 
    614    /* require page alignment */
    615    if (!VG_IS_PAGE_ALIGNED(s->start)) return False;
    616    if (!VG_IS_PAGE_ALIGNED(s->end+1)) return False;
    617 
    618    switch (s->kind) {
    619 
    620       case SkFree:
    621          return
    622             s->smode == SmFixed
    623             && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
    624             && !s->hasR && !s->hasW && !s->hasX && !s->hasT
    625             && !s->isCH;
    626 
    627       case SkAnonC: case SkAnonV: case SkShmC:
    628          return
    629             s->smode == SmFixed
    630             && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
    631             && (s->kind==SkAnonC ? True : !s->isCH);
    632 
    633       case SkFileC: case SkFileV:
    634          return
    635             s->smode == SmFixed
    636             && ML_(am_sane_segname)(s->fnIdx)
    637             && !s->isCH;
    638 
    639       case SkResvn:
    640          return
    641             s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
    642             && !s->hasR && !s->hasW && !s->hasX && !s->hasT
    643             && !s->isCH;
    644 
    645       default:
    646          return False;
    647    }
    648 }
    649 
    650 
    651 /* Try merging s2 into s1, if possible.  If successful, s1 is
    652    modified, and True is returned.  Otherwise s1 is unchanged and
    653    False is returned. */
    654 
    655 static Bool maybe_merge_nsegments ( NSegment* s1, const NSegment* s2 )
    656 {
    657    if (s1->kind != s2->kind)
    658       return False;
    659 
    660    if (s1->end+1 != s2->start)
    661       return False;
    662 
    663    /* reject cases which would cause wraparound */
    664    if (s1->start > s2->end)
    665       return False;
    666 
    667    switch (s1->kind) {
    668 
    669       case SkFree:
    670          s1->end = s2->end;
    671          return True;
    672 
    673       case SkAnonC: case SkAnonV:
    674          if (s1->hasR == s2->hasR && s1->hasW == s2->hasW
    675              && s1->hasX == s2->hasX && s1->isCH == s2->isCH) {
    676             s1->end = s2->end;
    677             s1->hasT |= s2->hasT;
    678             return True;
    679          }
    680          break;
    681 
    682       case SkFileC: case SkFileV:
    683          if (s1->hasR == s2->hasR
    684              && s1->hasW == s2->hasW && s1->hasX == s2->hasX
    685              && s1->dev == s2->dev && s1->ino == s2->ino
    686              && s2->offset == s1->offset
    687                               + ((ULong)s2->start) - ((ULong)s1->start) ) {
    688             s1->end = s2->end;
    689             s1->hasT |= s2->hasT;
    690             ML_(am_dec_refcount)(s1->fnIdx);
    691             return True;
    692          }
    693          break;
    694 
    695       case SkShmC:
    696          return False;
    697 
    698       case SkResvn:
    699          if (s1->smode == SmFixed && s2->smode == SmFixed) {
    700             s1->end = s2->end;
    701             return True;
    702          }
    703 
    704       default:
    705          break;
    706 
    707    }
    708 
    709    return False;
    710 }
    711 
    712 
    713 /* Sanity-check and canonicalise the segment array (merge mergable
    714    segments).  Returns True if any segments were merged. */
    715 
    716 static Bool preen_nsegments ( void )
    717 {
    718    Int i, r, w, nsegments_used_old = nsegments_used;
    719 
    720    /* Pass 1: check the segment array covers the entire address space
    721       exactly once, and also that each segment is sane. */
    722    aspacem_assert(nsegments_used > 0);
    723    aspacem_assert(nsegments[0].start == Addr_MIN);
    724    aspacem_assert(nsegments[nsegments_used-1].end == Addr_MAX);
    725 
    726    aspacem_assert(sane_NSegment(&nsegments[0]));
    727    for (i = 1; i < nsegments_used; i++) {
    728       aspacem_assert(sane_NSegment(&nsegments[i]));
    729       aspacem_assert(nsegments[i-1].end+1 == nsegments[i].start);
    730    }
    731 
    732    /* Pass 2: merge as much as possible, using
    733       maybe_merge_segments. */
    734    w = 0;
    735    for (r = 1; r < nsegments_used; r++) {
    736       if (maybe_merge_nsegments(&nsegments[w], &nsegments[r])) {
    737          /* nothing */
    738       } else {
    739          w++;
    740          if (w != r)
    741             nsegments[w] = nsegments[r];
    742       }
    743    }
    744    w++;
    745    aspacem_assert(w > 0 && w <= nsegments_used);
    746    nsegments_used = w;
    747 
    748    return nsegments_used != nsegments_used_old;
    749 }
    750 
    751 
    752 /* Check the segment array corresponds with the kernel's view of
    753    memory layout.  sync_check_ok returns True if no anomalies were
    754    found, else False.  In the latter case the mismatching segments are
    755    displayed.
    756 
    757    The general idea is: we get the kernel to show us all its segments
    758    and also the gaps in between.  For each such interval, try and find
    759    a sequence of appropriate intervals in our segment array which
    760    cover or more than cover the kernel's interval, and which all have
    761    suitable kinds/permissions etc.
    762 
    763    Although any specific kernel interval is not matched exactly to a
    764    valgrind interval or sequence thereof, eventually any disagreement
    765    on mapping boundaries will be detected.  This is because, if for
    766    example valgrind's intervals cover a greater range than the current
    767    kernel interval, it must be the case that a neighbouring free-space
    768    interval belonging to valgrind cannot cover the neighbouring
    769    free-space interval belonging to the kernel.  So the disagreement
    770    is detected.
    771 
    772    In other words, we examine each kernel interval in turn, and check
    773    we do not disagree over the range of that interval.  Because all of
    774    the address space is examined, any disagreements must eventually be
    775    detected.
    776 */
    777 
    778 static Bool sync_check_ok = False;
    779 
    780 static void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot,
    781                                           ULong dev, ULong ino, Off64T offset,
    782                                           const HChar* filename )
    783 {
    784    Int  iLo, iHi, i;
    785    Bool sloppyXcheck, sloppyRcheck;
    786 
    787    /* If a problem has already been detected, don't continue comparing
    788       segments, so as to avoid flooding the output with error
    789       messages. */
    790 #if !defined(VGO_darwin)
    791    /* GrP fixme not */
    792    if (!sync_check_ok)
    793       return;
    794 #endif
    795    if (len == 0)
    796       return;
    797 
    798    /* The kernel should not give us wraparounds. */
    799    aspacem_assert(addr <= addr + len - 1);
    800 
    801    iLo = find_nsegment_idx( addr );
    802    iHi = find_nsegment_idx( addr + len - 1 );
    803 
    804    /* These 5 should be guaranteed by find_nsegment_idx. */
    805    aspacem_assert(0 <= iLo && iLo < nsegments_used);
    806    aspacem_assert(0 <= iHi && iHi < nsegments_used);
    807    aspacem_assert(iLo <= iHi);
    808    aspacem_assert(nsegments[iLo].start <= addr );
    809    aspacem_assert(nsegments[iHi].end   >= addr + len - 1 );
    810 
    811    /* x86 doesn't differentiate 'x' and 'r' (at least, all except the
    812       most recent NX-bit enabled CPUs) and so recent kernels attempt
    813       to provide execute protection by placing all executable mappings
    814       low down in the address space and then reducing the size of the
    815       code segment to prevent code at higher addresses being executed.
    816 
    817       These kernels report which mappings are really executable in
    818       the /proc/self/maps output rather than mirroring what was asked
    819       for when each mapping was created. In order to cope with this we
    820       have a sloppyXcheck mode which we enable on x86 and s390 - in this
    821       mode we allow the kernel to report execute permission when we weren't
    822       expecting it but not vice versa. */
    823 #  if defined(VGA_x86) || defined (VGA_s390x)
    824    sloppyXcheck = True;
    825 #  else
    826    sloppyXcheck = False;
    827 #  endif
    828 
    829    /* Some kernels on s390 provide 'r' permission even when it was not
    830       explicitly requested. It seems that 'x' permission implies 'r'.
    831       This behaviour also occurs on OS X. */
    832 #  if defined(VGA_s390x) || defined(VGO_darwin)
    833    sloppyRcheck = True;
    834 #  else
    835    sloppyRcheck = False;
    836 #  endif
    837 
    838    /* NSegments iLo .. iHi inclusive should agree with the presented
    839       data. */
    840    for (i = iLo; i <= iHi; i++) {
    841 
    842       Bool same, cmp_offsets, cmp_devino;
    843       UInt seg_prot;
    844 
    845       /* compare the kernel's offering against ours. */
    846       same = nsegments[i].kind == SkAnonC
    847              || nsegments[i].kind == SkAnonV
    848              || nsegments[i].kind == SkFileC
    849              || nsegments[i].kind == SkFileV
    850              || nsegments[i].kind == SkShmC;
    851 
    852       seg_prot = 0;
    853       if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
    854       if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
    855       if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
    856 
    857       cmp_offsets
    858          = nsegments[i].kind == SkFileC || nsegments[i].kind == SkFileV;
    859 
    860       cmp_devino
    861          = nsegments[i].dev != 0 || nsegments[i].ino != 0;
    862 
    863       /* Consider other reasons to not compare dev/inode */
    864 #if defined(VGO_linux)
    865       /* bproc does some godawful hack on /dev/zero at process
    866          migration, which changes the name of it, and its dev & ino */
    867       if (filename && 0==VG_(strcmp)(filename, "/dev/zero (deleted)"))
    868          cmp_devino = False;
    869 
    870       /* hack apparently needed on MontaVista Linux */
    871       if (filename && VG_(strstr)(filename, "/.lib-ro/"))
    872          cmp_devino = False;
    873 #endif
    874 
    875 #if defined(VGO_darwin)
    876       // GrP fixme kernel info doesn't have dev/inode
    877       cmp_devino = False;
    878 
    879       // GrP fixme V and kernel don't agree on offsets
    880       cmp_offsets = False;
    881 #endif
    882 
    883       /* If we are doing sloppy execute permission checks then we
    884          allow segment to have X permission when we weren't expecting
    885          it (but not vice versa) so if the kernel reported execute
    886          permission then pretend that this segment has it regardless
    887          of what we were expecting. */
    888       if (sloppyXcheck && (prot & VKI_PROT_EXEC) != 0) {
    889          seg_prot |= VKI_PROT_EXEC;
    890       }
    891 
    892       if (sloppyRcheck && (prot & (VKI_PROT_EXEC | VKI_PROT_READ)) ==
    893           (VKI_PROT_EXEC | VKI_PROT_READ)) {
    894          seg_prot |= VKI_PROT_READ;
    895       }
    896 
    897       same = same
    898              && seg_prot == prot
    899              && (cmp_devino
    900                    ? (nsegments[i].dev == dev && nsegments[i].ino == ino)
    901                    : True)
    902              && (cmp_offsets
    903                    ? nsegments[i].start-nsegments[i].offset == addr-offset
    904                    : True);
    905       if (!same) {
    906          Addr start = addr;
    907          Addr end = start + len - 1;
    908          HChar len_buf[20];
    909          show_len_concisely(len_buf, start, end);
    910 
    911          sync_check_ok = False;
    912 
    913          VG_(debugLog)(
    914             0,"aspacem",
    915               "segment mismatch: V's seg 1st, kernel's 2nd:\n");
    916          show_nsegment_full( 0, i, &nsegments[i] );
    917          VG_(debugLog)(0,"aspacem",
    918             "...: .... %010lx-%010lx %s %c%c%c.. ....... "
    919             "d=0x%03llx i=%-7llu o=%-7lld (.) m=. %s\n",
    920             start, end, len_buf,
    921             prot & VKI_PROT_READ  ? 'r' : '-',
    922             prot & VKI_PROT_WRITE ? 'w' : '-',
    923             prot & VKI_PROT_EXEC  ? 'x' : '-',
    924             dev, ino, offset, filename ? filename : "(none)" );
    925 
    926          return;
    927       }
    928    }
    929 
    930    /* Looks harmless.  Keep going. */
    931    return;
    932 }
    933 
    934 static void sync_check_gap_callback ( Addr addr, SizeT len )
    935 {
    936    Int iLo, iHi, i;
    937 
    938    /* If a problem has already been detected, don't continue comparing
    939       segments, so as to avoid flooding the output with error
    940       messages. */
    941 #if !defined(VGO_darwin)
    942    /* GrP fixme not */
    943    if (!sync_check_ok)
    944       return;
    945 #endif
    946    if (len == 0)
    947       return;
    948 
    949    /* The kernel should not give us wraparounds. */
    950    aspacem_assert(addr <= addr + len - 1);
    951 
    952    iLo = find_nsegment_idx( addr );
    953    iHi = find_nsegment_idx( addr + len - 1 );
    954 
    955    /* These 5 should be guaranteed by find_nsegment_idx. */
    956    aspacem_assert(0 <= iLo && iLo < nsegments_used);
    957    aspacem_assert(0 <= iHi && iHi < nsegments_used);
    958    aspacem_assert(iLo <= iHi);
    959    aspacem_assert(nsegments[iLo].start <= addr );
    960    aspacem_assert(nsegments[iHi].end   >= addr + len - 1 );
    961 
    962    /* NSegments iLo .. iHi inclusive should agree with the presented
    963       data. */
    964    for (i = iLo; i <= iHi; i++) {
    965 
    966       Bool same;
    967 
    968       /* compare the kernel's offering against ours. */
    969       same = nsegments[i].kind == SkFree
    970              || nsegments[i].kind == SkResvn;
    971 
    972       if (!same) {
    973          Addr start = addr;
    974          Addr end = start + len - 1;
    975          HChar len_buf[20];
    976          show_len_concisely(len_buf, start, end);
    977 
    978          sync_check_ok = False;
    979 
    980          VG_(debugLog)(
    981             0,"aspacem",
    982               "segment mismatch: V's gap 1st, kernel's 2nd:\n");
    983          show_nsegment_full( 0, i, &nsegments[i] );
    984          VG_(debugLog)(0,"aspacem",
    985             "   : .... %010lx-%010lx %s\n",
    986             start, end, len_buf);
    987          return;
    988       }
    989    }
    990 
    991    /* Looks harmless.  Keep going. */
    992    return;
    993 }
    994 
    995 
    996 /* Sanity check: check that Valgrind and the kernel agree on the
    997    address space layout.  Prints offending segments and call point if
    998    a discrepancy is detected, but does not abort the system.  Returned
    999    Bool is False if a discrepancy was found. */
   1000 
   1001 Bool VG_(am_do_sync_check) ( const HChar* fn,
   1002                              const HChar* file, Int line )
   1003 {
   1004    sync_check_ok = True;
   1005    if (0)
   1006       VG_(debugLog)(0,"aspacem", "do_sync_check %s:%d\n", file,line);
   1007    parse_procselfmaps( sync_check_mapping_callback,
   1008                        sync_check_gap_callback );
   1009    if (!sync_check_ok) {
   1010       VG_(debugLog)(0,"aspacem",
   1011                       "sync check at %s:%d (%s): FAILED\n",
   1012                       file, line, fn);
   1013       VG_(debugLog)(0,"aspacem", "\n");
   1014 
   1015 #     if 0
   1016       {
   1017          HChar buf[100];   // large enough
   1018          VG_(am_show_nsegments)(0,"post syncheck failure");
   1019          VG_(sprintf)(buf, "/bin/cat /proc/%d/maps", VG_(getpid)());
   1020          VG_(system)(buf);
   1021       }
   1022 #     endif
   1023 
   1024    }
   1025    return sync_check_ok;
   1026 }
   1027 
   1028 /* Hook to allow sanity checks to be done from aspacemgr-common.c. */
   1029 void ML_(am_do_sanity_check)( void )
   1030 {
   1031    AM_SANITY_CHECK;
   1032 }
   1033 
   1034 
   1035 /*-----------------------------------------------------------------*/
   1036 /*---                                                           ---*/
   1037 /*--- Low level access / modification of the segment array.     ---*/
   1038 /*---                                                           ---*/
   1039 /*-----------------------------------------------------------------*/
   1040 
   1041 /* Binary search the interval array for a given address.  Since the
   1042    array covers the entire address space the search cannot fail.  The
   1043    _WRK function does the real work.  Its caller (just below) caches
   1044    the results thereof, to save time.  With N_CACHE of 63 we get a hit
   1045    rate exceeding 90% when running OpenOffice.
   1046 
   1047    Re ">> 12", it doesn't matter that the page size of some targets
   1048    might be different from 12.  Really "(a >> 12) % N_CACHE" is merely
   1049    a hash function, and the actual cache entry is always validated
   1050    correctly against the selected cache entry before use.
   1051 */
   1052 /* Don't call find_nsegment_idx_WRK; use find_nsegment_idx instead. */
   1053 __attribute__((noinline))
   1054 static Int find_nsegment_idx_WRK ( Addr a )
   1055 {
   1056    Addr a_mid_lo, a_mid_hi;
   1057    Int  mid,
   1058         lo = 0,
   1059         hi = nsegments_used-1;
   1060    while (True) {
   1061       /* current unsearched space is from lo to hi, inclusive. */
   1062       if (lo > hi) {
   1063          /* Not found.  This can't happen. */
   1064          ML_(am_barf)("find_nsegment_idx: not found");
   1065       }
   1066       mid      = (lo + hi) / 2;
   1067       a_mid_lo = nsegments[mid].start;
   1068       a_mid_hi = nsegments[mid].end;
   1069 
   1070       if (a < a_mid_lo) { hi = mid-1; continue; }
   1071       if (a > a_mid_hi) { lo = mid+1; continue; }
   1072       aspacem_assert(a >= a_mid_lo && a <= a_mid_hi);
   1073       aspacem_assert(0 <= mid && mid < nsegments_used);
   1074       return mid;
   1075    }
   1076 }
   1077 
   1078 inline static Int find_nsegment_idx ( Addr a )
   1079 {
   1080 #  define N_CACHE 131 /*prime*/
   1081    static Addr cache_pageno[N_CACHE];
   1082    static Int  cache_segidx[N_CACHE];
   1083    static Bool cache_inited = False;
   1084 
   1085    static UWord n_q = 0;
   1086    static UWord n_m = 0;
   1087 
   1088    UWord ix;
   1089 
   1090    if (LIKELY(cache_inited)) {
   1091       /* do nothing */
   1092    } else {
   1093       for (ix = 0; ix < N_CACHE; ix++) {
   1094          cache_pageno[ix] = 0;
   1095          cache_segidx[ix] = -1;
   1096       }
   1097       cache_inited = True;
   1098    }
   1099 
   1100    ix = (a >> 12) % N_CACHE;
   1101 
   1102    n_q++;
   1103    if (0 && 0 == (n_q & 0xFFFF))
   1104       VG_(debugLog)(0,"xxx","find_nsegment_idx: %lu %lu\n", n_q, n_m);
   1105 
   1106    if ((a >> 12) == cache_pageno[ix]
   1107        && cache_segidx[ix] >= 0
   1108        && cache_segidx[ix] < nsegments_used
   1109        && nsegments[cache_segidx[ix]].start <= a
   1110        && a <= nsegments[cache_segidx[ix]].end) {
   1111       /* hit */
   1112       /* aspacem_assert( cache_segidx[ix] == find_nsegment_idx_WRK(a) ); */
   1113       return cache_segidx[ix];
   1114    }
   1115    /* miss */
   1116    n_m++;
   1117    cache_segidx[ix] = find_nsegment_idx_WRK(a);
   1118    cache_pageno[ix] = a >> 12;
   1119    return cache_segidx[ix];
   1120 #  undef N_CACHE
   1121 }
   1122 
   1123 
   1124 /* Finds the segment containing 'a'.  Only returns non-SkFree segments. */
   1125 NSegment const * VG_(am_find_nsegment) ( Addr a )
   1126 {
   1127    Int i = find_nsegment_idx(a);
   1128    aspacem_assert(i >= 0 && i < nsegments_used);
   1129    aspacem_assert(nsegments[i].start <= a);
   1130    aspacem_assert(a <= nsegments[i].end);
   1131    if (nsegments[i].kind == SkFree)
   1132       return NULL;
   1133    else
   1134       return &nsegments[i];
   1135 }
   1136 
   1137 /* Finds an anonymous segment containing 'a'. Returned pointer is read only. */
   1138 NSegment const *VG_(am_find_anon_segment) ( Addr a )
   1139 {
   1140    Int i = find_nsegment_idx(a);
   1141    aspacem_assert(i >= 0 && i < nsegments_used);
   1142    aspacem_assert(nsegments[i].start <= a);
   1143    aspacem_assert(a <= nsegments[i].end);
   1144    if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV)
   1145       return &nsegments[i];
   1146    else
   1147       return NULL;
   1148 }
   1149 
   1150 /* Map segment pointer to segment index. */
   1151 static Int segAddr_to_index ( const NSegment* seg )
   1152 {
   1153    aspacem_assert(seg >= &nsegments[0] && seg < &nsegments[nsegments_used]);
   1154 
   1155    return seg - &nsegments[0];
   1156 }
   1157 
   1158 
   1159 /* Find the next segment along from 'here', if it is a non-SkFree segment. */
   1160 NSegment const * VG_(am_next_nsegment) ( const NSegment* here, Bool fwds )
   1161 {
   1162    Int i = segAddr_to_index(here);
   1163 
   1164    if (fwds) {
   1165       i++;
   1166       if (i >= nsegments_used)
   1167          return NULL;
   1168    } else {
   1169       i--;
   1170       if (i < 0)
   1171          return NULL;
   1172    }
   1173    if (nsegments[i].kind == SkFree)
   1174       return NULL;
   1175    else
   1176       return &nsegments[i];
   1177 }
   1178 
   1179 
   1180 /* Trivial fn: return the total amount of space in anonymous mappings,
   1181    both for V and the client.  Is used for printing stats in
   1182    out-of-memory messages. */
   1183 ULong VG_(am_get_anonsize_total)( void )
   1184 {
   1185    Int   i;
   1186    ULong total = 0;
   1187    for (i = 0; i < nsegments_used; i++) {
   1188       if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV) {
   1189          total += (ULong)nsegments[i].end
   1190                   - (ULong)nsegments[i].start + 1ULL;
   1191       }
   1192    }
   1193    return total;
   1194 }
   1195 
   1196 
   1197 /* Test if a piece of memory is addressable by client or by valgrind with at
   1198    least the "prot" protection permissions by examining the underlying
   1199    segments. The KINDS argument specifies the allowed segments ADDR may
   1200    belong to in order to be considered "valid".
   1201 */
   1202 static
   1203 Bool is_valid_for( UInt kinds, Addr start, SizeT len, UInt prot )
   1204 {
   1205    Int  i, iLo, iHi;
   1206    Bool needR, needW, needX;
   1207 
   1208    if (len == 0)
   1209       return True; /* somewhat dubious case */
   1210    if (start + len < start)
   1211       return False; /* reject wraparounds */
   1212 
   1213    needR = toBool(prot & VKI_PROT_READ);
   1214    needW = toBool(prot & VKI_PROT_WRITE);
   1215    needX = toBool(prot & VKI_PROT_EXEC);
   1216 
   1217    iLo = find_nsegment_idx(start);
   1218    aspacem_assert(start >= nsegments[iLo].start);
   1219 
   1220    if (start+len-1 <= nsegments[iLo].end) {
   1221       /* This is a speedup hack which avoids calling find_nsegment_idx
   1222          a second time when possible.  It is always correct to just
   1223          use the "else" clause below, but is_valid_for_client is
   1224          called a lot by the leak checker, so avoiding pointless calls
   1225          to find_nsegment_idx, which can be expensive, is helpful. */
   1226       iHi = iLo;
   1227    } else {
   1228       iHi = find_nsegment_idx(start + len - 1);
   1229    }
   1230 
   1231    for (i = iLo; i <= iHi; i++) {
   1232       if ( (nsegments[i].kind & kinds) != 0
   1233            && (needR ? nsegments[i].hasR : True)
   1234            && (needW ? nsegments[i].hasW : True)
   1235            && (needX ? nsegments[i].hasX : True) ) {
   1236          /* ok */
   1237       } else {
   1238          return False;
   1239       }
   1240    }
   1241 
   1242    return True;
   1243 }
   1244 
   1245 /* Test if a piece of memory is addressable by the client with at
   1246    least the "prot" protection permissions by examining the underlying
   1247    segments. */
   1248 Bool VG_(am_is_valid_for_client)( Addr start, SizeT len,
   1249                                   UInt prot )
   1250 {
   1251    const UInt kinds = SkFileC | SkAnonC | SkShmC;
   1252 
   1253    return is_valid_for(kinds, start, len, prot);
   1254 }
   1255 
   1256 /* Variant of VG_(am_is_valid_for_client) which allows free areas to
   1257    be consider part of the client's addressable space.  It also
   1258    considers reservations to be allowable, since from the client's
   1259    point of view they don't exist. */
   1260 Bool VG_(am_is_valid_for_client_or_free_or_resvn)
   1261    ( Addr start, SizeT len, UInt prot )
   1262 {
   1263    const UInt kinds = SkFileC | SkAnonC | SkShmC | SkFree | SkResvn;
   1264 
   1265    return is_valid_for(kinds, start, len, prot);
   1266 }
   1267 
   1268 /* Checks if a piece of memory consists of either free or reservation
   1269    segments. */
   1270 Bool VG_(am_is_free_or_resvn)( Addr start, SizeT len )
   1271 {
   1272    const UInt kinds = SkFree | SkResvn;
   1273 
   1274    return is_valid_for(kinds, start, len, 0);
   1275 }
   1276 
   1277 
   1278 Bool VG_(am_is_valid_for_valgrind) ( Addr start, SizeT len, UInt prot )
   1279 {
   1280    const UInt kinds = SkFileV | SkAnonV;
   1281 
   1282    return is_valid_for(kinds, start, len, prot);
   1283 }
   1284 
   1285 
   1286 /* Returns True if any part of the address range is marked as having
   1287    translations made from it.  This is used to determine when to
   1288    discard code, so if in doubt return True. */
   1289 
   1290 static Bool any_Ts_in_range ( Addr start, SizeT len )
   1291 {
   1292    Int iLo, iHi, i;
   1293    aspacem_assert(len > 0);
   1294    aspacem_assert(start + len > start);
   1295    iLo = find_nsegment_idx(start);
   1296    iHi = find_nsegment_idx(start + len - 1);
   1297    for (i = iLo; i <= iHi; i++) {
   1298       if (nsegments[i].hasT)
   1299          return True;
   1300    }
   1301    return False;
   1302 }
   1303 
   1304 
   1305 /* Check whether ADDR looks like an address or address-to-be located in an
   1306    extensible client stack segment. Return true if
   1307    (1) ADDR is located in an already mapped stack segment, OR
   1308    (2) ADDR is located in a reservation segment into which an abutting SkAnonC
   1309        segment can be extended. */
   1310 Bool VG_(am_addr_is_in_extensible_client_stack)( Addr addr )
   1311 {
   1312    const NSegment *seg = nsegments + find_nsegment_idx(addr);
   1313 
   1314    switch (seg->kind) {
   1315    case SkFree:
   1316    case SkAnonV:
   1317    case SkFileV:
   1318    case SkFileC:
   1319    case SkShmC:
   1320       return False;
   1321 
   1322    case SkResvn: {
   1323       if (seg->smode != SmUpper) return False;
   1324       /* If the abutting segment towards higher addresses is an SkAnonC
   1325          segment, then ADDR is a future stack pointer. */
   1326       const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ True);
   1327       if (next == NULL || next->kind != SkAnonC) return False;
   1328 
   1329       /* OK; looks like a stack segment */
   1330       return True;
   1331    }
   1332 
   1333    case SkAnonC: {
   1334       /* If the abutting segment towards lower addresses is an SkResvn
   1335          segment, then ADDR is a stack pointer into mapped memory. */
   1336       const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ False);
   1337       if (next == NULL || next->kind != SkResvn || next->smode != SmUpper)
   1338          return False;
   1339 
   1340       /* OK; looks like a stack segment */
   1341       return True;
   1342    }
   1343 
   1344    default:
   1345       aspacem_assert(0);   // should never happen
   1346    }
   1347 }
   1348 
   1349 /*-----------------------------------------------------------------*/
   1350 /*---                                                           ---*/
   1351 /*--- Modifying the segment array, and constructing segments.   ---*/
   1352 /*---                                                           ---*/
   1353 /*-----------------------------------------------------------------*/
   1354 
   1355 /* Split the segment containing 'a' into two, so that 'a' is
   1356    guaranteed to be the start of a new segment.  If 'a' is already the
   1357    start of a segment, do nothing. */
   1358 
   1359 static void split_nsegment_at ( Addr a )
   1360 {
   1361    Int i, j;
   1362 
   1363    aspacem_assert(a > 0);
   1364    aspacem_assert(VG_IS_PAGE_ALIGNED(a));
   1365 
   1366    i = find_nsegment_idx(a);
   1367    aspacem_assert(i >= 0 && i < nsegments_used);
   1368 
   1369    if (nsegments[i].start == a)
   1370       /* 'a' is already the start point of a segment, so nothing to be
   1371          done. */
   1372       return;
   1373 
   1374    /* else we have to slide the segments upwards to make a hole */
   1375    if (nsegments_used >= VG_N_SEGMENTS)
   1376       ML_(am_barf_toolow)("VG_N_SEGMENTS");
   1377    for (j = nsegments_used-1; j > i; j--)
   1378       nsegments[j+1] = nsegments[j];
   1379    nsegments_used++;
   1380 
   1381    nsegments[i+1]       = nsegments[i];
   1382    nsegments[i+1].start = a;
   1383    nsegments[i].end     = a-1;
   1384 
   1385    if (nsegments[i].kind == SkFileV || nsegments[i].kind == SkFileC)
   1386       nsegments[i+1].offset
   1387          += ((ULong)nsegments[i+1].start) - ((ULong)nsegments[i].start);
   1388 
   1389    ML_(am_inc_refcount)(nsegments[i].fnIdx);
   1390 
   1391    aspacem_assert(sane_NSegment(&nsegments[i]));
   1392    aspacem_assert(sane_NSegment(&nsegments[i+1]));
   1393 }
   1394 
   1395 
   1396 /* Do the minimum amount of segment splitting necessary to ensure that
   1397    sLo is the first address denoted by some segment and sHi is the
   1398    highest address denoted by some other segment.  Returns the indices
   1399    of the lowest and highest segments in the range. */
   1400 
   1401 static
   1402 void split_nsegments_lo_and_hi ( Addr sLo, Addr sHi,
   1403                                  /*OUT*/Int* iLo,
   1404                                  /*OUT*/Int* iHi )
   1405 {
   1406    aspacem_assert(sLo < sHi);
   1407    aspacem_assert(VG_IS_PAGE_ALIGNED(sLo));
   1408    aspacem_assert(VG_IS_PAGE_ALIGNED(sHi+1));
   1409 
   1410    if (sLo > 0)
   1411       split_nsegment_at(sLo);
   1412    if (sHi < sHi+1)
   1413       split_nsegment_at(sHi+1);
   1414 
   1415    *iLo = find_nsegment_idx(sLo);
   1416    *iHi = find_nsegment_idx(sHi);
   1417    aspacem_assert(0 <= *iLo && *iLo < nsegments_used);
   1418    aspacem_assert(0 <= *iHi && *iHi < nsegments_used);
   1419    aspacem_assert(*iLo <= *iHi);
   1420    aspacem_assert(nsegments[*iLo].start == sLo);
   1421    aspacem_assert(nsegments[*iHi].end == sHi);
   1422    /* Not that I'm overly paranoid or anything, definitely not :-) */
   1423 }
   1424 
   1425 
   1426 /* Add SEG to the collection, deleting/truncating any it overlaps.
   1427    This deals with all the tricky cases of splitting up segments as
   1428    needed. */
   1429 
   1430 static void add_segment ( const NSegment* seg )
   1431 {
   1432    Int  i, iLo, iHi, delta;
   1433    Bool segment_is_sane;
   1434 
   1435    Addr sStart = seg->start;
   1436    Addr sEnd   = seg->end;
   1437 
   1438    aspacem_assert(sStart <= sEnd);
   1439    aspacem_assert(VG_IS_PAGE_ALIGNED(sStart));
   1440    aspacem_assert(VG_IS_PAGE_ALIGNED(sEnd+1));
   1441 
   1442    segment_is_sane = sane_NSegment(seg);
   1443    if (!segment_is_sane) show_nsegment_full(0,-1,seg);
   1444    aspacem_assert(segment_is_sane);
   1445 
   1446    split_nsegments_lo_and_hi( sStart, sEnd, &iLo, &iHi );
   1447 
   1448    /* Now iLo .. iHi inclusive is the range of segment indices which
   1449       seg will replace.  If we're replacing more than one segment,
   1450       slide those above the range down to fill the hole. Before doing
   1451       that decrement the reference counters for the segments names of
   1452       the replaced segments. */
   1453    for (i = iLo; i <= iHi; ++i)
   1454       ML_(am_dec_refcount)(nsegments[i].fnIdx);
   1455    delta = iHi - iLo;
   1456    aspacem_assert(delta >= 0);
   1457    if (delta > 0) {
   1458       for (i = iLo; i < nsegments_used-delta; i++)
   1459          nsegments[i] = nsegments[i+delta];
   1460       nsegments_used -= delta;
   1461    }
   1462 
   1463    nsegments[iLo] = *seg;
   1464 
   1465    (void)preen_nsegments();
   1466    if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)");
   1467 }
   1468 
   1469 
   1470 /* Clear out an NSegment record. */
   1471 
   1472 static void init_nsegment ( /*OUT*/NSegment* seg )
   1473 {
   1474    seg->kind     = SkFree;
   1475    seg->start    = 0;
   1476    seg->end      = 0;
   1477    seg->smode    = SmFixed;
   1478    seg->dev      = 0;
   1479    seg->ino      = 0;
   1480    seg->mode     = 0;
   1481    seg->offset   = 0;
   1482    seg->fnIdx    = -1;
   1483    seg->hasR = seg->hasW = seg->hasX = seg->hasT = seg->isCH = False;
   1484 }
   1485 
   1486 /* Make an NSegment which holds a reservation. */
   1487 
   1488 static void init_resvn ( /*OUT*/NSegment* seg, Addr start, Addr end )
   1489 {
   1490    aspacem_assert(start < end);
   1491    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
   1492    aspacem_assert(VG_IS_PAGE_ALIGNED(end+1));
   1493    init_nsegment(seg);
   1494    seg->kind  = SkResvn;
   1495    seg->start = start;
   1496    seg->end   = end;
   1497 }
   1498 
   1499 
   1500 /*-----------------------------------------------------------------*/
   1501 /*---                                                           ---*/
   1502 /*--- Startup, including reading /proc/self/maps.               ---*/
   1503 /*---                                                           ---*/
   1504 /*-----------------------------------------------------------------*/
   1505 
   1506 static void read_maps_callback ( Addr addr, SizeT len, UInt prot,
   1507                                  ULong dev, ULong ino, Off64T offset,
   1508                                  const HChar* filename )
   1509 {
   1510    NSegment seg;
   1511    init_nsegment( &seg );
   1512    seg.start  = addr;
   1513    seg.end    = addr+len-1;
   1514    seg.dev    = dev;
   1515    seg.ino    = ino;
   1516    seg.offset = offset;
   1517    seg.hasR   = toBool(prot & VKI_PROT_READ);
   1518    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
   1519    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
   1520    seg.hasT   = False;
   1521 
   1522    /* A segment in the initial /proc/self/maps is considered a FileV
   1523       segment if either it has a file name associated with it or both its
   1524       device and inode numbers are != 0. See bug #124528. */
   1525    seg.kind = SkAnonV;
   1526    if (filename || (dev != 0 && ino != 0))
   1527       seg.kind = SkFileV;
   1528 
   1529 #  if defined(VGO_darwin)
   1530    // GrP fixme no dev/ino on darwin
   1531    if (offset != 0)
   1532       seg.kind = SkFileV;
   1533 #  endif // defined(VGO_darwin)
   1534 
   1535 #  if defined(VGP_arm_linux)
   1536    /* The standard handling of entries read from /proc/self/maps will
   1537       cause the faked up commpage segment to have type SkAnonV, which
   1538       is a problem because it contains code we want the client to
   1539       execute, and so later m_translate will segfault the client when
   1540       it tries to go in there.  Hence change the ownership of it here
   1541       to the client (SkAnonC).  The least-worst kludge I could think
   1542       of. */
   1543    if (addr == ARM_LINUX_FAKE_COMMPAGE_START
   1544        && addr + len == ARM_LINUX_FAKE_COMMPAGE_END1
   1545        && seg.kind == SkAnonV)
   1546       seg.kind = SkAnonC;
   1547 #  endif // defined(VGP_arm_linux)
   1548 
   1549    if (filename)
   1550       seg.fnIdx = ML_(am_allocate_segname)( filename );
   1551 
   1552    if (0) show_nsegment( 2,0, &seg );
   1553    add_segment( &seg );
   1554 }
   1555 
   1556 Bool
   1557 VG_(am_is_valid_for_aspacem_minAddr)( Addr addr, const HChar **errmsg )
   1558 {
   1559    const Addr min = VKI_PAGE_SIZE;
   1560 #if VG_WORDSIZE == 4
   1561    const Addr max = 0x40000000;  // 1Gb
   1562 #else
   1563    const Addr max = 0x200000000; // 8Gb
   1564 #endif
   1565    Bool ok = VG_IS_PAGE_ALIGNED(addr) && addr >= min && addr <= max;
   1566 
   1567    if (errmsg) {
   1568       *errmsg = "";
   1569       if (! ok) {
   1570          const HChar fmt[] = "Must be a page aligned address between "
   1571                              "0x%lx and 0x%lx";
   1572          static HChar buf[sizeof fmt + 2 * 16];   // large enough
   1573          ML_(am_sprintf)(buf, fmt, min, max);
   1574          *errmsg = buf;
   1575       }
   1576    }
   1577    return ok;
   1578 }
   1579 
   1580 /* See description in pub_core_aspacemgr.h */
   1581 Addr VG_(am_startup) ( Addr sp_at_startup )
   1582 {
   1583    NSegment seg;
   1584    Addr     suggested_clstack_end;
   1585 
   1586    aspacem_assert(sizeof(Word)   == sizeof(void*));
   1587    aspacem_assert(sizeof(Addr)   == sizeof(void*));
   1588    aspacem_assert(sizeof(SizeT)  == sizeof(void*));
   1589    aspacem_assert(sizeof(SSizeT) == sizeof(void*));
   1590 
   1591    /* Initialise the string table for segment names. */
   1592    ML_(am_segnames_init)();
   1593 
   1594    /* Check that we can store the largest imaginable dev, ino and
   1595       offset numbers in an NSegment. */
   1596    aspacem_assert(sizeof(seg.dev)    == 8);
   1597    aspacem_assert(sizeof(seg.ino)    == 8);
   1598    aspacem_assert(sizeof(seg.offset) == 8);
   1599    aspacem_assert(sizeof(seg.mode)   == 4);
   1600 
   1601    /* Add a single interval covering the entire address space. */
   1602    init_nsegment(&seg);
   1603    seg.kind        = SkFree;
   1604    seg.start       = Addr_MIN;
   1605    seg.end         = Addr_MAX;
   1606    nsegments[0]    = seg;
   1607    nsegments_used  = 1;
   1608 
   1609    aspacem_minAddr = VG_(clo_aspacem_minAddr);
   1610 
   1611 #if defined(VGO_darwin)
   1612 
   1613 # if VG_WORDSIZE == 4
   1614    aspacem_maxAddr = (Addr) 0xffffffff;
   1615 
   1616    aspacem_cStart = aspacem_minAddr;
   1617    aspacem_vStart = 0xf0000000;  // 0xc0000000..0xf0000000 available
   1618 # else
   1619    aspacem_maxAddr = (Addr) 0x7fffffffffff;
   1620 
   1621    aspacem_cStart = aspacem_minAddr;
   1622    aspacem_vStart = 0x700000000000; // 0x7000:00000000..0x7fff:5c000000 avail
   1623    // 0x7fff:5c000000..0x7fff:ffe00000? is stack, dyld, shared cache
   1624 # endif
   1625 
   1626    suggested_clstack_end = -1; // ignored; Mach-O specifies its stack
   1627 
   1628 #elif defined(VGO_solaris)
   1629 #  if VG_WORDSIZE == 4
   1630    /*
   1631       Intended address space partitioning:
   1632 
   1633       ,--------------------------------, 0x00000000
   1634       |                                |
   1635       |--------------------------------|
   1636       | initial stack given to V by OS |
   1637       |--------------------------------| 0x08000000
   1638       |          client text           |
   1639       |--------------------------------|
   1640       |                                |
   1641       |                                |
   1642       |--------------------------------|
   1643       |          client stack          |
   1644       |--------------------------------| 0x38000000
   1645       |            V's text            |
   1646       |--------------------------------|
   1647       |                                |
   1648       |                                |
   1649       |--------------------------------|
   1650       |     dynamic shared objects     |
   1651       '--------------------------------' 0xffffffff
   1652 
   1653       */
   1654 
   1655    /* Anonymous pages need to fit under user limit (USERLIMIT32)
   1656       which is 4KB + 16MB below the top of the 32-bit range. */
   1657 #    ifdef ENABLE_INNER
   1658      aspacem_maxAddr = (Addr)0x4fffffff; // 1.25GB
   1659      aspacem_vStart  = (Addr)0x40000000; // 1GB
   1660 #    else
   1661      aspacem_maxAddr = (Addr)0xfefff000 - 1; // 4GB - 16MB - 4KB
   1662      aspacem_vStart  = (Addr)0x50000000; // 1.25GB
   1663 #    endif
   1664 #  elif VG_WORDSIZE == 8
   1665    /*
   1666       Intended address space partitioning:
   1667 
   1668       ,--------------------------------, 0x00000000_00000000
   1669       |                                |
   1670       |--------------------------------| 0x00000000_00400000
   1671       |          client text           |
   1672       |--------------------------------|
   1673       |                                |
   1674       |                                |
   1675       |--------------------------------|
   1676       |          client stack          |
   1677       |--------------------------------| 0x00000000_38000000
   1678       |            V's text            |
   1679       |--------------------------------|
   1680       |                                |
   1681       |--------------------------------|
   1682       |     dynamic shared objects     |
   1683       |--------------------------------| 0x0000000f_ffffffff
   1684       |                                |
   1685       |                                |
   1686       |--------------------------------|
   1687       | initial stack given to V by OS |
   1688       '--------------------------------' 0xffffffff_ffffffff
   1689 
   1690       */
   1691 
   1692    /* Kernel likes to place objects at the end of the address space.
   1693       However accessing memory beyond 64GB makes memcheck slow
   1694       (see memcheck/mc_main.c, internal representation). Therefore:
   1695       - mmapobj() syscall is emulated so that libraries are subject to
   1696         Valgrind's aspacemgr control
   1697       - Kernel shared pages (such as schedctl and hrt) are left as they are
   1698         because kernel cannot be told where they should be put */
   1699 #    ifdef ENABLE_INNER
   1700      aspacem_maxAddr = (Addr) 0x00000007ffffffff; // 32GB
   1701      aspacem_vStart  = (Addr) 0x0000000400000000; // 16GB
   1702 #    else
   1703      aspacem_maxAddr = (Addr) 0x0000000fffffffff; // 64GB
   1704      aspacem_vStart  = (Addr) 0x0000000800000000; // 32GB
   1705 #    endif
   1706 #  else
   1707 #    error "Unknown word size"
   1708 #  endif
   1709 
   1710    aspacem_cStart = aspacem_minAddr;
   1711 #  ifdef ENABLE_INNER
   1712    suggested_clstack_end = (Addr) 0x27ff0000 - 1; // 64kB below V's text
   1713 #  else
   1714    suggested_clstack_end = (Addr) 0x37ff0000 - 1; // 64kB below V's text
   1715 #  endif
   1716 
   1717 #else
   1718 
   1719    /* Establish address limits and block out unusable parts
   1720       accordingly. */
   1721 
   1722    VG_(debugLog)(2, "aspacem",
   1723                     "        sp_at_startup = 0x%010lx (supplied)\n",
   1724                     sp_at_startup );
   1725 
   1726 #  if VG_WORDSIZE == 8
   1727      aspacem_maxAddr = (Addr)0x1000000000ULL - 1; // 64G
   1728 #    ifdef ENABLE_INNER
   1729      { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1;
   1730        if (aspacem_maxAddr > cse)
   1731           aspacem_maxAddr = cse;
   1732      }
   1733 #    endif
   1734 #  else
   1735      aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1;
   1736 #  endif
   1737 
   1738    aspacem_cStart = aspacem_minAddr;
   1739    aspacem_vStart = VG_PGROUNDUP(aspacem_minAddr
   1740                                  + (aspacem_maxAddr - aspacem_minAddr + 1) / 2);
   1741 #  ifdef ENABLE_INNER
   1742    aspacem_vStart -= 0x10000000; // 256M
   1743 #  endif
   1744 
   1745    suggested_clstack_end = aspacem_maxAddr - 16*1024*1024ULL
   1746                                            + VKI_PAGE_SIZE;
   1747 
   1748 #endif
   1749 
   1750    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr));
   1751    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1));
   1752    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_cStart));
   1753    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_vStart));
   1754    aspacem_assert(VG_IS_PAGE_ALIGNED(suggested_clstack_end + 1));
   1755 
   1756    VG_(debugLog)(2, "aspacem",
   1757                     "              minAddr = 0x%010lx (computed)\n",
   1758                     aspacem_minAddr);
   1759    VG_(debugLog)(2, "aspacem",
   1760                     "              maxAddr = 0x%010lx (computed)\n",
   1761                     aspacem_maxAddr);
   1762    VG_(debugLog)(2, "aspacem",
   1763                     "               cStart = 0x%010lx (computed)\n",
   1764                     aspacem_cStart);
   1765    VG_(debugLog)(2, "aspacem",
   1766                     "               vStart = 0x%010lx (computed)\n",
   1767                     aspacem_vStart);
   1768    VG_(debugLog)(2, "aspacem",
   1769                     "suggested_clstack_end = 0x%010lx (computed)\n",
   1770                     suggested_clstack_end);
   1771 
   1772    if (aspacem_cStart > Addr_MIN) {
   1773       init_resvn(&seg, Addr_MIN, aspacem_cStart-1);
   1774       add_segment(&seg);
   1775    }
   1776    if (aspacem_maxAddr < Addr_MAX) {
   1777       init_resvn(&seg, aspacem_maxAddr+1, Addr_MAX);
   1778       add_segment(&seg);
   1779    }
   1780 
   1781    /* Create a 1-page reservation at the notional initial
   1782       client/valgrind boundary.  This isn't strictly necessary, but
   1783       because the advisor does first-fit and starts searches for
   1784       valgrind allocations at the boundary, this is kind of necessary
   1785       in order to get it to start allocating in the right place. */
   1786    init_resvn(&seg, aspacem_vStart,  aspacem_vStart + VKI_PAGE_SIZE - 1);
   1787    add_segment(&seg);
   1788 
   1789    VG_(am_show_nsegments)(2, "Initial layout");
   1790 
   1791    VG_(debugLog)(2, "aspacem", "Reading /proc/self/maps\n");
   1792    parse_procselfmaps( read_maps_callback, NULL );
   1793    /* NB: on arm-linux, parse_procselfmaps automagically kludges up
   1794       (iow, hands to its callbacks) a description of the ARM Commpage,
   1795       since that's not listed in /proc/self/maps (kernel bug IMO).  We
   1796       have to fake up its existence in parse_procselfmaps and not
   1797       merely add it here as an extra segment, because doing the latter
   1798       causes sync checking to fail: we see we have an extra segment in
   1799       the segments array, which isn't listed in /proc/self/maps.
   1800       Hence we must make it appear that /proc/self/maps contained this
   1801       segment all along.  Sigh. */
   1802 
   1803    VG_(am_show_nsegments)(2, "With contents of /proc/self/maps");
   1804 
   1805    AM_SANITY_CHECK;
   1806    return suggested_clstack_end;
   1807 }
   1808 
   1809 
   1810 /*-----------------------------------------------------------------*/
   1811 /*---                                                           ---*/
   1812 /*--- The core query-notify mechanism.                          ---*/
   1813 /*---                                                           ---*/
   1814 /*-----------------------------------------------------------------*/
   1815 
   1816 /* Query aspacem to ask where a mapping should go. */
   1817 
   1818 Addr VG_(am_get_advisory) ( const MapRequest*  req,
   1819                             Bool  forClient,
   1820                             /*OUT*/Bool* ok )
   1821 {
   1822    /* This function implements allocation policy.
   1823 
   1824       The nature of the allocation request is determined by req, which
   1825       specifies the start and length of the request and indicates
   1826       whether the start address is mandatory, a hint, or irrelevant,
   1827       and by forClient, which says whether this is for the client or
   1828       for V.
   1829 
   1830       Return values: the request can be vetoed (*ok is set to False),
   1831       in which case the caller should not attempt to proceed with
   1832       making the mapping.  Otherwise, *ok is set to True, the caller
   1833       may proceed, and the preferred address at which the mapping
   1834       should happen is returned.
   1835 
   1836       Note that this is an advisory system only: the kernel can in
   1837       fact do whatever it likes as far as placement goes, and we have
   1838       no absolute control over it.
   1839 
   1840       Allocations will never be granted in a reserved area.
   1841 
   1842       The Default Policy is:
   1843 
   1844         Search the address space for two free intervals: one of them
   1845         big enough to contain the request without regard to the
   1846         specified address (viz, as if it was a floating request) and
   1847         the other being able to contain the request at the specified
   1848         address (viz, as if were a fixed request).  Then, depending on
   1849         the outcome of the search and the kind of request made, decide
   1850         whether the request is allowable and what address to advise.
   1851 
   1852       The Default Policy is overriden by Policy Exception #1:
   1853 
   1854         If the request is for a fixed client map, we are prepared to
   1855         grant it providing all areas inside the request are either
   1856         free, reservations, or mappings belonging to the client.  In
   1857         other words we are prepared to let the client trash its own
   1858         mappings if it wants to.
   1859 
   1860       The Default Policy is overriden by Policy Exception #2:
   1861 
   1862         If the request is for a hinted client map, we are prepared to
   1863         grant it providing all areas inside the request are either
   1864         free or reservations.  In other words we are prepared to let
   1865         the client have a hinted mapping anywhere it likes provided
   1866         it does not trash either any of its own mappings or any of
   1867         valgrind's mappings.
   1868    */
   1869    Int  i, j;
   1870    Addr holeStart, holeEnd, holeLen;
   1871    Bool fixed_not_required;
   1872 
   1873 #if defined(VGO_solaris)
   1874    Addr startPoint = forClient ? aspacem_vStart - 1 : aspacem_maxAddr - 1;
   1875 #else
   1876    Addr startPoint = forClient ? aspacem_cStart : aspacem_vStart;
   1877 #endif /* VGO_solaris */
   1878 
   1879    Addr reqStart = req->rkind==MFixed || req->rkind==MHint ? req->start : 0;
   1880    Addr reqEnd   = reqStart + req->len - 1;
   1881    Addr reqLen   = req->len;
   1882 
   1883    /* These hold indices for segments found during search, or -1 if not
   1884       found. */
   1885    Int floatIdx = -1;
   1886    Int fixedIdx = -1;
   1887 
   1888    aspacem_assert(nsegments_used > 0);
   1889 
   1890    if (0) {
   1891       VG_(am_show_nsegments)(0,"getAdvisory");
   1892       VG_(debugLog)(0,"aspacem", "getAdvisory 0x%lx %lu\n",
   1893                     req->start, req->len);
   1894    }
   1895 
   1896    /* Reject zero-length requests */
   1897    if (req->len == 0) {
   1898       *ok = False;
   1899       return 0;
   1900    }
   1901 
   1902    /* Reject wraparounds */
   1903    if (req->start + req->len < req->start) {
   1904       *ok = False;
   1905       return 0;
   1906    }
   1907 
   1908    /* ------ Implement Policy Exception #1 ------ */
   1909 
   1910    if (forClient && req->rkind == MFixed) {
   1911       Int  iLo   = find_nsegment_idx(reqStart);
   1912       Int  iHi   = find_nsegment_idx(reqEnd);
   1913       Bool allow = True;
   1914       for (i = iLo; i <= iHi; i++) {
   1915          if (nsegments[i].kind == SkFree
   1916              || nsegments[i].kind == SkFileC
   1917              || nsegments[i].kind == SkAnonC
   1918              || nsegments[i].kind == SkShmC
   1919              || nsegments[i].kind == SkResvn) {
   1920             /* ok */
   1921          } else {
   1922             allow = False;
   1923             break;
   1924          }
   1925       }
   1926       if (allow) {
   1927          /* Acceptable.  Granted. */
   1928          *ok = True;
   1929          return reqStart;
   1930       }
   1931       /* Not acceptable.  Fail. */
   1932       *ok = False;
   1933       return 0;
   1934    }
   1935 
   1936    /* ------ Implement Policy Exception #2 ------ */
   1937 
   1938    if (forClient && req->rkind == MHint) {
   1939       Int  iLo   = find_nsegment_idx(reqStart);
   1940       Int  iHi   = find_nsegment_idx(reqEnd);
   1941       Bool allow = True;
   1942       for (i = iLo; i <= iHi; i++) {
   1943          if (nsegments[i].kind == SkFree
   1944              || nsegments[i].kind == SkResvn) {
   1945             /* ok */
   1946          } else {
   1947             allow = False;
   1948             break;
   1949          }
   1950       }
   1951       if (allow) {
   1952          /* Acceptable.  Granted. */
   1953          *ok = True;
   1954          return reqStart;
   1955       }
   1956       /* Not acceptable.  Fall through to the default policy. */
   1957    }
   1958 
   1959    /* ------ Implement the Default Policy ------ */
   1960 
   1961    /* Don't waste time looking for a fixed match if not requested to. */
   1962    fixed_not_required = req->rkind == MAny || req->rkind == MAlign;
   1963 
   1964    i = find_nsegment_idx(startPoint);
   1965 
   1966 #if defined(VGO_solaris)
   1967 #  define UPDATE_INDEX(index)                               \
   1968       (index)--;                                            \
   1969       if ((index) <= 0)                                     \
   1970          (index) = nsegments_used - 1;
   1971 #  define ADVISE_ADDRESS(segment)                           \
   1972        VG_PGROUNDDN((segment)->end + 1 - reqLen)
   1973 #  define ADVISE_ADDRESS_ALIGNED(segment)                   \
   1974         VG_ROUNDDN((segment)->end + 1 - reqLen, req->start)
   1975 
   1976 #else
   1977 
   1978 #  define UPDATE_INDEX(index)                               \
   1979       (index)++;                                            \
   1980       if ((index) >= nsegments_used)                        \
   1981          (index) = 0;
   1982 #  define ADVISE_ADDRESS(segment)                           \
   1983       (segment)->start
   1984 #  define ADVISE_ADDRESS_ALIGNED(segment)                   \
   1985       VG_ROUNDUP((segment)->start, req->start)
   1986 #endif /* VGO_solaris */
   1987 
   1988    /* Examine holes from index i back round to i-1.  Record the
   1989       index first fixed hole and the first floating hole which would
   1990       satisfy the request. */
   1991    for (j = 0; j < nsegments_used; j++) {
   1992 
   1993       if (nsegments[i].kind != SkFree) {
   1994          UPDATE_INDEX(i);
   1995          continue;
   1996       }
   1997 
   1998       holeStart = nsegments[i].start;
   1999       holeEnd   = nsegments[i].end;
   2000 
   2001       /* Stay sane .. */
   2002       aspacem_assert(holeStart <= holeEnd);
   2003       aspacem_assert(aspacem_minAddr <= holeStart);
   2004       aspacem_assert(holeEnd <= aspacem_maxAddr);
   2005 
   2006       if (req->rkind == MAlign) {
   2007          holeStart = VG_ROUNDUP(holeStart, req->start);
   2008          if (holeStart >= holeEnd) {
   2009             /* This hole can't be used. */
   2010             UPDATE_INDEX(i);
   2011             continue;
   2012          }
   2013       }
   2014 
   2015       /* See if it's any use to us. */
   2016       holeLen = holeEnd - holeStart + 1;
   2017 
   2018       if (fixedIdx == -1 && holeStart <= reqStart && reqEnd <= holeEnd)
   2019          fixedIdx = i;
   2020 
   2021       if (floatIdx == -1 && holeLen >= reqLen)
   2022          floatIdx = i;
   2023 
   2024       /* Don't waste time searching once we've found what we wanted. */
   2025       if ((fixed_not_required || fixedIdx >= 0) && floatIdx >= 0)
   2026          break;
   2027 
   2028       UPDATE_INDEX(i);
   2029    }
   2030 
   2031    aspacem_assert(fixedIdx >= -1 && fixedIdx < nsegments_used);
   2032    if (fixedIdx >= 0)
   2033       aspacem_assert(nsegments[fixedIdx].kind == SkFree);
   2034 
   2035    aspacem_assert(floatIdx >= -1 && floatIdx < nsegments_used);
   2036    if (floatIdx >= 0)
   2037       aspacem_assert(nsegments[floatIdx].kind == SkFree);
   2038 
   2039    AM_SANITY_CHECK;
   2040 
   2041    /* Now see if we found anything which can satisfy the request. */
   2042    switch (req->rkind) {
   2043       case MFixed:
   2044          if (fixedIdx >= 0) {
   2045             *ok = True;
   2046             return req->start;
   2047          } else {
   2048             *ok = False;
   2049             return 0;
   2050          }
   2051          break;
   2052       case MHint:
   2053          if (fixedIdx >= 0) {
   2054             *ok = True;
   2055             return req->start;
   2056          }
   2057          if (floatIdx >= 0) {
   2058             *ok = True;
   2059             return ADVISE_ADDRESS(&nsegments[floatIdx]);
   2060          }
   2061          *ok = False;
   2062          return 0;
   2063       case MAny:
   2064          if (floatIdx >= 0) {
   2065             *ok = True;
   2066             return ADVISE_ADDRESS(&nsegments[floatIdx]);
   2067          }
   2068          *ok = False;
   2069          return 0;
   2070       case MAlign:
   2071          if (floatIdx >= 0) {
   2072             *ok = True;
   2073             return ADVISE_ADDRESS_ALIGNED(&nsegments[floatIdx]);
   2074          }
   2075          *ok = False;
   2076          return 0;
   2077       default:
   2078          break;
   2079    }
   2080 
   2081    /*NOTREACHED*/
   2082    ML_(am_barf)("getAdvisory: unknown request kind");
   2083    *ok = False;
   2084    return 0;
   2085 
   2086 #undef UPDATE_INDEX
   2087 #undef ADVISE_ADDRESS
   2088 #undef ADVISE_ADDRESS_ALIGNED
   2089 }
   2090 
   2091 /* Convenience wrapper for VG_(am_get_advisory) for client floating or
   2092    fixed requests.  If start is zero, a floating request is issued; if
   2093    nonzero, a fixed request at that address is issued.  Same comments
   2094    about return values apply. */
   2095 
   2096 Addr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len,
   2097                                           /*OUT*/Bool* ok )
   2098 {
   2099    MapRequest mreq;
   2100    mreq.rkind = start==0 ? MAny : MFixed;
   2101    mreq.start = start;
   2102    mreq.len   = len;
   2103    return VG_(am_get_advisory)( &mreq, True/*forClient*/, ok );
   2104 }
   2105 
   2106 /* Similar to VG_(am_find_nsegment) but only returns free segments. */
   2107 static NSegment const * VG_(am_find_free_nsegment) ( Addr a )
   2108 {
   2109    Int i = find_nsegment_idx(a);
   2110    aspacem_assert(i >= 0 && i < nsegments_used);
   2111    aspacem_assert(nsegments[i].start <= a);
   2112    aspacem_assert(a <= nsegments[i].end);
   2113    if (nsegments[i].kind == SkFree)
   2114       return &nsegments[i];
   2115    else
   2116       return NULL;
   2117 }
   2118 
   2119 Bool VG_(am_covered_by_single_free_segment)
   2120    ( Addr start, SizeT len)
   2121 {
   2122    NSegment const* segLo = VG_(am_find_free_nsegment)( start );
   2123    NSegment const* segHi = VG_(am_find_free_nsegment)( start + len - 1 );
   2124 
   2125    return segLo != NULL && segHi != NULL && segLo == segHi;
   2126 }
   2127 
   2128 
   2129 /* Notifies aspacem that the client completed an mmap successfully.
   2130    The segment array is updated accordingly.  If the returned Bool is
   2131    True, the caller should immediately discard translations from the
   2132    specified address range. */
   2133 
   2134 Bool
   2135 VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
   2136                             Int fd, Off64T offset )
   2137 {
   2138    HChar    buf[VKI_PATH_MAX];
   2139    ULong    dev, ino;
   2140    UInt     mode;
   2141    NSegment seg;
   2142    Bool     needDiscard;
   2143 
   2144    aspacem_assert(len > 0);
   2145    aspacem_assert(VG_IS_PAGE_ALIGNED(a));
   2146    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
   2147    aspacem_assert(VG_IS_PAGE_ALIGNED(offset));
   2148 
   2149    /* Discard is needed if any of the just-trashed range had T. */
   2150    needDiscard = any_Ts_in_range( a, len );
   2151 
   2152    init_nsegment( &seg );
   2153    seg.kind   = (flags & VKI_MAP_ANONYMOUS) ? SkAnonC : SkFileC;
   2154    seg.start  = a;
   2155    seg.end    = a + len - 1;
   2156    seg.hasR   = toBool(prot & VKI_PROT_READ);
   2157    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
   2158    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
   2159    if (!(flags & VKI_MAP_ANONYMOUS)) {
   2160       // Nb: We ignore offset requests in anonymous mmaps (see bug #126722)
   2161       seg.offset = offset;
   2162       if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
   2163          seg.dev = dev;
   2164          seg.ino = ino;
   2165          seg.mode = mode;
   2166       }
   2167       if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
   2168          seg.fnIdx = ML_(am_allocate_segname)( buf );
   2169       }
   2170    }
   2171    add_segment( &seg );
   2172    AM_SANITY_CHECK;
   2173    return needDiscard;
   2174 }
   2175 
   2176 /* Notifies aspacem that the client completed a shmat successfully.
   2177    The segment array is updated accordingly.  If the returned Bool is
   2178    True, the caller should immediately discard translations from the
   2179    specified address range. */
   2180 
   2181 Bool
   2182 VG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot )
   2183 {
   2184    NSegment seg;
   2185    Bool     needDiscard;
   2186 
   2187    aspacem_assert(len > 0);
   2188    aspacem_assert(VG_IS_PAGE_ALIGNED(a));
   2189    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
   2190 
   2191    /* Discard is needed if any of the just-trashed range had T. */
   2192    needDiscard = any_Ts_in_range( a, len );
   2193 
   2194    init_nsegment( &seg );
   2195    seg.kind   = SkShmC;
   2196    seg.start  = a;
   2197    seg.end    = a + len - 1;
   2198    seg.offset = 0;
   2199    seg.hasR   = toBool(prot & VKI_PROT_READ);
   2200    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
   2201    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
   2202    add_segment( &seg );
   2203    AM_SANITY_CHECK;
   2204    return needDiscard;
   2205 }
   2206 
   2207 /* Notifies aspacem that an mprotect was completed successfully.  The
   2208    segment array is updated accordingly.  Note, as with
   2209    VG_(am_notify_munmap), it is not the job of this function to reject
   2210    stupid mprotects, for example the client doing mprotect of
   2211    non-client areas.  Such requests should be intercepted earlier, by
   2212    the syscall wrapper for mprotect.  This function merely records
   2213    whatever it is told.  If the returned Bool is True, the caller
   2214    should immediately discard translations from the specified address
   2215    range. */
   2216 
   2217 Bool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot )
   2218 {
   2219    Int  i, iLo, iHi;
   2220    Bool newR, newW, newX, needDiscard;
   2221 
   2222    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
   2223    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
   2224 
   2225    if (len == 0)
   2226       return False;
   2227 
   2228    newR = toBool(prot & VKI_PROT_READ);
   2229    newW = toBool(prot & VKI_PROT_WRITE);
   2230    newX = toBool(prot & VKI_PROT_EXEC);
   2231 
   2232    /* Discard is needed if we're dumping X permission */
   2233    needDiscard = any_Ts_in_range( start, len ) && !newX;
   2234 
   2235    split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
   2236 
   2237    iLo = find_nsegment_idx(start);
   2238    iHi = find_nsegment_idx(start + len - 1);
   2239 
   2240    for (i = iLo; i <= iHi; i++) {
   2241       /* Apply the permissions to all relevant segments. */
   2242       switch (nsegments[i].kind) {
   2243          case SkAnonC: case SkAnonV: case SkFileC: case SkFileV: case SkShmC:
   2244             nsegments[i].hasR = newR;
   2245             nsegments[i].hasW = newW;
   2246             nsegments[i].hasX = newX;
   2247             aspacem_assert(sane_NSegment(&nsegments[i]));
   2248             break;
   2249          default:
   2250             break;
   2251       }
   2252    }
   2253 
   2254    /* Changing permissions could have made previously un-mergable
   2255       segments mergeable.  Therefore have to re-preen them. */
   2256    (void)preen_nsegments();
   2257    AM_SANITY_CHECK;
   2258    return needDiscard;
   2259 }
   2260 
   2261 
   2262 /* Notifies aspacem that an munmap completed successfully.  The
   2263    segment array is updated accordingly.  As with
   2264    VG_(am_notify_mprotect), we merely record the given info, and don't
   2265    check it for sensibleness.  If the returned Bool is True, the
   2266    caller should immediately discard translations from the specified
   2267    address range. */
   2268 
   2269 Bool VG_(am_notify_munmap)( Addr start, SizeT len )
   2270 {
   2271    NSegment seg;
   2272    Bool     needDiscard;
   2273    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
   2274    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
   2275 
   2276    if (len == 0)
   2277       return False;
   2278 
   2279    needDiscard = any_Ts_in_range( start, len );
   2280 
   2281    init_nsegment( &seg );
   2282    seg.start = start;
   2283    seg.end   = start + len - 1;
   2284 
   2285    /* The segment becomes unused (free).  Segments from above
   2286       aspacem_maxAddr were originally SkResvn and so we make them so
   2287       again.  Note, this isn't really right when the segment straddles
   2288       the aspacem_maxAddr boundary - then really it should be split in
   2289       two, the lower part marked as SkFree and the upper part as
   2290       SkResvn.  Ah well. */
   2291    if (start > aspacem_maxAddr
   2292        && /* check previous comparison is meaningful */
   2293           aspacem_maxAddr < Addr_MAX)
   2294       seg.kind = SkResvn;
   2295    else
   2296    /* Ditto for segments from below aspacem_minAddr. */
   2297    if (seg.end < aspacem_minAddr && aspacem_minAddr > 0)
   2298       seg.kind = SkResvn;
   2299    else
   2300       seg.kind = SkFree;
   2301 
   2302    add_segment( &seg );
   2303 
   2304    /* Unmapping could create two adjacent free segments, so a preen is
   2305       needed.  add_segment() will do that, so no need to here. */
   2306    AM_SANITY_CHECK;
   2307    return needDiscard;
   2308 }
   2309 
   2310 
   2311 /*-----------------------------------------------------------------*/
   2312 /*---                                                           ---*/
   2313 /*--- Handling mappings which do not arise directly from the    ---*/
   2314 /*--- simulation of the client.                                 ---*/
   2315 /*---                                                           ---*/
   2316 /*-----------------------------------------------------------------*/
   2317 
   2318 /* --- --- --- map, unmap, protect  --- --- --- */
   2319 
   2320 /* Map a file at a fixed address for the client, and update the
   2321    segment array accordingly. */
   2322 
   2323 SysRes VG_(am_mmap_file_fixed_client)
   2324      ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset )
   2325 {
   2326    UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
   2327    return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
   2328                                                      fd, offset, NULL);
   2329 }
   2330 
   2331 SysRes VG_(am_mmap_file_fixed_client_flags)
   2332      ( Addr start, SizeT length, UInt prot, UInt flags, Int fd, Off64T offset )
   2333 {
   2334    return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
   2335                                                      fd, offset, NULL);
   2336 }
   2337 
   2338 SysRes VG_(am_mmap_named_file_fixed_client)
   2339      ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name )
   2340 {
   2341    UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
   2342    return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
   2343                                                      fd, offset, name);
   2344 }
   2345 
   2346 SysRes VG_(am_mmap_named_file_fixed_client_flags)
   2347      ( Addr start, SizeT length, UInt prot, UInt flags,
   2348        Int fd, Off64T offset, const HChar *name )
   2349 {
   2350    SysRes     sres;
   2351    NSegment   seg;
   2352    Addr       advised;
   2353    Bool       ok;
   2354    MapRequest req;
   2355    ULong      dev, ino;
   2356    UInt       mode;
   2357    HChar      buf[VKI_PATH_MAX];
   2358 
   2359    /* Not allowable. */
   2360    if (length == 0
   2361        || !VG_IS_PAGE_ALIGNED(start)
   2362        || !VG_IS_PAGE_ALIGNED(offset))
   2363       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2364 
   2365    /* Ask for an advisory.  If it's negative, fail immediately. */
   2366    req.rkind = MFixed;
   2367    req.start = start;
   2368    req.len   = length;
   2369    advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
   2370    if (!ok || advised != start)
   2371       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2372 
   2373    /* We have been advised that the mapping is allowable at the
   2374       specified address.  So hand it off to the kernel, and propagate
   2375       any resulting failure immediately. */
   2376    // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
   2377    sres = VG_(am_do_mmap_NO_NOTIFY)(
   2378              start, length, prot, flags,
   2379              fd, offset
   2380           );
   2381    if (sr_isError(sres))
   2382       return sres;
   2383 
   2384    if (sr_Res(sres) != start) {
   2385       /* I don't think this can happen.  It means the kernel made a
   2386          fixed map succeed but not at the requested location.  Try to
   2387          repair the damage, then return saying the mapping failed. */
   2388       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
   2389       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2390    }
   2391 
   2392    /* Ok, the mapping succeeded.  Now notify the interval map. */
   2393    init_nsegment( &seg );
   2394    seg.kind   = SkFileC;
   2395    seg.start  = start;
   2396    seg.end    = seg.start + VG_PGROUNDUP(length) - 1;
   2397    seg.offset = offset;
   2398    seg.hasR   = toBool(prot & VKI_PROT_READ);
   2399    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
   2400    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
   2401    if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
   2402       seg.dev = dev;
   2403       seg.ino = ino;
   2404       seg.mode = mode;
   2405    }
   2406    if (name) {
   2407       seg.fnIdx = ML_(am_allocate_segname)( name );
   2408    } else if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
   2409       seg.fnIdx = ML_(am_allocate_segname)( buf );
   2410    }
   2411    add_segment( &seg );
   2412 
   2413    AM_SANITY_CHECK;
   2414    return sres;
   2415 }
   2416 
   2417 
   2418 /* Map anonymously at a fixed address for the client, and update
   2419    the segment array accordingly. */
   2420 
   2421 SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
   2422 {
   2423    SysRes     sres;
   2424    NSegment   seg;
   2425    Addr       advised;
   2426    Bool       ok;
   2427    MapRequest req;
   2428 
   2429    /* Not allowable. */
   2430    if (length == 0 || !VG_IS_PAGE_ALIGNED(start))
   2431       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2432 
   2433    /* Ask for an advisory.  If it's negative, fail immediately. */
   2434    req.rkind = MFixed;
   2435    req.start = start;
   2436    req.len   = length;
   2437    advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
   2438    if (!ok || advised != start)
   2439       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2440 
   2441    /* We have been advised that the mapping is allowable at the
   2442       specified address.  So hand it off to the kernel, and propagate
   2443       any resulting failure immediately. */
   2444    // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
   2445    sres = VG_(am_do_mmap_NO_NOTIFY)(
   2446              start, length, prot,
   2447              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   2448              0, 0
   2449           );
   2450    if (sr_isError(sres))
   2451       return sres;
   2452 
   2453    if (sr_Res(sres) != start) {
   2454       /* I don't think this can happen.  It means the kernel made a
   2455          fixed map succeed but not at the requested location.  Try to
   2456          repair the damage, then return saying the mapping failed. */
   2457       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
   2458       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2459    }
   2460 
   2461    /* Ok, the mapping succeeded.  Now notify the interval map. */
   2462    init_nsegment( &seg );
   2463    seg.kind  = SkAnonC;
   2464    seg.start = start;
   2465    seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
   2466    seg.hasR  = toBool(prot & VKI_PROT_READ);
   2467    seg.hasW  = toBool(prot & VKI_PROT_WRITE);
   2468    seg.hasX  = toBool(prot & VKI_PROT_EXEC);
   2469    add_segment( &seg );
   2470 
   2471    AM_SANITY_CHECK;
   2472    return sres;
   2473 }
   2474 
   2475 
   2476 /* Map anonymously at an unconstrained address for the client, and
   2477    update the segment array accordingly.  */
   2478 
   2479 SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
   2480 {
   2481    SysRes     sres;
   2482    NSegment   seg;
   2483    Addr       advised;
   2484    Bool       ok;
   2485    MapRequest req;
   2486 
   2487    /* Not allowable. */
   2488    if (length == 0)
   2489       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2490 
   2491    /* Ask for an advisory.  If it's negative, fail immediately. */
   2492    req.rkind = MAny;
   2493    req.start = 0;
   2494    req.len   = length;
   2495    advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
   2496    if (!ok)
   2497       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2498 
   2499    /* We have been advised that the mapping is allowable at the
   2500       advised address.  So hand it off to the kernel, and propagate
   2501       any resulting failure immediately. */
   2502    // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
   2503    sres = VG_(am_do_mmap_NO_NOTIFY)(
   2504              advised, length, prot,
   2505              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   2506              0, 0
   2507           );
   2508    if (sr_isError(sres))
   2509       return sres;
   2510 
   2511    if (sr_Res(sres) != advised) {
   2512       /* I don't think this can happen.  It means the kernel made a
   2513          fixed map succeed but not at the requested location.  Try to
   2514          repair the damage, then return saying the mapping failed. */
   2515       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
   2516       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2517    }
   2518 
   2519    /* Ok, the mapping succeeded.  Now notify the interval map. */
   2520    init_nsegment( &seg );
   2521    seg.kind  = SkAnonC;
   2522    seg.start = advised;
   2523    seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
   2524    seg.hasR  = toBool(prot & VKI_PROT_READ);
   2525    seg.hasW  = toBool(prot & VKI_PROT_WRITE);
   2526    seg.hasX  = toBool(prot & VKI_PROT_EXEC);
   2527    add_segment( &seg );
   2528 
   2529    AM_SANITY_CHECK;
   2530    return sres;
   2531 }
   2532 
   2533 
   2534 /* Map anonymously at an unconstrained address for V, and update the
   2535    segment array accordingly.  This is fundamentally how V allocates
   2536    itself more address space when needed. */
   2537 
   2538 SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
   2539 {
   2540    SysRes     sres;
   2541    NSegment   seg;
   2542    Addr       advised;
   2543    Bool       ok;
   2544    MapRequest req;
   2545 
   2546    /* Not allowable. */
   2547    if (length == 0)
   2548       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2549 
   2550    /* Ask for an advisory.  If it's negative, fail immediately. */
   2551    req.rkind = MAny;
   2552    req.start = 0;
   2553    req.len   = length;
   2554    advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
   2555    if (!ok)
   2556       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2557 
   2558 // On Darwin, for anonymous maps you can pass in a tag which is used by
   2559 // programs like vmmap for statistical purposes.
   2560 #ifndef VM_TAG_VALGRIND
   2561 #  define VM_TAG_VALGRIND 0
   2562 #endif
   2563 
   2564    /* We have been advised that the mapping is allowable at the
   2565       specified address.  So hand it off to the kernel, and propagate
   2566       any resulting failure immediately. */
   2567    /* GrP fixme darwin: use advisory as a hint only, otherwise syscall in
   2568       another thread can pre-empt our spot.  [At one point on the DARWIN
   2569       branch the VKI_MAP_FIXED was commented out;  unclear if this is
   2570       necessary or not given the second Darwin-only call that immediately
   2571       follows if this one fails.  --njn]
   2572       Also, an inner valgrind cannot observe the mmap syscalls done by
   2573       the outer valgrind. The outer Valgrind might make the mmap
   2574       fail here, as the inner valgrind believes that a segment is free,
   2575       while it is in fact used by the outer valgrind.
   2576       So, for an inner valgrind, similarly to DARWIN, if the fixed mmap
   2577       fails, retry the mmap without map fixed.
   2578       This is a kludge which on linux is only activated for the inner.
   2579       The state of the inner aspacemgr is not made correct by this kludge
   2580       and so a.o. VG_(am_do_sync_check) could fail.
   2581       A proper solution implies a better collaboration between the
   2582       inner and the outer (e.g. inner VG_(am_get_advisory) should do
   2583       a client request to call the outer VG_(am_get_advisory). */
   2584    sres = VG_(am_do_mmap_NO_NOTIFY)(
   2585              advised, length,
   2586              VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
   2587              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   2588              VM_TAG_VALGRIND, 0
   2589           );
   2590 #if defined(VGO_darwin) || defined(ENABLE_INNER)
   2591    /* Kludge on Darwin and inner linux if the fixed mmap failed. */
   2592    if (sr_isError(sres)) {
   2593        /* try again, ignoring the advisory */
   2594        sres = VG_(am_do_mmap_NO_NOTIFY)(
   2595              0, length,
   2596              VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
   2597              /*VKI_MAP_FIXED|*/VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   2598              VM_TAG_VALGRIND, 0
   2599           );
   2600    }
   2601 #endif
   2602    if (sr_isError(sres))
   2603       return sres;
   2604 
   2605 #if defined(VGO_linux) && !defined(ENABLE_INNER)
   2606    /* Doing the check only in linux not inner, as the below
   2607       check can fail when the kludge above has been used. */
   2608    if (sr_Res(sres) != advised) {
   2609       /* I don't think this can happen.  It means the kernel made a
   2610          fixed map succeed but not at the requested location.  Try to
   2611          repair the damage, then return saying the mapping failed. */
   2612       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
   2613       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2614    }
   2615 #endif
   2616 
   2617    /* Ok, the mapping succeeded.  Now notify the interval map. */
   2618    init_nsegment( &seg );
   2619    seg.kind  = SkAnonV;
   2620    seg.start = sr_Res(sres);
   2621    seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
   2622    seg.hasR  = True;
   2623    seg.hasW  = True;
   2624    seg.hasX  = True;
   2625    add_segment( &seg );
   2626 
   2627    AM_SANITY_CHECK;
   2628    return sres;
   2629 }
   2630 
   2631 /* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
   2632 
   2633 void* VG_(am_shadow_alloc)(SizeT size)
   2634 {
   2635    SysRes sres = VG_(am_mmap_anon_float_valgrind)( size );
   2636    return sr_isError(sres) ? NULL : (void*)sr_Res(sres);
   2637 }
   2638 
   2639 /* Map a file at an unconstrained address for V, and update the
   2640    segment array accordingly. Use the provided flags */
   2641 
   2642 static SysRes VG_(am_mmap_file_float_valgrind_flags) ( SizeT length, UInt prot,
   2643                                                        UInt flags,
   2644                                                        Int fd, Off64T offset )
   2645 {
   2646    SysRes     sres;
   2647    NSegment   seg;
   2648    Addr       advised;
   2649    Bool       ok;
   2650    MapRequest req;
   2651    ULong      dev, ino;
   2652    UInt       mode;
   2653    HChar      buf[VKI_PATH_MAX];
   2654 
   2655    /* Not allowable. */
   2656    if (length == 0 || !VG_IS_PAGE_ALIGNED(offset))
   2657       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2658 
   2659    /* Ask for an advisory.  If it's negative, fail immediately. */
   2660    req.rkind = MAny;
   2661    req.start = 0;
   2662    #if defined(VGA_arm) || defined(VGA_arm64) \
   2663       || defined(VGA_mips32) || defined(VGA_mips64)
   2664    aspacem_assert(VKI_SHMLBA >= VKI_PAGE_SIZE);
   2665    #else
   2666    aspacem_assert(VKI_SHMLBA == VKI_PAGE_SIZE);
   2667    #endif
   2668    if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags)) {
   2669       /* arm-linux only. See ML_(generic_PRE_sys_shmat) and bug 290974 */
   2670       req.len = length + VKI_SHMLBA - VKI_PAGE_SIZE;
   2671    } else {
   2672       req.len = length;
   2673    }
   2674    advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
   2675    if (!ok)
   2676       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2677    if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags))
   2678       advised = VG_ROUNDUP(advised, VKI_SHMLBA);
   2679 
   2680    /* We have been advised that the mapping is allowable at the
   2681       specified address.  So hand it off to the kernel, and propagate
   2682       any resulting failure immediately. */
   2683    sres = VG_(am_do_mmap_NO_NOTIFY)(
   2684              advised, length, prot,
   2685              flags,
   2686              fd, offset
   2687           );
   2688    if (sr_isError(sres))
   2689       return sres;
   2690 
   2691    if (sr_Res(sres) != advised) {
   2692       /* I don't think this can happen.  It means the kernel made a
   2693          fixed map succeed but not at the requested location.  Try to
   2694          repair the damage, then return saying the mapping failed. */
   2695       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
   2696       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2697    }
   2698 
   2699    /* Ok, the mapping succeeded.  Now notify the interval map. */
   2700    init_nsegment( &seg );
   2701    seg.kind   = SkFileV;
   2702    seg.start  = sr_Res(sres);
   2703    seg.end    = seg.start + VG_PGROUNDUP(length) - 1;
   2704    seg.offset = offset;
   2705    seg.hasR   = toBool(prot & VKI_PROT_READ);
   2706    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
   2707    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
   2708    if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
   2709       seg.dev  = dev;
   2710       seg.ino  = ino;
   2711       seg.mode = mode;
   2712    }
   2713    if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
   2714       seg.fnIdx = ML_(am_allocate_segname)( buf );
   2715    }
   2716    add_segment( &seg );
   2717 
   2718    AM_SANITY_CHECK;
   2719    return sres;
   2720 }
   2721 /* Map privately a file at an unconstrained address for V, and update the
   2722    segment array accordingly.  This is used by V for transiently
   2723    mapping in object files to read their debug info.  */
   2724 
   2725 SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot,
   2726                                           Int fd, Off64T offset )
   2727 {
   2728    return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
   2729                                                   VKI_MAP_FIXED|VKI_MAP_PRIVATE,
   2730                                                   fd, offset );
   2731 }
   2732 
   2733 SysRes VG_(am_shared_mmap_file_float_valgrind)
   2734    ( SizeT length, UInt prot, Int fd, Off64T offset )
   2735 {
   2736    return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
   2737                                                   VKI_MAP_FIXED|VKI_MAP_SHARED,
   2738                                                   fd, offset );
   2739 }
   2740 
   2741 /* Convenience wrapper around VG_(am_mmap_anon_float_client) which also
   2742    marks the segment as containing the client heap. This is for the benefit
   2743    of the leak checker which needs to be able to identify such segments
   2744    so as not to use them as sources of roots during leak checks. */
   2745 SysRes VG_(am_mmap_client_heap) ( SizeT length, Int prot )
   2746 {
   2747    SysRes res = VG_(am_mmap_anon_float_client)(length, prot);
   2748 
   2749    if (! sr_isError(res)) {
   2750       Addr addr = sr_Res(res);
   2751       Int ix = find_nsegment_idx(addr);
   2752 
   2753       nsegments[ix].isCH = True;
   2754    }
   2755    return res;
   2756 }
   2757 
   2758 /* --- --- munmap helper --- --- */
   2759 
   2760 static
   2761 SysRes am_munmap_both_wrk ( /*OUT*/Bool* need_discard,
   2762                             Addr start, SizeT len, Bool forClient )
   2763 {
   2764    Bool   d;
   2765    SysRes sres;
   2766 
   2767    if (!VG_IS_PAGE_ALIGNED(start))
   2768       goto eINVAL;
   2769 
   2770    if (len == 0) {
   2771       *need_discard = False;
   2772       return VG_(mk_SysRes_Success)( 0 );
   2773    }
   2774 
   2775    if (start + len < len)
   2776       goto eINVAL;
   2777 
   2778    len = VG_PGROUNDUP(len);
   2779    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
   2780    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
   2781 
   2782    if (forClient) {
   2783       if (!VG_(am_is_valid_for_client_or_free_or_resvn)
   2784             ( start, len, VKI_PROT_NONE ))
   2785          goto eINVAL;
   2786    } else {
   2787       if (!VG_(am_is_valid_for_valgrind)
   2788             ( start, len, VKI_PROT_NONE ))
   2789          goto eINVAL;
   2790    }
   2791 
   2792    d = any_Ts_in_range( start, len );
   2793 
   2794    sres = ML_(am_do_munmap_NO_NOTIFY)( start, len );
   2795    if (sr_isError(sres))
   2796       return sres;
   2797 
   2798    VG_(am_notify_munmap)( start, len );
   2799    AM_SANITY_CHECK;
   2800    *need_discard = d;
   2801    return sres;
   2802 
   2803   eINVAL:
   2804    return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2805 }
   2806 
   2807 /* Unmap the given address range and update the segment array
   2808    accordingly.  This fails if the range isn't valid for the client.
   2809    If *need_discard is True after a successful return, the caller
   2810    should immediately discard translations from the specified address
   2811    range. */
   2812 
   2813 SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
   2814                               Addr start, SizeT len )
   2815 {
   2816    return am_munmap_both_wrk( need_discard, start, len, True/*client*/ );
   2817 }
   2818 
   2819 /* Unmap the given address range and update the segment array
   2820    accordingly.  This fails if the range isn't valid for valgrind. */
   2821 
   2822 SysRes VG_(am_munmap_valgrind)( Addr start, SizeT len )
   2823 {
   2824    Bool need_discard;
   2825    SysRes r = am_munmap_both_wrk( &need_discard,
   2826                                   start, len, False/*valgrind*/ );
   2827    /* If this assertion fails, it means we allowed translations to be
   2828       made from a V-owned section.  Which shouldn't happen. */
   2829    if (!sr_isError(r))
   2830       aspacem_assert(!need_discard);
   2831    return r;
   2832 }
   2833 
   2834 /* Let (start,len) denote an area within a single Valgrind-owned
   2835   segment (anon or file).  Change the ownership of [start, start+len)
   2836   to the client instead.  Fails if (start,len) does not denote a
   2837   suitable segment. */
   2838 
   2839 Bool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len )
   2840 {
   2841    Int i, iLo, iHi;
   2842 
   2843    if (len == 0)
   2844       return True;
   2845    if (start + len < start)
   2846       return False;
   2847    if (!VG_IS_PAGE_ALIGNED(start) || !VG_IS_PAGE_ALIGNED(len))
   2848       return False;
   2849 
   2850    i = find_nsegment_idx(start);
   2851    if (nsegments[i].kind != SkFileV && nsegments[i].kind != SkAnonV)
   2852       return False;
   2853    if (start+len-1 > nsegments[i].end)
   2854       return False;
   2855 
   2856    aspacem_assert(start >= nsegments[i].start);
   2857    aspacem_assert(start+len-1 <= nsegments[i].end);
   2858 
   2859    /* This scheme is like how mprotect works: split the to-be-changed
   2860       range into its own segment(s), then mess with them (it).  There
   2861       should be only one. */
   2862    split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
   2863    aspacem_assert(iLo == iHi);
   2864    switch (nsegments[iLo].kind) {
   2865       case SkFileV: nsegments[iLo].kind = SkFileC; break;
   2866       case SkAnonV: nsegments[iLo].kind = SkAnonC; break;
   2867       default: aspacem_assert(0); /* can't happen - guarded above */
   2868    }
   2869 
   2870    preen_nsegments();
   2871    return True;
   2872 }
   2873 
   2874 /* Set the 'hasT' bit on the segment containing ADDR indicating that
   2875    translations have or may have been taken from this segment. ADDR is
   2876    expected to belong to a client segment. */
   2877 void VG_(am_set_segment_hasT)( Addr addr )
   2878 {
   2879    Int i = find_nsegment_idx(addr);
   2880    SegKind kind = nsegments[i].kind;
   2881    aspacem_assert(kind == SkAnonC || kind == SkFileC || kind == SkShmC);
   2882    nsegments[i].hasT = True;
   2883 }
   2884 
   2885 
   2886 /* --- --- --- reservations --- --- --- */
   2887 
   2888 /* Create a reservation from START .. START+LENGTH-1, with the given
   2889    ShrinkMode.  When checking whether the reservation can be created,
   2890    also ensure that at least abs(EXTRA) extra free bytes will remain
   2891    above (> 0) or below (< 0) the reservation.
   2892 
   2893    The reservation will only be created if it, plus the extra-zone,
   2894    falls entirely within a single free segment.  The returned Bool
   2895    indicates whether the creation succeeded. */
   2896 
   2897 Bool VG_(am_create_reservation) ( Addr start, SizeT length,
   2898                                   ShrinkMode smode, SSizeT extra )
   2899 {
   2900    Int      startI, endI;
   2901    NSegment seg;
   2902 
   2903    /* start and end, not taking into account the extra space. */
   2904    Addr start1 = start;
   2905    Addr end1   = start + length - 1;
   2906 
   2907    /* start and end, taking into account the extra space. */
   2908    Addr start2 = start1;
   2909    Addr end2   = end1;
   2910 
   2911    if (extra < 0) start2 += extra; // this moves it down :-)
   2912    if (extra > 0) end2 += extra;
   2913 
   2914    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
   2915    aspacem_assert(VG_IS_PAGE_ALIGNED(start+length));
   2916    aspacem_assert(VG_IS_PAGE_ALIGNED(start2));
   2917    aspacem_assert(VG_IS_PAGE_ALIGNED(end2+1));
   2918 
   2919    startI = find_nsegment_idx( start2 );
   2920    endI = find_nsegment_idx( end2 );
   2921 
   2922    /* If the start and end points don't fall within the same (free)
   2923       segment, we're hosed.  This does rely on the assumption that all
   2924       mergeable adjacent segments can be merged, but add_segment()
   2925       should ensure that. */
   2926    if (startI != endI)
   2927       return False;
   2928 
   2929    if (nsegments[startI].kind != SkFree)
   2930       return False;
   2931 
   2932    /* Looks good - make the reservation. */
   2933    aspacem_assert(nsegments[startI].start <= start2);
   2934    aspacem_assert(end2 <= nsegments[startI].end);
   2935 
   2936    init_nsegment( &seg );
   2937    seg.kind  = SkResvn;
   2938    seg.start = start1;  /* NB: extra space is not included in the
   2939                            reservation. */
   2940    seg.end   = end1;
   2941    seg.smode = smode;
   2942    add_segment( &seg );
   2943 
   2944    AM_SANITY_CHECK;
   2945    return True;
   2946 }
   2947 
   2948 
   2949 /* ADDR is the start address of an anonymous client mapping.  This fn extends
   2950    the mapping by DELTA bytes, taking the space from a reservation section
   2951    which must be adjacent.  If DELTA is positive, the segment is
   2952    extended forwards in the address space, and the reservation must be
   2953    the next one along.  If DELTA is negative, the segment is extended
   2954    backwards in the address space and the reservation must be the
   2955    previous one.  DELTA must be page aligned.  abs(DELTA) must not
   2956    exceed the size of the reservation segment minus one page, that is,
   2957    the reservation segment after the operation must be at least one
   2958    page long. The function returns a pointer to the resized segment. */
   2959 
   2960 const NSegment *VG_(am_extend_into_adjacent_reservation_client)( Addr addr,
   2961                                                                  SSizeT delta,
   2962                                                                  Bool *overflow)
   2963 {
   2964    Int    segA, segR;
   2965    UInt   prot;
   2966    SysRes sres;
   2967 
   2968    *overflow = False;
   2969 
   2970    segA = find_nsegment_idx(addr);
   2971    aspacem_assert(nsegments[segA].kind == SkAnonC);
   2972 
   2973    if (delta == 0)
   2974       return nsegments + segA;
   2975 
   2976    prot =   (nsegments[segA].hasR ? VKI_PROT_READ : 0)
   2977           | (nsegments[segA].hasW ? VKI_PROT_WRITE : 0)
   2978           | (nsegments[segA].hasX ? VKI_PROT_EXEC : 0);
   2979 
   2980    aspacem_assert(VG_IS_PAGE_ALIGNED(delta<0 ? -delta : delta));
   2981 
   2982    if (delta > 0) {
   2983 
   2984       /* Extending the segment forwards. */
   2985       segR = segA+1;
   2986       if (segR >= nsegments_used
   2987           || nsegments[segR].kind != SkResvn
   2988           || nsegments[segR].smode != SmLower)
   2989          return NULL;
   2990 
   2991       if (delta + VKI_PAGE_SIZE
   2992                 > (nsegments[segR].end - nsegments[segR].start + 1)) {
   2993          *overflow = True;
   2994          return NULL;
   2995       }
   2996 
   2997       /* Extend the kernel's mapping. */
   2998       // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
   2999       sres = VG_(am_do_mmap_NO_NOTIFY)(
   3000                 nsegments[segR].start, delta,
   3001                 prot,
   3002                 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   3003                 0, 0
   3004              );
   3005       if (sr_isError(sres))
   3006          return NULL; /* kernel bug if this happens? */
   3007       if (sr_Res(sres) != nsegments[segR].start) {
   3008          /* kernel bug if this happens? */
   3009         (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
   3010         return NULL;
   3011       }
   3012 
   3013       /* Ok, success with the kernel.  Update our structures. */
   3014       nsegments[segR].start += delta;
   3015       nsegments[segA].end += delta;
   3016       aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
   3017 
   3018    } else {
   3019 
   3020       /* Extending the segment backwards. */
   3021       delta = -delta;
   3022       aspacem_assert(delta > 0);
   3023 
   3024       segR = segA-1;
   3025       if (segR < 0
   3026           || nsegments[segR].kind != SkResvn
   3027           || nsegments[segR].smode != SmUpper)
   3028          return NULL;
   3029 
   3030       if (delta + VKI_PAGE_SIZE
   3031                 > (nsegments[segR].end - nsegments[segR].start + 1)) {
   3032          *overflow = True;
   3033          return NULL;
   3034       }
   3035 
   3036       /* Extend the kernel's mapping. */
   3037       // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
   3038       sres = VG_(am_do_mmap_NO_NOTIFY)(
   3039                 nsegments[segA].start-delta, delta,
   3040                 prot,
   3041                 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   3042                 0, 0
   3043              );
   3044       if (sr_isError(sres))
   3045          return NULL; /* kernel bug if this happens? */
   3046       if (sr_Res(sres) != nsegments[segA].start-delta) {
   3047          /* kernel bug if this happens? */
   3048         (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
   3049         return NULL;
   3050       }
   3051 
   3052       /* Ok, success with the kernel.  Update our structures. */
   3053       nsegments[segR].end -= delta;
   3054       nsegments[segA].start -= delta;
   3055       aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
   3056    }
   3057 
   3058    AM_SANITY_CHECK;
   3059    return nsegments + segA;
   3060 }
   3061 
   3062 
   3063 /* --- --- --- resizing/move a mapping --- --- --- */
   3064 
   3065 #if HAVE_MREMAP
   3066 
   3067 /* This function grows a client mapping in place into an adjacent free segment.
   3068    ADDR is the client mapping's start address and DELTA, which must be page
   3069    aligned, is the growth amount. The function returns a pointer to the
   3070    resized segment. The function is used in support of mremap. */
   3071 const NSegment *VG_(am_extend_map_client)( Addr addr, SizeT delta )
   3072 {
   3073    Addr     xStart;
   3074    SysRes   sres;
   3075 
   3076    if (0)
   3077       VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) BEFORE");
   3078 
   3079    /* Get the client segment */
   3080    Int ix = find_nsegment_idx(addr);
   3081    aspacem_assert(ix >= 0 && ix < nsegments_used);
   3082 
   3083    NSegment *seg = nsegments + ix;
   3084 
   3085    aspacem_assert(seg->kind == SkFileC || seg->kind == SkAnonC ||
   3086                   seg->kind == SkShmC);
   3087    aspacem_assert(delta > 0 && VG_IS_PAGE_ALIGNED(delta)) ;
   3088 
   3089    xStart = seg->end+1;
   3090    aspacem_assert(xStart + delta >= delta);   // no wrap-around
   3091 
   3092    /* The segment following the client segment must be a free segment and
   3093       it must be large enough to cover the additional memory. */
   3094    NSegment *segf = seg + 1;
   3095    aspacem_assert(segf->kind == SkFree);
   3096    aspacem_assert(segf->start == xStart);
   3097    aspacem_assert(xStart + delta - 1 <= segf->end);
   3098 
   3099    SizeT seg_old_len = seg->end + 1 - seg->start;
   3100 
   3101    AM_SANITY_CHECK;
   3102    sres = ML_(am_do_extend_mapping_NO_NOTIFY)( seg->start,
   3103                                                seg_old_len,
   3104                                                seg_old_len + delta );
   3105    if (sr_isError(sres)) {
   3106       AM_SANITY_CHECK;
   3107       return NULL;
   3108    } else {
   3109       /* the area must not have moved */
   3110       aspacem_assert(sr_Res(sres) == seg->start);
   3111    }
   3112 
   3113    NSegment seg_copy = *seg;
   3114    seg_copy.end += delta;
   3115    add_segment( &seg_copy );
   3116 
   3117    if (0)
   3118       VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) AFTER");
   3119 
   3120    AM_SANITY_CHECK;
   3121    return nsegments + find_nsegment_idx(addr);
   3122 }
   3123 
   3124 
   3125 /* Remap the old address range to the new address range.  Fails if any
   3126    parameter is not page aligned, if the either size is zero, if any
   3127    wraparound is implied, if the old address range does not fall
   3128    entirely within a single segment, if the new address range overlaps
   3129    with the old one, or if the old address range is not a valid client
   3130    mapping.  If *need_discard is True after a successful return, the
   3131    caller should immediately discard translations from both specified
   3132    address ranges.  */
   3133 
   3134 Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
   3135                                         Addr old_addr, SizeT old_len,
   3136                                         Addr new_addr, SizeT new_len )
   3137 {
   3138    Int      iLo, iHi;
   3139    SysRes   sres;
   3140    NSegment seg;
   3141 
   3142    if (old_len == 0 || new_len == 0)
   3143       return False;
   3144 
   3145    if (!VG_IS_PAGE_ALIGNED(old_addr) || !VG_IS_PAGE_ALIGNED(old_len)
   3146        || !VG_IS_PAGE_ALIGNED(new_addr) || !VG_IS_PAGE_ALIGNED(new_len))
   3147       return False;
   3148 
   3149    if (old_addr + old_len < old_addr
   3150        || new_addr + new_len < new_addr)
   3151       return False;
   3152 
   3153    if (old_addr + old_len - 1 < new_addr
   3154        || new_addr + new_len - 1 < old_addr) {
   3155       /* no overlap */
   3156    } else
   3157       return False;
   3158 
   3159    iLo = find_nsegment_idx( old_addr );
   3160    iHi = find_nsegment_idx( old_addr + old_len - 1 );
   3161    if (iLo != iHi)
   3162       return False;
   3163 
   3164    if (nsegments[iLo].kind != SkFileC && nsegments[iLo].kind != SkAnonC &&
   3165        nsegments[iLo].kind != SkShmC)
   3166       return False;
   3167 
   3168    sres = ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)
   3169              ( old_addr, old_len, new_addr, new_len );
   3170    if (sr_isError(sres)) {
   3171       AM_SANITY_CHECK;
   3172       return False;
   3173    } else {
   3174       aspacem_assert(sr_Res(sres) == new_addr);
   3175    }
   3176 
   3177    *need_discard = any_Ts_in_range( old_addr, old_len )
   3178                    || any_Ts_in_range( new_addr, new_len );
   3179 
   3180    seg = nsegments[iLo];
   3181 
   3182    /* Mark the new area based on the old seg. */
   3183    if (seg.kind == SkFileC) {
   3184       seg.offset += ((ULong)old_addr) - ((ULong)seg.start);
   3185    }
   3186    seg.start = new_addr;
   3187    seg.end   = new_addr + new_len - 1;
   3188    add_segment( &seg );
   3189 
   3190    /* Create a free hole in the old location. */
   3191    init_nsegment( &seg );
   3192    seg.start = old_addr;
   3193    seg.end   = old_addr + old_len - 1;
   3194    /* See comments in VG_(am_notify_munmap) about this SkResvn vs
   3195       SkFree thing. */
   3196    if (old_addr > aspacem_maxAddr
   3197        && /* check previous comparison is meaningful */
   3198           aspacem_maxAddr < Addr_MAX)
   3199       seg.kind = SkResvn;
   3200    else
   3201       seg.kind = SkFree;
   3202 
   3203    add_segment( &seg );
   3204 
   3205    AM_SANITY_CHECK;
   3206    return True;
   3207 }
   3208 
   3209 #endif // HAVE_MREMAP
   3210 
   3211 
   3212 #if defined(VGO_linux)
   3213 
   3214 /*-----------------------------------------------------------------*/
   3215 /*---                                                           ---*/
   3216 /*--- A simple parser for /proc/self/maps on Linux 2.4.X/2.6.X. ---*/
   3217 /*--- Almost completely independent of the stuff above.  The    ---*/
   3218 /*--- only function it 'exports' to the code above this comment ---*/
   3219 /*--- is parse_procselfmaps.                                    ---*/
   3220 /*---                                                           ---*/
   3221 /*-----------------------------------------------------------------*/
   3222 
   3223 /*------BEGIN-procmaps-parser-for-Linux--------------------------*/
   3224 
   3225 /* Size of a smallish table used to read /proc/self/map entries. */
   3226 #define M_PROCMAP_BUF 100000
   3227 
   3228 /* static ... to keep it out of the stack frame. */
   3229 static HChar procmap_buf[M_PROCMAP_BUF];
   3230 
   3231 /* Records length of /proc/self/maps read into procmap_buf. */
   3232 static Int  buf_n_tot;
   3233 
   3234 /* Helper fns. */
   3235 
   3236 static Int hexdigit ( HChar c )
   3237 {
   3238    if (c >= '0' && c <= '9') return (Int)(c - '0');
   3239    if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a');
   3240    if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A');
   3241    return -1;
   3242 }
   3243 
   3244 static Int decdigit ( HChar c )
   3245 {
   3246    if (c >= '0' && c <= '9') return (Int)(c - '0');
   3247    return -1;
   3248 }
   3249 
   3250 static Int readchar ( const HChar* buf, HChar* ch )
   3251 {
   3252    if (*buf == 0) return 0;
   3253    *ch = *buf;
   3254    return 1;
   3255 }
   3256 
   3257 static Int readhex ( const HChar* buf, UWord* val )
   3258 {
   3259    /* Read a word-sized hex number. */
   3260    Int n = 0;
   3261    *val = 0;
   3262    while (hexdigit(*buf) >= 0) {
   3263       *val = (*val << 4) + hexdigit(*buf);
   3264       n++; buf++;
   3265    }
   3266    return n;
   3267 }
   3268 
   3269 static Int readhex64 ( const HChar* buf, ULong* val )
   3270 {
   3271    /* Read a potentially 64-bit hex number. */
   3272    Int n = 0;
   3273    *val = 0;
   3274    while (hexdigit(*buf) >= 0) {
   3275       *val = (*val << 4) + hexdigit(*buf);
   3276       n++; buf++;
   3277    }
   3278    return n;
   3279 }
   3280 
   3281 static Int readdec64 ( const HChar* buf, ULong* val )
   3282 {
   3283    Int n = 0;
   3284    *val = 0;
   3285    while (decdigit(*buf) >= 0) {
   3286       *val = (*val * 10) + decdigit(*buf);
   3287       n++; buf++;
   3288    }
   3289    return n;
   3290 }
   3291 
   3292 
   3293 /* Get the contents of /proc/self/maps into a static buffer.  If
   3294    there's a syntax error, it won't fit, or other failure, just
   3295    abort. */
   3296 
   3297 static void read_procselfmaps_into_buf ( void )
   3298 {
   3299    Int    n_chunk;
   3300    SysRes fd;
   3301 
   3302    /* Read the initial memory mapping from the /proc filesystem. */
   3303    fd = ML_(am_open)( "/proc/self/maps", VKI_O_RDONLY, 0 );
   3304    if (sr_isError(fd))
   3305       ML_(am_barf)("can't open /proc/self/maps");
   3306 
   3307    buf_n_tot = 0;
   3308    do {
   3309       n_chunk = ML_(am_read)( sr_Res(fd), &procmap_buf[buf_n_tot],
   3310                               M_PROCMAP_BUF - buf_n_tot );
   3311       if (n_chunk >= 0)
   3312          buf_n_tot += n_chunk;
   3313    } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
   3314 
   3315    ML_(am_close)(sr_Res(fd));
   3316 
   3317    if (buf_n_tot >= M_PROCMAP_BUF-5)
   3318       ML_(am_barf_toolow)("M_PROCMAP_BUF");
   3319    if (buf_n_tot == 0)
   3320       ML_(am_barf)("I/O error on /proc/self/maps");
   3321 
   3322    procmap_buf[buf_n_tot] = 0;
   3323 }
   3324 
   3325 /* Parse /proc/self/maps.  For each map entry, call
   3326    record_mapping, passing it, in this order:
   3327 
   3328       start address in memory
   3329       length
   3330       page protections (using the VKI_PROT_* flags)
   3331       mapped file device and inode
   3332       offset in file, or zero if no file
   3333       filename, zero terminated, or NULL if no file
   3334 
   3335    So the sig of the called fn might be
   3336 
   3337       void (*record_mapping)( Addr start, SizeT size, UInt prot,
   3338 			      UInt dev, UInt info,
   3339                               ULong foffset, UChar* filename )
   3340 
   3341    Note that the supplied filename is transiently stored; record_mapping
   3342    should make a copy if it wants to keep it.
   3343 
   3344    Nb: it is important that this function does not alter the contents of
   3345        procmap_buf!
   3346 */
   3347 static void parse_procselfmaps (
   3348       void (*record_mapping)( Addr addr, SizeT len, UInt prot,
   3349                               ULong dev, ULong ino, Off64T offset,
   3350                               const HChar* filename ),
   3351       void (*record_gap)( Addr addr, SizeT len )
   3352    )
   3353 {
   3354    Int    i, j, i_eol;
   3355    Addr   start, endPlusOne, gapStart;
   3356    HChar* filename;
   3357    HChar  rr, ww, xx, pp, ch, tmp;
   3358    UInt	  prot;
   3359    UWord  maj, min;
   3360    ULong  foffset, dev, ino;
   3361 
   3362    foffset = ino = 0; /* keep gcc-4.1.0 happy */
   3363 
   3364    read_procselfmaps_into_buf();
   3365 
   3366    aspacem_assert('\0' != procmap_buf[0] && 0 != buf_n_tot);
   3367 
   3368    if (0)
   3369       VG_(debugLog)(0, "procselfmaps", "raw:\n%s\n", procmap_buf);
   3370 
   3371    /* Ok, it's safely aboard.  Parse the entries. */
   3372    i = 0;
   3373    gapStart = Addr_MIN;
   3374    while (True) {
   3375       if (i >= buf_n_tot) break;
   3376 
   3377       /* Read (without fscanf :) the pattern %16x-%16x %c%c%c%c %16x %2x:%2x %d */
   3378       j = readhex(&procmap_buf[i], &start);
   3379       if (j > 0) i += j; else goto syntaxerror;
   3380       j = readchar(&procmap_buf[i], &ch);
   3381       if (j == 1 && ch == '-') i += j; else goto syntaxerror;
   3382       j = readhex(&procmap_buf[i], &endPlusOne);
   3383       if (j > 0) i += j; else goto syntaxerror;
   3384 
   3385       j = readchar(&procmap_buf[i], &ch);
   3386       if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
   3387 
   3388       j = readchar(&procmap_buf[i], &rr);
   3389       if (j == 1 && (rr == 'r' || rr == '-')) i += j; else goto syntaxerror;
   3390       j = readchar(&procmap_buf[i], &ww);
   3391       if (j == 1 && (ww == 'w' || ww == '-')) i += j; else goto syntaxerror;
   3392       j = readchar(&procmap_buf[i], &xx);
   3393       if (j == 1 && (xx == 'x' || xx == '-')) i += j; else goto syntaxerror;
   3394       /* This field is the shared/private flag */
   3395       j = readchar(&procmap_buf[i], &pp);
   3396       if (j == 1 && (pp == 'p' || pp == '-' || pp == 's'))
   3397                                               i += j; else goto syntaxerror;
   3398 
   3399       j = readchar(&procmap_buf[i], &ch);
   3400       if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
   3401 
   3402       j = readhex64(&procmap_buf[i], &foffset);
   3403       if (j > 0) i += j; else goto syntaxerror;
   3404 
   3405       j = readchar(&procmap_buf[i], &ch);
   3406       if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
   3407 
   3408       j = readhex(&procmap_buf[i], &maj);
   3409       if (j > 0) i += j; else goto syntaxerror;
   3410       j = readchar(&procmap_buf[i], &ch);
   3411       if (j == 1 && ch == ':') i += j; else goto syntaxerror;
   3412       j = readhex(&procmap_buf[i], &min);
   3413       if (j > 0) i += j; else goto syntaxerror;
   3414 
   3415       j = readchar(&procmap_buf[i], &ch);
   3416       if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
   3417 
   3418       j = readdec64(&procmap_buf[i], &ino);
   3419       if (j > 0) i += j; else goto syntaxerror;
   3420 
   3421       goto read_line_ok;
   3422 
   3423     syntaxerror:
   3424       VG_(debugLog)(0, "Valgrind:",
   3425                        "FATAL: syntax error reading /proc/self/maps\n");
   3426       { Int k, m;
   3427         HChar buf50[51];
   3428         m = 0;
   3429         buf50[m] = 0;
   3430         k = i - 50;
   3431         if (k < 0) k = 0;
   3432         for (; k <= i; k++) {
   3433            buf50[m] = procmap_buf[k];
   3434            buf50[m+1] = 0;
   3435            if (m < 50-1) m++;
   3436         }
   3437         VG_(debugLog)(0, "procselfmaps", "Last 50 chars: '%s'\n", buf50);
   3438       }
   3439       ML_(am_exit)(1);
   3440 
   3441     read_line_ok:
   3442 
   3443       aspacem_assert(i < buf_n_tot);
   3444 
   3445       /* Try and find the name of the file mapped to this segment, if
   3446          it exists.  Note that file names can contain spaces. */
   3447 
   3448       // Move i to the next non-space char, which should be either a '/',
   3449       // a '[', or a newline.
   3450       while (procmap_buf[i] == ' ') i++;
   3451 
   3452       // Move i_eol to the end of the line.
   3453       i_eol = i;
   3454       while (procmap_buf[i_eol] != '\n') i_eol++;
   3455 
   3456       // If there's a filename...
   3457       if (procmap_buf[i] == '/') {
   3458          /* Minor hack: put a '\0' at the filename end for the call to
   3459             'record_mapping', then restore the old char with 'tmp'. */
   3460          filename = &procmap_buf[i];
   3461          tmp = filename[i_eol - i];
   3462          filename[i_eol - i] = '\0';
   3463       } else {
   3464 	 tmp = 0;
   3465          filename = NULL;
   3466          foffset = 0;
   3467       }
   3468 
   3469       prot = 0;
   3470       if (rr == 'r') prot |= VKI_PROT_READ;
   3471       if (ww == 'w') prot |= VKI_PROT_WRITE;
   3472       if (xx == 'x') prot |= VKI_PROT_EXEC;
   3473 
   3474       /* Linux has two ways to encode a device number when it
   3475          is exposed to user space (via fstat etc). The old way
   3476          is the traditional unix scheme that produces a 16 bit
   3477          device number with the top 8 being the major number and
   3478          the bottom 8 the minor number.
   3479 
   3480          The new scheme allows for a 12 bit major number and
   3481          a 20 bit minor number by using a 32 bit device number
   3482          and putting the top 12 bits of the minor number into
   3483          the top 12 bits of the device number thus leaving an
   3484          extra 4 bits for the major number.
   3485 
   3486          If the minor and major number are both single byte
   3487          values then both schemes give the same result so we
   3488          use the new scheme here in case either number is
   3489          outside the 0-255 range and then use fstat64 when
   3490          available (or fstat on 64 bit systems) so that we
   3491          should always have a new style device number and
   3492          everything should match. */
   3493       dev = (min & 0xff) | (maj << 8) | ((min & ~0xff) << 12);
   3494 
   3495       if (record_gap && gapStart < start)
   3496          (*record_gap) ( gapStart, start-gapStart );
   3497 
   3498       if (record_mapping && start < endPlusOne)
   3499          (*record_mapping) ( start, endPlusOne-start,
   3500                              prot, dev, ino,
   3501                              foffset, filename );
   3502 
   3503       if ('\0' != tmp) {
   3504          filename[i_eol - i] = tmp;
   3505       }
   3506 
   3507       i = i_eol + 1;
   3508       gapStart = endPlusOne;
   3509    }
   3510 
   3511 #  if defined(VGP_arm_linux)
   3512    /* ARM puts code at the end of memory that contains processor
   3513       specific stuff (cmpxchg, getting the thread local storage, etc.)
   3514       This isn't specified in /proc/self/maps, so do it here.  This
   3515       kludgery causes the view of memory, as presented to
   3516       record_gap/record_mapping, to actually reflect reality.  IMO
   3517       (JRS, 2010-Jan-03) the fact that /proc/.../maps does not list
   3518       the commpage should be regarded as a bug in the kernel. */
   3519    { const Addr commpage_start = ARM_LINUX_FAKE_COMMPAGE_START;
   3520      const Addr commpage_end1  = ARM_LINUX_FAKE_COMMPAGE_END1;
   3521      if (gapStart < commpage_start) {
   3522         if (record_gap)
   3523            (*record_gap)( gapStart, commpage_start - gapStart );
   3524         if (record_mapping)
   3525            (*record_mapping)( commpage_start, commpage_end1 - commpage_start,
   3526                               VKI_PROT_READ|VKI_PROT_EXEC,
   3527                               0/*dev*/, 0/*ino*/, 0/*foffset*/,
   3528                               NULL);
   3529         gapStart = commpage_end1;
   3530      }
   3531    }
   3532 #  endif
   3533 
   3534    if (record_gap && gapStart < Addr_MAX)
   3535       (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
   3536 }
   3537 
   3538 /*------END-procmaps-parser-for-Linux----------------------------*/
   3539 
   3540 /*------BEGIN-procmaps-parser-for-Darwin-------------------------*/
   3541 
   3542 #elif defined(VGO_darwin)
   3543 #include <mach/mach.h>
   3544 #include <mach/mach_vm.h>
   3545 
   3546 static unsigned int mach2vki(unsigned int vm_prot)
   3547 {
   3548    return
   3549       ((vm_prot & VM_PROT_READ)    ? VKI_PROT_READ    : 0) |
   3550       ((vm_prot & VM_PROT_WRITE)   ? VKI_PROT_WRITE   : 0) |
   3551       ((vm_prot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC    : 0) ;
   3552 }
   3553 
   3554 static UInt stats_machcalls = 0;
   3555 
   3556 static void parse_procselfmaps (
   3557       void (*record_mapping)( Addr addr, SizeT len, UInt prot,
   3558                               ULong dev, ULong ino, Off64T offset,
   3559                               const HChar* filename ),
   3560       void (*record_gap)( Addr addr, SizeT len )
   3561    )
   3562 {
   3563    vm_address_t iter;
   3564    unsigned int depth;
   3565    vm_address_t last;
   3566 
   3567    iter = 0;
   3568    depth = 0;
   3569    last = 0;
   3570    while (1) {
   3571       mach_vm_address_t addr = iter;
   3572       mach_vm_size_t size;
   3573       vm_region_submap_short_info_data_64_t info;
   3574       kern_return_t kr;
   3575 
   3576       while (1) {
   3577          mach_msg_type_number_t info_count
   3578             = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
   3579          stats_machcalls++;
   3580          kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth,
   3581                                      (vm_region_info_t)&info, &info_count);
   3582          if (kr)
   3583             return;
   3584          if (info.is_submap) {
   3585             depth++;
   3586             continue;
   3587          }
   3588          break;
   3589       }
   3590       iter = addr + size;
   3591 
   3592       if (addr > last  &&  record_gap) {
   3593          (*record_gap)(last, addr - last);
   3594       }
   3595       if (record_mapping) {
   3596          (*record_mapping)(addr, size, mach2vki(info.protection),
   3597                            0, 0, info.offset, NULL);
   3598       }
   3599       last = addr + size;
   3600    }
   3601 
   3602    if ((Addr)-1 > last  &&  record_gap)
   3603       (*record_gap)(last, (Addr)-1 - last);
   3604 }
   3605 
   3606 // Urr.  So much for thread safety.
   3607 static Bool        css_overflowed;
   3608 static ChangedSeg* css_local;
   3609 static Int         css_size_local;
   3610 static Int         css_used_local;
   3611 
   3612 static Addr Addr__max ( Addr a, Addr b ) { return a > b ? a : b; }
   3613 static Addr Addr__min ( Addr a, Addr b ) { return a < b ? a : b; }
   3614 
   3615 static void add_mapping_callback(Addr addr, SizeT len, UInt prot,
   3616                                  ULong dev, ULong ino, Off64T offset,
   3617                                  const HChar *filename)
   3618 {
   3619    // derived from sync_check_mapping_callback()
   3620 
   3621    /* JRS 2012-Mar-07: this all seems very dubious to me.  It would be
   3622       safer to see if we can find, in V's segment collection, one
   3623       single segment that completely covers the range [addr, +len)
   3624       (and possibly more), and that has the exact same other
   3625       properties (prot, dev, ino, offset, etc) as the data presented
   3626       here.  If found, we just skip.  Otherwise add the data presented
   3627       here into css_local[]. */
   3628 
   3629    Int iLo, iHi, i;
   3630 
   3631    if (len == 0) return;
   3632 
   3633    /* The kernel should not give us wraparounds. */
   3634    aspacem_assert(addr <= addr + len - 1);
   3635 
   3636    iLo = find_nsegment_idx( addr );
   3637    iHi = find_nsegment_idx( addr + len - 1 );
   3638 
   3639    /* NSegments iLo .. iHi inclusive should agree with the presented
   3640       data. */
   3641    for (i = iLo; i <= iHi; i++) {
   3642 
   3643       UInt seg_prot;
   3644 
   3645       if (nsegments[i].kind == SkAnonV  ||  nsegments[i].kind == SkFileV) {
   3646          /* Ignore V regions */
   3647          continue;
   3648       }
   3649       else if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) {
   3650          /* Add mapping for SkResvn regions */
   3651          ChangedSeg* cs = &css_local[css_used_local];
   3652          if (css_used_local < css_size_local) {
   3653             cs->is_added = True;
   3654             cs->start    = addr;
   3655             cs->end      = addr + len - 1;
   3656             cs->prot     = prot;
   3657             cs->offset   = offset;
   3658             css_used_local++;
   3659          } else {
   3660             css_overflowed = True;
   3661          }
   3662          return;
   3663 
   3664       }
   3665       else if (nsegments[i].kind == SkAnonC ||
   3666                nsegments[i].kind == SkFileC ||
   3667                nsegments[i].kind == SkShmC)
   3668       {
   3669          /* Check permissions on client regions */
   3670          // GrP fixme
   3671          seg_prot = 0;
   3672          if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
   3673          if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
   3674 #        if defined(VGA_x86)
   3675          // GrP fixme sloppyXcheck
   3676          // darwin: kernel X ignored and spuriously changes? (vm_copy)
   3677          seg_prot |= (prot & VKI_PROT_EXEC);
   3678 #        else
   3679          if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
   3680 #        endif
   3681          if (seg_prot != prot) {
   3682              if (VG_(clo_trace_syscalls))
   3683                  VG_(debugLog)(0,"aspacem","region %p..%p permission "
   3684                                  "mismatch (kernel %x, V %x)\n",
   3685                                  (void*)nsegments[i].start,
   3686                                  (void*)(nsegments[i].end+1), prot, seg_prot);
   3687             /* Add mapping for regions with protection changes */
   3688             ChangedSeg* cs = &css_local[css_used_local];
   3689             if (css_used_local < css_size_local) {
   3690                cs->is_added = True;
   3691                cs->start    = addr;
   3692                cs->end      = addr + len - 1;
   3693                cs->prot     = prot;
   3694                cs->offset   = offset;
   3695                css_used_local++;
   3696             } else {
   3697                css_overflowed = True;
   3698             }
   3699 	    return;
   3700 
   3701          }
   3702 
   3703       } else {
   3704          aspacem_assert(0);
   3705       }
   3706    }
   3707 }
   3708 
   3709 static void remove_mapping_callback(Addr addr, SizeT len)
   3710 {
   3711    // derived from sync_check_gap_callback()
   3712 
   3713    Int iLo, iHi, i;
   3714 
   3715    if (len == 0)
   3716       return;
   3717 
   3718    /* The kernel should not give us wraparounds. */
   3719    aspacem_assert(addr <= addr + len - 1);
   3720 
   3721    iLo = find_nsegment_idx( addr );
   3722    iHi = find_nsegment_idx( addr + len - 1 );
   3723 
   3724    /* NSegments iLo .. iHi inclusive should agree with the presented data. */
   3725    for (i = iLo; i <= iHi; i++) {
   3726       if (nsegments[i].kind != SkFree && nsegments[i].kind != SkResvn) {
   3727          /* V has a mapping, kernel doesn't.  Add to css_local[],
   3728             directives to chop off the part of the V mapping that
   3729             falls within the gap that the kernel tells us is
   3730             present. */
   3731          ChangedSeg* cs = &css_local[css_used_local];
   3732          if (css_used_local < css_size_local) {
   3733             cs->is_added = False;
   3734             cs->start    = Addr__max(nsegments[i].start, addr);
   3735             cs->end      = Addr__min(nsegments[i].end,   addr + len - 1);
   3736             aspacem_assert(VG_IS_PAGE_ALIGNED(cs->start));
   3737             aspacem_assert(VG_IS_PAGE_ALIGNED(cs->end+1));
   3738             /* I don't think the following should fail.  But if it
   3739                does, just omit the css_used_local++ in the cases where
   3740                it doesn't hold. */
   3741             aspacem_assert(cs->start < cs->end);
   3742             cs->prot     = 0;
   3743             cs->offset   = 0;
   3744             css_used_local++;
   3745          } else {
   3746             css_overflowed = True;
   3747          }
   3748       }
   3749    }
   3750 }
   3751 
   3752 
   3753 // Returns False if 'css' wasn't big enough.
   3754 Bool VG_(get_changed_segments)(
   3755       const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css,
   3756       Int css_size, /*OUT*/Int* css_used)
   3757 {
   3758    static UInt stats_synccalls = 1;
   3759    aspacem_assert(when && where);
   3760 
   3761    if (0)
   3762       VG_(debugLog)(0,"aspacem",
   3763          "[%u,%u] VG_(get_changed_segments)(%s, %s)\n",
   3764          stats_synccalls++, stats_machcalls, when, where
   3765       );
   3766 
   3767    css_overflowed = False;
   3768    css_local = css;
   3769    css_size_local = css_size;
   3770    css_used_local = 0;
   3771 
   3772    // Get the list of segs that need to be added/removed.
   3773    parse_procselfmaps(&add_mapping_callback, &remove_mapping_callback);
   3774 
   3775    *css_used = css_used_local;
   3776 
   3777    if (css_overflowed) {
   3778       aspacem_assert(css_used_local == css_size_local);
   3779    }
   3780 
   3781    return !css_overflowed;
   3782 }
   3783 
   3784 #endif // defined(VGO_darwin)
   3785 
   3786 /*------END-procmaps-parser-for-Darwin---------------------------*/
   3787 
   3788 /*------BEGIN-procmaps-parser-for-Solaris------------------------*/
   3789 
   3790 #if defined(VGO_solaris)
   3791 
   3792 /* Note: /proc/self/xmap contains extended information about already
   3793    materialized mappings whereas /proc/self/rmap contains information about
   3794    all mappings including reserved but yet-to-materialize mappings (mmap'ed
   3795    with MAP_NORESERVE flag, such as thread stacks). But /proc/self/rmap does
   3796    not contain extended information found in /proc/self/xmap. Therefore
   3797    information from both sources need to be combined.
   3798  */
   3799 
   3800 typedef struct
   3801 {
   3802    Addr   addr;
   3803    SizeT  size;
   3804    UInt   prot;
   3805    ULong  dev;
   3806    ULong  ino;
   3807    Off64T foffset;
   3808    HChar  filename[VKI_PATH_MAX];
   3809 } Mapping;
   3810 
   3811 static SizeT read_proc_file(const HChar *filename, HChar *buf,
   3812                             SizeT buf_size, const HChar *buf_size_name,
   3813                             SizeT entry_size)
   3814 {
   3815    SysRes res = ML_(am_open)(filename, VKI_O_RDONLY, 0);
   3816    if (sr_isError(res)) {
   3817       HChar message[100];
   3818       ML_(am_sprintf)(message, "Cannot open %s.", filename);
   3819       ML_(am_barf)(message);
   3820    }
   3821    Int fd = sr_Res(res);
   3822 
   3823    Int r = ML_(am_read)(fd, buf, buf_size);
   3824    ML_(am_close)(fd);
   3825    if (r < 0) {
   3826       HChar message[100];
   3827       ML_(am_sprintf)(message, "I/O error on %s.", filename);
   3828       ML_(am_barf)(message);
   3829    }
   3830 
   3831    if (r >= buf_size)
   3832       ML_(am_barf_toolow)(buf_size_name);
   3833 
   3834    if (r % entry_size != 0) {
   3835       HChar message[100];
   3836       ML_(am_sprintf)(message, "Bogus values read from %s.", filename);
   3837       ML_(am_barf)(message);
   3838    }
   3839 
   3840    return r / entry_size;
   3841 }
   3842 
   3843 static Mapping *next_xmap(const HChar *buffer, SizeT entries, SizeT *idx,
   3844                           Mapping *mapping)
   3845 {
   3846    aspacem_assert(idx);
   3847    aspacem_assert(mapping);
   3848 
   3849    if (*idx >= entries)
   3850       return NULL; /* No more entries */
   3851 
   3852    const vki_prxmap_t *map = (const vki_prxmap_t *)buffer + *idx;
   3853 
   3854    mapping->addr = map->pr_vaddr;
   3855    mapping->size = map->pr_size;
   3856 
   3857    mapping->prot = 0;
   3858    if (map->pr_mflags & VKI_MA_READ)
   3859       mapping->prot |= VKI_PROT_READ;
   3860    if (map->pr_mflags & VKI_MA_WRITE)
   3861       mapping->prot |= VKI_PROT_WRITE;
   3862    if (map->pr_mflags & VKI_MA_EXEC)
   3863       mapping->prot |= VKI_PROT_EXEC;
   3864 
   3865    if (map->pr_dev != VKI_PRNODEV) {
   3866       mapping->dev = map->pr_dev;
   3867       mapping->ino = map->pr_ino;
   3868       mapping->foffset = map->pr_offset;
   3869    }
   3870    else {
   3871       mapping->dev = 0;
   3872       mapping->ino = 0;
   3873       mapping->foffset = 0;
   3874    }
   3875 
   3876    /* Try to get the filename. */
   3877    mapping->filename[0] = '\0';
   3878    if (map->pr_mapname[0] != '\0') {
   3879       ML_(am_sprintf)(mapping->filename, "/proc/self/path/%s",
   3880                       map->pr_mapname);
   3881       Int r = ML_(am_readlink)(mapping->filename, mapping->filename,
   3882                                sizeof(mapping->filename) - 1);
   3883       if (r == -1) {
   3884          /* If Valgrind is executed in a non-global zone and the link in
   3885             /proc/self/path/ represents a file that is available through lofs
   3886             from a global zone then the kernel may not be able to resolve the
   3887             link.
   3888 
   3889             In such a case, return a corresponding /proc/self/object/ file to
   3890             allow Valgrind to read the file if it is necessary.
   3891 
   3892             This can create some discrepancy for the sanity check. For
   3893             instance, if a client program mmaps some file then the address
   3894             space manager will have a correct zone-local name of that file,
   3895             but the sanity check will receive a different file name from this
   3896             code. This currently does not represent a problem because the
   3897             sanity check ignores the file names (it uses device and inode
   3898             numbers for the comparison).
   3899           */
   3900          ML_(am_sprintf)(mapping->filename, "/proc/self/object/%s",
   3901                          map->pr_mapname);
   3902       }
   3903       else {
   3904          aspacem_assert(r >= 0);
   3905          mapping->filename[r] = '\0';
   3906       }
   3907    }
   3908 
   3909    *idx += 1;
   3910    return mapping;
   3911 }
   3912 
   3913 static Mapping *next_rmap(const HChar *buffer, SizeT entries, SizeT *idx,
   3914                           Mapping *mapping)
   3915 {
   3916    aspacem_assert(idx);
   3917    aspacem_assert(mapping);
   3918 
   3919    if (*idx >= entries)
   3920       return NULL; /* No more entries */
   3921 
   3922    const vki_prmap_t *map = (const vki_prmap_t *)buffer + *idx;
   3923 
   3924    mapping->addr = map->pr_vaddr;
   3925    mapping->size = map->pr_size;
   3926 
   3927    mapping->prot = 0;
   3928    if (map->pr_mflags & VKI_MA_READ)
   3929       mapping->prot |= VKI_PROT_READ;
   3930    if (map->pr_mflags & VKI_MA_WRITE)
   3931       mapping->prot |= VKI_PROT_WRITE;
   3932    if (map->pr_mflags & VKI_MA_EXEC)
   3933       mapping->prot |= VKI_PROT_EXEC;
   3934 
   3935    mapping->dev = 0;
   3936    mapping->ino = 0;
   3937    mapping->foffset = 0;
   3938    mapping->filename[0] = '\0';
   3939 
   3940    *idx += 1;
   3941    return mapping;
   3942 }
   3943 
   3944 /* Used for two purposes:
   3945    1. Establish initial mappings upon the process startup
   3946    2. Check mappings during aspacemgr sanity check
   3947  */
   3948 static void parse_procselfmaps (
   3949       void (*record_mapping)( Addr addr, SizeT len, UInt prot,
   3950                               ULong dev, ULong ino, Off64T offset,
   3951                               const HChar *filename ),
   3952       void (*record_gap)( Addr addr, SizeT len )
   3953    )
   3954 {
   3955    Addr start = Addr_MIN;
   3956    Addr gap_start = Addr_MIN;
   3957 
   3958 #define M_XMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prxmap_t))
   3959    /* Static to keep it out of stack frame... */
   3960    static HChar xmap_buf[M_XMAP_BUF];
   3961    const Mapping *xmap = NULL;
   3962    SizeT xmap_index = 0; /* Current entry */
   3963    SizeT xmap_entries;
   3964    Mapping xmap_mapping;
   3965    Bool advance_xmap;
   3966 
   3967 #define M_RMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prmap_t))
   3968    static HChar rmap_buf[M_RMAP_BUF];
   3969    const Mapping *rmap = NULL;
   3970    SizeT rmap_index = 0; /* Current entry */
   3971    SizeT rmap_entries;
   3972    Mapping rmap_mapping;
   3973    Bool advance_rmap;
   3974 
   3975    /* Read fully /proc/self/xmap and /proc/self/rmap. */
   3976    xmap_entries = read_proc_file("/proc/self/xmap", xmap_buf, M_XMAP_BUF,
   3977                                  "M_XMAP_BUF", sizeof(vki_prxmap_t));
   3978 
   3979    rmap_entries = read_proc_file("/proc/self/rmap", rmap_buf, M_RMAP_BUF,
   3980                                  "M_RMAP_BUF", sizeof(vki_prmap_t));
   3981 
   3982    /* Get the first xmap and rmap. */
   3983    advance_xmap = True;
   3984    advance_rmap = True;
   3985 
   3986    while (1) {
   3987       /* Get next xmap or rmap if necessary. */
   3988       if (advance_xmap) {
   3989          xmap = next_xmap(xmap_buf, xmap_entries, &xmap_index, &xmap_mapping);
   3990          advance_xmap = False;
   3991       }
   3992       if (advance_rmap) {
   3993          rmap = next_rmap(rmap_buf, rmap_entries, &rmap_index, &rmap_mapping);
   3994          advance_rmap = False;
   3995       }
   3996 
   3997       /* Check if the end has been reached. */
   3998       if (rmap == NULL)
   3999          break;
   4000 
   4001       /* Invariants */
   4002       if (xmap != NULL) {
   4003          aspacem_assert(start <= xmap->addr);
   4004          aspacem_assert(rmap->addr <= xmap->addr);
   4005       }
   4006 
   4007       if (xmap != NULL && start == xmap->addr) {
   4008          /* xmap mapping reached. */
   4009          aspacem_assert(xmap->addr >= rmap->addr &&
   4010                         xmap->addr + xmap->size <= rmap->addr + rmap->size);
   4011          aspacem_assert(xmap->prot == rmap->prot);
   4012 
   4013          if (record_mapping != NULL)
   4014             (*record_mapping)(xmap->addr, xmap->size, xmap->prot, xmap->dev,
   4015                               xmap->ino, xmap->foffset,
   4016                               (xmap->filename[0] != '\0') ?
   4017                                xmap->filename : NULL);
   4018 
   4019          start = xmap->addr + xmap->size;
   4020          advance_xmap = True;
   4021       }
   4022       else if (start >= rmap->addr) {
   4023          /* Reserved-only part. */
   4024          /* First calculate size until the end of this reserved mapping... */
   4025          SizeT size = rmap->addr + rmap->size - start;
   4026          /* ... but shrink it if some xmap is in a way. */
   4027          if (xmap != NULL && size > xmap->addr - start)
   4028             size = xmap->addr - start;
   4029 
   4030          if (record_mapping != NULL)
   4031             (*record_mapping)(start, size, rmap->prot, 0, 0, 0, NULL);
   4032          start += size;
   4033       }
   4034       else {
   4035          /* Gap. */
   4036          if (record_gap != NULL && gap_start < start)
   4037             (*record_gap)(gap_start, start - gap_start);
   4038          start = rmap->addr;
   4039       }
   4040 
   4041       if (rmap->addr + rmap->size <= start)
   4042          advance_rmap = True;
   4043 
   4044       gap_start = start;
   4045    }
   4046 
   4047    if (record_gap != NULL && gap_start < Addr_MAX)
   4048       (*record_gap)(gap_start, Addr_MAX - gap_start + 1);
   4049 }
   4050 
   4051 #endif // defined(VGO_solaris)
   4052 
   4053 /*------END-procmaps-parser-for-Solaris--------------------------*/
   4054 
   4055 #endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
   4056 
   4057 /*--------------------------------------------------------------------*/
   4058 /*--- end                                                          ---*/
   4059 /*--------------------------------------------------------------------*/
   4060