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