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