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