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