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