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