]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_aspacemgr/aspacemgr-l4re.c
update
[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 /* Convenience wrapper for VG_(am_get_advisory) for Valgrind floating or
1993    fixed requests.  If start is zero, a floating request is issued; if
1994    nonzero, a fixed request at that address is issued.  Same comments
1995    about return values apply. */
1996
1997 Addr VG_(am_get_advisory_valgrind_simple) ( Addr start, SizeT len, 
1998                                                                                         /*OUT*/Bool* ok )
1999 {
2000         MapRequest mreq;
2001         mreq.rkind = start==0 ? MAny : MFixed;
2002         mreq.start = start;
2003         mreq.len   = len;
2004         return VG_(am_get_advisory)( &mreq, False/*Valgrind*/, ok );
2005 }
2006
2007
2008 /* Notifies aspacem that the client completed an mmap successfully.
2009    The segment array is updated accordingly.  If the returned Bool is
2010    True, the caller should immediately discard translations from the
2011    specified address range. */
2012
2013 Bool
2014 VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
2015                             Int fd, Off64T offset )
2016 {
2017 #define DEBUG_MYSELF 0
2018    HChar    buf[VKI_PATH_MAX];
2019    ULong    dev, ino;
2020    UInt     mode;
2021    NSegment seg;
2022    Bool     needDiscard;
2023
2024 #if DEBUG_MYSELF
2025    if (!(len > 0))
2026        enter_kdebug("!len>0");
2027 #endif
2028    aspacem_assert(len > 0);
2029    aspacem_assert(VG_IS_PAGE_ALIGNED(a));
2030    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2031    aspacem_assert(VG_IS_PAGE_ALIGNED(offset));
2032
2033    /* Discard is needed if any of the just-trashed range had T. */
2034    needDiscard = any_Ts_in_range( a, len );
2035
2036    init_nsegment( &seg );
2037    seg.kind   = (flags & VKI_MAP_ANONYMOUS) ? SkAnonC : SkFileC;
2038    seg.start  = a;
2039    seg.end    = a + len - 1;
2040    seg.hasR   = toBool(prot & VKI_PROT_READ);
2041    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
2042    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
2043    if (!(flags & VKI_MAP_ANONYMOUS)) {
2044       // Nb: We ignore offset requests in anonymous mmaps (see bug #126722)
2045       seg.offset = offset;
2046       if (get_inode_for_fd(fd, &dev, &ino, &mode)) {
2047          seg.dev = dev;
2048          seg.ino = ino;
2049          seg.mode = mode;
2050       }
2051       if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
2052          seg.fnIdx = allocate_segname( buf );
2053       }
2054    }
2055    add_segment( &seg );
2056    AM_SANITY_CHECK;
2057    return needDiscard;
2058 #undef DEBUG_MYSELF
2059 }
2060
2061 /* Notifies aspacem that the valgrind completed an mmap successfully.
2062    The segment array is updated accordingly.  If the returned Bool is
2063    True, the caller should immediately discard translations from the
2064    specified address range. */
2065
2066 Bool
2067 VG_(am_notify_valgrind_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
2068                             Int fd, Off64T offset )
2069 {
2070    HChar    buf[VKI_PATH_MAX];
2071    NSegment seg;
2072    Bool     needDiscard;
2073
2074    aspacem_assert(len > 0);
2075    aspacem_assert(VG_IS_PAGE_ALIGNED(a));
2076    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2077    aspacem_assert(VG_IS_PAGE_ALIGNED(offset));
2078
2079    /* Discard is needed if any of the just-trashed range had T. */
2080    needDiscard = any_Ts_in_range( a, len );
2081
2082    init_nsegment( &seg );
2083    seg.kind   = (flags & VKI_MAP_ANONYMOUS) ? SkAnonV : SkFileV;
2084    seg.start  = a;
2085    seg.end    = a + len - 1;
2086    seg.hasR   = toBool(prot & VKI_PROT_READ);
2087    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
2088    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
2089    if (!(flags & VKI_MAP_ANONYMOUS)) {
2090       // Nb: We ignore offset requests in anonymous mmaps (see bug #126722)
2091       seg.offset = offset;
2092       if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
2093          seg.fnIdx = allocate_segname( buf );
2094       }
2095    }
2096    add_segment( &seg );
2097    AM_SANITY_CHECK;
2098    return needDiscard;
2099 }
2100
2101
2102 /* Notifies aspacem that the client completed a shmat successfully.
2103    The segment array is updated accordingly.  If the returned Bool is
2104    True, the caller should immediately discard translations from the
2105    specified address range. */
2106
2107 Bool
2108 VG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot )
2109 {
2110    NSegment seg;
2111    Bool     needDiscard;
2112
2113    aspacem_assert(len > 0);
2114    aspacem_assert(VG_IS_PAGE_ALIGNED(a));
2115    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2116
2117    /* Discard is needed if any of the just-trashed range had T. */
2118    needDiscard = any_Ts_in_range( a, len );
2119
2120    init_nsegment( &seg );
2121    seg.kind   = SkShmC;
2122    seg.start  = a;
2123    seg.end    = a + len - 1;
2124    seg.offset = 0;
2125    seg.hasR   = toBool(prot & VKI_PROT_READ);
2126    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
2127    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
2128    add_segment( &seg );
2129    AM_SANITY_CHECK;
2130    return needDiscard;
2131 }
2132
2133 /* Notifies aspacem that an mprotect was completed successfully.  The
2134    segment array is updated accordingly.  Note, as with
2135    VG_(am_notify_munmap), it is not the job of this function to reject
2136    stupid mprotects, for example the client doing mprotect of
2137    non-client areas.  Such requests should be intercepted earlier, by
2138    the syscall wrapper for mprotect.  This function merely records
2139    whatever it is told.  If the returned Bool is True, the caller
2140    should immediately discard translations from the specified address
2141    range. */
2142
2143 Bool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot )
2144 {
2145    Int  i, iLo, iHi;
2146    Bool newR, newW, newX, needDiscard;
2147
2148    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2149    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2150
2151    if (len == 0)
2152       return False;
2153
2154    newR = toBool(prot & VKI_PROT_READ);
2155    newW = toBool(prot & VKI_PROT_WRITE);
2156    newX = toBool(prot & VKI_PROT_EXEC);
2157
2158    /* Discard is needed if we're dumping X permission */
2159    needDiscard = any_Ts_in_range( start, len ) && !newX;
2160
2161    split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
2162
2163    iLo = find_nsegment_idx(start);
2164    iHi = find_nsegment_idx(start + len - 1);
2165
2166    for (i = iLo; i <= iHi; i++) {
2167       /* Apply the permissions to all relevant segments. */
2168       switch (nsegments[i].kind) {
2169          case SkAnonC: case SkAnonV: case SkFileC: case SkFileV: case SkShmC:
2170             nsegments[i].hasR = newR;
2171             nsegments[i].hasW = newW;
2172             nsegments[i].hasX = newX;
2173             aspacem_assert(sane_NSegment(&nsegments[i]));
2174             break;
2175          default:
2176             break;
2177       }
2178    }
2179
2180    /* Changing permissions could have made previously un-mergable
2181       segments mergeable.  Therefore have to re-preen them. */
2182    (void)preen_nsegments();
2183    AM_SANITY_CHECK;
2184    return needDiscard;
2185 }
2186
2187
2188 /* Notifies aspacem that an munmap completed successfully.  The
2189    segment array is updated accordingly.  As with
2190    VG_(am_notify_munmap), we merely record the given info, and don't
2191    check it for sensibleness.  If the returned Bool is True, the
2192    caller should immediately discard translations from the specified
2193    address range. */
2194
2195 Bool VG_(am_notify_munmap)( Addr start, SizeT len )
2196 {
2197    NSegment seg;
2198    Bool     needDiscard;
2199    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2200    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2201
2202    if (len == 0)
2203       return False;
2204
2205    needDiscard = any_Ts_in_range( start, len );
2206
2207    init_nsegment( &seg );
2208    seg.start = start;
2209    seg.end   = start + len - 1;
2210
2211    /* The segment becomes unused (free).  Segments from above
2212       aspacem_maxAddr were originally SkResvn and so we make them so
2213       again.  Note, this isn't really right when the segment straddles
2214       the aspacem_maxAddr boundary - then really it should be split in
2215       two, the lower part marked as SkFree and the upper part as
2216       SkResvn.  Ah well. */
2217    if (start > aspacem_maxAddr 
2218        && /* check previous comparison is meaningful */
2219           aspacem_maxAddr < Addr_MAX)
2220       seg.kind = SkResvn;
2221    else 
2222    /* Ditto for segments from below aspacem_minAddr. */
2223    if (seg.end < aspacem_minAddr && aspacem_minAddr > 0)
2224       seg.kind = SkResvn;
2225    else
2226       seg.kind = SkFree;
2227
2228    add_segment( &seg );
2229
2230    /* Unmapping could create two adjacent free segments, so a preen is
2231       needed.  add_segment() will do that, so no need to here. */
2232    AM_SANITY_CHECK;
2233    return needDiscard;
2234 }
2235
2236
2237 /*-----------------------------------------------------------------*/
2238 /*---                                                           ---*/
2239 /*--- Handling mappings which do not arise directly from the    ---*/
2240 /*--- simulation of the client.                                 ---*/
2241 /*---                                                           ---*/
2242 /*-----------------------------------------------------------------*/
2243
2244 /* --- --- --- map, unmap, protect  --- --- --- */
2245
2246 /* Map a file at a fixed address for the client, and update the
2247    segment array accordingly. */
2248
2249 SysRes VG_(am_mmap_file_fixed_client)
2250      ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset )
2251 {
2252    SysRes     sres;
2253    NSegment   seg;
2254    Addr       advised;
2255    Bool       ok;
2256    MapRequest req;
2257    ULong      dev, ino;
2258    UInt       mode;
2259    HChar      buf[VKI_PATH_MAX];
2260
2261    /* Not allowable. */
2262    if (length == 0 
2263        || !VG_IS_PAGE_ALIGNED(start)
2264        || !VG_IS_PAGE_ALIGNED(offset))
2265       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2266
2267    /* Ask for an advisory.  If it's negative, fail immediately. */
2268    req.rkind = MFixed;
2269    req.start = start;
2270    req.len   = length;
2271    advised = VG_(am_get_advisory)( &req, True/*client*/, &ok );
2272    if (!ok || advised != start)
2273       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2274
2275    /* We have been advised that the mapping is allowable at the
2276       specified address.  So hand it off to the kernel, and propagate
2277       any resulting failure immediately. */
2278    sres = VG_(am_do_mmap_NO_NOTIFY)( 
2279              start, length, prot, 
2280              VKI_MAP_FIXED|VKI_MAP_PRIVATE, 
2281              fd, offset 
2282           );
2283    if (sr_isError(sres))
2284       return sres;
2285
2286    if (sr_Res(sres) != start) {
2287       /* I don't think this can happen.  It means the kernel made a
2288          fixed map succeed but not at the requested location.  Try to
2289          repair the damage, then return saying the mapping failed. */
2290       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2291       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2292    }
2293
2294 #  if !VGO_l4re
2295    /* Ok, the mapping succeeded.  Now notify the interval map. */
2296    init_nsegment( &seg );
2297    seg.kind   = SkFileC;
2298    seg.start  = start;
2299    seg.end    = seg.start + VG_PGROUNDUP(length) - 1;
2300    seg.offset = offset;
2301    seg.hasR   = toBool(prot & VKI_PROT_READ);
2302    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
2303    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
2304    
2305    if (get_inode_for_fd(fd, &dev, &ino, &mode)) {
2306       seg.dev = dev;
2307       seg.ino = ino;
2308       seg.mode = mode;
2309    }
2310    
2311    if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
2312       seg.fnIdx = allocate_segname( buf );
2313    }
2314    add_segment( &seg );
2315 #else
2316    /* In L4Re the NO_NOTIFY part is actually bogus as we use the segment array
2317     * for region management and thus now already have a segment set up for this
2318     * region. Therefore we simply look it up and adapt it a bit.
2319     */
2320    NSegment *s = VG_(am_find_nsegment)(sr_Res(sres));
2321    s->kind   = SkFileC;
2322    s->offset = offset;
2323    s->hasR   = toBool(prot & VKI_PROT_READ);
2324    s->hasW   = toBool(prot & VKI_PROT_WRITE);
2325    s->hasX   = toBool(prot & VKI_PROT_EXEC);
2326
2327    if (get_inode_for_fd(fd, &dev, &ino, &mode)) {
2328       s->dev   = dev;
2329       s->ino   = ino;
2330       s->mode  = mode;
2331    }
2332
2333    if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
2334       s->fnIdx = allocate_segname( buf );
2335    }
2336    (void)seg;
2337 #endif
2338
2339    AM_SANITY_CHECK;
2340    return sres;
2341 }
2342
2343
2344 /* Map anonymously at a fixed address for the client, and update
2345    the segment array accordingly. */
2346
2347 SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
2348 {
2349    SysRes     sres;
2350 #  if !VGO_l4re
2351    NSegment   seg;
2352 #endif
2353    Addr       advised;
2354    Bool       ok;
2355    MapRequest req;
2356    /* Not allowable. */
2357    if (length == 0 || !VG_IS_PAGE_ALIGNED(start))
2358       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2359
2360    /* Ask for an advisory.  If it's negative, fail immediately. */
2361    req.rkind = MFixed;
2362    req.start = start;
2363    req.len   = length;
2364    advised = VG_(am_get_advisory)( &req, True/*client*/, &ok );
2365    if (!ok || advised != start)
2366       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2367
2368    /* We have been advised that the mapping is allowable at the
2369       specified address.  So hand it off to the kernel, and propagate
2370       any resulting failure immediately. */
2371    sres = VG_(am_do_mmap_NO_NOTIFY)( 
2372              start, length, prot, 
2373              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
2374              0, 0 
2375           );
2376    if (sr_isError(sres))
2377       return sres;
2378
2379    if (sr_Res(sres) != start) {
2380       /* I don't think this can happen.  It means the kernel made a
2381          fixed map succeed but not at the requested location.  Try to
2382          repair the damage, then return saying the mapping failed. */
2383       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2384       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2385    }
2386
2387 #  if !VGO_l4re
2388    /* Ok, the mapping succeeded.  Now notify the interval map. */
2389    init_nsegment( &seg );
2390    seg.kind  = SkAnonC;
2391    seg.start = start;
2392    seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
2393    seg.hasR  = toBool(prot & VKI_PROT_READ);
2394    seg.hasW  = toBool(prot & VKI_PROT_WRITE);
2395    seg.hasX  = toBool(prot & VKI_PROT_EXEC);
2396    add_segment( &seg );
2397 #else
2398    /* In L4Re the NO_NOTIFY part is actually bogus as we use the segment array
2399     * for region management and thus now already have a segment set up for this
2400     * region. Therefore we simply look it up and adapt it a bit.
2401     */
2402    NSegment *seg = VG_(am_find_nsegment)(sr_Res(sres));
2403    seg->kind = SkAnonC;
2404 #endif
2405
2406    AM_SANITY_CHECK;
2407    return sres;
2408 }
2409
2410
2411 /* Map anonymously at an unconstrained address for the client, and
2412    update the segment array accordingly.  */
2413
2414 SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
2415 {
2416    SysRes     sres;
2417 #if !VGO_l4re
2418    NSegment   seg;
2419 #endif
2420    Addr       advised;
2421    Bool       ok;
2422    MapRequest req;
2423  
2424    /* Not allowable. */
2425    if (length == 0)
2426       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2427
2428    /* Ask for an advisory.  If it's negative, fail immediately. */
2429    req.rkind = MAny;
2430    req.start = 0;
2431    req.len   = length;
2432    advised = VG_(am_get_advisory)( &req, True/*client*/, &ok );
2433    if (!ok)
2434       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2435
2436    /* We have been advised that the mapping is allowable at the
2437       advised address.  So hand it off to the kernel, and propagate
2438       any resulting failure immediately. */
2439    sres = VG_(am_do_mmap_NO_NOTIFY)( 
2440              advised, length, prot, 
2441              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
2442              0, 0 
2443           );
2444    if (sr_isError(sres))
2445       return sres;
2446
2447    if (sr_Res(sres) != advised) {
2448       /* I don't think this can happen.  It means the kernel made a
2449          fixed map succeed but not at the requested location.  Try to
2450          repair the damage, then return saying the mapping failed. */
2451       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2452       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2453    }
2454
2455 #if !VGO_l4re
2456    /* Ok, the mapping succeeded.  Now notify the interval map. */
2457    init_nsegment( &seg );
2458    seg.kind  = SkAnonC;
2459    seg.start = advised;
2460    seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
2461    seg.hasR  = toBool(prot & VKI_PROT_READ);
2462    seg.hasW  = toBool(prot & VKI_PROT_WRITE);
2463    seg.hasX  = toBool(prot & VKI_PROT_EXEC);
2464    add_segment( &seg );
2465 #else
2466    NSegment *seg = VG_(am_find_nsegment)(sr_Res(sres));
2467    seg->kind  = SkAnonC;
2468    seg->hasR  = toBool(prot & VKI_PROT_READ);
2469    seg->hasW  = toBool(prot & VKI_PROT_WRITE);
2470    seg->hasX  = toBool(prot & VKI_PROT_EXEC);
2471 #endif
2472
2473    AM_SANITY_CHECK;
2474    return sres;
2475 }
2476
2477
2478 /* Similarly, acquire new address space for the client but with
2479    considerable restrictions on what can be done with it: (1) the
2480    actual protections may exceed those stated in 'prot', (2) the
2481    area's protections cannot be later changed using any form of
2482    mprotect, and (3) the area cannot be freed using any form of
2483    munmap.  On Linux this behaves the same as
2484    VG_(am_mmap_anon_float_client).  On AIX5 this *may* allocate memory
2485    by using sbrk, so as to make use of large pages on AIX. */
2486
2487 SysRes VG_(am_sbrk_anon_float_client) ( SizeT length, Int prot )
2488 {
2489    return VG_(am_mmap_anon_float_client) ( length, prot );
2490 }
2491
2492
2493 /* Map a file at an unconstrained address for V, and update the
2494    segment array accordingly. Use the provided flags */
2495
2496 static SysRes VG_(am_mmap_file_float_valgrind_flags) ( SizeT length, UInt prot,
2497                                                        UInt flags,
2498                                                        Int fd, Off64T offset )
2499 {
2500    SysRes     sres;
2501    NSegment   seg;
2502    Addr       advised;
2503    Bool       ok;
2504    MapRequest req;
2505    ULong      dev, ino;
2506    UInt       mode;
2507    HChar      buf[VKI_PATH_MAX];
2508  
2509    /* Not allowable. */
2510    if (length == 0 || !VG_IS_PAGE_ALIGNED(offset))
2511       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2512
2513    /* Ask for an advisory.  If it's negative, fail immediately. */
2514    req.rkind = MAny;
2515    req.start = 0;
2516    req.len   = length;
2517    advised = VG_(am_get_advisory)( &req, True/*client*/, &ok );
2518    if (!ok)
2519       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2520
2521    /* We have been advised that the mapping is allowable at the
2522       specified address.  So hand it off to the kernel, and propagate
2523       any resulting failure immediately. */
2524    sres = VG_(am_do_mmap_NO_NOTIFY)( 
2525              advised, length, prot, 
2526              flags,
2527              fd, offset 
2528           );
2529    if (sr_isError(sres))
2530       return sres;
2531
2532    if (sr_Res(sres) != advised) {
2533       /* I don't think this can happen.  It means the kernel made a
2534          fixed map succeed but not at the requested location.  Try to
2535          repair the damage, then return saying the mapping failed. */
2536       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2537       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2538    }
2539
2540 #ifndef VGO_l4re
2541    /* Ok, the mapping succeeded.  Now notify the interval map. */
2542    init_nsegment( &seg );
2543    seg.kind   = SkFileV;
2544    seg.start  = sr_Res(sres);
2545    seg.end    = seg.start + VG_PGROUNDUP(length) - 1;
2546    seg.offset = offset;
2547    seg.hasR   = toBool(prot & VKI_PROT_READ);
2548    seg.hasW   = toBool(prot & VKI_PROT_WRITE);
2549    seg.hasX   = toBool(prot & VKI_PROT_EXEC);
2550    if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
2551       seg.dev  = dev;
2552       seg.ino  = ino;
2553       seg.mode = mode;
2554    }
2555    if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
2556       seg.fnIdx = allocate_segname( buf );
2557    }
2558    add_segment( &seg );
2559 #else
2560    (void)seg; (void)dev; (void)ino; (void)buf;
2561    {
2562        NSegment *s = VG_(am_find_nsegment)(sr_Res(sres));
2563        if (!s)
2564            VG_(printf)("error!!!\n");
2565        s->kind   = SkFileV;
2566        s->offset = offset;
2567        s->hasR   = True;
2568        s->hasW   = True;
2569        s->hasX   = True;
2570        if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
2571           s->fnIdx = allocate_segname( buf );
2572        }
2573    }
2574 #endif
2575
2576    AM_SANITY_CHECK;
2577    return sres;
2578 }
2579 /* Map privately a file at an unconstrained address for V, and update the
2580    segment array accordingly.  This is used by V for transiently
2581    mapping in object files to read their debug info.  */
2582
2583 SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot, 
2584                                           Int fd, Off64T offset )
2585 {
2586    return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
2587                                                   VKI_MAP_FIXED|VKI_MAP_PRIVATE,
2588                                                   fd, offset );
2589 }
2590
2591 extern SysRes VG_(am_shared_mmap_file_float_valgrind)
2592    ( SizeT length, UInt prot, Int fd, Off64T offset )
2593 {
2594    return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
2595                                                   VKI_MAP_FIXED|VKI_MAP_SHARED,
2596                                                   fd, offset );
2597 }
2598
2599 /* Map anonymously at an unconstrained address for V, and update the
2600    segment array accordingly.  This is fundamentally how V allocates
2601    itself more address space when needed. */
2602
2603 SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
2604 {
2605    SysRes     sres;
2606    NSegment   seg;
2607    Addr       advised;
2608    Bool       ok;
2609    MapRequest req;
2610  
2611    /* Not allowable. */
2612    if (length == 0)
2613       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2614
2615    /* Ask for an advisory.  If it's negative, fail immediately. */
2616    req.rkind = MAny;
2617    req.start = 0;
2618    req.len   = length;
2619    advised = VG_(am_get_advisory)( &req, False/*valgrind*/, &ok );
2620    if (!ok)
2621       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2622    
2623    /* We have been advised that the mapping is allowable at the
2624       specified address.  So hand it off to the kernel, and propagate
2625       any resulting failure immediately. */
2626    sres = VG_(am_do_mmap_NO_NOTIFY)( 
2627              advised, length, 
2628              VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC, 
2629              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
2630              0, 0 
2631           );
2632    if (sr_isError(sres))
2633       return sres;
2634
2635    if (sr_Res(sres) != advised) {
2636       /* I don't think this can happen.  It means the kernel made a
2637          fixed map succeed but not at the requested location.  Try to
2638          repair the damage, then return saying the mapping failed. */
2639       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2640       return VG_(mk_SysRes_Error)( VKI_EINVAL );
2641    }
2642
2643 #if defined(VGO_l4re)
2644    if (!vcap_running) {
2645 #endif
2646        /* Ok, the mapping succeeded.  Now notify the interval map. */
2647        init_nsegment( &seg );
2648        seg.kind  = SkAnonV;
2649        seg.start = advised;
2650        seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
2651        seg.hasR  = True;
2652        seg.hasW  = True;
2653        seg.hasX  = True;
2654        vrm_segment_fixup(&seg);
2655        add_segment( &seg );
2656 #if defined(VGO_l4re)
2657    } else {
2658        NSegment *s = VG_(am_find_nsegment)(sr_Res(sres));
2659        if (!s) {
2660            VG_(printf)("Could not find segment that should be existing!\n");
2661                    enter_kdebug("error");
2662            }
2663        s->kind  = SkAnonV;
2664        s->hasR  = True;
2665        s->hasW  = True;
2666        s->hasX  = True;
2667    }
2668 #endif
2669
2670    AM_SANITY_CHECK;
2671    return sres;
2672 }
2673
2674 /* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
2675
2676 void* VG_(am_shadow_alloc)(SizeT size)
2677 {
2678    SysRes sres = VG_(am_mmap_anon_float_valgrind)( size );
2679    return sr_isError(sres) ? NULL : (void*)sr_Res(sres);
2680 }
2681
2682 /* Same comments apply as per VG_(am_sbrk_anon_float_client).  On
2683    Linux this behaves the same as VG_(am_mmap_anon_float_valgrind). */
2684
2685 SysRes VG_(am_sbrk_anon_float_valgrind)( SizeT cszB )
2686 {
2687    return VG_(am_mmap_anon_float_valgrind)( cszB );
2688 }
2689
2690
2691 /* --- --- munmap helper --- --- */
2692
2693 static 
2694 SysRes am_munmap_both_wrk ( /*OUT*/Bool* need_discard,
2695                             Addr start, SizeT len, Bool forClient )
2696 {
2697    Bool   d;
2698    SysRes sres;
2699
2700    if (!VG_IS_PAGE_ALIGNED(start))
2701       goto eINVAL;
2702
2703    if (len == 0) {
2704       *need_discard = False;
2705       return VG_(mk_SysRes_Success)( 0 );
2706    }
2707
2708    if (start + len < len)
2709       goto eINVAL;
2710
2711    len = VG_PGROUNDUP(len);
2712    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2713    aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2714
2715    if (forClient) {
2716       if (!VG_(am_is_valid_for_client_or_free_or_resvn)
2717             ( start, len, VKI_PROT_NONE ))
2718          goto eINVAL;
2719    } else {
2720       if (!is_valid_for_valgrind( start, len ))
2721          goto eINVAL;
2722    }
2723
2724    d = any_Ts_in_range( start, len );
2725
2726    sres = ML_(am_do_munmap_NO_NOTIFY)( start, len );
2727    if (sr_isError(sres))
2728       return sres;
2729
2730    VG_(am_notify_munmap)( start, len );
2731    AM_SANITY_CHECK;
2732    *need_discard = d;
2733    return sres;
2734
2735   eINVAL:
2736    return VG_(mk_SysRes_Error)( VKI_EINVAL );
2737 }
2738
2739 /* Unmap the given address range and update the segment array
2740    accordingly.  This fails if the range isn't valid for the client.
2741    If *need_discard is True after a successful return, the caller
2742    should immediately discard translations from the specified address
2743    range. */
2744
2745 SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
2746                               Addr start, SizeT len )
2747 {
2748    return am_munmap_both_wrk( need_discard, start, len, True/*client*/ );
2749 }
2750
2751 /* Unmap the given address range and update the segment array
2752    accordingly.  This fails if the range isn't valid for valgrind. */
2753
2754 SysRes VG_(am_munmap_valgrind)( Addr start, SizeT len )
2755 {
2756    Bool need_discard;
2757    SysRes r = am_munmap_both_wrk( &need_discard, 
2758                                   start, len, False/*valgrind*/ );
2759    /* If this assertion fails, it means we allowed translations to be
2760       made from a V-owned section.  Which shouldn't happen. */
2761    if (!sr_isError(r))
2762       aspacem_assert(!need_discard);
2763    return r;
2764 }
2765
2766 /* Let (start,len) denote an area within a single Valgrind-owned
2767   segment (anon or file).  Change the ownership of [start, start+len)
2768   to the client instead.  Fails if (start,len) does not denote a
2769   suitable segment. */
2770
2771 Bool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len )
2772 {
2773    Int i, iLo, iHi;
2774
2775    if (len == 0)
2776       return True;
2777    if (start + len < start)
2778       return False;
2779    if (!VG_IS_PAGE_ALIGNED(start) || !VG_IS_PAGE_ALIGNED(len))
2780       return False;
2781
2782    i = find_nsegment_idx(start);
2783    if (nsegments[i].kind != SkFileV && nsegments[i].kind != SkAnonV)
2784       return False;
2785    if (start+len-1 > nsegments[i].end)
2786       return False;
2787
2788    aspacem_assert(start >= nsegments[i].start);
2789    aspacem_assert(start+len-1 <= nsegments[i].end);
2790
2791    /* This scheme is like how mprotect works: split the to-be-changed
2792       range into its own segment(s), then mess with them (it).  There
2793       should be only one. */
2794    split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
2795    aspacem_assert(iLo == iHi);
2796    switch (nsegments[iLo].kind) {
2797       case SkFileV: nsegments[iLo].kind = SkFileC; break;
2798       case SkAnonV: nsegments[iLo].kind = SkAnonC; break;
2799       default: aspacem_assert(0); /* can't happen - guarded above */
2800    }
2801
2802    preen_nsegments();
2803    return True;
2804 }
2805
2806 /* 'seg' must be NULL or have been obtained from
2807    VG_(am_find_nsegment), and still valid.  If non-NULL, and if it
2808    denotes a SkAnonC (anonymous client mapping) area, set the .isCH
2809    (is-client-heap) flag for that area.  Otherwise do nothing.
2810    (Bizarre interface so that the same code works for both Linux and
2811    AIX and does not impose inefficiencies on the Linux version.) */
2812 void VG_(am_set_segment_isCH_if_SkAnonC)( NSegment* seg )
2813 {
2814    Int i = segAddr_to_index( seg );
2815    aspacem_assert(i >= 0 && i < nsegments_used);
2816    if (nsegments[i].kind == SkAnonC) {
2817       nsegments[i].isCH = True;
2818    } else {
2819       aspacem_assert(nsegments[i].isCH == False);
2820    }
2821 }
2822
2823 /* Same idea as VG_(am_set_segment_isCH_if_SkAnonC), except set the
2824    segment's hasT bit (has-cached-code) if this is SkFileC or SkAnonC
2825    segment. */
2826 void VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( NSegment* seg )
2827 {
2828    Int i = segAddr_to_index( seg );
2829    aspacem_assert(i >= 0 && i < nsegments_used);
2830    if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkFileC) {
2831       nsegments[i].hasT = True;
2832    }
2833 }
2834
2835
2836 /* --- --- --- reservations --- --- --- */
2837
2838 /* Create a reservation from START .. START+LENGTH-1, with the given
2839    ShrinkMode.  When checking whether the reservation can be created,
2840    also ensure that at least abs(EXTRA) extra free bytes will remain
2841    above (> 0) or below (< 0) the reservation.
2842
2843    The reservation will only be created if it, plus the extra-zone,
2844    falls entirely within a single free segment.  The returned Bool
2845    indicates whether the creation succeeded. */
2846
2847 Bool VG_(am_create_reservation) ( Addr start, SizeT length, 
2848                                   ShrinkMode smode, SSizeT extra )
2849 {
2850    Int      startI, endI;
2851    NSegment seg;
2852
2853    /* start and end, not taking into account the extra space. */
2854    Addr start1 = start;
2855    Addr end1   = start + length - 1;
2856
2857    /* start and end, taking into account the extra space. */
2858    Addr start2 = start1;
2859    Addr end2   = end1;
2860
2861    if (extra < 0) start2 += extra; // this moves it down :-)
2862    if (extra > 0) end2 += extra;
2863
2864    aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2865    aspacem_assert(VG_IS_PAGE_ALIGNED(start+length));
2866    aspacem_assert(VG_IS_PAGE_ALIGNED(start2));
2867    aspacem_assert(VG_IS_PAGE_ALIGNED(end2+1));
2868
2869    startI = find_nsegment_idx( start2 );
2870    endI = find_nsegment_idx( end2 );
2871
2872    /* If the start and end points don't fall within the same (free)
2873       segment, we're hosed.  This does rely on the assumption that all
2874       mergeable adjacent segments can be merged, but add_segment()
2875       should ensure that. */
2876    if (startI != endI)
2877       return False;
2878
2879    if (nsegments[startI].kind != SkFree)
2880       return False;
2881
2882    /* Looks good - make the reservation. */
2883    aspacem_assert(nsegments[startI].start <= start2);
2884    aspacem_assert(end2 <= nsegments[startI].end);
2885
2886    init_nsegment( &seg );
2887    seg.kind  = SkResvn;
2888    if (0) {
2889       VG_(debugLog)(0, "aspacem", "%s: setting segment.kind to SkResvn\n", __func__);
2890       show_nsegment_full(0, &seg);
2891    }
2892  
2893    seg.start = start1;  /* NB: extra space is not included in the
2894                            reservation. */
2895    seg.end   = end1;
2896    seg.smode = smode;
2897    add_segment( &seg );
2898
2899    AM_SANITY_CHECK;
2900    return True;
2901 }
2902
2903
2904 /* Let SEG be an anonymous client mapping.  This fn extends the
2905    mapping by DELTA bytes, taking the space from a reservation section
2906    which must be adjacent.  If DELTA is positive, the segment is
2907    extended forwards in the address space, and the reservation must be
2908    the next one along.  If DELTA is negative, the segment is extended
2909    backwards in the address space and the reservation must be the
2910    previous one.  DELTA must be page aligned.  abs(DELTA) must not
2911    exceed the size of the reservation segment minus one page, that is,
2912    the reservation segment after the operation must be at least one
2913    page long. */
2914
2915 Bool VG_(am_extend_into_adjacent_reservation_client) ( NSegment* seg, 
2916                                                        SSizeT    delta )
2917 {
2918    Int    segA, segR;
2919    UInt   prot;
2920    SysRes sres;
2921
2922    /* Find the segment array index for SEG.  If the assertion fails it
2923       probably means you passed in a bogus SEG. */
2924    segA = segAddr_to_index( seg );
2925    aspacem_assert(segA >= 0 && segA < nsegments_used);
2926
2927    if (nsegments[segA].kind != SkAnonC)
2928       return False;
2929
2930    if (delta == 0)
2931       return True;
2932
2933    prot =   (nsegments[segA].hasR ? VKI_PROT_READ : 0)
2934           | (nsegments[segA].hasW ? VKI_PROT_WRITE : 0)
2935           | (nsegments[segA].hasX ? VKI_PROT_EXEC : 0);
2936
2937    aspacem_assert(VG_IS_PAGE_ALIGNED(delta<0 ? -delta : delta));
2938
2939    if (delta > 0) {
2940
2941       /* Extending the segment forwards. */
2942       segR = segA+1;
2943       if (segR >= nsegments_used
2944           || nsegments[segR].kind != SkResvn
2945           || nsegments[segR].smode != SmLower
2946           || nsegments[segR].start != nsegments[segA].end + 1
2947           || delta + VKI_PAGE_SIZE 
2948                 > (nsegments[segR].end - nsegments[segR].start + 1))
2949         return False;
2950         
2951       /* Extend the kernel's mapping. */
2952       sres = VG_(am_do_mmap_NO_NOTIFY)( 
2953                 nsegments[segR].start, delta,
2954                 prot,
2955                 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
2956                 0, 0 
2957              );
2958       if (sr_isError(sres))
2959          return False; /* kernel bug if this happens? */
2960       if (sr_Res(sres) != nsegments[segR].start) {
2961          /* kernel bug if this happens? */
2962         (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
2963         return False;
2964       }
2965
2966       /* Ok, success with the kernel.  Update our structures. */
2967       nsegments[segR].start += delta;
2968       nsegments[segA].end += delta;
2969       aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
2970
2971    } else {
2972
2973       /* Extending the segment backwards. */
2974       delta = -delta;
2975       aspacem_assert(delta > 0);
2976
2977       segR = segA-1;
2978       if (segR < 0
2979           || nsegments[segR].kind != SkResvn
2980           || nsegments[segR].smode != SmUpper
2981           || nsegments[segR].end + 1 != nsegments[segA].start
2982           || delta + VKI_PAGE_SIZE 
2983                 > (nsegments[segR].end - nsegments[segR].start + 1))
2984         return False;
2985         
2986       /* Extend the kernel's mapping. */
2987       sres = VG_(am_do_mmap_NO_NOTIFY)( 
2988                 nsegments[segA].start-delta, delta,
2989                 prot,
2990                 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
2991                 0, 0 
2992              );
2993       if (sr_isError(sres))
2994          return False; /* kernel bug if this happens? */
2995       if (sr_Res(sres) != nsegments[segA].start-delta) {
2996          /* kernel bug if this happens? */
2997         (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
2998         return False;
2999       }
3000
3001       /* Ok, success with the kernel.  Update our structures. */
3002       nsegments[segR].end -= delta;
3003       nsegments[segA].start -= delta;
3004       aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
3005
3006    }
3007
3008    AM_SANITY_CHECK;
3009    return True;
3010 }
3011
3012
3013 /* --- --- --- resizing/move a mapping --- --- --- */
3014
3015 /* Let SEG be a client mapping (anonymous or file).  This fn extends
3016    the mapping forwards only by DELTA bytes, and trashes whatever was
3017    in the new area.  Fails if SEG is not a single client mapping or if
3018    the new area is not accessible to the client.  Fails if DELTA is
3019    not page aligned.  *seg is invalid after a successful return.  If
3020    *need_discard is True after a successful return, the caller should
3021    immediately discard translations from the new area. */
3022
3023 Bool VG_(am_extend_map_client)( /*OUT*/Bool* need_discard,
3024                                 NSegment* seg, SizeT delta )
3025 {
3026    Addr     xStart;
3027    SysRes   sres;
3028    NSegment seg_copy = *seg;
3029    SizeT    seg_old_len = seg->end + 1 - seg->start;
3030
3031    if (0)
3032       VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) BEFORE");
3033
3034    if (seg->kind != SkFileC && seg->kind != SkAnonC)
3035       return False;
3036
3037    if (delta == 0 || !VG_IS_PAGE_ALIGNED(delta)) 
3038       return False;
3039
3040    xStart = seg->end+1;
3041    if (xStart + delta < delta)
3042       return False;
3043
3044    if (!VG_(am_is_valid_for_client_or_free_or_resvn)( xStart, delta, 
3045                                                       VKI_PROT_NONE ))
3046       return False;
3047
3048    AM_SANITY_CHECK;
3049    sres = ML_(am_do_extend_mapping_NO_NOTIFY)( seg->start, 
3050                                                seg_old_len,
3051                                                seg_old_len + delta );
3052    if (sr_isError(sres)) {
3053       AM_SANITY_CHECK;
3054       return False;
3055    } else {
3056       /* the area must not have moved */
3057       aspacem_assert(sr_Res(sres) == seg->start);
3058    }
3059
3060    *need_discard = any_Ts_in_range( seg_copy.end+1, delta );
3061
3062    seg_copy.end += delta;
3063    add_segment( &seg_copy );
3064
3065    if (0)
3066       VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) AFTER");
3067
3068    AM_SANITY_CHECK;
3069    return True;
3070 }
3071
3072
3073 /* Remap the old address range to the new address range.  Fails if any
3074    parameter is not page aligned, if the either size is zero, if any
3075    wraparound is implied, if the old address range does not fall
3076    entirely within a single segment, if the new address range overlaps
3077    with the old one, or if the old address range is not a valid client
3078    mapping.  If *need_discard is True after a successful return, the
3079    caller should immediately discard translations from both specified
3080    address ranges.  */
3081
3082 Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
3083                                         Addr old_addr, SizeT old_len,
3084                                         Addr new_addr, SizeT new_len )
3085 {
3086    Int      iLo, iHi;
3087    SysRes   sres;
3088    NSegment seg;
3089
3090    if (old_len == 0 || new_len == 0)
3091       return False;
3092
3093    if (!VG_IS_PAGE_ALIGNED(old_addr) || !VG_IS_PAGE_ALIGNED(old_len)
3094        || !VG_IS_PAGE_ALIGNED(new_addr) || !VG_IS_PAGE_ALIGNED(new_len))
3095       return False;
3096
3097    if (old_addr + old_len < old_addr
3098        || new_addr + new_len < new_addr)
3099       return False;
3100
3101    if (old_addr + old_len - 1 < new_addr
3102        || new_addr + new_len - 1 < old_addr) {
3103       /* no overlap */
3104    } else
3105       return False;
3106
3107    iLo = find_nsegment_idx( old_addr );
3108    iHi = find_nsegment_idx( old_addr + old_len - 1 );
3109    if (iLo != iHi)
3110       return False;
3111
3112    if (nsegments[iLo].kind != SkFileC && nsegments[iLo].kind != SkAnonC)
3113       return False;
3114
3115    sres = ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)
3116              ( old_addr, old_len, new_addr, new_len );
3117    if (sr_isError(sres)) {
3118       AM_SANITY_CHECK;
3119       return False;
3120    } else {
3121       aspacem_assert(sr_Res(sres) == new_addr);
3122    }
3123
3124    *need_discard = any_Ts_in_range( old_addr, old_len )
3125                    || any_Ts_in_range( new_addr, new_len );
3126
3127    seg = nsegments[iLo];
3128
3129    /* Mark the new area based on the old seg. */
3130    if (seg.kind == SkFileC) {
3131       seg.offset += ((ULong)old_addr) - ((ULong)seg.start);
3132    } else {
3133       aspacem_assert(seg.kind == SkAnonC);
3134       aspacem_assert(seg.offset == 0);
3135    }
3136    seg.start = new_addr;
3137    seg.end   = new_addr + new_len - 1;
3138    add_segment( &seg );
3139
3140    /* Create a free hole in the old location. */
3141    init_nsegment( &seg );
3142    seg.start = old_addr;
3143    seg.end   = old_addr + old_len - 1;
3144    /* See comments in VG_(am_notify_munmap) about this SkResvn vs
3145       SkFree thing. */
3146    if (old_addr > aspacem_maxAddr 
3147        && /* check previous comparison is meaningful */
3148           aspacem_maxAddr < Addr_MAX)
3149       seg.kind = SkResvn;
3150    else
3151       seg.kind = SkFree;
3152
3153    add_segment( &seg );
3154
3155    AM_SANITY_CHECK;
3156    return True;
3157 }
3158
3159
3160 /*-----------------------------------------------------------------*/
3161 /*---                                                           ---*/
3162 /*--- A simple parser for /proc/self/maps on Linux 2.4.X/2.6.X. ---*/
3163 /*--- Almost completely independent of the stuff above.  The    ---*/
3164 /*--- only function it 'exports' to the code above this comment ---*/
3165 /*--- is parse_procselfmaps.                                    ---*/
3166 /*---                                                           ---*/
3167 /*-----------------------------------------------------------------*/
3168
3169 /* Size of a smallish table used to read /proc/self/map entries. */
3170 #define M_PROCMAP_BUF 100000
3171
3172 /* static ... to keep it out of the stack frame. */
3173 static Char procmap_buf[M_PROCMAP_BUF];
3174
3175 /* Records length of /proc/self/maps read into procmap_buf. */
3176 static Int  buf_n_tot;
3177
3178 /* Helper fns. */
3179
3180 static Int hexdigit ( Char c )
3181 {
3182    if (c >= '0' && c <= '9') return (Int)(c - '0');
3183    if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a');
3184    if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A');
3185    return -1;
3186 }
3187
3188 static Int decdigit ( Char c )
3189 {
3190    if (c >= '0' && c <= '9') return (Int)(c - '0');
3191    return -1;
3192 }
3193
3194 static Int readchar ( const Char* buf, Char* ch )
3195 {
3196    if (*buf == 0) return 0;
3197    *ch = *buf;
3198    return 1;
3199 }
3200
3201 static Int readhex ( const Char* buf, UWord* val )
3202 {
3203    /* Read a word-sized hex number. */
3204    Int n = 0;
3205    *val = 0;
3206    while (hexdigit(*buf) >= 0) {
3207       *val = (*val << 4) + hexdigit(*buf);
3208       n++; buf++;
3209    }
3210    return n;
3211 }
3212
3213 static Int readhex64 ( const Char* buf, ULong* val )
3214 {
3215    /* Read a potentially 64-bit hex number. */
3216    Int n = 0;
3217    *val = 0;
3218    while (hexdigit(*buf) >= 0) {
3219       *val = (*val << 4) + hexdigit(*buf);
3220       n++; buf++;
3221    }
3222    return n;
3223 }
3224
3225 static Int readdec64 ( const Char* buf, ULong* val )
3226 {
3227    Int n = 0;
3228    *val = 0;
3229    while (hexdigit(*buf) >= 0) {
3230       *val = (*val * 10) + decdigit(*buf);
3231       n++; buf++;
3232    }
3233    return n;
3234 }
3235
3236
3237 /* Get the contents of /proc/self/maps into a static buffer.  If
3238    there's a syntax error, it won't fit, or other failure, just
3239    abort. */
3240
3241 static void read_procselfmaps_into_buf ( void )
3242 {
3243    Int    n_chunk;
3244    SysRes fd;
3245    
3246    /* Read the initial memory mapping from the /proc filesystem. */
3247    fd = ML_(am_open)( "/proc/self/maps", VKI_O_RDONLY, 0 );
3248    if (sr_isError(fd))
3249       ML_(am_barf)("can't open /proc/self/maps");
3250
3251    buf_n_tot = 0;
3252    do {
3253       n_chunk = ML_(am_read)( sr_Res(fd), &procmap_buf[buf_n_tot],
3254                               M_PROCMAP_BUF - buf_n_tot );
3255       if (n_chunk >= 0)
3256          buf_n_tot += n_chunk;
3257    } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
3258
3259    ML_(am_close)(sr_Res(fd));
3260
3261    if (buf_n_tot >= M_PROCMAP_BUF-5)
3262       ML_(am_barf_toolow)("M_PROCMAP_BUF");
3263    if (buf_n_tot == 0)
3264       ML_(am_barf)("I/O error on /proc/self/maps");
3265
3266    procmap_buf[buf_n_tot] = 0;
3267 }
3268
3269 /* Parse /proc/self/maps.  For each map entry, call
3270    record_mapping, passing it, in this order:
3271
3272       start address in memory
3273       length
3274       page protections (using the VKI_PROT_* flags)
3275       mapped file device and inode
3276       offset in file, or zero if no file
3277       filename, zero terminated, or NULL if no file
3278
3279    So the sig of the called fn might be
3280
3281       void (*record_mapping)( Addr start, SizeT size, UInt prot,
3282                   UInt dev, UInt info,
3283                               ULong foffset, UChar* filename )
3284
3285    Note that the supplied filename is transiently stored; record_mapping 
3286    should make a copy if it wants to keep it.
3287
3288    Nb: it is important that this function does not alter the contents of
3289        procmap_buf!
3290 */
3291
3292 static void fetch_regionlist(void) {
3293    VG_(memset)(&r_ls, 0, sizeof(struct vrm_region_lists));
3294    VG_(memset)(regions, 0, sizeof(struct vrm_region) * N_REGIONS);
3295
3296    r_ls.regions = regions;
3297    r_ls.areas = areas;
3298
3299    vrm_get_lists(&r_ls, N_REGIONS, N_AREAS);
3300 }
3301
3302
3303 static void parse_regionlist (
3304       void (*record_mapping)( Addr addr, SizeT len, UInt prot,
3305                               ULong dev, ULong ino, ULong offset, 
3306                               const UChar* filename ),
3307       void (*record_gap)( Addr addr, SizeT len )
3308    )
3309 {
3310    int i;
3311    Addr start, endPlusOne, gapStart;
3312    ULong  foffset, dev, ino;
3313    UInt prot;
3314    UChar *filename = NULL;
3315    dev = ino = 0;
3316    if (0) l4re_rm_show_lists();
3317
3318    VG_(debugLog)(1, "main", "region_count = %d, area_count = %d\n", r_ls.region_count, r_ls.area_count);
3319    VG_(debugLog)(1, "main", "Region maping: limits [%lx-%lx]\n", r_ls.min_addr, r_ls.max_addr);
3320
3321    gapStart = Addr_MIN;
3322
3323    VG_(debugLog)(1, "main", " Area map:\n");
3324    for (i = 0; i < r_ls.area_count; i++) 
3325      VG_(debugLog)(1, "main", "  [%10lx-%10lx] -> flags=%x\n", r_ls.areas[i].start, r_ls.areas[i].end, r_ls.areas[i].flags);
3326
3327    VG_(debugLog)(1, "main", " Region map:\n");
3328    
3329    for (i = 0; i < r_ls.region_count; i++) {
3330      start = r_ls.regions[i].start;
3331      endPlusOne = r_ls.regions[i].end + 1;
3332
3333      // TODO offset from ds not from region
3334      foffset = 0; //r_ls.regions[i].offset;
3335      
3336      prot = 0;
3337  
3338      prot |= VKI_PROT_READ;
3339      if ((r_ls.regions[i].flags | 1) == 1)
3340         prot |= VKI_PROT_WRITE;
3341      prot |= VKI_PROT_EXEC;
3342      
3343      if (start == L4RE_KIP_ADDR)
3344        prot = VKI_PROT_READ | VKI_PROT_WRITE | VKI_PROT_EXEC;
3345        
3346      VG_(debugLog)(1, "main", "  [%10lx-%10lx] -> (offs=%lx, ds=%lx, flags=%x)\n", 
3347                    r_ls.regions[i].start,  r_ls.regions[i].end,  
3348                    r_ls.regions[i].offset_in_ds,  r_ls.regions[i].ds, 
3349                    r_ls.regions[i].flags);
3350
3351      if (record_gap && gapStart < start)
3352         (*record_gap) ( gapStart, start-gapStart );
3353  
3354      if (record_mapping && start < endPlusOne) {
3355          (*record_mapping) ( start, endPlusOne-start,
3356                              prot, dev, ino,
3357                              foffset, filename );
3358          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);
3359      }
3360
3361      gapStart = endPlusOne;
3362    }
3363    if (record_gap && gapStart < Addr_MAX)
3364       (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
3365 }
3366
3367 /*--------------------------------------------------------------------*/
3368 /*--- end                                                          ---*/
3369 /*--------------------------------------------------------------------*/