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