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