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-2017 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 separation 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 #  ifdef N_Q_M_STATS
   1086    static UWord n_q = 0;
   1087    static UWord n_m = 0;
   1088    n_q++;
   1089    if (0 == (n_q & 0xFFFF))
   1090       VG_(debugLog)(0,"xxx","find_nsegment_idx: %lu %lu\n", n_q, n_m);
   1091 #  endif
   1092 
   1093    UWord ix;
   1094 
   1095    if (LIKELY(cache_inited)) {
   1096       /* do nothing */
   1097    } else {
   1098       for (ix = 0; ix < N_CACHE; ix++) {
   1099          cache_pageno[ix] = 0;
   1100          cache_segidx[ix] = -1;
   1101       }
   1102       cache_inited = True;
   1103    }
   1104 
   1105    ix = (a >> 12) % N_CACHE;
   1106 
   1107    if ((a >> 12) == cache_pageno[ix]
   1108        && cache_segidx[ix] >= 0
   1109        && cache_segidx[ix] < nsegments_used
   1110        && nsegments[cache_segidx[ix]].start <= a
   1111        && a <= nsegments[cache_segidx[ix]].end) {
   1112       /* hit */
   1113       /* aspacem_assert( cache_segidx[ix] == find_nsegment_idx_WRK(a) ); */
   1114       return cache_segidx[ix];
   1115    }
   1116    /* miss */
   1117 #  ifdef N_Q_M_STATS
   1118    n_m++;
   1119 #  endif
   1120    cache_segidx[ix] = find_nsegment_idx_WRK(a);
   1121    cache_pageno[ix] = a >> 12;
   1122    return cache_segidx[ix];
   1123 #  undef N_CACHE
   1124 }
   1125 
   1126 
   1127 /* Finds the segment containing 'a'.  Only returns non-SkFree segments. */
   1128 NSegment const * VG_(am_find_nsegment) ( Addr a )
   1129 {
   1130    Int i = find_nsegment_idx(a);
   1131    aspacem_assert(i >= 0 && i < nsegments_used);
   1132    aspacem_assert(nsegments[i].start <= a);
   1133    aspacem_assert(a <= nsegments[i].end);
   1134    if (nsegments[i].kind == SkFree)
   1135       return NULL;
   1136    else
   1137       return &nsegments[i];
   1138 }
   1139 
   1140 /* Finds an anonymous segment containing 'a'. Returned pointer is read only. */
   1141 NSegment const *VG_(am_find_anon_segment) ( Addr a )
   1142 {
   1143    Int i = find_nsegment_idx(a);
   1144    aspacem_assert(i >= 0 && i < nsegments_used);
   1145    aspacem_assert(nsegments[i].start <= a);
   1146    aspacem_assert(a <= nsegments[i].end);
   1147    if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV)
   1148       return &nsegments[i];
   1149    else
   1150       return NULL;
   1151 }
   1152 
   1153 /* Map segment pointer to segment index. */
   1154 static Int segAddr_to_index ( const NSegment* seg )
   1155 {
   1156    aspacem_assert(seg >= &nsegments[0] && seg < &nsegments[nsegments_used]);
   1157 
   1158    return seg - &nsegments[0];
   1159 }
   1160 
   1161 
   1162 /* Find the next segment along from 'here', if it is a non-SkFree segment. */
   1163 NSegment const * VG_(am_next_nsegment) ( const NSegment* here, Bool fwds )
   1164 {
   1165    Int i = segAddr_to_index(here);
   1166 
   1167    if (fwds) {
   1168       i++;
   1169       if (i >= nsegments_used)
   1170          return NULL;
   1171    } else {
   1172       i--;
   1173       if (i < 0)
   1174          return NULL;
   1175    }
   1176    if (nsegments[i].kind == SkFree)
   1177       return NULL;
   1178    else
   1179       return &nsegments[i];
   1180 }
   1181 
   1182 
   1183 /* Trivial fn: return the total amount of space in anonymous mappings,
   1184    both for V and the client.  Is used for printing stats in
   1185    out-of-memory messages. */
   1186 ULong VG_(am_get_anonsize_total)( void )
   1187 {
   1188    Int   i;
   1189    ULong total = 0;
   1190    for (i = 0; i < nsegments_used; i++) {
   1191       if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV) {
   1192          total += (ULong)nsegments[i].end
   1193                   - (ULong)nsegments[i].start + 1ULL;
   1194       }
   1195    }
   1196    return total;
   1197 }
   1198 
   1199 
   1200 /* Test if a piece of memory is addressable by client or by valgrind with at
   1201    least the "prot" protection permissions by examining the underlying
   1202    segments. The KINDS argument specifies the allowed segments ADDR may
   1203    belong to in order to be considered "valid".
   1204 */
   1205 static
   1206 Bool is_valid_for( UInt kinds, Addr start, SizeT len, UInt prot )
   1207 {
   1208    Int  i, iLo, iHi;
   1209    Bool needR, needW, needX;
   1210 
   1211    if (len == 0)
   1212       return True; /* somewhat dubious case */
   1213    if (start + len < start)
   1214       return False; /* reject wraparounds */
   1215 
   1216    needR = toBool(prot & VKI_PROT_READ);
   1217    needW = toBool(prot & VKI_PROT_WRITE);
   1218    needX = toBool(prot & VKI_PROT_EXEC);
   1219 
   1220    iLo = find_nsegment_idx(start);
   1221    aspacem_assert(start >= nsegments[iLo].start);
   1222 
   1223    if (start+len-1 <= nsegments[iLo].end) {
   1224       /* This is a speedup hack which avoids calling find_nsegment_idx
   1225          a second time when possible.  It is always correct to just
   1226          use the "else" clause below, but is_valid_for_client is
   1227          called a lot by the leak checker, so avoiding pointless calls
   1228          to find_nsegment_idx, which can be expensive, is helpful. */
   1229       iHi = iLo;
   1230    } else {
   1231       iHi = find_nsegment_idx(start + len - 1);
   1232    }
   1233 
   1234    for (i = iLo; i <= iHi; i++) {
   1235       if ( (nsegments[i].kind & kinds) != 0
   1236            && (needR ? nsegments[i].hasR : True)
   1237            && (needW ? nsegments[i].hasW : True)
   1238            && (needX ? nsegments[i].hasX : True) ) {
   1239          /* ok */
   1240       } else {
   1241          return False;
   1242       }
   1243    }
   1244 
   1245    return True;
   1246 }
   1247 
   1248 /* Test if a piece of memory is addressable by the client with at
   1249    least the "prot" protection permissions by examining the underlying
   1250    segments. */
   1251 Bool VG_(am_is_valid_for_client)( Addr start, SizeT len,
   1252                                   UInt prot )
   1253 {
   1254    const UInt kinds = SkFileC | SkAnonC | SkShmC;
   1255 
   1256    return is_valid_for(kinds, start, len, prot);
   1257 }
   1258 
   1259 /* Variant of VG_(am_is_valid_for_client) which allows free areas to
   1260    be consider part of the client's addressable space.  It also
   1261    considers reservations to be allowable, since from the client's
   1262    point of view they don't exist. */
   1263 Bool VG_(am_is_valid_for_client_or_free_or_resvn)
   1264    ( Addr start, SizeT len, UInt prot )
   1265 {
   1266    const UInt kinds = SkFileC | SkAnonC | SkShmC | SkFree | SkResvn;
   1267 
   1268    return is_valid_for(kinds, start, len, prot);
   1269 }
   1270 
   1271 /* Checks if a piece of memory consists of either free or reservation
   1272    segments. */
   1273 Bool VG_(am_is_free_or_resvn)( Addr start, SizeT len )
   1274 {
   1275    const UInt kinds = SkFree | SkResvn;
   1276 
   1277    return is_valid_for(kinds, start, len, 0);
   1278 }
   1279 
   1280 
   1281 Bool VG_(am_is_valid_for_valgrind) ( Addr start, SizeT len, UInt prot )
   1282 {
   1283    const UInt kinds = SkFileV | SkAnonV;
   1284 
   1285    return is_valid_for(kinds, start, len, prot);
   1286 }
   1287 
   1288 
   1289 /* Returns True if any part of the address range is marked as having
   1290    translations made from it.  This is used to determine when to
   1291    discard code, so if in doubt return True. */
   1292 
   1293 static Bool any_Ts_in_range ( Addr start, SizeT len )
   1294 {
   1295    Int iLo, iHi, i;
   1296    aspacem_assert(len > 0);
   1297    aspacem_assert(start + len > start);
   1298    iLo = find_nsegment_idx(start);
   1299    iHi = find_nsegment_idx(start + len - 1);
   1300    for (i = iLo; i <= iHi; i++) {
   1301       if (nsegments[i].hasT)
   1302          return True;
   1303    }
   1304    return False;
   1305 }
   1306 
   1307 
   1308 /* Check whether ADDR looks like an address or address-to-be located in an
   1309    extensible client stack segment. Return true if
   1310    (1) ADDR is located in an already mapped stack segment, OR
   1311    (2) ADDR is located in a reservation segment into which an abutting SkAnonC
   1312        segment can be extended. */
   1313 Bool VG_(am_addr_is_in_extensible_client_stack)( Addr addr )
   1314 {
   1315    const NSegment *seg = nsegments + find_nsegment_idx(addr);
   1316 
   1317    switch (seg->kind) {
   1318    case SkFree:
   1319    case SkAnonV:
   1320    case SkFileV:
   1321    case SkFileC:
   1322    case SkShmC:
   1323       return False;
   1324 
   1325    case SkResvn: {
   1326       if (seg->smode != SmUpper) return False;
   1327       /* If the abutting segment towards higher addresses is an SkAnonC
   1328          segment, then ADDR is a future stack pointer. */
   1329       const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ True);
   1330       if (next == NULL || next->kind != SkAnonC) return False;
   1331 
   1332       /* OK; looks like a stack segment */
   1333       return True;
   1334    }
   1335 
   1336    case SkAnonC: {
   1337       /* If the abutting segment towards lower addresses is an SkResvn
   1338          segment, then ADDR is a stack pointer into mapped memory. */
   1339       const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ False);
   1340       if (next == NULL || next->kind != SkResvn || next->smode != SmUpper)
   1341          return False;
   1342 
   1343       /* OK; looks like a stack segment */
   1344       return True;
   1345    }
   1346 
   1347    default:
   1348       aspacem_assert(0);   // should never happen
   1349    }
   1350 }
   1351 
   1352 /*-----------------------------------------------------------------*/
   1353 /*---                                                           ---*/
   1354 /*--- Modifying the segment array, and constructing segments.   ---*/
   1355 /*---                                                           ---*/
   1356 /*-----------------------------------------------------------------*/
   1357 
   1358 /* Split the segment containing 'a' into two, so that 'a' is
   1359    guaranteed to be the start of a new segment.  If 'a' is already the
   1360    start of a segment, do nothing. */
   1361 
   1362 static void split_nsegment_at ( Addr a )
   1363 {
   1364    Int i, j;
   1365 
   1366    aspacem_assert(a > 0);
   1367    aspacem_assert(VG_IS_PAGE_ALIGNED(a));
   1368 
   1369    i = find_nsegment_idx(a);
   1370    aspacem_assert(i >= 0 && i < nsegments_used);
   1371 
   1372    if (nsegments[i].start == a)
   1373       /* 'a' is already the start point of a segment, so nothing to be
   1374          done. */
   1375       return;
   1376 
   1377    /* else we have to slide the segments upwards to make a hole */
   1378    if (nsegments_used >= VG_N_SEGMENTS)
   1379       ML_(am_barf_toolow)("VG_N_SEGMENTS");
   1380    for (j = nsegments_used-1; j > i; j--)
   1381       nsegments[j+1] = nsegments[j];
   1382    nsegments_used++;
   1383 
   1384    nsegments[i+1]       = nsegments[i];
   1385    nsegments[i+1].start = a;
   1386    nsegments[i].end     = a-1;
   1387 
   1388    if (nsegments[i].kind == SkFileV || nsegments[i].kind == SkFileC)
   1389       nsegments[i+1].offset
   1390          += ((ULong)nsegments[i+1].start) - ((ULong)nsegments[i].start);
   1391 
   1392    ML_(am_inc_refcount)(nsegments[i].fnIdx);
   1393 
   1394    aspacem_assert(sane_NSegment(&nsegments[i]));
   1395    aspacem_assert(sane_NSegment(&nsegments[i+1]));
   1396 }
   1397 
   1398 
   1399 /* Do the minimum amount of segment splitting necessary to ensure that
   1400    sLo is the first address denoted by some segment and sHi is the
   1401    highest address denoted by some other segment.  Returns the indices
   1402    of the lowest and highest segments in the range. */
   1403 
   1404 static
   1405 void split_nsegments_lo_and_hi ( Addr sLo, Addr sHi,
   1406                                  /*OUT*/Int* iLo,
   1407                                  /*OUT*/Int* iHi )
   1408 {
   1409    aspacem_assert(sLo < sHi);
   1410    aspacem_assert(VG_IS_PAGE_ALIGNED(sLo));
   1411    aspacem_assert(VG_IS_PAGE_ALIGNED(sHi+1));
   1412 
   1413    if (sLo > 0)
   1414       split_nsegment_at(sLo);
   1415    if (sHi < sHi+1)
   1416       split_nsegment_at(sHi+1);
   1417 
   1418    *iLo = find_nsegment_idx(sLo);
   1419    *iHi = find_nsegment_idx(sHi);
   1420    aspacem_assert(0 <= *iLo && *iLo < nsegments_used);
   1421    aspacem_assert(0 <= *iHi && *iHi < nsegments_used);
   1422    aspacem_assert(*iLo <= *iHi);
   1423    aspacem_assert(nsegments[*iLo].start == sLo);
   1424    aspacem_assert(nsegments[*iHi].end == sHi);
   1425    /* Not that I'm overly paranoid or anything, definitely not :-) */
   1426 }
   1427 
   1428 
   1429 /* Add SEG to the collection, deleting/truncating any it overlaps.
   1430    This deals with all the tricky cases of splitting up segments as
   1431    needed. */
   1432 
   1433 static void add_segment ( const NSegment* seg )
   1434 {
   1435    Int  i, iLo, iHi, delta;
   1436    Bool segment_is_sane;
   1437 
   1438    Addr sStart = seg->start;
   1439    Addr sEnd   = seg->end;
   1440 
   1441    aspacem_assert(sStart <= sEnd);
   1442    aspacem_assert(VG_IS_PAGE_ALIGNED(sStart));
   1443    aspacem_assert(VG_IS_PAGE_ALIGNED(sEnd+1));
   1444 
   1445    segment_is_sane = sane_NSegment(seg);
   1446    if (!segment_is_sane) show_nsegment_full(0,-1,seg);
   1447    aspacem_assert(segment_is_sane);
   1448 
   1449    split_nsegments_lo_and_hi( sStart, sEnd, &iLo, &iHi );
   1450 
   1451    /* Increase the reference count of SEG's name. We need to do this
   1452       *before* decreasing the reference count of the names of the replaced
   1453       segments. Consider the case where the segment name of SEG and one of
   1454       the replaced segments are the same. If the refcount of that name is 1,
   1455       then decrementing first would put the slot for that name on the free
   1456       list. Attempting to increment the refcount later would then fail
   1457       because the slot is no longer allocated. */
   1458    ML_(am_inc_refcount)(seg->fnIdx);
   1459 
   1460    /* Now iLo .. iHi inclusive is the range of segment indices which
   1461       seg will replace.  If we're replacing more than one segment,
   1462       slide those above the range down to fill the hole. Before doing
   1463       that decrement the reference counters for the segments names of
   1464       the replaced segments. */
   1465    for (i = iLo; i <= iHi; ++i)
   1466       ML_(am_dec_refcount)(nsegments[i].fnIdx);
   1467    delta = iHi - iLo;
   1468    aspacem_assert(delta >= 0);
   1469    if (delta > 0) {
   1470       for (i = iLo; i < nsegments_used-delta; i++)
   1471          nsegments[i] = nsegments[i+delta];
   1472       nsegments_used -= delta;
   1473    }
   1474 
   1475    nsegments[iLo] = *seg;
   1476 
   1477    (void)preen_nsegments();
   1478    if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)");
   1479 }
   1480 
   1481 
   1482 /* Clear out an NSegment record. */
   1483 
   1484 static void init_nsegment ( /*OUT*/NSegment* seg )
   1485 {
   1486    seg->kind     = SkFree;
   1487    seg->start    = 0;
   1488    seg->end      = 0;
   1489    seg->smode    = SmFixed;
   1490    seg->dev      = 0;
   1491    seg->ino      = 0;
   1492    seg->mode     = 0;
   1493    seg->offset   = 0;
   1494    seg->fnIdx    = -1;
   1495    seg->hasR = seg->hasW = seg->hasX = seg->hasT = seg->isCH = False;
   1496 }
   1497 
   1498 /* Make an NSegment which holds a reservation. */
   1499 
   1500 static void init_resvn ( /*OUT*/NSegment* seg, Addr start, Addr end )
   1501 {
   1502    aspacem_assert(start < end);
   1503    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
   1504    aspacem_assert(VG_IS_PAGE_ALIGNED(end+1));
   1505    init_nsegment(seg);
   1506    seg->kind  = SkResvn;
   1507    seg->start = start;
   1508    seg->end   = end;
   1509 }
   1510 
   1511 
   1512 /*-----------------------------------------------------------------*/
   1513 /*---                                                           ---*/
   1514 /*--- Startup, including reading /proc/self/maps.               ---*/
   1515 /*---                                                           ---*/
   1516 /*-----------------------------------------------------------------*/
   1517 
   1518 static void read_maps_callback ( Addr addr, SizeT len, UInt prot,
   1519                                  ULong dev, ULong ino, Off64T offset,
   1520                                  const HChar* filename )
   1521 {
   1522    NSegment seg;
   1523    init_nsegment( &seg );
   1524    seg.start  = addr;
   1525    seg.end    = addr+len-1;
   1526    seg.dev    = dev;
   1527    seg.ino    = ino;
   1528    seg.offset = offset;
   1529    seg.hasR   = toBool(prot & VKI_PROT_READ);
   1530    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
   1531    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
   1532    seg.hasT   = False;
   1533 
   1534    /* A segment in the initial /proc/self/maps is considered a FileV
   1535       segment if either it has a file name associated with it or both its
   1536       device and inode numbers are != 0. See bug #124528. */
   1537    seg.kind = SkAnonV;
   1538    if (filename || (dev != 0 && ino != 0))
   1539       seg.kind = SkFileV;
   1540 
   1541 #  if defined(VGO_darwin)
   1542    // GrP fixme no dev/ino on darwin
   1543    if (offset != 0)
   1544       seg.kind = SkFileV;
   1545 #  endif // defined(VGO_darwin)
   1546 
   1547 #  if defined(VGP_arm_linux)
   1548    /* The standard handling of entries read from /proc/self/maps will
   1549       cause the faked up commpage segment to have type SkAnonV, which
   1550       is a problem because it contains code we want the client to
   1551       execute, and so later m_translate will segfault the client when
   1552       it tries to go in there.  Hence change the ownership of it here
   1553       to the client (SkAnonC).  The least-worst kludge I could think
   1554       of. */
   1555    if (addr == ARM_LINUX_FAKE_COMMPAGE_START
   1556        && addr + len == ARM_LINUX_FAKE_COMMPAGE_END1
   1557        && seg.kind == SkAnonV)
   1558       seg.kind = SkAnonC;
   1559 #  endif // defined(VGP_arm_linux)
   1560 
   1561    if (filename)
   1562       seg.fnIdx = ML_(am_allocate_segname)( filename );
   1563 
   1564    if (0) show_nsegment( 2,0, &seg );
   1565    add_segment( &seg );
   1566 }
   1567 
   1568 Bool
   1569 VG_(am_is_valid_for_aspacem_minAddr)( Addr addr, const HChar **errmsg )
   1570 {
   1571    const Addr min = VKI_PAGE_SIZE;
   1572 #if VG_WORDSIZE == 4
   1573    const Addr max = 0x40000000;  // 1Gb
   1574 #else
   1575    const Addr max = 0x200000000; // 8Gb
   1576 #endif
   1577    Bool ok = VG_IS_PAGE_ALIGNED(addr) && addr >= min && addr <= max;
   1578 
   1579    if (errmsg) {
   1580       *errmsg = "";
   1581       if (! ok) {
   1582          const HChar fmt[] = "Must be a page aligned address between "
   1583                              "0x%lx and 0x%lx";
   1584          static HChar buf[sizeof fmt + 2 * 16];   // large enough
   1585          ML_(am_sprintf)(buf, fmt, min, max);
   1586          *errmsg = buf;
   1587       }
   1588    }
   1589    return ok;
   1590 }
   1591 
   1592 /* See description in pub_core_aspacemgr.h */
   1593 Addr VG_(am_startup) ( Addr sp_at_startup )
   1594 {
   1595    NSegment seg;
   1596    Addr     suggested_clstack_end;
   1597 
   1598    aspacem_assert(sizeof(Word)   == sizeof(void*));
   1599    aspacem_assert(sizeof(Addr)   == sizeof(void*));
   1600    aspacem_assert(sizeof(SizeT)  == sizeof(void*));
   1601    aspacem_assert(sizeof(SSizeT) == sizeof(void*));
   1602 
   1603    /* Initialise the string table for segment names. */
   1604    ML_(am_segnames_init)();
   1605 
   1606    /* Check that we can store the largest imaginable dev, ino and
   1607       offset numbers in an NSegment. */
   1608    aspacem_assert(sizeof(seg.dev)    == 8);
   1609    aspacem_assert(sizeof(seg.ino)    == 8);
   1610    aspacem_assert(sizeof(seg.offset) == 8);
   1611    aspacem_assert(sizeof(seg.mode)   == 4);
   1612 
   1613    /* Add a single interval covering the entire address space. */
   1614    init_nsegment(&seg);
   1615    seg.kind        = SkFree;
   1616    seg.start       = Addr_MIN;
   1617    seg.end         = Addr_MAX;
   1618    nsegments[0]    = seg;
   1619    nsegments_used  = 1;
   1620 
   1621    aspacem_minAddr = VG_(clo_aspacem_minAddr);
   1622 
   1623    // --- Darwin -------------------------------------------
   1624 #if defined(VGO_darwin)
   1625 
   1626 # if VG_WORDSIZE == 4
   1627    aspacem_maxAddr = (Addr) 0xffffffff;
   1628 
   1629    aspacem_cStart = aspacem_minAddr;
   1630    aspacem_vStart = 0xf0000000;  // 0xc0000000..0xf0000000 available
   1631 # else
   1632    aspacem_maxAddr = (Addr) 0x7fffffffffff;
   1633 
   1634    aspacem_cStart = aspacem_minAddr;
   1635    aspacem_vStart = 0x700000000000; // 0x7000:00000000..0x7fff:5c000000 avail
   1636    // 0x7fff:5c000000..0x7fff:ffe00000? is stack, dyld, shared cache
   1637 # endif
   1638 
   1639    suggested_clstack_end = -1; // ignored; Mach-O specifies its stack
   1640 
   1641    // --- Solaris ------------------------------------------
   1642 #elif defined(VGO_solaris)
   1643 #  if VG_WORDSIZE == 4
   1644    /*
   1645       Intended address space partitioning:
   1646 
   1647       ,--------------------------------, 0x00000000
   1648       |                                |
   1649       |--------------------------------|
   1650       | initial stack given to V by OS |
   1651       |--------------------------------| 0x08000000
   1652       |          client text           |
   1653       |--------------------------------|
   1654       |                                |
   1655       |                                |
   1656       |--------------------------------|
   1657       |          client stack          |
   1658       |--------------------------------| 0x58000000
   1659       |            V's text            |
   1660       |--------------------------------|
   1661       |                                |
   1662       |                                |
   1663       |--------------------------------|
   1664       |     dynamic shared objects     |
   1665       '--------------------------------' 0xffffffff
   1666 
   1667       */
   1668 
   1669    /* Anonymous pages need to fit under user limit (USERLIMIT32)
   1670       which is 4KB + 16MB below the top of the 32-bit range. */
   1671 #    ifdef ENABLE_INNER
   1672      aspacem_maxAddr = (Addr)0x4fffffff; // 1.25GB
   1673      aspacem_vStart  = (Addr)0x40000000; // 1GB
   1674 #    else
   1675      aspacem_maxAddr = (Addr)0xfefff000 - 1; // 4GB - 16MB - 4KB
   1676      aspacem_vStart  = (Addr)0x50000000; // 1.25GB
   1677 #    endif
   1678 #  elif VG_WORDSIZE == 8
   1679    /*
   1680       Intended address space partitioning:
   1681 
   1682       ,--------------------------------, 0x00000000_00000000
   1683       |                                |
   1684       |--------------------------------| 0x00000000_00400000
   1685       |          client text           |
   1686       |--------------------------------|
   1687       |                                |
   1688       |                                |
   1689       |--------------------------------|
   1690       |          client stack          |
   1691       |--------------------------------| 0x00000000_58000000
   1692       |            V's text            |
   1693       |--------------------------------|
   1694       |                                |
   1695       |--------------------------------|
   1696       |     dynamic shared objects     |
   1697       |--------------------------------| 0x0000001f_ffffffff
   1698       |                                |
   1699       |                                |
   1700       |--------------------------------|
   1701       | initial stack given to V by OS |
   1702       '--------------------------------' 0xffffffff_ffffffff
   1703 
   1704       */
   1705 
   1706    /* Kernel likes to place objects at the end of the address space.
   1707       However accessing memory beyond 128GB makes memcheck slow
   1708       (see memcheck/mc_main.c, internal representation). Therefore:
   1709       - mmapobj() syscall is emulated so that libraries are subject to
   1710         Valgrind's aspacemgr control
   1711       - Kernel shared pages (such as schedctl and hrt) are left as they are
   1712         because kernel cannot be told where they should be put */
   1713 #    ifdef ENABLE_INNER
   1714      aspacem_maxAddr = (Addr) 0x0000000fffffffff; // 64GB
   1715      aspacem_vStart  = (Addr) 0x0000000800000000; // 32GB
   1716 #    else
   1717      aspacem_maxAddr = (Addr) 0x0000001fffffffff; // 128GB
   1718      aspacem_vStart  = (Addr) 0x0000001000000000; // 64GB
   1719 #    endif
   1720 #  else
   1721 #    error "Unknown word size"
   1722 #  endif
   1723 
   1724    aspacem_cStart = aspacem_minAddr;
   1725 #  ifdef ENABLE_INNER
   1726    suggested_clstack_end = (Addr) 0x37ff0000 - 1; // 64kB below V's text
   1727 #  else
   1728    suggested_clstack_end = (Addr) 0x57ff0000 - 1; // 64kB below V's text
   1729 #  endif
   1730 
   1731    // --- Linux --------------------------------------------
   1732 #else
   1733 
   1734    /* Establish address limits and block out unusable parts
   1735       accordingly. */
   1736 
   1737    VG_(debugLog)(2, "aspacem",
   1738                     "        sp_at_startup = 0x%010lx (supplied)\n",
   1739                     sp_at_startup );
   1740 
   1741 #  if VG_WORDSIZE == 8
   1742      aspacem_maxAddr = (Addr)0x2000000000ULL - 1; // 128G
   1743 #    ifdef ENABLE_INNER
   1744      { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1;
   1745        if (aspacem_maxAddr > cse)
   1746           aspacem_maxAddr = cse;
   1747      }
   1748 #    endif
   1749 #  else
   1750      aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1;
   1751 #  endif
   1752 
   1753    aspacem_cStart = aspacem_minAddr;
   1754    aspacem_vStart = VG_PGROUNDUP(aspacem_minAddr
   1755                                  + (aspacem_maxAddr - aspacem_minAddr + 1) / 2);
   1756 #  ifdef ENABLE_INNER
   1757    aspacem_vStart -= 0x20000000; // 512M
   1758 #  endif
   1759 
   1760    suggested_clstack_end = aspacem_maxAddr - 16*1024*1024ULL
   1761                                            + VKI_PAGE_SIZE;
   1762 
   1763 #endif
   1764    // --- (end) --------------------------------------------
   1765 
   1766    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr));
   1767    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1));
   1768    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_cStart));
   1769    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_vStart));
   1770    aspacem_assert(VG_IS_PAGE_ALIGNED(suggested_clstack_end + 1));
   1771 
   1772    VG_(debugLog)(2, "aspacem",
   1773                     "              minAddr = 0x%010lx (computed)\n",
   1774                     aspacem_minAddr);
   1775    VG_(debugLog)(2, "aspacem",
   1776                     "              maxAddr = 0x%010lx (computed)\n",
   1777                     aspacem_maxAddr);
   1778    VG_(debugLog)(2, "aspacem",
   1779                     "               cStart = 0x%010lx (computed)\n",
   1780                     aspacem_cStart);
   1781    VG_(debugLog)(2, "aspacem",
   1782                     "               vStart = 0x%010lx (computed)\n",
   1783                     aspacem_vStart);
   1784    VG_(debugLog)(2, "aspacem",
   1785                     "suggested_clstack_end = 0x%010lx (computed)\n",
   1786                     suggested_clstack_end);
   1787 
   1788    if (aspacem_cStart > Addr_MIN) {
   1789       init_resvn(&seg, Addr_MIN, aspacem_cStart-1);
   1790       add_segment(&seg);
   1791    }
   1792    if (aspacem_maxAddr < Addr_MAX) {
   1793       init_resvn(&seg, aspacem_maxAddr+1, Addr_MAX);
   1794       add_segment(&seg);
   1795    }
   1796 
   1797    /* Create a 1-page reservation at the notional initial
   1798       client/valgrind boundary.  This isn't strictly necessary, but
   1799       because the advisor does first-fit and starts searches for
   1800       valgrind allocations at the boundary, this is kind of necessary
   1801       in order to get it to start allocating in the right place. */
   1802    init_resvn(&seg, aspacem_vStart,  aspacem_vStart + VKI_PAGE_SIZE - 1);
   1803    add_segment(&seg);
   1804 
   1805    VG_(am_show_nsegments)(2, "Initial layout");
   1806 
   1807    VG_(debugLog)(2, "aspacem", "Reading /proc/self/maps\n");
   1808    parse_procselfmaps( read_maps_callback, NULL );
   1809    /* NB: on arm-linux, parse_procselfmaps automagically kludges up
   1810       (iow, hands to its callbacks) a description of the ARM Commpage,
   1811       since that's not listed in /proc/self/maps (kernel bug IMO).  We
   1812       have to fake up its existence in parse_procselfmaps and not
   1813       merely add it here as an extra segment, because doing the latter
   1814       causes sync checking to fail: we see we have an extra segment in
   1815       the segments array, which isn't listed in /proc/self/maps.
   1816       Hence we must make it appear that /proc/self/maps contained this
   1817       segment all along.  Sigh. */
   1818 
   1819    VG_(am_show_nsegments)(2, "With contents of /proc/self/maps");
   1820 
   1821    AM_SANITY_CHECK;
   1822    return suggested_clstack_end;
   1823 }
   1824 
   1825 
   1826 /*-----------------------------------------------------------------*/
   1827 /*---                                                           ---*/
   1828 /*--- The core query-notify mechanism.                          ---*/
   1829 /*---                                                           ---*/
   1830 /*-----------------------------------------------------------------*/
   1831 
   1832 /* Query aspacem to ask where a mapping should go. */
   1833 
   1834 Addr VG_(am_get_advisory) ( const MapRequest*  req,
   1835                             Bool  forClient,
   1836                             /*OUT*/Bool* ok )
   1837 {
   1838    /* This function implements allocation policy.
   1839 
   1840       The nature of the allocation request is determined by req, which
   1841       specifies the start and length of the request and indicates
   1842       whether the start address is mandatory, a hint, or irrelevant,
   1843       and by forClient, which says whether this is for the client or
   1844       for V.
   1845 
   1846       Return values: the request can be vetoed (*ok is set to False),
   1847       in which case the caller should not attempt to proceed with
   1848       making the mapping.  Otherwise, *ok is set to True, the caller
   1849       may proceed, and the preferred address at which the mapping
   1850       should happen is returned.
   1851 
   1852       Note that this is an advisory system only: the kernel can in
   1853       fact do whatever it likes as far as placement goes, and we have
   1854       no absolute control over it.
   1855 
   1856       Allocations will never be granted in a reserved area.
   1857 
   1858       The Default Policy is:
   1859 
   1860         Search the address space for two free intervals: one of them
   1861         big enough to contain the request without regard to the
   1862         specified address (viz, as if it was a floating request) and
   1863         the other being able to contain the request at the specified
   1864         address (viz, as if were a fixed request).  Then, depending on
   1865         the outcome of the search and the kind of request made, decide
   1866         whether the request is allowable and what address to advise.
   1867 
   1868       The Default Policy is overridden by Policy Exception #1:
   1869 
   1870         If the request is for a fixed client map, we are prepared to
   1871         grant it providing all areas inside the request are either
   1872         free, reservations, or mappings belonging to the client.  In
   1873         other words we are prepared to let the client trash its own
   1874         mappings if it wants to.
   1875 
   1876       The Default Policy is overridden by Policy Exception #2:
   1877 
   1878         If the request is for a hinted client map, we are prepared to
   1879         grant it providing all areas inside the request are either
   1880         free or reservations.  In other words we are prepared to let
   1881         the client have a hinted mapping anywhere it likes provided
   1882         it does not trash either any of its own mappings or any of
   1883         valgrind's mappings.
   1884    */
   1885    Int  i, j;
   1886    Addr holeStart, holeEnd, holeLen;
   1887    Bool fixed_not_required;
   1888 
   1889 #if defined(VGO_solaris)
   1890    Addr startPoint = forClient ? aspacem_vStart - 1 : aspacem_maxAddr - 1;
   1891 #else
   1892    Addr startPoint = forClient ? aspacem_cStart : aspacem_vStart;
   1893 #endif /* VGO_solaris */
   1894 
   1895    Addr reqStart = req->rkind==MFixed || req->rkind==MHint ? req->start : 0;
   1896    Addr reqEnd   = reqStart + req->len - 1;
   1897    Addr reqLen   = req->len;
   1898 
   1899    /* These hold indices for segments found during search, or -1 if not
   1900       found. */
   1901    Int floatIdx = -1;
   1902    Int fixedIdx = -1;
   1903 
   1904    aspacem_assert(nsegments_used > 0);
   1905 
   1906    if (0) {
   1907       VG_(am_show_nsegments)(0,"getAdvisory");
   1908       VG_(debugLog)(0,"aspacem", "getAdvisory 0x%lx %lu\n",
   1909                     req->start, req->len);
   1910    }
   1911 
   1912    /* Reject zero-length requests */
   1913    if (req->len == 0) {
   1914       *ok = False;
   1915       return 0;
   1916    }
   1917 
   1918    /* Reject wraparounds */
   1919    if (req->start + req->len < req->start) {
   1920       *ok = False;
   1921       return 0;
   1922    }
   1923 
   1924    /* ------ Implement Policy Exception #1 ------ */
   1925 
   1926    if (forClient && req->rkind == MFixed) {
   1927       Int  iLo   = find_nsegment_idx(reqStart);
   1928       Int  iHi   = find_nsegment_idx(reqEnd);
   1929       Bool allow = True;
   1930       for (i = iLo; i <= iHi; i++) {
   1931          if (nsegments[i].kind == SkFree
   1932              || nsegments[i].kind == SkFileC
   1933              || nsegments[i].kind == SkAnonC
   1934              || nsegments[i].kind == SkShmC
   1935              || nsegments[i].kind == SkResvn) {
   1936             /* ok */
   1937          } else {
   1938             allow = False;
   1939             break;
   1940          }
   1941       }
   1942       if (allow) {
   1943          /* Acceptable.  Granted. */
   1944          *ok = True;
   1945          return reqStart;
   1946       }
   1947       /* Not acceptable.  Fail. */
   1948       *ok = False;
   1949       return 0;
   1950    }
   1951 
   1952    /* ------ Implement Policy Exception #2 ------ */
   1953 
   1954    if (forClient && req->rkind == MHint) {
   1955       Int  iLo   = find_nsegment_idx(reqStart);
   1956       Int  iHi   = find_nsegment_idx(reqEnd);
   1957       Bool allow = True;
   1958       for (i = iLo; i <= iHi; i++) {
   1959          if (nsegments[i].kind == SkFree
   1960              || nsegments[i].kind == SkResvn) {
   1961             /* ok */
   1962          } else {
   1963             allow = False;
   1964             break;
   1965          }
   1966       }
   1967       if (allow) {
   1968          /* Acceptable.  Granted. */
   1969          *ok = True;
   1970          return reqStart;
   1971       }
   1972       /* Not acceptable.  Fall through to the default policy. */
   1973    }
   1974 
   1975    /* ------ Implement the Default Policy ------ */
   1976 
   1977    /* Don't waste time looking for a fixed match if not requested to. */
   1978    fixed_not_required = req->rkind == MAny || req->rkind == MAlign;
   1979 
   1980    i = find_nsegment_idx(startPoint);
   1981 
   1982 #if defined(VGO_solaris)
   1983 #  define UPDATE_INDEX(index)                               \
   1984       (index)--;                                            \
   1985       if ((index) <= 0)                                     \
   1986          (index) = nsegments_used - 1;
   1987 #  define ADVISE_ADDRESS(segment)                           \
   1988        VG_PGROUNDDN((segment)->end + 1 - reqLen)
   1989 #  define ADVISE_ADDRESS_ALIGNED(segment)                   \
   1990         VG_ROUNDDN((segment)->end + 1 - reqLen, req->start)
   1991 
   1992 #else
   1993 
   1994 #  define UPDATE_INDEX(index)                               \
   1995       (index)++;                                            \
   1996       if ((index) >= nsegments_used)                        \
   1997          (index) = 0;
   1998 #  define ADVISE_ADDRESS(segment)                           \
   1999       (segment)->start
   2000 #  define ADVISE_ADDRESS_ALIGNED(segment)                   \
   2001       VG_ROUNDUP((segment)->start, req->start)
   2002 #endif /* VGO_solaris */
   2003 
   2004    /* Examine holes from index i back round to i-1.  Record the
   2005       index first fixed hole and the first floating hole which would
   2006       satisfy the request. */
   2007    for (j = 0; j < nsegments_used; j++) {
   2008 
   2009       if (nsegments[i].kind != SkFree) {
   2010          UPDATE_INDEX(i);
   2011          continue;
   2012       }
   2013 
   2014       holeStart = nsegments[i].start;
   2015       holeEnd   = nsegments[i].end;
   2016 
   2017       /* Stay sane .. */
   2018       aspacem_assert(holeStart <= holeEnd);
   2019       aspacem_assert(aspacem_minAddr <= holeStart);
   2020       aspacem_assert(holeEnd <= aspacem_maxAddr);
   2021 
   2022       if (req->rkind == MAlign) {
   2023          holeStart = VG_ROUNDUP(holeStart, req->start);
   2024          if (holeStart >= holeEnd) {
   2025             /* This hole can't be used. */
   2026             UPDATE_INDEX(i);
   2027             continue;
   2028          }
   2029       }
   2030 
   2031       /* See if it's any use to us. */
   2032       holeLen = holeEnd - holeStart + 1;
   2033 
   2034       if (fixedIdx == -1 && holeStart <= reqStart && reqEnd <= holeEnd)
   2035          fixedIdx = i;
   2036 
   2037       if (floatIdx == -1 && holeLen >= reqLen)
   2038          floatIdx = i;
   2039 
   2040       /* Don't waste time searching once we've found what we wanted. */
   2041       if ((fixed_not_required || fixedIdx >= 0) && floatIdx >= 0)
   2042          break;
   2043 
   2044       UPDATE_INDEX(i);
   2045    }
   2046 
   2047    aspacem_assert(fixedIdx >= -1 && fixedIdx < nsegments_used);
   2048    if (fixedIdx >= 0)
   2049       aspacem_assert(nsegments[fixedIdx].kind == SkFree);
   2050 
   2051    aspacem_assert(floatIdx >= -1 && floatIdx < nsegments_used);
   2052    if (floatIdx >= 0)
   2053       aspacem_assert(nsegments[floatIdx].kind == SkFree);
   2054 
   2055    AM_SANITY_CHECK;
   2056 
   2057    /* Now see if we found anything which can satisfy the request. */
   2058    switch (req->rkind) {
   2059       case MFixed:
   2060          if (fixedIdx >= 0) {
   2061             *ok = True;
   2062             return req->start;
   2063          } else {
   2064             *ok = False;
   2065             return 0;
   2066          }
   2067          break;
   2068       case MHint:
   2069          if (fixedIdx >= 0) {
   2070             *ok = True;
   2071             return req->start;
   2072          }
   2073          if (floatIdx >= 0) {
   2074             *ok = True;
   2075             return ADVISE_ADDRESS(&nsegments[floatIdx]);
   2076          }
   2077          *ok = False;
   2078          return 0;
   2079       case MAny:
   2080          if (floatIdx >= 0) {
   2081             *ok = True;
   2082             return ADVISE_ADDRESS(&nsegments[floatIdx]);
   2083          }
   2084          *ok = False;
   2085          return 0;
   2086       case MAlign:
   2087          if (floatIdx >= 0) {
   2088             *ok = True;
   2089             return ADVISE_ADDRESS_ALIGNED(&nsegments[floatIdx]);
   2090          }
   2091          *ok = False;
   2092          return 0;
   2093       default:
   2094          break;
   2095    }
   2096 
   2097    /*NOTREACHED*/
   2098    ML_(am_barf)("getAdvisory: unknown request kind");
   2099    *ok = False;
   2100    return 0;
   2101 
   2102 #undef UPDATE_INDEX
   2103 #undef ADVISE_ADDRESS
   2104 #undef ADVISE_ADDRESS_ALIGNED
   2105 }
   2106 
   2107 /* Convenience wrapper for VG_(am_get_advisory) for client floating or
   2108    fixed requests.  If start is zero, a floating request is issued; if
   2109    nonzero, a fixed request at that address is issued.  Same comments
   2110    about return values apply. */
   2111 
   2112 Addr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len,
   2113                                           /*OUT*/Bool* ok )
   2114 {
   2115    MapRequest mreq;
   2116    mreq.rkind = start==0 ? MAny : MFixed;
   2117    mreq.start = start;
   2118    mreq.len   = len;
   2119    return VG_(am_get_advisory)( &mreq, True/*forClient*/, ok );
   2120 }
   2121 
   2122 /* Similar to VG_(am_find_nsegment) but only returns free segments. */
   2123 static NSegment const * VG_(am_find_free_nsegment) ( Addr a )
   2124 {
   2125    Int i = find_nsegment_idx(a);
   2126    aspacem_assert(i >= 0 && i < nsegments_used);
   2127    aspacem_assert(nsegments[i].start <= a);
   2128    aspacem_assert(a <= nsegments[i].end);
   2129    if (nsegments[i].kind == SkFree)
   2130       return &nsegments[i];
   2131    else
   2132       return NULL;
   2133 }
   2134 
   2135 Bool VG_(am_covered_by_single_free_segment)
   2136    ( Addr start, SizeT len)
   2137 {
   2138    NSegment const* segLo = VG_(am_find_free_nsegment)( start );
   2139    NSegment const* segHi = VG_(am_find_free_nsegment)( start + len - 1 );
   2140 
   2141    return segLo != NULL && segHi != NULL && segLo == segHi;
   2142 }
   2143 
   2144 
   2145 /* Notifies aspacem that the client completed an mmap successfully.
   2146    The segment array is updated accordingly.  If the returned Bool is
   2147    True, the caller should immediately discard translations from the
   2148    specified address range. */
   2149 
   2150 Bool
   2151 VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
   2152                             Int fd, Off64T offset )
   2153 {
   2154    HChar    buf[VKI_PATH_MAX];
   2155    ULong    dev, ino;
   2156    UInt     mode;
   2157    NSegment seg;
   2158    Bool     needDiscard;
   2159 
   2160    aspacem_assert(len > 0);
   2161    aspacem_assert(VG_IS_PAGE_ALIGNED(a));
   2162    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
   2163    aspacem_assert(VG_IS_PAGE_ALIGNED(offset));
   2164 
   2165    /* Discard is needed if any of the just-trashed range had T. */
   2166    needDiscard = any_Ts_in_range( a, len );
   2167 
   2168    init_nsegment( &seg );
   2169    seg.kind   = (flags & VKI_MAP_ANONYMOUS) ? SkAnonC : SkFileC;
   2170    seg.start  = a;
   2171    seg.end    = a + len - 1;
   2172    seg.hasR   = toBool(prot & VKI_PROT_READ);
   2173    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
   2174    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
   2175    if (!(flags & VKI_MAP_ANONYMOUS)) {
   2176       // Nb: We ignore offset requests in anonymous mmaps (see bug #126722)
   2177       seg.offset = offset;
   2178       if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
   2179          seg.dev = dev;
   2180          seg.ino = ino;
   2181          seg.mode = mode;
   2182       }
   2183       if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
   2184          seg.fnIdx = ML_(am_allocate_segname)( buf );
   2185       }
   2186    }
   2187    add_segment( &seg );
   2188    AM_SANITY_CHECK;
   2189    return needDiscard;
   2190 }
   2191 
   2192 /* Notifies aspacem that the client completed a shmat successfully.
   2193    The segment array is updated accordingly.  If the returned Bool is
   2194    True, the caller should immediately discard translations from the
   2195    specified address range. */
   2196 
   2197 Bool
   2198 VG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot )
   2199 {
   2200    NSegment seg;
   2201    Bool     needDiscard;
   2202 
   2203    aspacem_assert(len > 0);
   2204    aspacem_assert(VG_IS_PAGE_ALIGNED(a));
   2205    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
   2206 
   2207    /* Discard is needed if any of the just-trashed range had T. */
   2208    needDiscard = any_Ts_in_range( a, len );
   2209 
   2210    init_nsegment( &seg );
   2211    seg.kind   = SkShmC;
   2212    seg.start  = a;
   2213    seg.end    = a + len - 1;
   2214    seg.offset = 0;
   2215    seg.hasR   = toBool(prot & VKI_PROT_READ);
   2216    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
   2217    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
   2218    add_segment( &seg );
   2219    AM_SANITY_CHECK;
   2220    return needDiscard;
   2221 }
   2222 
   2223 /* Notifies aspacem that an mprotect was completed successfully.  The
   2224    segment array is updated accordingly.  Note, as with
   2225    VG_(am_notify_munmap), it is not the job of this function to reject
   2226    stupid mprotects, for example the client doing mprotect of
   2227    non-client areas.  Such requests should be intercepted earlier, by
   2228    the syscall wrapper for mprotect.  This function merely records
   2229    whatever it is told.  If the returned Bool is True, the caller
   2230    should immediately discard translations from the specified address
   2231    range. */
   2232 
   2233 Bool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot )
   2234 {
   2235    Int  i, iLo, iHi;
   2236    Bool newR, newW, newX, needDiscard;
   2237 
   2238    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
   2239    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
   2240 
   2241    if (len == 0)
   2242       return False;
   2243 
   2244    newR = toBool(prot & VKI_PROT_READ);
   2245    newW = toBool(prot & VKI_PROT_WRITE);
   2246    newX = toBool(prot & VKI_PROT_EXEC);
   2247 
   2248    /* Discard is needed if we're dumping X permission */
   2249    needDiscard = any_Ts_in_range( start, len ) && !newX;
   2250 
   2251    split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
   2252 
   2253    iLo = find_nsegment_idx(start);
   2254    iHi = find_nsegment_idx(start + len - 1);
   2255 
   2256    for (i = iLo; i <= iHi; i++) {
   2257       /* Apply the permissions to all relevant segments. */
   2258       switch (nsegments[i].kind) {
   2259          case SkAnonC: case SkAnonV: case SkFileC: case SkFileV: case SkShmC:
   2260             nsegments[i].hasR = newR;
   2261             nsegments[i].hasW = newW;
   2262             nsegments[i].hasX = newX;
   2263             aspacem_assert(sane_NSegment(&nsegments[i]));
   2264             break;
   2265          default:
   2266             break;
   2267       }
   2268    }
   2269 
   2270    /* Changing permissions could have made previously un-mergable
   2271       segments mergeable.  Therefore have to re-preen them. */
   2272    (void)preen_nsegments();
   2273    AM_SANITY_CHECK;
   2274    return needDiscard;
   2275 }
   2276 
   2277 
   2278 /* Notifies aspacem that an munmap completed successfully.  The
   2279    segment array is updated accordingly.  As with
   2280    VG_(am_notify_mprotect), we merely record the given info, and don't
   2281    check it for sensibleness.  If the returned Bool is True, the
   2282    caller should immediately discard translations from the specified
   2283    address range. */
   2284 
   2285 Bool VG_(am_notify_munmap)( Addr start, SizeT len )
   2286 {
   2287    NSegment seg;
   2288    Bool     needDiscard;
   2289    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
   2290    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
   2291 
   2292    if (len == 0)
   2293       return False;
   2294 
   2295    needDiscard = any_Ts_in_range( start, len );
   2296 
   2297    init_nsegment( &seg );
   2298    seg.start = start;
   2299    seg.end   = start + len - 1;
   2300 
   2301    /* The segment becomes unused (free).  Segments from above
   2302       aspacem_maxAddr were originally SkResvn and so we make them so
   2303       again.  Note, this isn't really right when the segment straddles
   2304       the aspacem_maxAddr boundary - then really it should be split in
   2305       two, the lower part marked as SkFree and the upper part as
   2306       SkResvn.  Ah well. */
   2307    if (start > aspacem_maxAddr
   2308        && /* check previous comparison is meaningful */
   2309           aspacem_maxAddr < Addr_MAX)
   2310       seg.kind = SkResvn;
   2311    else
   2312    /* Ditto for segments from below aspacem_minAddr. */
   2313    if (seg.end < aspacem_minAddr && aspacem_minAddr > 0)
   2314       seg.kind = SkResvn;
   2315    else
   2316       seg.kind = SkFree;
   2317 
   2318    add_segment( &seg );
   2319 
   2320    /* Unmapping could create two adjacent free segments, so a preen is
   2321       needed.  add_segment() will do that, so no need to here. */
   2322    AM_SANITY_CHECK;
   2323    return needDiscard;
   2324 }
   2325 
   2326 
   2327 /*-----------------------------------------------------------------*/
   2328 /*---                                                           ---*/
   2329 /*--- Handling mappings which do not arise directly from the    ---*/
   2330 /*--- simulation of the client.                                 ---*/
   2331 /*---                                                           ---*/
   2332 /*-----------------------------------------------------------------*/
   2333 
   2334 /* --- --- --- map, unmap, protect  --- --- --- */
   2335 
   2336 /* Map a file at a fixed address for the client, and update the
   2337    segment array accordingly. */
   2338 
   2339 SysRes VG_(am_mmap_file_fixed_client)
   2340      ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset )
   2341 {
   2342    UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
   2343    return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
   2344                                                      fd, offset, NULL);
   2345 }
   2346 
   2347 SysRes VG_(am_mmap_file_fixed_client_flags)
   2348      ( Addr start, SizeT length, UInt prot, UInt flags, Int fd, Off64T offset )
   2349 {
   2350    return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
   2351                                                      fd, offset, NULL);
   2352 }
   2353 
   2354 SysRes VG_(am_mmap_named_file_fixed_client)
   2355      ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name )
   2356 {
   2357    UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
   2358    return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
   2359                                                      fd, offset, name);
   2360 }
   2361 
   2362 SysRes VG_(am_mmap_named_file_fixed_client_flags)
   2363      ( Addr start, SizeT length, UInt prot, UInt flags,
   2364        Int fd, Off64T offset, const HChar *name )
   2365 {
   2366    SysRes     sres;
   2367    NSegment   seg;
   2368    Addr       advised;
   2369    Bool       ok;
   2370    MapRequest req;
   2371    ULong      dev, ino;
   2372    UInt       mode;
   2373    HChar      buf[VKI_PATH_MAX];
   2374 
   2375    /* Not allowable. */
   2376    if (length == 0
   2377        || !VG_IS_PAGE_ALIGNED(start)
   2378        || !VG_IS_PAGE_ALIGNED(offset))
   2379       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2380 
   2381    /* Ask for an advisory.  If it's negative, fail immediately. */
   2382    req.rkind = MFixed;
   2383    req.start = start;
   2384    req.len   = length;
   2385    advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
   2386    if (!ok || advised != start)
   2387       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2388 
   2389    /* We have been advised that the mapping is allowable at the
   2390       specified address.  So hand it off to the kernel, and propagate
   2391       any resulting failure immediately. */
   2392    // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
   2393    sres = VG_(am_do_mmap_NO_NOTIFY)(
   2394              start, length, prot, flags,
   2395              fd, offset
   2396           );
   2397    if (sr_isError(sres))
   2398       return sres;
   2399 
   2400    if (sr_Res(sres) != start) {
   2401       /* I don't think this can happen.  It means the kernel made a
   2402          fixed map succeed but not at the requested location.  Try to
   2403          repair the damage, then return saying the mapping failed. */
   2404       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
   2405       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2406    }
   2407 
   2408    /* Ok, the mapping succeeded.  Now notify the interval map. */
   2409    init_nsegment( &seg );
   2410    seg.kind   = SkFileC;
   2411    seg.start  = start;
   2412    seg.end    = seg.start + VG_PGROUNDUP(length) - 1;
   2413    seg.offset = offset;
   2414    seg.hasR   = toBool(prot & VKI_PROT_READ);
   2415    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
   2416    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
   2417    if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
   2418       seg.dev = dev;
   2419       seg.ino = ino;
   2420       seg.mode = mode;
   2421    }
   2422    if (name) {
   2423       seg.fnIdx = ML_(am_allocate_segname)( name );
   2424    } else if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
   2425       seg.fnIdx = ML_(am_allocate_segname)( buf );
   2426    }
   2427    add_segment( &seg );
   2428 
   2429    AM_SANITY_CHECK;
   2430    return sres;
   2431 }
   2432 
   2433 
   2434 /* Map anonymously at a fixed address for the client, and update
   2435    the segment array accordingly. */
   2436 
   2437 SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
   2438 {
   2439    SysRes     sres;
   2440    NSegment   seg;
   2441    Addr       advised;
   2442    Bool       ok;
   2443    MapRequest req;
   2444 
   2445    /* Not allowable. */
   2446    if (length == 0 || !VG_IS_PAGE_ALIGNED(start))
   2447       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2448 
   2449    /* Ask for an advisory.  If it's negative, fail immediately. */
   2450    req.rkind = MFixed;
   2451    req.start = start;
   2452    req.len   = length;
   2453    advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
   2454    if (!ok || advised != start)
   2455       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2456 
   2457    /* We have been advised that the mapping is allowable at the
   2458       specified address.  So hand it off to the kernel, and propagate
   2459       any resulting failure immediately. */
   2460    // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
   2461    sres = VG_(am_do_mmap_NO_NOTIFY)(
   2462              start, length, prot,
   2463              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   2464              0, 0
   2465           );
   2466    if (sr_isError(sres))
   2467       return sres;
   2468 
   2469    if (sr_Res(sres) != start) {
   2470       /* I don't think this can happen.  It means the kernel made a
   2471          fixed map succeed but not at the requested location.  Try to
   2472          repair the damage, then return saying the mapping failed. */
   2473       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
   2474       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2475    }
   2476 
   2477    /* Ok, the mapping succeeded.  Now notify the interval map. */
   2478    init_nsegment( &seg );
   2479    seg.kind  = SkAnonC;
   2480    seg.start = start;
   2481    seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
   2482    seg.hasR  = toBool(prot & VKI_PROT_READ);
   2483    seg.hasW  = toBool(prot & VKI_PROT_WRITE);
   2484    seg.hasX  = toBool(prot & VKI_PROT_EXEC);
   2485    add_segment( &seg );
   2486 
   2487    AM_SANITY_CHECK;
   2488    return sres;
   2489 }
   2490 
   2491 
   2492 /* Map anonymously at an unconstrained address for the client, and
   2493    update the segment array accordingly.  */
   2494 
   2495 static SysRes am_mmap_anon_float_client ( SizeT length, Int prot, Bool isCH )
   2496 {
   2497    SysRes     sres;
   2498    NSegment   seg;
   2499    Addr       advised;
   2500    Bool       ok;
   2501    MapRequest req;
   2502 
   2503    /* Not allowable. */
   2504    if (length == 0)
   2505       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2506 
   2507    /* Ask for an advisory.  If it's negative, fail immediately. */
   2508    req.rkind = MAny;
   2509    req.start = 0;
   2510    req.len   = length;
   2511    advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
   2512    if (!ok)
   2513       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2514 
   2515    /* We have been advised that the mapping is allowable at the
   2516       advised address.  So hand it off to the kernel, and propagate
   2517       any resulting failure immediately. */
   2518    // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
   2519    sres = VG_(am_do_mmap_NO_NOTIFY)(
   2520              advised, length, prot,
   2521              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   2522              0, 0
   2523           );
   2524    if (sr_isError(sres))
   2525       return sres;
   2526 
   2527    if (sr_Res(sres) != advised) {
   2528       /* I don't think this can happen.  It means the kernel made a
   2529          fixed map succeed but not at the requested location.  Try to
   2530          repair the damage, then return saying the mapping failed. */
   2531       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
   2532       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2533    }
   2534 
   2535    /* Ok, the mapping succeeded.  Now notify the interval map. */
   2536    init_nsegment( &seg );
   2537    seg.kind  = SkAnonC;
   2538    seg.start = advised;
   2539    seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
   2540    seg.hasR  = toBool(prot & VKI_PROT_READ);
   2541    seg.hasW  = toBool(prot & VKI_PROT_WRITE);
   2542    seg.hasX  = toBool(prot & VKI_PROT_EXEC);
   2543    seg.isCH  = isCH;
   2544    add_segment( &seg );
   2545 
   2546    AM_SANITY_CHECK;
   2547    return sres;
   2548 }
   2549 
   2550 SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
   2551 {
   2552    return am_mmap_anon_float_client (length, prot, False /* isCH */);
   2553 }
   2554 
   2555 /* Map anonymously at an unconstrained address for V, and update the
   2556    segment array accordingly.  This is fundamentally how V allocates
   2557    itself more address space when needed. */
   2558 
   2559 SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
   2560 {
   2561    SysRes     sres;
   2562    NSegment   seg;
   2563    Addr       advised;
   2564    Bool       ok;
   2565    MapRequest req;
   2566 
   2567    /* Not allowable. */
   2568    if (length == 0)
   2569       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2570 
   2571    /* Ask for an advisory.  If it's negative, fail immediately. */
   2572    req.rkind = MAny;
   2573    req.start = 0;
   2574    req.len   = length;
   2575    advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
   2576    if (!ok)
   2577       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2578 
   2579 // On Darwin, for anonymous maps you can pass in a tag which is used by
   2580 // programs like vmmap for statistical purposes.
   2581 #ifndef VM_TAG_VALGRIND
   2582 #  define VM_TAG_VALGRIND 0
   2583 #endif
   2584 
   2585    /* We have been advised that the mapping is allowable at the
   2586       specified address.  So hand it off to the kernel, and propagate
   2587       any resulting failure immediately. */
   2588    /* GrP fixme darwin: use advisory as a hint only, otherwise syscall in
   2589       another thread can pre-empt our spot.  [At one point on the DARWIN
   2590       branch the VKI_MAP_FIXED was commented out;  unclear if this is
   2591       necessary or not given the second Darwin-only call that immediately
   2592       follows if this one fails.  --njn]
   2593       Also, an inner valgrind cannot observe the mmap syscalls done by
   2594       the outer valgrind. The outer Valgrind might make the mmap
   2595       fail here, as the inner valgrind believes that a segment is free,
   2596       while it is in fact used by the outer valgrind.
   2597       So, for an inner valgrind, similarly to DARWIN, if the fixed mmap
   2598       fails, retry the mmap without map fixed.
   2599       This is a kludge which on linux is only activated for the inner.
   2600       The state of the inner aspacemgr is not made correct by this kludge
   2601       and so a.o. VG_(am_do_sync_check) could fail.
   2602       A proper solution implies a better collaboration between the
   2603       inner and the outer (e.g. inner VG_(am_get_advisory) should do
   2604       a client request to call the outer VG_(am_get_advisory). */
   2605    sres = VG_(am_do_mmap_NO_NOTIFY)(
   2606              advised, length,
   2607              VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
   2608              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   2609              VM_TAG_VALGRIND, 0
   2610           );
   2611 #if defined(VGO_darwin) || defined(ENABLE_INNER)
   2612    /* Kludge on Darwin and inner linux if the fixed mmap failed. */
   2613    if (sr_isError(sres)) {
   2614        /* try again, ignoring the advisory */
   2615        sres = VG_(am_do_mmap_NO_NOTIFY)(
   2616              0, length,
   2617              VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
   2618              /*VKI_MAP_FIXED|*/VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   2619              VM_TAG_VALGRIND, 0
   2620           );
   2621    }
   2622 #endif
   2623    if (sr_isError(sres))
   2624       return sres;
   2625 
   2626 #if defined(VGO_linux) && !defined(ENABLE_INNER)
   2627    /* Doing the check only in linux not inner, as the below
   2628       check can fail when the kludge above has been used. */
   2629    if (sr_Res(sres) != advised) {
   2630       /* I don't think this can happen.  It means the kernel made a
   2631          fixed map succeed but not at the requested location.  Try to
   2632          repair the damage, then return saying the mapping failed. */
   2633       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
   2634       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2635    }
   2636 #endif
   2637 
   2638    /* Ok, the mapping succeeded.  Now notify the interval map. */
   2639    init_nsegment( &seg );
   2640    seg.kind  = SkAnonV;
   2641    seg.start = sr_Res(sres);
   2642    seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
   2643    seg.hasR  = True;
   2644    seg.hasW  = True;
   2645    seg.hasX  = True;
   2646    add_segment( &seg );
   2647 
   2648    AM_SANITY_CHECK;
   2649    return sres;
   2650 }
   2651 
   2652 /* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
   2653 
   2654 void* VG_(am_shadow_alloc)(SizeT size)
   2655 {
   2656    SysRes sres = VG_(am_mmap_anon_float_valgrind)( size );
   2657    return sr_isError(sres) ? NULL : (void*)sr_Res(sres);
   2658 }
   2659 
   2660 /* Map a file at an unconstrained address for V, and update the
   2661    segment array accordingly. Use the provided flags */
   2662 
   2663 static SysRes VG_(am_mmap_file_float_valgrind_flags) ( SizeT length, UInt prot,
   2664                                                        UInt flags,
   2665                                                        Int fd, Off64T offset )
   2666 {
   2667    SysRes     sres;
   2668    NSegment   seg;
   2669    Addr       advised;
   2670    Bool       ok;
   2671    MapRequest req;
   2672    ULong      dev, ino;
   2673    UInt       mode;
   2674    HChar      buf[VKI_PATH_MAX];
   2675 
   2676    /* Not allowable. */
   2677    if (length == 0 || !VG_IS_PAGE_ALIGNED(offset))
   2678       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2679 
   2680    /* Ask for an advisory.  If it's negative, fail immediately. */
   2681    req.rkind = MAny;
   2682    req.start = 0;
   2683    #if defined(VGA_arm) || defined(VGA_arm64) \
   2684       || defined(VGA_mips32) || defined(VGA_mips64)
   2685    aspacem_assert(VKI_SHMLBA >= VKI_PAGE_SIZE);
   2686    #else
   2687    aspacem_assert(VKI_SHMLBA == VKI_PAGE_SIZE);
   2688    #endif
   2689    if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags)) {
   2690       /* arm-linux only. See ML_(generic_PRE_sys_shmat) and bug 290974 */
   2691       req.len = length + VKI_SHMLBA - VKI_PAGE_SIZE;
   2692    } else {
   2693       req.len = length;
   2694    }
   2695    advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
   2696    if (!ok)
   2697       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2698    if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags))
   2699       advised = VG_ROUNDUP(advised, VKI_SHMLBA);
   2700 
   2701    /* We have been advised that the mapping is allowable at the
   2702       specified address.  So hand it off to the kernel, and propagate
   2703       any resulting failure immediately. */
   2704    sres = VG_(am_do_mmap_NO_NOTIFY)(
   2705              advised, length, prot,
   2706              flags,
   2707              fd, offset
   2708           );
   2709    if (sr_isError(sres))
   2710       return sres;
   2711 
   2712    if (sr_Res(sres) != advised) {
   2713       /* I don't think this can happen.  It means the kernel made a
   2714          fixed map succeed but not at the requested location.  Try to
   2715          repair the damage, then return saying the mapping failed. */
   2716       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
   2717       return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2718    }
   2719 
   2720    /* Ok, the mapping succeeded.  Now notify the interval map. */
   2721    init_nsegment( &seg );
   2722    seg.kind   = SkFileV;
   2723    seg.start  = sr_Res(sres);
   2724    seg.end    = seg.start + VG_PGROUNDUP(length) - 1;
   2725    seg.offset = offset;
   2726    seg.hasR   = toBool(prot & VKI_PROT_READ);
   2727    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
   2728    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
   2729    if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
   2730       seg.dev  = dev;
   2731       seg.ino  = ino;
   2732       seg.mode = mode;
   2733    }
   2734    if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
   2735       seg.fnIdx = ML_(am_allocate_segname)( buf );
   2736    }
   2737    add_segment( &seg );
   2738 
   2739    AM_SANITY_CHECK;
   2740    return sres;
   2741 }
   2742 /* Map privately a file at an unconstrained address for V, and update the
   2743    segment array accordingly.  This is used by V for transiently
   2744    mapping in object files to read their debug info.  */
   2745 
   2746 SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot,
   2747                                           Int fd, Off64T offset )
   2748 {
   2749    return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
   2750                                                   VKI_MAP_FIXED|VKI_MAP_PRIVATE,
   2751                                                   fd, offset );
   2752 }
   2753 
   2754 SysRes VG_(am_shared_mmap_file_float_valgrind)
   2755    ( SizeT length, UInt prot, Int fd, Off64T offset )
   2756 {
   2757    return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
   2758                                                   VKI_MAP_FIXED|VKI_MAP_SHARED,
   2759                                                   fd, offset );
   2760 }
   2761 
   2762 /* Similar to VG_(am_mmap_anon_float_client) but also
   2763    marks the segment as containing the client heap. This is for the benefit
   2764    of the leak checker which needs to be able to identify such segments
   2765    so as not to use them as sources of roots during leak checks. */
   2766 SysRes VG_(am_mmap_client_heap) ( SizeT length, Int prot )
   2767 {
   2768    return am_mmap_anon_float_client (length, prot, True /* isCH */);
   2769 }
   2770 
   2771 /* --- --- munmap helper --- --- */
   2772 
   2773 static
   2774 SysRes am_munmap_both_wrk ( /*OUT*/Bool* need_discard,
   2775                             Addr start, SizeT len, Bool forClient )
   2776 {
   2777    Bool   d;
   2778    SysRes sres;
   2779 
   2780    /* Be safe with this regardless of return path. */
   2781    *need_discard = False;
   2782 
   2783    if (!VG_IS_PAGE_ALIGNED(start))
   2784       goto eINVAL;
   2785 
   2786    if (len == 0) {
   2787       *need_discard = False;
   2788       return VG_(mk_SysRes_Success)( 0 );
   2789    }
   2790 
   2791    if (start + len < len)
   2792       goto eINVAL;
   2793 
   2794    len = VG_PGROUNDUP(len);
   2795    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
   2796    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
   2797 
   2798    if (forClient) {
   2799       if (!VG_(am_is_valid_for_client_or_free_or_resvn)
   2800             ( start, len, VKI_PROT_NONE ))
   2801          goto eINVAL;
   2802    } else {
   2803       if (!VG_(am_is_valid_for_valgrind)
   2804             ( start, len, VKI_PROT_NONE ))
   2805          goto eINVAL;
   2806    }
   2807 
   2808    d = any_Ts_in_range( start, len );
   2809 
   2810    sres = ML_(am_do_munmap_NO_NOTIFY)( start, len );
   2811    if (sr_isError(sres))
   2812       return sres;
   2813 
   2814    VG_(am_notify_munmap)( start, len );
   2815    AM_SANITY_CHECK;
   2816    *need_discard = d;
   2817    return sres;
   2818 
   2819   eINVAL:
   2820    return VG_(mk_SysRes_Error)( VKI_EINVAL );
   2821 }
   2822 
   2823 /* Unmap the given address range and update the segment array
   2824    accordingly.  This fails if the range isn't valid for the client.
   2825    If *need_discard is True after a successful return, the caller
   2826    should immediately discard translations from the specified address
   2827    range. */
   2828 
   2829 SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
   2830                               Addr start, SizeT len )
   2831 {
   2832    return am_munmap_both_wrk( need_discard, start, len, True/*client*/ );
   2833 }
   2834 
   2835 /* Unmap the given address range and update the segment array
   2836    accordingly.  This fails if the range isn't valid for valgrind. */
   2837 
   2838 SysRes VG_(am_munmap_valgrind)( Addr start, SizeT len )
   2839 {
   2840    Bool need_discard;
   2841    SysRes r = am_munmap_both_wrk( &need_discard,
   2842                                   start, len, False/*valgrind*/ );
   2843    /* If this assertion fails, it means we allowed translations to be
   2844       made from a V-owned section.  Which shouldn't happen. */
   2845    if (!sr_isError(r))
   2846       aspacem_assert(!need_discard);
   2847    return r;
   2848 }
   2849 
   2850 /* Let (start,len) denote an area within a single Valgrind-owned
   2851   segment (anon or file).  Change the ownership of [start, start+len)
   2852   to the client instead.  Fails if (start,len) does not denote a
   2853   suitable segment. */
   2854 
   2855 Bool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len )
   2856 {
   2857    Int i, iLo, iHi;
   2858 
   2859    if (len == 0)
   2860       return True;
   2861    if (start + len < start)
   2862       return False;
   2863    if (!VG_IS_PAGE_ALIGNED(start) || !VG_IS_PAGE_ALIGNED(len))
   2864       return False;
   2865 
   2866    i = find_nsegment_idx(start);
   2867    if (nsegments[i].kind != SkFileV && nsegments[i].kind != SkAnonV)
   2868       return False;
   2869    if (start+len-1 > nsegments[i].end)
   2870       return False;
   2871 
   2872    aspacem_assert(start >= nsegments[i].start);
   2873    aspacem_assert(start+len-1 <= nsegments[i].end);
   2874 
   2875    /* This scheme is like how mprotect works: split the to-be-changed
   2876       range into its own segment(s), then mess with them (it).  There
   2877       should be only one. */
   2878    split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
   2879    aspacem_assert(iLo == iHi);
   2880    switch (nsegments[iLo].kind) {
   2881       case SkFileV: nsegments[iLo].kind = SkFileC; break;
   2882       case SkAnonV: nsegments[iLo].kind = SkAnonC; break;
   2883       default: aspacem_assert(0); /* can't happen - guarded above */
   2884    }
   2885 
   2886    preen_nsegments();
   2887    return True;
   2888 }
   2889 
   2890 /* Set the 'hasT' bit on the segment containing ADDR indicating that
   2891    translations have or may have been taken from this segment. ADDR is
   2892    expected to belong to a client segment. */
   2893 void VG_(am_set_segment_hasT)( Addr addr )
   2894 {
   2895    Int i = find_nsegment_idx(addr);
   2896    SegKind kind = nsegments[i].kind;
   2897    aspacem_assert(kind == SkAnonC || kind == SkFileC || kind == SkShmC);
   2898    nsegments[i].hasT = True;
   2899 }
   2900 
   2901 
   2902 /* --- --- --- reservations --- --- --- */
   2903 
   2904 /* Create a reservation from START .. START+LENGTH-1, with the given
   2905    ShrinkMode.  When checking whether the reservation can be created,
   2906    also ensure that at least abs(EXTRA) extra free bytes will remain
   2907    above (> 0) or below (< 0) the reservation.
   2908 
   2909    The reservation will only be created if it, plus the extra-zone,
   2910    falls entirely within a single free segment.  The returned Bool
   2911    indicates whether the creation succeeded. */
   2912 
   2913 Bool VG_(am_create_reservation) ( Addr start, SizeT length,
   2914                                   ShrinkMode smode, SSizeT extra )
   2915 {
   2916    Int      startI, endI;
   2917    NSegment seg;
   2918 
   2919    /* start and end, not taking into account the extra space. */
   2920    Addr start1 = start;
   2921    Addr end1   = start + length - 1;
   2922 
   2923    /* start and end, taking into account the extra space. */
   2924    Addr start2 = start1;
   2925    Addr end2   = end1;
   2926 
   2927    if (extra < 0) start2 += extra; // this moves it down :-)
   2928    if (extra > 0) end2 += extra;
   2929 
   2930    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
   2931    aspacem_assert(VG_IS_PAGE_ALIGNED(start+length));
   2932    aspacem_assert(VG_IS_PAGE_ALIGNED(start2));
   2933    aspacem_assert(VG_IS_PAGE_ALIGNED(end2+1));
   2934 
   2935    startI = find_nsegment_idx( start2 );
   2936    endI = find_nsegment_idx( end2 );
   2937 
   2938    /* If the start and end points don't fall within the same (free)
   2939       segment, we're hosed.  This does rely on the assumption that all
   2940       mergeable adjacent segments can be merged, but add_segment()
   2941       should ensure that. */
   2942    if (startI != endI)
   2943       return False;
   2944 
   2945    if (nsegments[startI].kind != SkFree)
   2946       return False;
   2947 
   2948    /* Looks good - make the reservation. */
   2949    aspacem_assert(nsegments[startI].start <= start2);
   2950    aspacem_assert(end2 <= nsegments[startI].end);
   2951 
   2952    init_nsegment( &seg );
   2953    seg.kind  = SkResvn;
   2954    seg.start = start1;  /* NB: extra space is not included in the
   2955                            reservation. */
   2956    seg.end   = end1;
   2957    seg.smode = smode;
   2958    add_segment( &seg );
   2959 
   2960    AM_SANITY_CHECK;
   2961    return True;
   2962 }
   2963 
   2964 
   2965 /* ADDR is the start address of an anonymous client mapping.  This fn extends
   2966    the mapping by DELTA bytes, taking the space from a reservation section
   2967    which must be adjacent.  If DELTA is positive, the segment is
   2968    extended forwards in the address space, and the reservation must be
   2969    the next one along.  If DELTA is negative, the segment is extended
   2970    backwards in the address space and the reservation must be the
   2971    previous one.  DELTA must be page aligned.  abs(DELTA) must not
   2972    exceed the size of the reservation segment minus one page, that is,
   2973    the reservation segment after the operation must be at least one
   2974    page long. The function returns a pointer to the resized segment. */
   2975 
   2976 const NSegment *VG_(am_extend_into_adjacent_reservation_client)( Addr addr,
   2977                                                                  SSizeT delta,
   2978                                                                  Bool *overflow)
   2979 {
   2980    Int    segA, segR;
   2981    UInt   prot;
   2982    SysRes sres;
   2983 
   2984    *overflow = False;
   2985 
   2986    segA = find_nsegment_idx(addr);
   2987    aspacem_assert(nsegments[segA].kind == SkAnonC);
   2988 
   2989    if (delta == 0)
   2990       return nsegments + segA;
   2991 
   2992    prot =   (nsegments[segA].hasR ? VKI_PROT_READ : 0)
   2993           | (nsegments[segA].hasW ? VKI_PROT_WRITE : 0)
   2994           | (nsegments[segA].hasX ? VKI_PROT_EXEC : 0);
   2995 
   2996    aspacem_assert(VG_IS_PAGE_ALIGNED(delta<0 ? -delta : delta));
   2997 
   2998    if (delta > 0) {
   2999 
   3000       /* Extending the segment forwards. */
   3001       segR = segA+1;
   3002       if (segR >= nsegments_used
   3003           || nsegments[segR].kind != SkResvn
   3004           || nsegments[segR].smode != SmLower)
   3005          return NULL;
   3006 
   3007       if (delta + VKI_PAGE_SIZE
   3008                 > (nsegments[segR].end - nsegments[segR].start + 1)) {
   3009          *overflow = True;
   3010          return NULL;
   3011       }
   3012 
   3013       /* Extend the kernel's mapping. */
   3014       // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
   3015       sres = VG_(am_do_mmap_NO_NOTIFY)(
   3016                 nsegments[segR].start, delta,
   3017                 prot,
   3018                 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   3019                 0, 0
   3020              );
   3021       if (sr_isError(sres))
   3022          return NULL; /* kernel bug if this happens? */
   3023       if (sr_Res(sres) != nsegments[segR].start) {
   3024          /* kernel bug if this happens? */
   3025         (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
   3026         return NULL;
   3027       }
   3028 
   3029       /* Ok, success with the kernel.  Update our structures. */
   3030       nsegments[segR].start += delta;
   3031       nsegments[segA].end += delta;
   3032       aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
   3033 
   3034    } else {
   3035 
   3036       /* Extending the segment backwards. */
   3037       delta = -delta;
   3038       aspacem_assert(delta > 0);
   3039 
   3040       segR = segA-1;
   3041       if (segR < 0
   3042           || nsegments[segR].kind != SkResvn
   3043           || nsegments[segR].smode != SmUpper)
   3044          return NULL;
   3045 
   3046       if (delta + VKI_PAGE_SIZE
   3047                 > (nsegments[segR].end - nsegments[segR].start + 1)) {
   3048          *overflow = True;
   3049          return NULL;
   3050       }
   3051 
   3052       /* Extend the kernel's mapping. */
   3053       // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
   3054       sres = VG_(am_do_mmap_NO_NOTIFY)(
   3055                 nsegments[segA].start-delta, delta,
   3056                 prot,
   3057                 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
   3058                 0, 0
   3059              );
   3060       if (sr_isError(sres))
   3061          return NULL; /* kernel bug if this happens? */
   3062       if (sr_Res(sres) != nsegments[segA].start-delta) {
   3063          /* kernel bug if this happens? */
   3064         (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
   3065         return NULL;
   3066       }
   3067 
   3068       /* Ok, success with the kernel.  Update our structures. */
   3069       nsegments[segR].end -= delta;
   3070       nsegments[segA].start -= delta;
   3071       aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
   3072    }
   3073 
   3074    AM_SANITY_CHECK;
   3075    return nsegments + segA;
   3076 }
   3077 
   3078 
   3079 /* --- --- --- resizing/move a mapping --- --- --- */
   3080 
   3081 #if HAVE_MREMAP
   3082 
   3083 /* This function grows a client mapping in place into an adjacent free segment.
   3084    ADDR is the client mapping's start address and DELTA, which must be page
   3085    aligned, is the growth amount. The function returns a pointer to the
   3086    resized segment. The function is used in support of mremap. */
   3087 const NSegment *VG_(am_extend_map_client)( Addr addr, SizeT delta )
   3088 {
   3089    Addr     xStart;
   3090    SysRes   sres;
   3091 
   3092    if (0)
   3093       VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) BEFORE");
   3094 
   3095    /* Get the client segment */
   3096    Int ix = find_nsegment_idx(addr);
   3097    aspacem_assert(ix >= 0 && ix < nsegments_used);
   3098 
   3099    NSegment *seg = nsegments + ix;
   3100 
   3101    aspacem_assert(seg->kind == SkFileC || seg->kind == SkAnonC ||
   3102                   seg->kind == SkShmC);
   3103    aspacem_assert(delta > 0 && VG_IS_PAGE_ALIGNED(delta)) ;
   3104 
   3105    xStart = seg->end+1;
   3106    aspacem_assert(xStart + delta >= delta);   // no wrap-around
   3107 
   3108    /* The segment following the client segment must be a free segment and
   3109       it must be large enough to cover the additional memory. */
   3110    NSegment *segf = seg + 1;
   3111    aspacem_assert(segf->kind == SkFree);
   3112    aspacem_assert(segf->start == xStart);
   3113    aspacem_assert(xStart + delta - 1 <= segf->end);
   3114 
   3115    SizeT seg_old_len = seg->end + 1 - seg->start;
   3116 
   3117    AM_SANITY_CHECK;
   3118    sres = ML_(am_do_extend_mapping_NO_NOTIFY)( seg->start,
   3119                                                seg_old_len,
   3120                                                seg_old_len + delta );
   3121    if (sr_isError(sres)) {
   3122       AM_SANITY_CHECK;
   3123       return NULL;
   3124    } else {
   3125       /* the area must not have moved */
   3126       aspacem_assert(sr_Res(sres) == seg->start);
   3127    }
   3128 
   3129    NSegment seg_copy = *seg;
   3130    seg_copy.end += delta;
   3131    add_segment( &seg_copy );
   3132 
   3133    if (0)
   3134       VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) AFTER");
   3135 
   3136    AM_SANITY_CHECK;
   3137    return nsegments + find_nsegment_idx(addr);
   3138 }
   3139 
   3140 
   3141 /* Remap the old address range to the new address range.  Fails if any
   3142    parameter is not page aligned, if the either size is zero, if any
   3143    wraparound is implied, if the old address range does not fall
   3144    entirely within a single segment, if the new address range overlaps
   3145    with the old one, or if the old address range is not a valid client
   3146    mapping.  If *need_discard is True after a successful return, the
   3147    caller should immediately discard translations from both specified
   3148    address ranges.  */
   3149 
   3150 Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
   3151                                         Addr old_addr, SizeT old_len,
   3152                                         Addr new_addr, SizeT new_len )
   3153 {
   3154    Int      iLo, iHi;
   3155    SysRes   sres;
   3156    NSegment seg;
   3157 
   3158    if (old_len == 0 || new_len == 0)
   3159       return False;
   3160 
   3161    if (!VG_IS_PAGE_ALIGNED(old_addr) || !VG_IS_PAGE_ALIGNED(old_len)
   3162        || !VG_IS_PAGE_ALIGNED(new_addr) || !VG_IS_PAGE_ALIGNED(new_len))
   3163       return False;
   3164 
   3165    if (old_addr + old_len < old_addr
   3166        || new_addr + new_len < new_addr)
   3167       return False;
   3168 
   3169    if (old_addr + old_len - 1 < new_addr
   3170        || new_addr + new_len - 1 < old_addr) {
   3171       /* no overlap */
   3172    } else
   3173       return False;
   3174 
   3175    iLo = find_nsegment_idx( old_addr );
   3176    iHi = find_nsegment_idx( old_addr + old_len - 1 );
   3177    if (iLo != iHi)
   3178       return False;
   3179 
   3180    if (nsegments[iLo].kind != SkFileC && nsegments[iLo].kind != SkAnonC &&
   3181        nsegments[iLo].kind != SkShmC)
   3182       return False;
   3183 
   3184    sres = ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)
   3185              ( old_addr, old_len, new_addr, new_len );
   3186    if (sr_isError(sres)) {
   3187       AM_SANITY_CHECK;
   3188       return False;
   3189    } else {
   3190       aspacem_assert(sr_Res(sres) == new_addr);
   3191    }
   3192 
   3193    *need_discard = any_Ts_in_range( old_addr, old_len )
   3194                    || any_Ts_in_range( new_addr, new_len );
   3195 
   3196    seg = nsegments[iLo];
   3197 
   3198    /* Mark the new area based on the old seg. */
   3199    if (seg.kind == SkFileC) {
   3200       seg.offset += ((ULong)old_addr) - ((ULong)seg.start);
   3201    }
   3202    seg.start = new_addr;
   3203    seg.end   = new_addr + new_len - 1;
   3204    add_segment( &seg );
   3205 
   3206    /* Create a free hole in the old location. */
   3207    init_nsegment( &seg );
   3208    seg.start = old_addr;
   3209    seg.end   = old_addr + old_len - 1;
   3210    /* See comments in VG_(am_notify_munmap) about this SkResvn vs
   3211       SkFree thing. */
   3212    if (old_addr > aspacem_maxAddr
   3213        && /* check previous comparison is meaningful */
   3214           aspacem_maxAddr < Addr_MAX)
   3215       seg.kind = SkResvn;
   3216    else
   3217       seg.kind = SkFree;
   3218 
   3219    add_segment( &seg );
   3220 
   3221    AM_SANITY_CHECK;
   3222    return True;
   3223 }
   3224 
   3225 #endif // HAVE_MREMAP
   3226 
   3227 
   3228 #if defined(VGO_linux)
   3229 
   3230 /*-----------------------------------------------------------------*/
   3231 /*---                                                           ---*/
   3232 /*--- A simple parser for /proc/self/maps on Linux 2.4.X/2.6.X. ---*/
   3233 /*--- Almost completely independent of the stuff above.  The    ---*/
   3234 /*--- only function it 'exports' to the code above this comment ---*/
   3235 /*--- is parse_procselfmaps.                                    ---*/
   3236 /*---                                                           ---*/
   3237 /*-----------------------------------------------------------------*/
   3238 
   3239 /*------BEGIN-procmaps-parser-for-Linux--------------------------*/
   3240 
   3241 /* Size of a smallish table used to read /proc/self/map entries. */
   3242 #define M_PROCMAP_BUF 100000
   3243 
   3244 /* static ... to keep it out of the stack frame. */
   3245 static HChar procmap_buf[M_PROCMAP_BUF];
   3246 
   3247 /* Records length of /proc/self/maps read into procmap_buf. */
   3248 static Int  buf_n_tot;
   3249 
   3250 /* Helper fns. */
   3251 
   3252 static Int hexdigit ( HChar c )
   3253 {
   3254    if (c >= '0' && c <= '9') return (Int)(c - '0');
   3255    if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a');
   3256    if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A');
   3257    return -1;
   3258 }
   3259 
   3260 static Int decdigit ( HChar c )
   3261 {
   3262    if (c >= '0' && c <= '9') return (Int)(c - '0');
   3263    return -1;
   3264 }
   3265 
   3266 static Int readchar ( const HChar* buf, HChar* ch )
   3267 {
   3268    if (*buf == 0) return 0;
   3269    *ch = *buf;
   3270    return 1;
   3271 }
   3272 
   3273 static Int readhex ( const HChar* buf, UWord* val )
   3274 {
   3275    /* Read a word-sized hex number. */
   3276    Int n = 0;
   3277    *val = 0;
   3278    while (hexdigit(*buf) >= 0) {
   3279       *val = (*val << 4) + hexdigit(*buf);
   3280       n++; buf++;
   3281    }
   3282    return n;
   3283 }
   3284 
   3285 static Int readhex64 ( const HChar* buf, ULong* val )
   3286 {
   3287    /* Read a potentially 64-bit hex number. */
   3288    Int n = 0;
   3289    *val = 0;
   3290    while (hexdigit(*buf) >= 0) {
   3291       *val = (*val << 4) + hexdigit(*buf);
   3292       n++; buf++;
   3293    }
   3294    return n;
   3295 }
   3296 
   3297 static Int readdec64 ( const HChar* buf, ULong* val )
   3298 {
   3299    Int n = 0;
   3300    *val = 0;
   3301    while (decdigit(*buf) >= 0) {
   3302       *val = (*val * 10) + decdigit(*buf);
   3303       n++; buf++;
   3304    }
   3305    return n;
   3306 }
   3307 
   3308 
   3309 /* Get the contents of /proc/self/maps into a static buffer.  If
   3310    there's a syntax error, it won't fit, or other failure, just
   3311    abort. */
   3312 
   3313 static void read_procselfmaps_into_buf ( void )
   3314 {
   3315    Int    n_chunk;
   3316    SysRes fd;
   3317 
   3318    /* Read the initial memory mapping from the /proc filesystem. */
   3319    fd = ML_(am_open)( "/proc/self/maps", VKI_O_RDONLY, 0 );
   3320    if (sr_isError(fd))
   3321       ML_(am_barf)("can't open /proc/self/maps");
   3322 
   3323    buf_n_tot = 0;
   3324    do {
   3325       n_chunk = ML_(am_read)( sr_Res(fd), &procmap_buf[buf_n_tot],
   3326                               M_PROCMAP_BUF - buf_n_tot );
   3327       if (n_chunk >= 0)
   3328          buf_n_tot += n_chunk;
   3329    } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
   3330 
   3331    ML_(am_close)(sr_Res(fd));
   3332 
   3333    if (buf_n_tot >= M_PROCMAP_BUF-5)
   3334       ML_(am_barf_toolow)("M_PROCMAP_BUF");
   3335    if (buf_n_tot == 0)
   3336       ML_(am_barf)("I/O error on /proc/self/maps");
   3337 
   3338    procmap_buf[buf_n_tot] = 0;
   3339 }
   3340 
   3341 /* Parse /proc/self/maps.  For each map entry, call
   3342    record_mapping, passing it, in this order:
   3343 
   3344       start address in memory
   3345       length
   3346       page protections (using the VKI_PROT_* flags)
   3347       mapped file device and inode
   3348       offset in file, or zero if no file
   3349       filename, zero terminated, or NULL if no file
   3350 
   3351    So the sig of the called fn might be
   3352 
   3353       void (*record_mapping)( Addr start, SizeT size, UInt prot,
   3354 			      UInt dev, UInt info,
   3355                               ULong foffset, UChar* filename )
   3356 
   3357    Note that the supplied filename is transiently stored; record_mapping
   3358    should make a copy if it wants to keep it.
   3359 
   3360    Nb: it is important that this function does not alter the contents of
   3361        procmap_buf!
   3362 */
   3363 static void parse_procselfmaps (
   3364       void (*record_mapping)( Addr addr, SizeT len, UInt prot,
   3365                               ULong dev, ULong ino, Off64T offset,
   3366                               const HChar* filename ),
   3367       void (*record_gap)( Addr addr, SizeT len )
   3368    )
   3369 {
   3370    Int    i, j, i_eol;
   3371    Addr   start, endPlusOne, gapStart;
   3372    HChar* filename;
   3373    HChar  rr, ww, xx, pp, ch, tmp;
   3374    UInt	  prot;
   3375    UWord  maj, min;
   3376    ULong  foffset, dev, ino;
   3377 
   3378    foffset = ino = 0; /* keep gcc-4.1.0 happy */
   3379 
   3380    read_procselfmaps_into_buf();
   3381 
   3382    aspacem_assert('\0' != procmap_buf[0] && 0 != buf_n_tot);
   3383 
   3384    if (0)
   3385       VG_(debugLog)(0, "procselfmaps", "raw:\n%s\n", procmap_buf);
   3386 
   3387    /* Ok, it's safely aboard.  Parse the entries. */
   3388    i = 0;
   3389    gapStart = Addr_MIN;
   3390    while (True) {
   3391       if (i >= buf_n_tot) break;
   3392 
   3393       /* Read (without fscanf :) the pattern %16x-%16x %c%c%c%c %16x %2x:%2x %d */
   3394       j = readhex(&procmap_buf[i], &start);
   3395       if (j > 0) i += j; else goto syntaxerror;
   3396       j = readchar(&procmap_buf[i], &ch);
   3397       if (j == 1 && ch == '-') i += j; else goto syntaxerror;
   3398       j = readhex(&procmap_buf[i], &endPlusOne);
   3399       if (j > 0) i += j; else goto syntaxerror;
   3400 
   3401       j = readchar(&procmap_buf[i], &ch);
   3402       if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
   3403 
   3404       j = readchar(&procmap_buf[i], &rr);
   3405       if (j == 1 && (rr == 'r' || rr == '-')) i += j; else goto syntaxerror;
   3406       j = readchar(&procmap_buf[i], &ww);
   3407       if (j == 1 && (ww == 'w' || ww == '-')) i += j; else goto syntaxerror;
   3408       j = readchar(&procmap_buf[i], &xx);
   3409       if (j == 1 && (xx == 'x' || xx == '-')) i += j; else goto syntaxerror;
   3410       /* This field is the shared/private flag */
   3411       j = readchar(&procmap_buf[i], &pp);
   3412       if (j == 1 && (pp == 'p' || pp == '-' || pp == 's'))
   3413                                               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 = readhex64(&procmap_buf[i], &foffset);
   3419       if (j > 0) i += j; else goto syntaxerror;
   3420 
   3421       j = readchar(&procmap_buf[i], &ch);
   3422       if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
   3423 
   3424       j = readhex(&procmap_buf[i], &maj);
   3425       if (j > 0) i += j; else goto syntaxerror;
   3426       j = readchar(&procmap_buf[i], &ch);
   3427       if (j == 1 && ch == ':') i += j; else goto syntaxerror;
   3428       j = readhex(&procmap_buf[i], &min);
   3429       if (j > 0) i += j; else goto syntaxerror;
   3430 
   3431       j = readchar(&procmap_buf[i], &ch);
   3432       if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
   3433 
   3434       j = readdec64(&procmap_buf[i], &ino);
   3435       if (j > 0) i += j; else goto syntaxerror;
   3436 
   3437       goto read_line_ok;
   3438 
   3439     syntaxerror:
   3440       VG_(debugLog)(0, "Valgrind:",
   3441                        "FATAL: syntax error reading /proc/self/maps\n");
   3442       { Int k, m;
   3443         HChar buf50[51];
   3444         m = 0;
   3445         buf50[m] = 0;
   3446         k = i - 50;
   3447         if (k < 0) k = 0;
   3448         for (; k <= i; k++) {
   3449            buf50[m] = procmap_buf[k];
   3450            buf50[m+1] = 0;
   3451            if (m < 50-1) m++;
   3452         }
   3453         VG_(debugLog)(0, "procselfmaps", "Last 50 chars: '%s'\n", buf50);
   3454       }
   3455       ML_(am_exit)(1);
   3456 
   3457     read_line_ok:
   3458 
   3459       aspacem_assert(i < buf_n_tot);
   3460 
   3461       /* Try and find the name of the file mapped to this segment, if
   3462          it exists.  Note that file names can contain spaces. */
   3463 
   3464       // Move i to the next non-space char, which should be either a '/',
   3465       // a '[', or a newline.
   3466       while (procmap_buf[i] == ' ') i++;
   3467 
   3468       // Move i_eol to the end of the line.
   3469       i_eol = i;
   3470       while (procmap_buf[i_eol] != '\n') i_eol++;
   3471 
   3472       // If there's a filename...
   3473       if (procmap_buf[i] == '/') {
   3474          /* Minor hack: put a '\0' at the filename end for the call to
   3475             'record_mapping', then restore the old char with 'tmp'. */
   3476          filename = &procmap_buf[i];
   3477          tmp = filename[i_eol - i];
   3478          filename[i_eol - i] = '\0';
   3479       } else {
   3480 	 tmp = 0;
   3481          filename = NULL;
   3482          foffset = 0;
   3483       }
   3484 
   3485       prot = 0;
   3486       if (rr == 'r') prot |= VKI_PROT_READ;
   3487       if (ww == 'w') prot |= VKI_PROT_WRITE;
   3488       if (xx == 'x') prot |= VKI_PROT_EXEC;
   3489 
   3490       /* Linux has two ways to encode a device number when it
   3491          is exposed to user space (via fstat etc). The old way
   3492          is the traditional unix scheme that produces a 16 bit
   3493          device number with the top 8 being the major number and
   3494          the bottom 8 the minor number.
   3495 
   3496          The new scheme allows for a 12 bit major number and
   3497          a 20 bit minor number by using a 32 bit device number
   3498          and putting the top 12 bits of the minor number into
   3499          the top 12 bits of the device number thus leaving an
   3500          extra 4 bits for the major number.
   3501 
   3502          If the minor and major number are both single byte
   3503          values then both schemes give the same result so we
   3504          use the new scheme here in case either number is
   3505          outside the 0-255 range and then use fstat64 when
   3506          available (or fstat on 64 bit systems) so that we
   3507          should always have a new style device number and
   3508          everything should match. */
   3509       dev = (min & 0xff) | (maj << 8) | ((min & ~0xff) << 12);
   3510 
   3511       if (record_gap && gapStart < start)
   3512          (*record_gap) ( gapStart, start-gapStart );
   3513 
   3514       if (record_mapping && start < endPlusOne)
   3515          (*record_mapping) ( start, endPlusOne-start,
   3516                              prot, dev, ino,
   3517                              foffset, filename );
   3518 
   3519       if ('\0' != tmp) {
   3520          filename[i_eol - i] = tmp;
   3521       }
   3522 
   3523       i = i_eol + 1;
   3524       gapStart = endPlusOne;
   3525    }
   3526 
   3527 #  if defined(VGP_arm_linux)
   3528    /* ARM puts code at the end of memory that contains processor
   3529       specific stuff (cmpxchg, getting the thread local storage, etc.)
   3530       This isn't specified in /proc/self/maps, so do it here.  This
   3531       kludgery causes the view of memory, as presented to
   3532       record_gap/record_mapping, to actually reflect reality.  IMO
   3533       (JRS, 2010-Jan-03) the fact that /proc/.../maps does not list
   3534       the commpage should be regarded as a bug in the kernel. */
   3535    { const Addr commpage_start = ARM_LINUX_FAKE_COMMPAGE_START;
   3536      const Addr commpage_end1  = ARM_LINUX_FAKE_COMMPAGE_END1;
   3537      if (gapStart < commpage_start) {
   3538         if (record_gap)
   3539            (*record_gap)( gapStart, commpage_start - gapStart );
   3540         if (record_mapping)
   3541            (*record_mapping)( commpage_start, commpage_end1 - commpage_start,
   3542                               VKI_PROT_READ|VKI_PROT_EXEC,
   3543                               0/*dev*/, 0/*ino*/, 0/*foffset*/,
   3544                               NULL);
   3545         gapStart = commpage_end1;
   3546      }
   3547    }
   3548 #  endif
   3549 
   3550    if (record_gap && gapStart < Addr_MAX)
   3551       (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
   3552 }
   3553 
   3554 /*------END-procmaps-parser-for-Linux----------------------------*/
   3555 
   3556 /*------BEGIN-procmaps-parser-for-Darwin-------------------------*/
   3557 
   3558 #elif defined(VGO_darwin)
   3559 #include <mach/mach.h>
   3560 #include <mach/mach_vm.h>
   3561 
   3562 static unsigned int mach2vki(unsigned int vm_prot)
   3563 {
   3564    return
   3565       ((vm_prot & VM_PROT_READ)    ? VKI_PROT_READ    : 0) |
   3566       ((vm_prot & VM_PROT_WRITE)   ? VKI_PROT_WRITE   : 0) |
   3567       ((vm_prot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC    : 0) ;
   3568 }
   3569 
   3570 static UInt stats_machcalls = 0;
   3571 
   3572 static void parse_procselfmaps (
   3573       void (*record_mapping)( Addr addr, SizeT len, UInt prot,
   3574                               ULong dev, ULong ino, Off64T offset,
   3575                               const HChar* filename ),
   3576       void (*record_gap)( Addr addr, SizeT len )
   3577    )
   3578 {
   3579    vm_address_t iter;
   3580    unsigned int depth;
   3581    vm_address_t last;
   3582 
   3583    iter = 0;
   3584    depth = 0;
   3585    last = 0;
   3586    while (1) {
   3587       mach_vm_address_t addr = iter;
   3588       mach_vm_size_t size;
   3589       vm_region_submap_short_info_data_64_t info;
   3590       kern_return_t kr;
   3591 
   3592       while (1) {
   3593          mach_msg_type_number_t info_count
   3594             = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
   3595          stats_machcalls++;
   3596          kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth,
   3597                                      (vm_region_info_t)&info, &info_count);
   3598          if (kr)
   3599             return;
   3600          if (info.is_submap) {
   3601             depth++;
   3602             continue;
   3603          }
   3604          break;
   3605       }
   3606       iter = addr + size;
   3607 
   3608       if (addr > last  &&  record_gap) {
   3609          (*record_gap)(last, addr - last);
   3610       }
   3611       if (record_mapping) {
   3612          (*record_mapping)(addr, size, mach2vki(info.protection),
   3613                            0, 0, info.offset, NULL);
   3614       }
   3615       last = addr + size;
   3616    }
   3617 
   3618    if ((Addr)-1 > last  &&  record_gap)
   3619       (*record_gap)(last, (Addr)-1 - last);
   3620 }
   3621 
   3622 // Urr.  So much for thread safety.
   3623 static Bool        css_overflowed;
   3624 static ChangedSeg* css_local;
   3625 static Int         css_size_local;
   3626 static Int         css_used_local;
   3627 
   3628 static Addr Addr__max ( Addr a, Addr b ) { return a > b ? a : b; }
   3629 static Addr Addr__min ( Addr a, Addr b ) { return a < b ? a : b; }
   3630 
   3631 static void add_mapping_callback(Addr addr, SizeT len, UInt prot,
   3632                                  ULong dev, ULong ino, Off64T offset,
   3633                                  const HChar *filename)
   3634 {
   3635    // derived from sync_check_mapping_callback()
   3636 
   3637    /* JRS 2012-Mar-07: this all seems very dubious to me.  It would be
   3638       safer to see if we can find, in V's segment collection, one
   3639       single segment that completely covers the range [addr, +len)
   3640       (and possibly more), and that has the exact same other
   3641       properties (prot, dev, ino, offset, etc) as the data presented
   3642       here.  If found, we just skip.  Otherwise add the data presented
   3643       here into css_local[]. */
   3644 
   3645    Int iLo, iHi, i;
   3646 
   3647    if (len == 0) return;
   3648 
   3649    /* The kernel should not give us wraparounds. */
   3650    aspacem_assert(addr <= addr + len - 1);
   3651 
   3652    iLo = find_nsegment_idx( addr );
   3653    iHi = find_nsegment_idx( addr + len - 1 );
   3654 
   3655    /* NSegments iLo .. iHi inclusive should agree with the presented
   3656       data. */
   3657    for (i = iLo; i <= iHi; i++) {
   3658 
   3659       UInt seg_prot;
   3660 
   3661       if (nsegments[i].kind == SkAnonV  ||  nsegments[i].kind == SkFileV) {
   3662          /* Ignore V regions */
   3663          continue;
   3664       }
   3665       else if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) {
   3666          /* Add mapping for SkResvn regions */
   3667          ChangedSeg* cs = &css_local[css_used_local];
   3668          if (css_used_local < css_size_local) {
   3669             cs->is_added = True;
   3670             cs->start    = addr;
   3671             cs->end      = addr + len - 1;
   3672             cs->prot     = prot;
   3673             cs->offset   = offset;
   3674             css_used_local++;
   3675          } else {
   3676             css_overflowed = True;
   3677          }
   3678          return;
   3679 
   3680       }
   3681       else if (nsegments[i].kind == SkAnonC ||
   3682                nsegments[i].kind == SkFileC ||
   3683                nsegments[i].kind == SkShmC)
   3684       {
   3685          /* Check permissions on client regions */
   3686          // GrP fixme
   3687          seg_prot = 0;
   3688          if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
   3689          if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
   3690 #        if defined(VGA_x86)
   3691          // GrP fixme sloppyXcheck
   3692          // darwin: kernel X ignored and spuriously changes? (vm_copy)
   3693          seg_prot |= (prot & VKI_PROT_EXEC);
   3694 #        else
   3695          if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
   3696 #        endif
   3697          if (seg_prot != prot) {
   3698              if (VG_(clo_trace_syscalls))
   3699                  VG_(debugLog)(0,"aspacem","region %p..%p permission "
   3700                                  "mismatch (kernel %x, V %x)\n",
   3701                                  (void*)nsegments[i].start,
   3702                                  (void*)(nsegments[i].end+1), prot, seg_prot);
   3703             /* Add mapping for regions with protection changes */
   3704             ChangedSeg* cs = &css_local[css_used_local];
   3705             if (css_used_local < css_size_local) {
   3706                cs->is_added = True;
   3707                cs->start    = addr;
   3708                cs->end      = addr + len - 1;
   3709                cs->prot     = prot;
   3710                cs->offset   = offset;
   3711                css_used_local++;
   3712             } else {
   3713                css_overflowed = True;
   3714             }
   3715 	    return;
   3716 
   3717          }
   3718 
   3719       } else {
   3720          aspacem_assert(0);
   3721       }
   3722    }
   3723 }
   3724 
   3725 static void remove_mapping_callback(Addr addr, SizeT len)
   3726 {
   3727    // derived from sync_check_gap_callback()
   3728 
   3729    Int iLo, iHi, i;
   3730 
   3731    if (len == 0)
   3732       return;
   3733 
   3734    /* The kernel should not give us wraparounds. */
   3735    aspacem_assert(addr <= addr + len - 1);
   3736 
   3737    iLo = find_nsegment_idx( addr );
   3738    iHi = find_nsegment_idx( addr + len - 1 );
   3739 
   3740    /* NSegments iLo .. iHi inclusive should agree with the presented data. */
   3741    for (i = iLo; i <= iHi; i++) {
   3742       if (nsegments[i].kind != SkFree && nsegments[i].kind != SkResvn) {
   3743          /* V has a mapping, kernel doesn't.  Add to css_local[],
   3744             directives to chop off the part of the V mapping that
   3745             falls within the gap that the kernel tells us is
   3746             present. */
   3747          ChangedSeg* cs = &css_local[css_used_local];
   3748          if (css_used_local < css_size_local) {
   3749             cs->is_added = False;
   3750             cs->start    = Addr__max(nsegments[i].start, addr);
   3751             cs->end      = Addr__min(nsegments[i].end,   addr + len - 1);
   3752             aspacem_assert(VG_IS_PAGE_ALIGNED(cs->start));
   3753             aspacem_assert(VG_IS_PAGE_ALIGNED(cs->end+1));
   3754             /* I don't think the following should fail.  But if it
   3755                does, just omit the css_used_local++ in the cases where
   3756                it doesn't hold. */
   3757             aspacem_assert(cs->start < cs->end);
   3758             cs->prot     = 0;
   3759             cs->offset   = 0;
   3760             css_used_local++;
   3761          } else {
   3762             css_overflowed = True;
   3763          }
   3764       }
   3765    }
   3766 }
   3767 
   3768 
   3769 // Returns False if 'css' wasn't big enough.
   3770 Bool VG_(get_changed_segments)(
   3771       const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css,
   3772       Int css_size, /*OUT*/Int* css_used)
   3773 {
   3774    static UInt stats_synccalls = 1;
   3775    aspacem_assert(when && where);
   3776 
   3777    if (0)
   3778       VG_(debugLog)(0,"aspacem",
   3779          "[%u,%u] VG_(get_changed_segments)(%s, %s)\n",
   3780          stats_synccalls++, stats_machcalls, when, where
   3781       );
   3782 
   3783    css_overflowed = False;
   3784    css_local = css;
   3785    css_size_local = css_size;
   3786    css_used_local = 0;
   3787 
   3788    // Get the list of segs that need to be added/removed.
   3789    parse_procselfmaps(&add_mapping_callback, &remove_mapping_callback);
   3790 
   3791    *css_used = css_used_local;
   3792 
   3793    if (css_overflowed) {
   3794       aspacem_assert(css_used_local == css_size_local);
   3795    }
   3796 
   3797    return !css_overflowed;
   3798 }
   3799 
   3800 #endif // defined(VGO_darwin)
   3801 
   3802 /*------END-procmaps-parser-for-Darwin---------------------------*/
   3803 
   3804 /*------BEGIN-procmaps-parser-for-Solaris------------------------*/
   3805 
   3806 #if defined(VGO_solaris)
   3807 
   3808 /* Note: /proc/self/xmap contains extended information about already
   3809    materialized mappings whereas /proc/self/rmap contains information about
   3810    all mappings including reserved but yet-to-materialize mappings (mmap'ed
   3811    with MAP_NORESERVE flag, such as thread stacks). But /proc/self/rmap does
   3812    not contain extended information found in /proc/self/xmap. Therefore
   3813    information from both sources need to be combined.
   3814  */
   3815 
   3816 typedef struct
   3817 {
   3818    Addr   addr;
   3819    SizeT  size;
   3820    UInt   prot;
   3821    ULong  dev;
   3822    ULong  ino;
   3823    Off64T foffset;
   3824    HChar  filename[VKI_PATH_MAX];
   3825 } Mapping;
   3826 
   3827 static SizeT read_proc_file(const HChar *filename, HChar *buf,
   3828                             SizeT buf_size, const HChar *buf_size_name,
   3829                             SizeT entry_size)
   3830 {
   3831    SysRes res = ML_(am_open)(filename, VKI_O_RDONLY, 0);
   3832    if (sr_isError(res)) {
   3833       HChar message[100];
   3834       ML_(am_sprintf)(message, "Cannot open %s.", filename);
   3835       ML_(am_barf)(message);
   3836    }
   3837    Int fd = sr_Res(res);
   3838 
   3839    Int r = ML_(am_read)(fd, buf, buf_size);
   3840    ML_(am_close)(fd);
   3841    if (r < 0) {
   3842       HChar message[100];
   3843       ML_(am_sprintf)(message, "I/O error on %s.", filename);
   3844       ML_(am_barf)(message);
   3845    }
   3846 
   3847    if (r >= buf_size)
   3848       ML_(am_barf_toolow)(buf_size_name);
   3849 
   3850    if (r % entry_size != 0) {
   3851       HChar message[100];
   3852       ML_(am_sprintf)(message, "Bogus values read from %s.", filename);
   3853       ML_(am_barf)(message);
   3854    }
   3855 
   3856    return r / entry_size;
   3857 }
   3858 
   3859 static Mapping *next_xmap(const HChar *buffer, SizeT entries, SizeT *idx,
   3860                           Mapping *mapping)
   3861 {
   3862    aspacem_assert(idx);
   3863    aspacem_assert(mapping);
   3864 
   3865    if (*idx >= entries)
   3866       return NULL; /* No more entries */
   3867 
   3868    const vki_prxmap_t *map = (const vki_prxmap_t *)buffer + *idx;
   3869 
   3870    mapping->addr = map->pr_vaddr;
   3871    mapping->size = map->pr_size;
   3872 
   3873    mapping->prot = 0;
   3874    if (map->pr_mflags & VKI_MA_READ)
   3875       mapping->prot |= VKI_PROT_READ;
   3876    if (map->pr_mflags & VKI_MA_WRITE)
   3877       mapping->prot |= VKI_PROT_WRITE;
   3878    if (map->pr_mflags & VKI_MA_EXEC)
   3879       mapping->prot |= VKI_PROT_EXEC;
   3880 
   3881    if (map->pr_dev != VKI_PRNODEV) {
   3882       mapping->dev = map->pr_dev;
   3883       mapping->ino = map->pr_ino;
   3884       mapping->foffset = map->pr_offset;
   3885    }
   3886    else {
   3887       mapping->dev = 0;
   3888       mapping->ino = 0;
   3889       mapping->foffset = 0;
   3890    }
   3891 
   3892    /* Try to get the filename. */
   3893    mapping->filename[0] = '\0';
   3894    if (map->pr_mapname[0] != '\0') {
   3895       ML_(am_sprintf)(mapping->filename, "/proc/self/path/%s",
   3896                       map->pr_mapname);
   3897       Int r = ML_(am_readlink)(mapping->filename, mapping->filename,
   3898                                sizeof(mapping->filename) - 1);
   3899       if (r == -1) {
   3900          /* If Valgrind is executed in a non-global zone and the link in
   3901             /proc/self/path/ represents a file that is available through lofs
   3902             from a global zone then the kernel may not be able to resolve the
   3903             link.
   3904 
   3905             In such a case, return a corresponding /proc/self/object/ file to
   3906             allow Valgrind to read the file if it is necessary.
   3907 
   3908             This can create some discrepancy for the sanity check. For
   3909             instance, if a client program mmaps some file then the address
   3910             space manager will have a correct zone-local name of that file,
   3911             but the sanity check will receive a different file name from this
   3912             code. This currently does not represent a problem because the
   3913             sanity check ignores the file names (it uses device and inode
   3914             numbers for the comparison).
   3915           */
   3916          ML_(am_sprintf)(mapping->filename, "/proc/self/object/%s",
   3917                          map->pr_mapname);
   3918       }
   3919       else {
   3920          aspacem_assert(r >= 0);
   3921          mapping->filename[r] = '\0';
   3922       }
   3923    }
   3924 
   3925    *idx += 1;
   3926    return mapping;
   3927 }
   3928 
   3929 static Mapping *next_rmap(const HChar *buffer, SizeT entries, SizeT *idx,
   3930                           Mapping *mapping)
   3931 {
   3932    aspacem_assert(idx);
   3933    aspacem_assert(mapping);
   3934 
   3935    if (*idx >= entries)
   3936       return NULL; /* No more entries */
   3937 
   3938    const vki_prmap_t *map = (const vki_prmap_t *)buffer + *idx;
   3939 
   3940    mapping->addr = map->pr_vaddr;
   3941    mapping->size = map->pr_size;
   3942 
   3943    mapping->prot = 0;
   3944    if (map->pr_mflags & VKI_MA_READ)
   3945       mapping->prot |= VKI_PROT_READ;
   3946    if (map->pr_mflags & VKI_MA_WRITE)
   3947       mapping->prot |= VKI_PROT_WRITE;
   3948    if (map->pr_mflags & VKI_MA_EXEC)
   3949       mapping->prot |= VKI_PROT_EXEC;
   3950 
   3951    mapping->dev = 0;
   3952    mapping->ino = 0;
   3953    mapping->foffset = 0;
   3954    mapping->filename[0] = '\0';
   3955 
   3956    *idx += 1;
   3957    return mapping;
   3958 }
   3959 
   3960 /* Used for two purposes:
   3961    1. Establish initial mappings upon the process startup
   3962    2. Check mappings during aspacemgr sanity check
   3963  */
   3964 static void parse_procselfmaps (
   3965       void (*record_mapping)( Addr addr, SizeT len, UInt prot,
   3966                               ULong dev, ULong ino, Off64T offset,
   3967                               const HChar *filename ),
   3968       void (*record_gap)( Addr addr, SizeT len )
   3969    )
   3970 {
   3971    Addr start = Addr_MIN;
   3972    Addr gap_start = Addr_MIN;
   3973 
   3974 #define M_XMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prxmap_t))
   3975    /* Static to keep it out of stack frame... */
   3976    static HChar xmap_buf[M_XMAP_BUF];
   3977    const Mapping *xmap = NULL;
   3978    SizeT xmap_index = 0; /* Current entry */
   3979    SizeT xmap_entries;
   3980    Mapping xmap_mapping;
   3981    Bool advance_xmap;
   3982 
   3983 #define M_RMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prmap_t))
   3984    static HChar rmap_buf[M_RMAP_BUF];
   3985    const Mapping *rmap = NULL;
   3986    SizeT rmap_index = 0; /* Current entry */
   3987    SizeT rmap_entries;
   3988    Mapping rmap_mapping;
   3989    Bool advance_rmap;
   3990 
   3991    /* Read fully /proc/self/xmap and /proc/self/rmap. */
   3992    xmap_entries = read_proc_file("/proc/self/xmap", xmap_buf, M_XMAP_BUF,
   3993                                  "M_XMAP_BUF", sizeof(vki_prxmap_t));
   3994 
   3995    rmap_entries = read_proc_file("/proc/self/rmap", rmap_buf, M_RMAP_BUF,
   3996                                  "M_RMAP_BUF", sizeof(vki_prmap_t));
   3997 
   3998    /* Get the first xmap and rmap. */
   3999    advance_xmap = True;
   4000    advance_rmap = True;
   4001 
   4002    while (1) {
   4003       /* Get next xmap or rmap if necessary. */
   4004       if (advance_xmap) {
   4005          xmap = next_xmap(xmap_buf, xmap_entries, &xmap_index, &xmap_mapping);
   4006          advance_xmap = False;
   4007       }
   4008       if (advance_rmap) {
   4009          rmap = next_rmap(rmap_buf, rmap_entries, &rmap_index, &rmap_mapping);
   4010          advance_rmap = False;
   4011       }
   4012 
   4013       /* Check if the end has been reached. */
   4014       if (rmap == NULL)
   4015          break;
   4016 
   4017       /* Invariants */
   4018       if (xmap != NULL) {
   4019          aspacem_assert(start <= xmap->addr);
   4020          aspacem_assert(rmap->addr <= xmap->addr);
   4021       }
   4022 
   4023       if (xmap != NULL && start == xmap->addr) {
   4024          /* xmap mapping reached. */
   4025          aspacem_assert(xmap->addr >= rmap->addr &&
   4026                         xmap->addr + xmap->size <= rmap->addr + rmap->size);
   4027          aspacem_assert(xmap->prot == rmap->prot);
   4028 
   4029          if (record_mapping != NULL)
   4030             (*record_mapping)(xmap->addr, xmap->size, xmap->prot, xmap->dev,
   4031                               xmap->ino, xmap->foffset,
   4032                               (xmap->filename[0] != '\0') ?
   4033                                xmap->filename : NULL);
   4034 
   4035          start = xmap->addr + xmap->size;
   4036          advance_xmap = True;
   4037       }
   4038       else if (start >= rmap->addr) {
   4039          /* Reserved-only part. */
   4040          /* First calculate size until the end of this reserved mapping... */
   4041          SizeT size = rmap->addr + rmap->size - start;
   4042          /* ... but shrink it if some xmap is in a way. */
   4043          if (xmap != NULL && size > xmap->addr - start)
   4044             size = xmap->addr - start;
   4045 
   4046          if (record_mapping != NULL)
   4047             (*record_mapping)(start, size, rmap->prot, 0, 0, 0, NULL);
   4048          start += size;
   4049       }
   4050       else {
   4051          /* Gap. */
   4052          if (record_gap != NULL && gap_start < start)
   4053             (*record_gap)(gap_start, start - gap_start);
   4054          start = rmap->addr;
   4055       }
   4056 
   4057       if (rmap->addr + rmap->size <= start)
   4058          advance_rmap = True;
   4059 
   4060       gap_start = start;
   4061    }
   4062 
   4063    if (record_gap != NULL && gap_start < Addr_MAX)
   4064       (*record_gap)(gap_start, Addr_MAX - gap_start + 1);
   4065 }
   4066 
   4067 /* parse_procselfmaps() callbacks do not allow for easy thread safety. */
   4068 static Addr found_addr;
   4069 static SizeT found_size;
   4070 static UInt found_prot;
   4071 
   4072 /* Reports a new mapping into variables above. */
   4073 static void new_segment_found_callback(Addr addr, SizeT len, UInt prot,
   4074    ULong dev, ULong ino, Off64T offset, const HChar *filename)
   4075 {
   4076    aspacem_assert(addr <= addr + len - 1);
   4077 
   4078    Int iLo = find_nsegment_idx(addr);
   4079    Int iHi = find_nsegment_idx(addr + len - 1);
   4080    aspacem_assert(iLo <= iHi);
   4081    aspacem_assert(nsegments[iLo].start <= addr);
   4082    aspacem_assert(nsegments[iHi].end   >= addr + len - 1);
   4083 
   4084    /* Do not perform any sanity checks. That is done in other places.
   4085       Just find if a reported mapping is found in aspacemgr's book keeping. */
   4086    for (Int i = iLo; i <= iHi; i++) {
   4087       if ((nsegments[i].kind == SkFree) || (nsegments[i].kind == SkResvn)) {
   4088          found_addr = addr;
   4089          found_size = len;
   4090          found_prot = prot;
   4091          break;
   4092       }
   4093    }
   4094 }
   4095 
   4096 /* Returns True if a new segment was found. */
   4097 Bool VG_(am_search_for_new_segment)(Addr *addr, SizeT *size, UInt *prot)
   4098 {
   4099    found_addr = 0;
   4100    parse_procselfmaps(new_segment_found_callback, NULL);
   4101 
   4102    if (found_addr != 0) {
   4103       *addr = found_addr;
   4104       *size = found_size;
   4105       *prot = found_prot;
   4106       return True;
   4107    } else {
   4108       return False;
   4109    }
   4110 }
   4111 
   4112 #endif // defined(VGO_solaris)
   4113 
   4114 /*------END-procmaps-parser-for-Solaris--------------------------*/
   4115 
   4116 #endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
   4117 
   4118 /*--------------------------------------------------------------------*/
   4119 /*--- end                                                          ---*/
   4120 /*--------------------------------------------------------------------*/
   4121