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