FreeBSD: changes for building with GCC
[valgrind.git] / coregrind / m_aspacemgr / aspacemgr-linux.c
blobda3db87fcdc088a056879821c9a2f18464c66409
1 /* -*- mode: C; c-basic-offset: 3; -*- */
3 /*--------------------------------------------------------------------*/
4 /*--- The address space manager: segment initialisation and ---*/
5 /*--- tracking, stack operations ---*/
6 /*--- ---*/
7 /*--- Implementation for Linux, Darwin, Solaris and FreeBSD ---*/
8 /*--------------------------------------------------------------------*/
11 This file is part of Valgrind, a dynamic binary instrumentation
12 framework.
14 Copyright (C) 2000-2017 Julian Seward
15 jseward@acm.org
17 This program is free software; you can redistribute it and/or
18 modify it under the terms of the GNU General Public License as
19 published by the Free Software Foundation; either version 2 of the
20 License, or (at your option) any later version.
22 This program is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program; if not, see <http://www.gnu.org/licenses/>.
30 The GNU General Public License is contained in the file COPYING.
33 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd)
35 /* *************************************************************
36 DO NOT INCLUDE ANY OTHER FILES HERE.
37 ADD NEW INCLUDES ONLY TO priv_aspacemgr.h
38 AND THEN ONLY AFTER READING DIRE WARNINGS THERE TOO.
39 ************************************************************* */
41 #include "priv_aspacemgr.h"
42 #include "config.h"
45 /* Note: many of the exported functions implemented below are
46 described more fully in comments in pub_core_aspacemgr.h.
50 /*-----------------------------------------------------------------*/
51 /*--- ---*/
52 /*--- Overview. ---*/
53 /*--- ---*/
54 /*-----------------------------------------------------------------*/
56 /* Purpose
57 ~~~~~~~
58 The purpose of the address space manager (aspacem) is:
60 (1) to record the disposition of all parts of the process' address
61 space at all times.
63 (2) to the extent that it can, influence layout in ways favourable
64 to our purposes.
66 It is important to appreciate that whilst it can and does attempt
67 to influence layout, and usually succeeds, it isn't possible to
68 impose absolute control: in the end, the kernel is the final
69 arbiter, and can always bounce our requests.
71 Strategy
72 ~~~~~~~~
73 The strategy is therefore as follows:
75 * Track ownership of mappings. Each one can belong either to
76 Valgrind or to the client.
78 * Try to place the client's fixed and hinted mappings at the
79 requested addresses. Fixed mappings are allowed anywhere except
80 in areas reserved by Valgrind; the client can trash its own
81 mappings if it wants. Hinted mappings are allowed providing they
82 fall entirely in free areas; if not, they will be placed by
83 aspacem in a free area.
85 * Anonymous mappings are allocated so as to keep Valgrind and
86 client areas widely separated when possible. If address space
87 runs low, then they may become intermingled: aspacem will attempt
88 to use all possible space. But under most circumstances lack of
89 address space is not a problem and so the areas will remain far
90 apart.
92 Searches for client space start at aspacem_cStart and will wrap
93 around the end of the available space if needed. Searches for
94 Valgrind space start at aspacem_vStart and will also wrap around.
95 Because aspacem_cStart is approximately at the start of the
96 available space and aspacem_vStart is approximately in the
97 middle, for the most part the client anonymous mappings will be
98 clustered towards the start of available space, and Valgrind ones
99 in the middle.
101 On Solaris, searches for client space start at (aspacem_vStart - 1)
102 and for Valgrind space start at (aspacem_maxAddr - 1) and go backwards.
103 This simulates what kernel does - brk limit grows from bottom and mmap'ed
104 objects from top. It is in contrary with Linux where data segment
105 and mmap'ed objects grow from bottom (leading to early data segment
106 exhaustion for tools which do not use m_replacemalloc). While Linux glibc
107 can cope with this problem by employing mmap, Solaris libc treats inability
108 to grow brk limit as a hard failure.
110 The available space is delimited by aspacem_minAddr and
111 aspacem_maxAddr. aspacem is flexible and can operate with these
112 at any (sane) setting. For 32-bit Linux, aspacem_minAddr is set
113 to some low-ish value at startup (64M) and aspacem_maxAddr is
114 derived from the stack pointer at system startup. This seems a
115 reliable way to establish the initial boundaries.
116 A command line option allows to change the value of aspacem_minAddr,
117 so as to allow memory hungry applications to use the lowest
118 part of the memory.
120 64-bit Linux is similar except for the important detail that the
121 upper boundary is set to 64G. The reason is so that all
122 anonymous mappings (basically all client data areas) are kept
123 below 64G, since that is the maximum range that memcheck can
124 track shadow memory using a fast 2-level sparse array. It can go
125 beyond that but runs much more slowly. The 64G limit is
126 arbitrary and is trivially changed. So, with the current
127 settings, programs on 64-bit Linux will appear to run out of
128 address space and presumably fail at the 64G limit. Given the
129 considerable space overhead of Memcheck, that means you should be
130 able to memcheckify programs that use up to about 32G natively.
132 Note that the aspacem_minAddr/aspacem_maxAddr limits apply only to
133 anonymous mappings. The client can still do fixed and hinted maps
134 at any addresses provided they do not overlap Valgrind's segments.
135 This makes Valgrind able to load prelinked .so's at their requested
136 addresses on 64-bit platforms, even if they are very high (eg,
137 112TB).
139 At startup, aspacem establishes the usable limits, and advises
140 m_main to place the client stack at the top of the range, which on
141 a 32-bit machine will be just below the real initial stack. One
142 effect of this is that self-hosting sort-of works, because an inner
143 valgrind will then place its client's stack just below its own
144 initial stack.
146 The segment array and segment kinds
147 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148 The central data structure is the segment array (segments[0
149 .. nsegments_used-1]). This covers the entire address space in
150 order, giving account of every byte of it. Free spaces are
151 represented explicitly as this makes many operations simpler.
152 Mergeable adjacent segments are aggressively merged so as to create
153 a "normalised" representation (preen_nsegments).
155 There are 7 (mutually-exclusive) segment kinds, the meaning of
156 which is important:
158 SkFree: a free space, which may be allocated either to Valgrind (V)
159 or the client (C).
161 SkAnonC: an anonymous mapping belonging to C. For these, aspacem
162 tracks a boolean indicating whether or not is is part of the
163 client's heap area (can't remember why).
165 SkFileC: a file mapping belonging to C.
167 SkShmC: a shared memory segment belonging to C.
169 SkAnonV: an anonymous mapping belonging to V. These cover all V's
170 dynamic memory needs, including non-client malloc/free areas,
171 shadow memory, and the translation cache.
173 SkFileV: a file mapping belonging to V. As far as I know these are
174 only created transiently for the purposes of reading debug info.
176 SkResvn: a reservation segment.
178 These are mostly straightforward. Reservation segments have some
179 subtlety, however.
181 A reservation segment is unmapped from the kernel's point of view,
182 but is an area in which aspacem will not create anonymous maps
183 (either Vs or Cs). The idea is that we will try to keep it clear
184 when the choice to do so is ours. Reservation segments are
185 'invisible' from the client's point of view: it may choose to park
186 a fixed mapping in the middle of one, and that's just tough -- we
187 can't do anything about that. From the client's perspective
188 reservations are semantically equivalent to (although
189 distinguishable from, if it makes enquiries) free areas.
191 Reservations are a primitive mechanism provided for whatever
192 purposes the rest of the system wants. Currently they are used to
193 reserve the expansion space into which a growdown stack is
194 expanded, and into which the data segment is extended. Note,
195 though, those uses are entirely external to this module, which only
196 supplies the primitives.
198 Reservations may be shrunk in order that an adjoining anonymous
199 mapping may be extended. This makes dataseg/stack expansion work.
200 A reservation may not be shrunk below one page.
202 The advise/notify concept
203 ~~~~~~~~~~~~~~~~~~~~~~~~~
204 All mmap-related calls must be routed via aspacem. Calling
205 sys_mmap directly from the rest of the system is very dangerous
206 because aspacem's data structures will become out of date.
208 The fundamental mode of operation of aspacem is to support client
209 mmaps. Here's what happens (in ML_(generic_PRE_sys_mmap)):
211 * m_syswrap intercepts the mmap call. It examines the parameters
212 and identifies the requested placement constraints. There are
213 three possibilities: no constraint (MAny), hinted (MHint, "I
214 prefer X but will accept anything"), and fixed (MFixed, "X or
215 nothing").
217 * This request is passed to VG_(am_get_advisory). This decides on
218 a placement as described in detail in Strategy above. It may
219 also indicate that the map should fail, because it would trash
220 one of Valgrind's areas, which would probably kill the system.
222 * Control returns to the wrapper. If VG_(am_get_advisory) has
223 declared that the map should fail, then it must be made to do so.
224 Usually, though, the request is considered acceptable, in which
225 case an "advised" address is supplied. The advised address
226 replaces the original address supplied by the client, and
227 MAP_FIXED is set.
229 Note at this point that although aspacem has been asked for
230 advice on where to place the mapping, no commitment has yet been
231 made by either it or the kernel.
233 * The adjusted request is handed off to the kernel.
235 * The kernel's result is examined. If the map succeeded, aspacem
236 is told of the outcome (VG_(am_notify_client_mmap)), so it can
237 update its records accordingly.
239 This then is the central advise-notify idiom for handling client
240 mmap/munmap/mprotect/shmat:
242 * ask aspacem for an advised placement (or a veto)
244 * if not vetoed, hand request to kernel, using the advised placement
246 * examine result, and if successful, notify aspacem of the result.
248 There are also many convenience functions, eg
249 VG_(am_mmap_anon_fixed_client), which do both phases entirely within
250 aspacem.
252 To debug all this, a sync-checker is provided. It reads
253 /proc/self/maps, compares what it sees with aspacem's records, and
254 complains if there is a difference. --sanity-level=3 runs it before
255 and after each syscall, which is a powerful, if slow way of finding
256 buggy syscall wrappers.
258 Loss of pointercheck
259 ~~~~~~~~~~~~~~~~~~~~
260 Up to and including Valgrind 2.4.1, x86 segmentation was used to
261 enforce separation of V and C, so that wild writes by C could not
262 trash V. This got called "pointercheck". Unfortunately, the new
263 more flexible memory layout, plus the need to be portable across
264 different architectures, means doing this in hardware is no longer
265 viable, and doing it in software is expensive. So at the moment we
266 don't do it at all.
270 /*-----------------------------------------------------------------*/
271 /*--- ---*/
272 /*--- The Address Space Manager's state. ---*/
273 /*--- ---*/
274 /*-----------------------------------------------------------------*/
276 /* ------ start of STATE for the address-space manager ------ */
278 /* Max number of segments we can track. On Android, virtual address
279 space is limited, so keep a low limit -- 5000 x sizef(NSegment) is
280 360KB. */
281 #if defined(VGPV_arm_linux_android) \
282 || defined(VGPV_x86_linux_android) \
283 || defined(VGPV_mips32_linux_android) \
284 || defined(VGPV_arm64_linux_android)
285 # define VG_N_SEGMENTS 5000
286 #else
287 # define VG_N_SEGMENTS 30000
288 #endif
290 /* Array [0 .. nsegments_used-1] of all mappings. */
291 /* Sorted by .addr field. */
292 /* I: len may not be zero. */
293 /* I: overlapping segments are not allowed. */
294 /* I: the segments cover the entire address space precisely. */
295 /* Each segment can optionally hold an index into the filename table. */
297 static NSegment nsegments[VG_N_SEGMENTS];
298 static Int nsegments_used = 0;
300 #define Addr_MIN ((Addr)0)
301 #define Addr_MAX ((Addr)(-1ULL))
303 /* Limits etc */
306 Addr VG_(clo_aspacem_minAddr)
307 #if defined(VGO_linux)
308 = (Addr) 0x04000000; // 64M
309 #elif defined(VGO_darwin)
310 # if VG_WORDSIZE == 4
311 = (Addr) 0x00001000;
312 # else
313 = (Addr) 0x100000000; // 4GB page zero
314 # endif
315 #elif defined(VGO_solaris)
316 = (Addr) 0x00100000; // 1MB
317 #elif defined(VGO_freebsd)
318 = (Addr) 0x04000000; // 64M
319 #else
320 #endif
323 // The smallest address that aspacem will try to allocate
324 static Addr aspacem_minAddr = 0;
326 // The largest address that aspacem will try to allocate
327 static Addr aspacem_maxAddr = 0;
329 // Where aspacem will start looking for client space
330 static Addr aspacem_cStart = 0;
332 // Where aspacem will start looking for Valgrind space
333 static Addr aspacem_vStart = 0;
335 #define AM_SANITY_CHECK \
336 do { \
337 if (VG_(clo_sanity_level) >= 3) \
338 aspacem_assert(VG_(am_do_sync_check) \
339 (__PRETTY_FUNCTION__,__FILE__,__LINE__)); \
340 } while (0)
342 /* ------ end of STATE for the address-space manager ------ */
344 /* ------ Forwards decls ------ */
345 inline
346 static Int find_nsegment_idx ( Addr a );
348 static void parse_procselfmaps (
349 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
350 ULong dev, ULong ino, Off64T offset,
351 const HChar* filename, Bool ignore_offset ),
352 void (*record_gap)( Addr addr, SizeT len )
355 /* ----- Hacks to do with the "commpage" on arm-linux ----- */
356 /* Not that I have anything against the commpage per se. It's just
357 that it's not listed in /proc/self/maps, which is a royal PITA --
358 we have to fake it up, in parse_procselfmaps.
360 But note also bug 254556 comment #2: this is now fixed in newer
361 kernels -- it is listed as a "[vectors]" entry. Presumably the
362 fake entry made here duplicates the [vectors] entry, and so, if at
363 some point in the future, we can stop supporting buggy kernels,
364 then this kludge can be removed entirely, since the procmap parser
365 below will read that entry in the normal way. */
366 #if defined(VGP_arm_linux)
367 # define ARM_LINUX_FAKE_COMMPAGE_START 0xFFFF0000
368 # define ARM_LINUX_FAKE_COMMPAGE_END1 0xFFFF1000
369 #endif
371 #if !defined(VKI_MAP_STACK)
372 /* this is only defined for FreeBSD
373 * for readability, define it to 0
374 * for other platforms */
375 #define VKI_MAP_STACK 0
376 #endif
378 /*-----------------------------------------------------------------*/
379 /*--- ---*/
380 /*--- Displaying the segment array. ---*/
381 /*--- ---*/
382 /*-----------------------------------------------------------------*/
384 static const HChar* show_SegKind ( SegKind sk )
386 switch (sk) {
387 case SkFree: return " ";
388 case SkAnonC: return "anon";
389 case SkAnonV: return "ANON";
390 case SkFileC: return "file";
391 case SkFileV: return "FILE";
392 case SkShmC: return "shm ";
393 case SkResvn: return "RSVN";
394 default: return "????";
398 static const HChar* show_ShrinkMode ( ShrinkMode sm )
400 switch (sm) {
401 case SmLower: return "SmLower";
402 case SmUpper: return "SmUpper";
403 case SmFixed: return "SmFixed";
404 default: return "Sm?????";
408 static void show_len_concisely ( /*OUT*/HChar* buf, Addr start, Addr end )
410 const HChar* fmt;
411 ULong len = ((ULong)end) - ((ULong)start) + 1;
413 if (len < 10*1000*1000ULL) {
414 fmt = "%7llu";
416 else if (len < 999999ULL * (1ULL<<20)) {
417 fmt = "%6llum";
418 len >>= 20;
420 else if (len < 999999ULL * (1ULL<<30)) {
421 fmt = "%6llug";
422 len >>= 30;
424 else if (len < 999999ULL * (1ULL<<40)) {
425 fmt = "%6llut";
426 len >>= 40;
428 else {
429 fmt = "%6llue";
430 len >>= 50;
432 ML_(am_sprintf)(buf, fmt, len);
435 /* Show full details of an NSegment */
437 static void show_nsegment_full ( Int logLevel, Int segNo, const NSegment* seg )
439 HChar len_buf[20];
440 const HChar* name = ML_(am_get_segname)( seg->fnIdx );
442 if (name == NULL)
443 name = "(none)";
445 show_len_concisely(len_buf, seg->start, seg->end);
447 VG_(debugLog)(
448 logLevel, "aspacem",
449 "%3d: %s %010lx-%010lx %s %c%c%c%c%c %s "
450 "d=0x%03llx i=%-7llu o=%-7lld (%d,%d) %s\n",
451 segNo, show_SegKind(seg->kind),
452 seg->start, seg->end, len_buf,
453 seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
454 seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
455 seg->isCH ? 'H' : '-',
456 show_ShrinkMode(seg->smode),
457 seg->dev, seg->ino, seg->offset,
458 ML_(am_segname_get_seqnr)(seg->fnIdx), seg->fnIdx,
459 name
464 /* Show an NSegment in a user-friendly-ish way. */
466 static void show_nsegment ( Int logLevel, Int segNo, const NSegment* seg )
468 HChar len_buf[20];
469 show_len_concisely(len_buf, seg->start, seg->end);
471 switch (seg->kind) {
473 case SkFree:
474 VG_(debugLog)(
475 logLevel, "aspacem",
476 "%3d: %s %010lx-%010lx %s\n",
477 segNo, show_SegKind(seg->kind),
478 seg->start, seg->end, len_buf
480 break;
482 case SkAnonC: case SkAnonV: case SkShmC:
483 VG_(debugLog)(
484 logLevel, "aspacem",
485 "%3d: %s %010lx-%010lx %s %c%c%c%c%c\n",
486 segNo, show_SegKind(seg->kind),
487 seg->start, seg->end, len_buf,
488 seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
489 seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
490 seg->isCH ? 'H' : '-'
492 break;
494 case SkFileC: case SkFileV:
495 VG_(debugLog)(
496 logLevel, "aspacem",
497 "%3d: %s %010lx-%010lx %s %c%c%c%c%c d=0x%03llx "
498 "i=%-7llu o=%-7lld (%d,%d)\n",
499 segNo, show_SegKind(seg->kind),
500 seg->start, seg->end, len_buf,
501 seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
502 seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
503 seg->isCH ? 'H' : '-',
504 seg->dev, seg->ino, seg->offset,
505 ML_(am_segname_get_seqnr)(seg->fnIdx), seg->fnIdx
507 break;
509 case SkResvn:
510 VG_(debugLog)(
511 logLevel, "aspacem",
512 "%3d: %s %010lx-%010lx %s %c%c%c%c%c %s\n",
513 segNo, show_SegKind(seg->kind),
514 seg->start, seg->end, len_buf,
515 seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
516 seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
517 seg->isCH ? 'H' : '-',
518 show_ShrinkMode(seg->smode)
520 break;
522 default:
523 VG_(debugLog)(
524 logLevel, "aspacem",
525 "%3d: ???? UNKNOWN SEGMENT KIND\n",
526 segNo
528 break;
532 /* Print out the segment array (debugging only!). */
533 void VG_(am_show_nsegments) ( Int logLevel, const HChar* who )
535 Int i;
536 VG_(debugLog)(logLevel, "aspacem",
537 "<<< SHOW_SEGMENTS: %s (%d segments)\n",
538 who, nsegments_used);
539 ML_(am_show_segnames)( logLevel, who);
540 for (i = 0; i < nsegments_used; i++)
541 show_nsegment( logLevel, i, &nsegments[i] );
542 VG_(debugLog)(logLevel, "aspacem",
543 ">>>\n");
547 /* Get the filename corresponding to this segment, if known and if it
548 has one. */
549 const HChar* VG_(am_get_filename)( NSegment const * seg )
551 aspacem_assert(seg);
552 return ML_(am_get_segname)( seg->fnIdx );
555 /* Collect up the start addresses of segments whose kind matches one of
556 the kinds specified in kind_mask.
557 The interface is a bit strange in order to avoid potential
558 segment-creation races caused by dynamic allocation of the result
559 buffer *starts.
561 The function first computes how many entries in the result
562 buffer *starts will be needed. If this number <= nStarts,
563 they are placed in starts[0..], and the number is returned.
564 If nStarts is not large enough, nothing is written to
565 starts[0..], and the negation of the size is returned.
567 Correct use of this function may mean calling it multiple times in
568 order to establish a suitably-sized buffer. */
570 Int VG_(am_get_segment_starts)( UInt kind_mask, Addr* starts, Int nStarts )
572 Int i, j, nSegs;
574 /* don't pass dumbass arguments */
575 aspacem_assert(nStarts > 0);
577 nSegs = 0;
578 for (i = 0; i < nsegments_used; i++) {
579 if ((nsegments[i].kind & kind_mask) != 0)
580 nSegs++;
583 if (nSegs > nStarts) {
584 /* The buffer isn't big enough. Tell the caller how big it needs
585 to be. */
586 return -nSegs;
589 /* There's enough space. So write into the result buffer. */
590 aspacem_assert(nSegs <= nStarts);
592 j = 0;
593 for (i = 0; i < nsegments_used; i++) {
594 if ((nsegments[i].kind & kind_mask) != 0)
595 starts[j++] = nsegments[i].start;
598 aspacem_assert(j == nSegs); /* this should not fail */
599 return nSegs;
603 /*-----------------------------------------------------------------*/
604 /*--- ---*/
605 /*--- Sanity checking and preening of the segment array. ---*/
606 /*--- ---*/
607 /*-----------------------------------------------------------------*/
609 /* Check representational invariants for NSegments. */
611 static Bool sane_NSegment ( const NSegment* s )
613 if (s == NULL) return False;
615 /* No zero sized segments and no wraparounds. */
616 if (s->start > s->end) return False;
618 /* require page alignment */
619 if (!VG_IS_PAGE_ALIGNED(s->start)) return False;
620 if (!VG_IS_PAGE_ALIGNED(s->end+1)) return False;
622 switch (s->kind) {
624 case SkFree:
625 return
626 s->smode == SmFixed
627 && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
628 && !s->hasR && !s->hasW && !s->hasX && !s->hasT
629 && !s->isCH;
631 case SkAnonC: case SkAnonV: case SkShmC:
632 return
633 s->smode == SmFixed
634 && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
635 && (s->kind==SkAnonC ? True : !s->isCH);
637 case SkFileC: case SkFileV:
638 return
639 s->smode == SmFixed
640 && ML_(am_sane_segname)(s->fnIdx)
641 && !s->isCH;
643 case SkResvn:
644 return
645 s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
646 && !s->hasR && !s->hasW && !s->hasX && !s->hasT
647 && !s->isCH;
649 default:
650 return False;
655 /* Try merging s2 into s1, if possible. If successful, s1 is
656 modified, and True is returned. Otherwise s1 is unchanged and
657 False is returned. */
659 static Bool maybe_merge_nsegments ( NSegment* s1, const NSegment* s2 )
661 if (s1->kind != s2->kind)
662 return False;
664 if (s1->end+1 != s2->start)
665 return False;
667 /* reject cases which would cause wraparound */
668 if (s1->start > s2->end)
669 return False;
671 switch (s1->kind) {
673 case SkFree:
674 s1->end = s2->end;
675 return True;
677 case SkAnonC: case SkAnonV:
678 if (s1->hasR == s2->hasR && s1->hasW == s2->hasW
679 && s1->hasX == s2->hasX && s1->isCH == s2->isCH) {
680 s1->end = s2->end;
681 s1->hasT |= s2->hasT;
682 return True;
684 break;
686 case SkFileC: case SkFileV:
687 if (s1->hasR == s2->hasR
688 && s1->hasW == s2->hasW && s1->hasX == s2->hasX
689 && s1->dev == s2->dev && s1->ino == s2->ino
690 && s2->offset == s1->offset
691 + ((ULong)s2->start) - ((ULong)s1->start) ) {
692 s1->end = s2->end;
693 s1->hasT |= s2->hasT;
694 ML_(am_dec_refcount)(s1->fnIdx);
695 return True;
697 break;
699 case SkShmC:
700 return False;
702 case SkResvn:
703 if (s1->smode == SmFixed && s2->smode == SmFixed) {
704 s1->end = s2->end;
705 return True;
708 default:
709 break;
713 return False;
717 /* Sanity-check and canonicalise the segment array (merge mergable
718 segments). Returns True if any segments were merged. */
720 static Bool preen_nsegments ( void )
722 Int i, r, w, nsegments_used_old = nsegments_used;
724 /* Pass 1: check the segment array covers the entire address space
725 exactly once, and also that each segment is sane. */
726 aspacem_assert(nsegments_used > 0);
727 aspacem_assert(nsegments[0].start == Addr_MIN);
728 aspacem_assert(nsegments[nsegments_used-1].end == Addr_MAX);
730 aspacem_assert(sane_NSegment(&nsegments[0]));
731 for (i = 1; i < nsegments_used; i++) {
732 aspacem_assert(sane_NSegment(&nsegments[i]));
733 aspacem_assert(nsegments[i-1].end+1 == nsegments[i].start);
736 /* Pass 2: merge as much as possible, using
737 maybe_merge_segments. */
738 w = 0;
739 for (r = 1; r < nsegments_used; r++) {
740 if (maybe_merge_nsegments(&nsegments[w], &nsegments[r])) {
741 /* nothing */
742 } else {
743 w++;
744 if (w != r)
745 nsegments[w] = nsegments[r];
748 w++;
749 aspacem_assert(w > 0 && w <= nsegments_used);
750 nsegments_used = w;
752 return nsegments_used != nsegments_used_old;
756 /* Check the segment array corresponds with the kernel's view of
757 memory layout. sync_check_ok returns True if no anomalies were
758 found, else False. In the latter case the mismatching segments are
759 displayed.
761 The general idea is: we get the kernel to show us all its segments
762 and also the gaps in between. For each such interval, try and find
763 a sequence of appropriate intervals in our segment array which
764 cover or more than cover the kernel's interval, and which all have
765 suitable kinds/permissions etc.
767 Although any specific kernel interval is not matched exactly to a
768 valgrind interval or sequence thereof, eventually any disagreement
769 on mapping boundaries will be detected. This is because, if for
770 example valgrind's intervals cover a greater range than the current
771 kernel interval, it must be the case that a neighbouring free-space
772 interval belonging to valgrind cannot cover the neighbouring
773 free-space interval belonging to the kernel. So the disagreement
774 is detected.
776 In other words, we examine each kernel interval in turn, and check
777 we do not disagree over the range of that interval. Because all of
778 the address space is examined, any disagreements must eventually be
779 detected.
782 static Bool sync_check_ok = False;
784 static void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot,
785 ULong dev, ULong ino, Off64T offset,
786 const HChar* filename, Bool ignore_offset )
788 Int iLo, iHi, i;
789 Bool sloppyXcheck, sloppyRcheck;
791 /* If a problem has already been detected, don't continue comparing
792 segments, so as to avoid flooding the output with error
793 messages. */
794 #if !defined(VGO_darwin)
795 /* GrP fixme not */
796 if (!sync_check_ok)
797 return;
798 #endif
799 if (len == 0)
800 return;
802 /* The kernel should not give us wraparounds. */
803 aspacem_assert(addr <= addr + len - 1);
805 iLo = find_nsegment_idx( addr );
806 iHi = find_nsegment_idx( addr + len - 1 );
808 /* These 5 should be guaranteed by find_nsegment_idx. */
809 aspacem_assert(0 <= iLo && iLo < nsegments_used);
810 aspacem_assert(0 <= iHi && iHi < nsegments_used);
811 aspacem_assert(iLo <= iHi);
812 aspacem_assert(nsegments[iLo].start <= addr );
813 aspacem_assert(nsegments[iHi].end >= addr + len - 1 );
815 /* x86 doesn't differentiate 'x' and 'r' (at least, all except the
816 most recent NX-bit enabled CPUs) and so recent kernels attempt
817 to provide execute protection by placing all executable mappings
818 low down in the address space and then reducing the size of the
819 code segment to prevent code at higher addresses being executed.
821 These kernels report which mappings are really executable in
822 the /proc/self/maps output rather than mirroring what was asked
823 for when each mapping was created. In order to cope with this we
824 have a sloppyXcheck mode which we enable on x86 and s390 - in this
825 mode we allow the kernel to report execute permission when we weren't
826 expecting it but not vice versa. */
827 # if defined(VGA_x86) || defined (VGA_s390x) || \
828 defined(VGA_mips32) || defined(VGA_mips64)
829 sloppyXcheck = True;
830 # else
831 sloppyXcheck = False;
832 # endif
834 /* Some kernels on s390 provide 'r' permission even when it was not
835 explicitly requested. It seems that 'x' permission implies 'r'.
836 This behaviour also occurs on OS X. */
837 # if defined(VGA_s390x) || defined(VGO_darwin)
838 sloppyRcheck = True;
839 # else
840 sloppyRcheck = False;
841 # endif
843 /* NSegments iLo .. iHi inclusive should agree with the presented
844 data. */
845 for (i = iLo; i <= iHi; i++) {
847 Bool same, cmp_offsets, cmp_devino;
848 UInt seg_prot;
850 /* compare the kernel's offering against ours. */
851 same = nsegments[i].kind == SkAnonC
852 || nsegments[i].kind == SkAnonV
853 || nsegments[i].kind == SkFileC
854 || nsegments[i].kind == SkFileV
855 || nsegments[i].kind == SkShmC;
857 seg_prot = 0;
858 if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
859 if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
860 if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
862 #if defined(VGO_darwin) || defined(VGO_freebsd)
863 // GrP fixme kernel info doesn't have dev/inode
864 cmp_devino = False;
866 // GrP fixme V and kernel don't agree on offsets
867 cmp_offsets = False;
868 #else
869 cmp_offsets
870 = nsegments[i].kind == SkFileC || nsegments[i].kind == SkFileV;
872 cmp_devino
873 = nsegments[i].dev != 0 || nsegments[i].ino != 0;
874 #endif
876 /* Consider other reasons to not compare dev/inode */
877 #if defined(VGO_linux)
878 /* bproc does some godawful hack on /dev/zero at process
879 migration, which changes the name of it, and its dev & ino */
880 if (filename && 0==VG_(strcmp)(filename, "/dev/zero (deleted)"))
881 cmp_devino = False;
883 /* hack apparently needed on MontaVista Linux */
884 if (filename && VG_(strstr)(filename, "/.lib-ro/"))
885 cmp_devino = False;
886 #endif
888 /* If we are doing sloppy execute permission checks then we
889 allow segment to have X permission when we weren't expecting
890 it (but not vice versa) so if the kernel reported execute
891 permission then pretend that this segment has it regardless
892 of what we were expecting. */
893 if (sloppyXcheck && (prot & VKI_PROT_EXEC) != 0) {
894 seg_prot |= VKI_PROT_EXEC;
897 if (sloppyRcheck && (prot & (VKI_PROT_EXEC | VKI_PROT_READ)) ==
898 (VKI_PROT_EXEC | VKI_PROT_READ)) {
899 seg_prot |= VKI_PROT_READ;
902 same = same
903 && seg_prot == prot
904 && (cmp_devino
905 ? (nsegments[i].dev == dev && nsegments[i].ino == ino)
906 : True)
907 && (cmp_offsets
908 ? nsegments[i].start-nsegments[i].offset == addr-offset
909 : True);
910 if (!same) {
911 Addr start = addr;
912 Addr end = start + len - 1;
913 HChar len_buf[20];
914 show_len_concisely(len_buf, start, end);
916 sync_check_ok = False;
918 VG_(debugLog)(
919 0,"aspacem",
920 "segment mismatch: V's seg 1st, kernel's 2nd:\n");
921 show_nsegment_full( 0, i, &nsegments[i] );
922 VG_(debugLog)(0,"aspacem",
923 "...: .... %010lx-%010lx %s %c%c%c.. ....... "
924 "d=0x%03llx i=%-7llu o=%-7lld (.) m=. %s\n",
925 start, end, len_buf,
926 prot & VKI_PROT_READ ? 'r' : '-',
927 prot & VKI_PROT_WRITE ? 'w' : '-',
928 prot & VKI_PROT_EXEC ? 'x' : '-',
929 dev, ino, offset, filename ? filename : "(none)" );
931 return;
935 /* Looks harmless. Keep going. */
936 return;
939 static void sync_check_gap_callback ( Addr addr, SizeT len )
941 Int iLo, iHi, i;
943 /* If a problem has already been detected, don't continue comparing
944 segments, so as to avoid flooding the output with error
945 messages. */
946 #if !defined(VGO_darwin)
947 /* GrP fixme not */
948 if (!sync_check_ok)
949 return;
950 #endif
951 if (len == 0)
952 return;
954 /* The kernel should not give us wraparounds. */
955 aspacem_assert(addr <= addr + len - 1);
957 iLo = find_nsegment_idx( addr );
958 iHi = find_nsegment_idx( addr + len - 1 );
960 /* These 5 should be guaranteed by find_nsegment_idx. */
961 aspacem_assert(0 <= iLo && iLo < nsegments_used);
962 aspacem_assert(0 <= iHi && iHi < nsegments_used);
963 aspacem_assert(iLo <= iHi);
964 aspacem_assert(nsegments[iLo].start <= addr );
965 aspacem_assert(nsegments[iHi].end >= addr + len - 1 );
967 /* NSegments iLo .. iHi inclusive should agree with the presented
968 data. */
969 for (i = iLo; i <= iHi; i++) {
971 Bool same;
973 /* compare the kernel's offering against ours. */
974 same = nsegments[i].kind == SkFree
975 || nsegments[i].kind == SkResvn;
977 if (!same) {
978 Addr start = addr;
979 Addr end = start + len - 1;
980 HChar len_buf[20];
981 show_len_concisely(len_buf, start, end);
983 sync_check_ok = False;
985 VG_(debugLog)(
986 0,"aspacem",
987 "segment mismatch: V's gap 1st, kernel's 2nd:\n");
988 show_nsegment_full( 0, i, &nsegments[i] );
989 VG_(debugLog)(0,"aspacem",
990 " : .... %010lx-%010lx %s\n",
991 start, end, len_buf);
992 return;
996 /* Looks harmless. Keep going. */
997 return;
1001 /* Sanity check: check that Valgrind and the kernel agree on the
1002 address space layout. Prints offending segments and call point if
1003 a discrepancy is detected, but does not abort the system. Returned
1004 Bool is False if a discrepancy was found. */
1006 Bool VG_(am_do_sync_check) ( const HChar* fn,
1007 const HChar* file, Int line )
1009 sync_check_ok = True;
1010 if (0)
1011 VG_(debugLog)(0,"aspacem", "do_sync_check %s:%d\n", file,line);
1012 parse_procselfmaps( sync_check_mapping_callback,
1013 sync_check_gap_callback );
1014 if (!sync_check_ok) {
1015 VG_(debugLog)(0,"aspacem",
1016 "sync check at %s:%d (%s): FAILED\n",
1017 file, line, fn);
1018 VG_(debugLog)(0,"aspacem", "\n");
1020 # if 0
1022 HChar buf[100]; // large enough
1023 VG_(am_show_nsegments)(0,"post syncheck failure");
1024 VG_(sprintf)(buf, "/bin/cat /proc/%d/maps", VG_(getpid)());
1025 VG_(system)(buf);
1027 # endif
1030 return sync_check_ok;
1033 /* Hook to allow sanity checks to be done from aspacemgr-common.c. */
1034 void ML_(am_do_sanity_check)( void )
1036 AM_SANITY_CHECK;
1040 /*-----------------------------------------------------------------*/
1041 /*--- ---*/
1042 /*--- Low level access / modification of the segment array. ---*/
1043 /*--- ---*/
1044 /*-----------------------------------------------------------------*/
1046 /* Binary search the interval array for a given address. Since the
1047 array covers the entire address space the search cannot fail. The
1048 _WRK function does the real work. Its caller (just below) caches
1049 the results thereof, to save time. With N_CACHE of 63 we get a hit
1050 rate exceeding 90% when running OpenOffice.
1052 Re ">> 12", it doesn't matter that the page size of some targets
1053 might be different from 12. Really "(a >> 12) % N_CACHE" is merely
1054 a hash function, and the actual cache entry is always validated
1055 correctly against the selected cache entry before use.
1057 /* Don't call find_nsegment_idx_WRK; use find_nsegment_idx instead. */
1058 __attribute__((noinline))
1059 static Int find_nsegment_idx_WRK ( Addr a )
1061 Addr a_mid_lo, a_mid_hi;
1062 Int mid,
1063 lo = 0,
1064 hi = nsegments_used-1;
1065 while (True) {
1066 /* current unsearched space is from lo to hi, inclusive. */
1067 if (lo > hi) {
1068 /* Not found. This can't happen. */
1069 ML_(am_barf)("find_nsegment_idx: not found");
1071 mid = (lo + hi) / 2;
1072 a_mid_lo = nsegments[mid].start;
1073 a_mid_hi = nsegments[mid].end;
1075 if (a < a_mid_lo) { hi = mid-1; continue; }
1076 if (a > a_mid_hi) { lo = mid+1; continue; }
1077 aspacem_assert(a >= a_mid_lo && a <= a_mid_hi);
1078 aspacem_assert(0 <= mid && mid < nsegments_used);
1079 return mid;
1083 inline static Int find_nsegment_idx ( Addr a )
1085 # define N_CACHE 131 /*prime*/
1086 static Addr cache_pageno[N_CACHE];
1087 static Int cache_segidx[N_CACHE];
1088 static Bool cache_inited = False;
1090 # ifdef N_Q_M_STATS
1091 static UWord n_q = 0;
1092 static UWord n_m = 0;
1093 n_q++;
1094 if (0 == (n_q & 0xFFFF))
1095 VG_(debugLog)(0,"xxx","find_nsegment_idx: %lu %lu\n", n_q, n_m);
1096 # endif
1098 UWord ix;
1100 if (LIKELY(cache_inited)) {
1101 /* do nothing */
1102 } else {
1103 for (ix = 0; ix < N_CACHE; ix++) {
1104 cache_pageno[ix] = 0;
1105 cache_segidx[ix] = -1;
1107 cache_inited = True;
1110 ix = (a >> 12) % N_CACHE;
1112 if ((a >> 12) == cache_pageno[ix]
1113 && cache_segidx[ix] >= 0
1114 && cache_segidx[ix] < nsegments_used
1115 && nsegments[cache_segidx[ix]].start <= a
1116 && a <= nsegments[cache_segidx[ix]].end) {
1117 /* hit */
1118 /* aspacem_assert( cache_segidx[ix] == find_nsegment_idx_WRK(a) ); */
1119 return cache_segidx[ix];
1121 /* miss */
1122 # ifdef N_Q_M_STATS
1123 n_m++;
1124 # endif
1125 cache_segidx[ix] = find_nsegment_idx_WRK(a);
1126 cache_pageno[ix] = a >> 12;
1127 return cache_segidx[ix];
1128 # undef N_CACHE
1132 /* Finds the segment containing 'a'. Only returns non-SkFree segments. */
1133 NSegment const * VG_(am_find_nsegment) ( Addr a )
1135 Int i = find_nsegment_idx(a);
1136 aspacem_assert(i >= 0 && i < nsegments_used);
1137 aspacem_assert(nsegments[i].start <= a);
1138 aspacem_assert(a <= nsegments[i].end);
1139 if (nsegments[i].kind == SkFree)
1140 return NULL;
1141 else
1142 return &nsegments[i];
1145 /* Finds an anonymous segment containing 'a'. Returned pointer is read only. */
1146 NSegment const *VG_(am_find_anon_segment) ( Addr a )
1148 Int i = find_nsegment_idx(a);
1149 aspacem_assert(i >= 0 && i < nsegments_used);
1150 aspacem_assert(nsegments[i].start <= a);
1151 aspacem_assert(a <= nsegments[i].end);
1152 if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV)
1153 return &nsegments[i];
1154 else
1155 return NULL;
1158 /* Map segment pointer to segment index. */
1159 static Int segAddr_to_index ( const NSegment* seg )
1161 aspacem_assert(seg >= &nsegments[0] && seg < &nsegments[nsegments_used]);
1163 return seg - &nsegments[0];
1167 /* Find the next segment along from 'here', if it is a non-SkFree segment. */
1168 NSegment const * VG_(am_next_nsegment) ( const NSegment* here, Bool fwds )
1170 Int i = segAddr_to_index(here);
1172 if (fwds) {
1173 i++;
1174 if (i >= nsegments_used)
1175 return NULL;
1176 } else {
1177 i--;
1178 if (i < 0)
1179 return NULL;
1181 if (nsegments[i].kind == SkFree)
1182 return NULL;
1183 else
1184 return &nsegments[i];
1188 /* Trivial fn: return the total amount of space in anonymous mappings,
1189 both for V and the client. Is used for printing stats in
1190 out-of-memory messages. */
1191 ULong VG_(am_get_anonsize_total)( void )
1193 Int i;
1194 ULong total = 0;
1195 for (i = 0; i < nsegments_used; i++) {
1196 if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV) {
1197 total += (ULong)nsegments[i].end
1198 - (ULong)nsegments[i].start + 1ULL;
1201 return total;
1205 /* Test if a piece of memory is addressable by client or by valgrind with at
1206 least the "prot" protection permissions by examining the underlying
1207 segments. The KINDS argument specifies the allowed segments ADDR may
1208 belong to in order to be considered "valid".
1210 static
1211 Bool is_valid_for( UInt kinds, Addr start, SizeT len, UInt prot )
1213 Int i, iLo, iHi;
1214 Bool needR, needW, needX;
1216 if (len == 0)
1217 return True; /* somewhat dubious case */
1218 if (start + len < start)
1219 return False; /* reject wraparounds */
1221 needR = toBool(prot & VKI_PROT_READ);
1222 needW = toBool(prot & VKI_PROT_WRITE);
1223 needX = toBool(prot & VKI_PROT_EXEC);
1225 iLo = find_nsegment_idx(start);
1226 aspacem_assert(start >= nsegments[iLo].start);
1228 if (start+len-1 <= nsegments[iLo].end) {
1229 /* This is a speedup hack which avoids calling find_nsegment_idx
1230 a second time when possible. It is always correct to just
1231 use the "else" clause below, but is_valid_for_client is
1232 called a lot by the leak checker, so avoiding pointless calls
1233 to find_nsegment_idx, which can be expensive, is helpful. */
1234 iHi = iLo;
1235 } else {
1236 iHi = find_nsegment_idx(start + len - 1);
1239 for (i = iLo; i <= iHi; i++) {
1240 if ( (nsegments[i].kind & kinds) != 0
1241 && (needR ? nsegments[i].hasR : True)
1242 && (needW ? nsegments[i].hasW : True)
1243 && (needX ? nsegments[i].hasX : True) ) {
1244 /* ok */
1245 } else {
1246 return False;
1250 return True;
1253 /* Test if a piece of memory is addressable by the client with at
1254 least the "prot" protection permissions by examining the underlying
1255 segments. */
1256 Bool VG_(am_is_valid_for_client)( Addr start, SizeT len,
1257 UInt prot )
1259 const UInt kinds = SkFileC | SkAnonC | SkShmC;
1261 return is_valid_for(kinds, start, len, prot);
1264 /* Variant of VG_(am_is_valid_for_client) which allows free areas to
1265 be consider part of the client's addressable space. It also
1266 considers reservations to be allowable, since from the client's
1267 point of view they don't exist. */
1268 Bool VG_(am_is_valid_for_client_or_free_or_resvn)
1269 ( Addr start, SizeT len, UInt prot )
1271 const UInt kinds = SkFileC | SkAnonC | SkShmC | SkFree | SkResvn;
1273 return is_valid_for(kinds, start, len, prot);
1276 /* Checks if a piece of memory consists of either free or reservation
1277 segments. */
1278 Bool VG_(am_is_free_or_resvn)( Addr start, SizeT len )
1280 const UInt kinds = SkFree | SkResvn;
1282 return is_valid_for(kinds, start, len, 0);
1286 Bool VG_(am_is_valid_for_valgrind) ( Addr start, SizeT len, UInt prot )
1288 const UInt kinds = SkFileV | SkAnonV;
1290 return is_valid_for(kinds, start, len, prot);
1294 /* Returns True if any part of the address range is marked as having
1295 translations made from it. This is used to determine when to
1296 discard code, so if in doubt return True. */
1298 static Bool any_Ts_in_range ( Addr start, SizeT len )
1300 Int iLo, iHi, i;
1301 aspacem_assert(len > 0);
1302 aspacem_assert(start + len > start);
1303 iLo = find_nsegment_idx(start);
1304 iHi = find_nsegment_idx(start + len - 1);
1305 for (i = iLo; i <= iHi; i++) {
1306 if (nsegments[i].hasT)
1307 return True;
1309 return False;
1313 /* Check whether ADDR looks like an address or address-to-be located in an
1314 extensible client stack segment. Return true if
1315 (1) ADDR is located in an already mapped stack segment, OR
1316 (2) ADDR is located in a reservation segment into which an abutting SkAnonC
1317 segment can be extended. */
1318 Bool VG_(am_addr_is_in_extensible_client_stack)( Addr addr )
1320 const NSegment *seg = nsegments + find_nsegment_idx(addr);
1322 switch (seg->kind) {
1323 case SkFree:
1324 case SkAnonV:
1325 case SkFileV:
1326 case SkFileC:
1327 case SkShmC:
1328 return False;
1330 case SkResvn: {
1331 if (seg->smode != SmUpper) return False;
1332 /* If the abutting segment towards higher addresses is an SkAnonC
1333 segment, then ADDR is a future stack pointer. */
1334 const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ True);
1335 if (next == NULL || next->kind != SkAnonC) return False;
1337 /* OK; looks like a stack segment */
1338 return True;
1341 case SkAnonC: {
1342 /* If the abutting segment towards lower addresses is an SkResvn
1343 segment, then ADDR is a stack pointer into mapped memory. */
1344 const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ False);
1345 if (next == NULL || next->kind != SkResvn || next->smode != SmUpper)
1346 return False;
1348 /* OK; looks like a stack segment */
1349 return True;
1352 default:
1353 aspacem_assert(0); // should never happen
1357 /*-----------------------------------------------------------------*/
1358 /*--- ---*/
1359 /*--- Modifying the segment array, and constructing segments. ---*/
1360 /*--- ---*/
1361 /*-----------------------------------------------------------------*/
1363 /* Split the segment containing 'a' into two, so that 'a' is
1364 guaranteed to be the start of a new segment. If 'a' is already the
1365 start of a segment, do nothing. */
1367 static void split_nsegment_at ( Addr a )
1369 Int i, j;
1371 aspacem_assert(a > 0);
1372 aspacem_assert(VG_IS_PAGE_ALIGNED(a));
1374 i = find_nsegment_idx(a);
1375 aspacem_assert(i >= 0 && i < nsegments_used);
1377 if (nsegments[i].start == a)
1378 /* 'a' is already the start point of a segment, so nothing to be
1379 done. */
1380 return;
1382 /* else we have to slide the segments upwards to make a hole */
1383 if (nsegments_used >= VG_N_SEGMENTS)
1384 ML_(am_barf_toolow)("VG_N_SEGMENTS");
1385 for (j = nsegments_used-1; j > i; j--)
1386 nsegments[j+1] = nsegments[j];
1387 nsegments_used++;
1389 nsegments[i+1] = nsegments[i];
1390 nsegments[i+1].start = a;
1391 nsegments[i].end = a-1;
1393 if (nsegments[i].kind == SkFileV || nsegments[i].kind == SkFileC)
1394 nsegments[i+1].offset
1395 += ((ULong)nsegments[i+1].start) - ((ULong)nsegments[i].start);
1397 ML_(am_inc_refcount)(nsegments[i].fnIdx);
1399 aspacem_assert(sane_NSegment(&nsegments[i]));
1400 aspacem_assert(sane_NSegment(&nsegments[i+1]));
1404 /* Do the minimum amount of segment splitting necessary to ensure that
1405 sLo is the first address denoted by some segment and sHi is the
1406 highest address denoted by some other segment. Returns the indices
1407 of the lowest and highest segments in the range. */
1409 static
1410 void split_nsegments_lo_and_hi ( Addr sLo, Addr sHi,
1411 /*OUT*/Int* iLo,
1412 /*OUT*/Int* iHi )
1414 aspacem_assert(sLo < sHi);
1415 aspacem_assert(VG_IS_PAGE_ALIGNED(sLo));
1416 aspacem_assert(VG_IS_PAGE_ALIGNED(sHi+1));
1418 if (sLo > 0)
1419 split_nsegment_at(sLo);
1420 if (sHi < sHi+1)
1421 split_nsegment_at(sHi+1);
1423 *iLo = find_nsegment_idx(sLo);
1424 *iHi = find_nsegment_idx(sHi);
1425 aspacem_assert(0 <= *iLo && *iLo < nsegments_used);
1426 aspacem_assert(0 <= *iHi && *iHi < nsegments_used);
1427 aspacem_assert(*iLo <= *iHi);
1428 aspacem_assert(nsegments[*iLo].start == sLo);
1429 aspacem_assert(nsegments[*iHi].end == sHi);
1430 /* Not that I'm overly paranoid or anything, definitely not :-) */
1434 /* Add SEG to the collection, deleting/truncating any it overlaps.
1435 This deals with all the tricky cases of splitting up segments as
1436 needed. */
1438 static void add_segment ( const NSegment* seg )
1440 Int i, iLo, iHi, delta;
1441 Bool segment_is_sane;
1443 Addr sStart = seg->start;
1444 Addr sEnd = seg->end;
1446 aspacem_assert(sStart <= sEnd);
1447 aspacem_assert(VG_IS_PAGE_ALIGNED(sStart));
1448 aspacem_assert(VG_IS_PAGE_ALIGNED(sEnd+1));
1450 segment_is_sane = sane_NSegment(seg);
1451 if (!segment_is_sane) show_nsegment_full(0,-1,seg);
1452 aspacem_assert(segment_is_sane);
1454 split_nsegments_lo_and_hi( sStart, sEnd, &iLo, &iHi );
1456 /* Increase the reference count of SEG's name. We need to do this
1457 *before* decreasing the reference count of the names of the replaced
1458 segments. Consider the case where the segment name of SEG and one of
1459 the replaced segments are the same. If the refcount of that name is 1,
1460 then decrementing first would put the slot for that name on the free
1461 list. Attempting to increment the refcount later would then fail
1462 because the slot is no longer allocated. */
1463 ML_(am_inc_refcount)(seg->fnIdx);
1465 /* Now iLo .. iHi inclusive is the range of segment indices which
1466 seg will replace. If we're replacing more than one segment,
1467 slide those above the range down to fill the hole. Before doing
1468 that decrement the reference counters for the segments names of
1469 the replaced segments. */
1470 for (i = iLo; i <= iHi; ++i)
1471 ML_(am_dec_refcount)(nsegments[i].fnIdx);
1472 delta = iHi - iLo;
1473 aspacem_assert(delta >= 0);
1474 if (delta > 0) {
1475 for (i = iLo; i < nsegments_used-delta; i++)
1476 nsegments[i] = nsegments[i+delta];
1477 nsegments_used -= delta;
1480 nsegments[iLo] = *seg;
1482 (void)preen_nsegments();
1483 if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)");
1487 /* Clear out an NSegment record. */
1489 static void init_nsegment ( /*OUT*/NSegment* seg )
1491 seg->kind = SkFree;
1492 seg->start = 0;
1493 seg->end = 0;
1494 seg->smode = SmFixed;
1495 seg->dev = 0;
1496 seg->ino = 0;
1497 seg->mode = 0;
1498 seg->offset = 0;
1499 seg->fnIdx = -1;
1501 seg->hasR = seg->hasW = seg->hasX = seg->hasT
1502 = seg->isCH = False;
1503 #if defined(VGO_freebsd)
1504 seg->isFF = False;
1505 seg->ignore_offset = False;
1506 #endif
1510 /* Make an NSegment which holds a reservation. */
1512 static void init_resvn ( /*OUT*/NSegment* seg, Addr start, Addr end )
1514 aspacem_assert(start < end);
1515 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
1516 aspacem_assert(VG_IS_PAGE_ALIGNED(end+1));
1517 init_nsegment(seg);
1518 seg->kind = SkResvn;
1519 seg->start = start;
1520 seg->end = end;
1524 /*-----------------------------------------------------------------*/
1525 /*--- ---*/
1526 /*--- Startup, including reading /proc/self/maps. ---*/
1527 /*--- ---*/
1528 /*-----------------------------------------------------------------*/
1530 static void read_maps_callback ( Addr addr, SizeT len, UInt prot,
1531 ULong dev, ULong ino, Off64T offset,
1532 const HChar* filename, Bool ignore_offset )
1534 NSegment seg;
1535 init_nsegment( &seg );
1536 seg.start = addr;
1537 seg.end = addr+len-1;
1538 seg.dev = dev;
1539 seg.ino = ino;
1540 seg.offset = offset;
1541 #if defined(VGO_freebsd)
1542 seg.ignore_offset = ignore_offset;
1543 #endif
1544 seg.hasR = toBool(prot & VKI_PROT_READ);
1545 seg.hasW = toBool(prot & VKI_PROT_WRITE);
1546 seg.hasX = toBool(prot & VKI_PROT_EXEC);
1547 seg.hasT = False;
1549 /* A segment in the initial /proc/self/maps is considered a FileV
1550 segment if either it has a file name associated with it or both its
1551 device and inode numbers are != 0. See bug #124528. */
1552 seg.kind = SkAnonV;
1553 if (filename || (dev != 0 && ino != 0))
1554 seg.kind = SkFileV;
1556 # if defined(VGO_darwin)
1557 // GrP fixme no dev/ino on darwin
1558 if (offset != 0)
1559 seg.kind = SkFileV;
1560 # endif // defined(VGO_darwin)
1562 # if defined(VGP_arm_linux)
1563 /* The standard handling of entries read from /proc/self/maps will
1564 cause the faked up commpage segment to have type SkAnonV, which
1565 is a problem because it contains code we want the client to
1566 execute, and so later m_translate will segfault the client when
1567 it tries to go in there. Hence change the ownership of it here
1568 to the client (SkAnonC). The least-worst kludge I could think
1569 of. */
1570 if (addr == ARM_LINUX_FAKE_COMMPAGE_START
1571 && addr + len == ARM_LINUX_FAKE_COMMPAGE_END1
1572 && seg.kind == SkAnonV)
1573 seg.kind = SkAnonC;
1574 # endif // defined(VGP_arm_linux)
1576 if (filename)
1577 seg.fnIdx = ML_(am_allocate_segname)( filename );
1579 if (0) show_nsegment( 2,0, &seg );
1580 add_segment( &seg );
1583 Bool
1584 VG_(am_is_valid_for_aspacem_minAddr)( Addr addr, const HChar **errmsg )
1586 const Addr min = VKI_PAGE_SIZE;
1587 #if VG_WORDSIZE == 4
1588 const Addr max = 0x40000000; // 1Gb
1589 #else
1590 const Addr max = 0x200000000; // 8Gb
1591 #endif
1592 Bool ok = VG_IS_PAGE_ALIGNED(addr) && addr >= min && addr <= max;
1594 if (errmsg) {
1595 *errmsg = "";
1596 if (! ok) {
1597 const HChar fmt[] = "Must be a page aligned address between "
1598 "0x%lx and 0x%lx";
1599 static HChar buf[sizeof fmt + 2 * 16]; // large enough
1600 ML_(am_sprintf)(buf, fmt, min, max);
1601 *errmsg = buf;
1604 return ok;
1607 /* See description in pub_core_aspacemgr.h */
1608 Addr VG_(am_startup) ( Addr sp_at_startup )
1610 NSegment seg;
1611 Addr suggested_clstack_end;
1613 aspacem_assert(sizeof(Word) == sizeof(void*));
1614 aspacem_assert(sizeof(Addr) == sizeof(void*));
1615 aspacem_assert(sizeof(SizeT) == sizeof(void*));
1616 aspacem_assert(sizeof(SSizeT) == sizeof(void*));
1618 /* Initialise the string table for segment names. */
1619 ML_(am_segnames_init)();
1621 /* Check that we can store the largest imaginable dev, ino and
1622 offset numbers in an NSegment. */
1623 aspacem_assert(sizeof(seg.dev) == 8);
1624 aspacem_assert(sizeof(seg.ino) == 8);
1625 aspacem_assert(sizeof(seg.offset) == 8);
1626 aspacem_assert(sizeof(seg.mode) == 4);
1628 /* Add a single interval covering the entire address space. */
1629 init_nsegment(&seg);
1630 seg.kind = SkFree;
1631 seg.start = Addr_MIN;
1632 seg.end = Addr_MAX;
1633 nsegments[0] = seg;
1634 nsegments_used = 1;
1636 aspacem_minAddr = VG_(clo_aspacem_minAddr);
1638 // --- Darwin -------------------------------------------
1639 #if defined(VGO_darwin)
1641 # if VG_WORDSIZE == 4
1642 aspacem_maxAddr = (Addr) 0xffffffff;
1644 aspacem_cStart = aspacem_minAddr;
1645 aspacem_vStart = 0xf0000000; // 0xc0000000..0xf0000000 available
1646 # else
1647 aspacem_maxAddr = (Addr) 0x7fffffffffff;
1649 aspacem_cStart = aspacem_minAddr;
1650 aspacem_vStart = 0x700000000000; // 0x7000:00000000..0x7fff:5c000000 avail
1651 // 0x7fff:5c000000..0x7fff:ffe00000? is stack, dyld, shared cache
1652 # endif
1654 suggested_clstack_end = -1; // ignored; Mach-O specifies its stack
1656 // --- Freebsd ------------------------------------------
1657 #elif defined(VGO_freebsd)
1660 VG_(debugLog)(2, "aspacem",
1661 " sp_at_startup = 0x%010lx (supplied)\n",
1662 sp_at_startup );
1664 # if VG_WORDSIZE == 4
1666 aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1;
1667 # else
1668 aspacem_maxAddr = (Addr)0x2000000000ULL - 1; // 128G
1669 # ifdef ENABLE_INNER
1670 { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1;
1671 if (aspacem_maxAddr > cse)
1672 aspacem_maxAddr = cse;
1674 # endif // ENABLE_INNER
1675 # endif
1677 aspacem_cStart = aspacem_minAddr;
1678 aspacem_vStart = VG_PGROUNDUP((aspacem_minAddr + aspacem_maxAddr + 1) / 2);
1680 # ifdef ENABLE_INNER
1681 aspacem_vStart -= 0x10000000UL; // 512M
1682 # endif // ENABLE_INNER
1684 // starting with FreeBSD 10.4, the stack is created with a zone
1685 // that is marked MAP_GUARD. This zone is reserved but unmapped,
1686 // and fills the space up to the end of the segment
1687 // see man mmap
1689 // Version number from
1690 // https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions-10.html
1692 // On x86 this is 0x3FE0000
1693 // And on amd64 it is 0x1FFE0000 (536739840)
1694 // There is less of an issue on amd64 as we just choose some arbitrary address rather then trying
1695 // to squeeze in just below the host stack
1697 // Some of this is in sys/vm/vm_map.c, for instance vm_map_stack and vm_map_stack_locked
1698 // These refer to the kernel global sgrowsiz, which seems to be the initial size
1699 // of the user stack, 128k on my system
1701 // This seems to be in the sysctl kern.sgrowsiz
1702 // Then there is kern.maxssiz which is the total stack size (grow size + guard area)
1703 // In other words guard area = maxssiz - sgrowsiz
1705 #if (__FreeBSD_version >= 1003516)
1707 #if 0
1708 // this block implements what is described above
1709 // this makes no changes to the regression tests
1710 // I'm keeping it for a rainy day.
1711 // note this needs
1712 // #include "pub_core_libcproc.h"
1713 SizeT kern_maxssiz;
1714 SizeT kern_sgrowsiz;
1715 SizeT sysctl_size = sizeof(SizeT);
1716 VG_(sysctlbyname)("kern.maxssiz", &kern_maxssiz, &sysctl_size, NULL, 0);
1717 VG_(sysctlbyname)("kern.sgrowsiz", &kern_sgrowsiz, &sysctl_size, NULL, 0);
1719 suggested_clstack_end = aspacem_maxAddr - (kern_maxssiz - kern_sgrowsiz) + VKI_PAGE_SIZE;
1720 #endif
1722 suggested_clstack_end = aspacem_maxAddr - 64*1024*1024UL
1723 + VKI_PAGE_SIZE;
1725 #else
1726 suggested_clstack_end = aspacem_maxAddr - 16*1024*1024UL
1727 + VKI_PAGE_SIZE;
1729 #endif
1731 // --- Solaris ------------------------------------------
1732 #elif defined(VGO_solaris)
1733 # if VG_WORDSIZE == 4
1735 Intended address space partitioning:
1737 ,--------------------------------, 0x00000000
1739 |--------------------------------|
1740 | initial stack given to V by OS |
1741 |--------------------------------| 0x08000000
1742 | client text |
1743 |--------------------------------|
1746 |--------------------------------|
1747 | client stack |
1748 |--------------------------------| 0x58000000
1749 | V's text |
1750 |--------------------------------|
1753 |--------------------------------|
1754 | dynamic shared objects |
1755 '--------------------------------' 0xffffffff
1759 /* Anonymous pages need to fit under user limit (USERLIMIT32)
1760 which is 4KB + 16MB below the top of the 32-bit range. */
1761 # ifdef ENABLE_INNER
1762 aspacem_maxAddr = (Addr)0x4fffffff; // 1.25GB
1763 aspacem_vStart = (Addr)0x40000000; // 1GB
1764 # else
1765 aspacem_maxAddr = (Addr)0xfefff000 - 1; // 4GB - 16MB - 4KB
1766 aspacem_vStart = (Addr)0x50000000; // 1.25GB
1767 # endif
1768 # elif VG_WORDSIZE == 8
1770 Intended address space partitioning:
1772 ,--------------------------------, 0x00000000_00000000
1774 |--------------------------------| 0x00000000_00400000
1775 | client text |
1776 |--------------------------------|
1779 |--------------------------------|
1780 | client stack |
1781 |--------------------------------| 0x00000000_58000000
1782 | V's text |
1783 |--------------------------------|
1785 |--------------------------------|
1786 | dynamic shared objects |
1787 |--------------------------------| 0x0000001f_ffffffff
1790 |--------------------------------|
1791 | initial stack given to V by OS |
1792 '--------------------------------' 0xffffffff_ffffffff
1796 /* Kernel likes to place objects at the end of the address space.
1797 However accessing memory beyond 128GB makes memcheck slow
1798 (see memcheck/mc_main.c, internal representation). Therefore:
1799 - mmapobj() syscall is emulated so that libraries are subject to
1800 Valgrind's aspacemgr control
1801 - Kernel shared pages (such as schedctl and hrt) are left as they are
1802 because kernel cannot be told where they should be put */
1803 # ifdef ENABLE_INNER
1804 aspacem_maxAddr = (Addr) 0x0000000fffffffff; // 64GB
1805 aspacem_vStart = (Addr) 0x0000000800000000; // 32GB
1806 # else
1807 aspacem_maxAddr = (Addr) 0x0000001fffffffff; // 128GB
1808 aspacem_vStart = (Addr) 0x0000001000000000; // 64GB
1809 # endif
1810 # else
1811 # error "Unknown word size"
1812 # endif
1814 aspacem_cStart = aspacem_minAddr;
1815 # ifdef ENABLE_INNER
1816 suggested_clstack_end = (Addr) 0x37ff0000 - 1; // 64kB below V's text
1817 # else
1818 suggested_clstack_end = (Addr) 0x57ff0000 - 1; // 64kB below V's text
1819 # endif
1821 // --- Linux --------------------------------------------
1822 #else
1824 /* Establish address limits and block out unusable parts
1825 accordingly. */
1827 VG_(debugLog)(2, "aspacem",
1828 " sp_at_startup = 0x%010lx (supplied)\n",
1829 sp_at_startup );
1831 # if VG_WORDSIZE == 8
1832 aspacem_maxAddr = (Addr)0x2000000000ULL - 1; // 128G
1833 # ifdef ENABLE_INNER
1834 { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1;
1835 if (aspacem_maxAddr > cse)
1836 aspacem_maxAddr = cse;
1838 # endif
1839 # else
1840 aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1;
1841 # endif
1843 aspacem_cStart = aspacem_minAddr;
1844 aspacem_vStart = VG_PGROUNDUP(aspacem_minAddr
1845 + (aspacem_maxAddr - aspacem_minAddr + 1) / 2);
1846 # ifdef ENABLE_INNER
1847 aspacem_vStart -= 0x20000000; // 512M
1848 # endif
1850 suggested_clstack_end = aspacem_maxAddr - 16*1024*1024ULL
1851 + VKI_PAGE_SIZE;
1853 #endif /* #else of 'defined(VGO_solaris)' */
1854 // --- (end) --------------------------------------------
1856 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr));
1857 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1));
1858 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_cStart));
1859 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_vStart));
1860 aspacem_assert(VG_IS_PAGE_ALIGNED(suggested_clstack_end + 1));
1862 VG_(debugLog)(2, "aspacem",
1863 " minAddr = 0x%010lx (computed)\n",
1864 aspacem_minAddr);
1865 VG_(debugLog)(2, "aspacem",
1866 " maxAddr = 0x%010lx (computed)\n",
1867 aspacem_maxAddr);
1868 VG_(debugLog)(2, "aspacem",
1869 " cStart = 0x%010lx (computed)\n",
1870 aspacem_cStart);
1871 VG_(debugLog)(2, "aspacem",
1872 " vStart = 0x%010lx (computed)\n",
1873 aspacem_vStart);
1874 VG_(debugLog)(2, "aspacem",
1875 "suggested_clstack_end = 0x%010lx (computed)\n",
1876 suggested_clstack_end);
1878 if (aspacem_cStart > Addr_MIN) {
1879 init_resvn(&seg, Addr_MIN, aspacem_cStart-1);
1880 add_segment(&seg);
1882 if (aspacem_maxAddr < Addr_MAX) {
1883 init_resvn(&seg, aspacem_maxAddr+1, Addr_MAX);
1884 add_segment(&seg);
1887 /* Create a 1-page reservation at the notional initial
1888 client/valgrind boundary. This isn't strictly necessary, but
1889 because the advisor does first-fit and starts searches for
1890 valgrind allocations at the boundary, this is kind of necessary
1891 in order to get it to start allocating in the right place. */
1892 init_resvn(&seg, aspacem_vStart, aspacem_vStart + VKI_PAGE_SIZE - 1);
1893 add_segment(&seg);
1895 VG_(am_show_nsegments)(2, "Initial layout");
1897 VG_(debugLog)(2, "aspacem", "Reading /proc/self/maps\n");
1898 parse_procselfmaps( read_maps_callback, NULL );
1899 /* NB: on arm-linux, parse_procselfmaps automagically kludges up
1900 (iow, hands to its callbacks) a description of the ARM Commpage,
1901 since that's not listed in /proc/self/maps (kernel bug IMO). We
1902 have to fake up its existence in parse_procselfmaps and not
1903 merely add it here as an extra segment, because doing the latter
1904 causes sync checking to fail: we see we have an extra segment in
1905 the segments array, which isn't listed in /proc/self/maps.
1906 Hence we must make it appear that /proc/self/maps contained this
1907 segment all along. Sigh. */
1909 VG_(am_show_nsegments)(2, "With contents of /proc/self/maps");
1911 AM_SANITY_CHECK;
1912 return suggested_clstack_end;
1916 /*-----------------------------------------------------------------*/
1917 /*--- ---*/
1918 /*--- The core query-notify mechanism. ---*/
1919 /*--- ---*/
1920 /*-----------------------------------------------------------------*/
1922 /* Query aspacem to ask where a mapping should go. */
1924 Addr VG_(am_get_advisory) ( const MapRequest* req,
1925 Bool forClient,
1926 /*OUT*/Bool* ok )
1928 /* This function implements allocation policy.
1930 The nature of the allocation request is determined by req, which
1931 specifies the start and length of the request and indicates
1932 whether the start address is mandatory, a hint, or irrelevant,
1933 and by forClient, which says whether this is for the client or
1934 for V.
1936 Return values: the request can be vetoed (*ok is set to False),
1937 in which case the caller should not attempt to proceed with
1938 making the mapping. Otherwise, *ok is set to True, the caller
1939 may proceed, and the preferred address at which the mapping
1940 should happen is returned.
1942 Note that this is an advisory system only: the kernel can in
1943 fact do whatever it likes as far as placement goes, and we have
1944 no absolute control over it.
1946 Allocations will never be granted in a reserved area.
1948 The Default Policy is:
1950 Search the address space for two free intervals: one of them
1951 big enough to contain the request without regard to the
1952 specified address (viz, as if it was a floating request) and
1953 the other being able to contain the request at the specified
1954 address (viz, as if were a fixed request). Then, depending on
1955 the outcome of the search and the kind of request made, decide
1956 whether the request is allowable and what address to advise.
1958 The Default Policy is overridden by Policy Exception #1:
1960 If the request is for a fixed client map, we are prepared to
1961 grant it providing all areas inside the request are either
1962 free, reservations, or mappings belonging to the client. In
1963 other words we are prepared to let the client trash its own
1964 mappings if it wants to.
1966 The Default Policy is overridden by Policy Exception #2:
1968 If the request is for a hinted client map, we are prepared to
1969 grant it providing all areas inside the request are either
1970 free or reservations. In other words we are prepared to let
1971 the client have a hinted mapping anywhere it likes provided
1972 it does not trash either any of its own mappings or any of
1973 valgrind's mappings.
1975 Int i, j;
1976 Addr holeStart, holeEnd, holeLen;
1977 Bool fixed_not_required;
1979 #if defined(VGO_solaris)
1980 Addr startPoint = forClient ? aspacem_vStart - 1 : aspacem_maxAddr - 1;
1981 #else
1982 Addr startPoint = forClient ? aspacem_cStart : aspacem_vStart;
1983 #endif /* VGO_solaris */
1985 Addr reqStart = req->rkind==MFixed || req->rkind==MHint ? req->start : 0;
1986 Addr reqEnd = reqStart + req->len - 1;
1987 Addr reqLen = req->len;
1989 /* These hold indices for segments found during search, or -1 if not
1990 found. */
1991 Int floatIdx = -1;
1992 Int fixedIdx = -1;
1994 aspacem_assert(nsegments_used > 0);
1996 if (0) {
1997 VG_(am_show_nsegments)(0,"getAdvisory");
1998 VG_(debugLog)(0,"aspacem", "getAdvisory 0x%lx %lu\n",
1999 req->start, req->len);
2002 /* Reject zero-length requests */
2003 if (req->len == 0) {
2004 *ok = False;
2005 return 0;
2008 /* Reject wraparounds */
2009 if (req->start + req->len < req->start) {
2010 *ok = False;
2011 return 0;
2014 /* ------ Implement Policy Exception #1 ------ */
2016 if (forClient && req->rkind == MFixed) {
2017 Int iLo = find_nsegment_idx(reqStart);
2018 Int iHi = find_nsegment_idx(reqEnd);
2019 Bool allow = True;
2020 for (i = iLo; i <= iHi; i++) {
2021 if (nsegments[i].kind == SkFree
2022 || nsegments[i].kind == SkFileC
2023 || nsegments[i].kind == SkAnonC
2024 || nsegments[i].kind == SkShmC
2025 || nsegments[i].kind == SkResvn) {
2026 /* ok */
2027 } else {
2028 allow = False;
2029 break;
2032 if (allow) {
2033 /* Acceptable. Granted. */
2034 *ok = True;
2035 return reqStart;
2037 /* Not acceptable. Fail. */
2038 *ok = False;
2039 return 0;
2042 /* ------ Implement Policy Exception #2 ------ */
2044 if (forClient && req->rkind == MHint) {
2045 Int iLo = find_nsegment_idx(reqStart);
2046 Int iHi = find_nsegment_idx(reqEnd);
2047 Bool allow = True;
2048 for (i = iLo; i <= iHi; i++) {
2049 if (nsegments[i].kind == SkFree
2050 || nsegments[i].kind == SkResvn) {
2051 /* ok */
2052 } else {
2053 allow = False;
2054 break;
2057 if (allow) {
2058 /* Acceptable. Granted. */
2059 *ok = True;
2060 return reqStart;
2062 /* Not acceptable. Fall through to the default policy. */
2065 /* ------ Implement the Default Policy ------ */
2067 /* Don't waste time looking for a fixed match if not requested to. */
2068 fixed_not_required = req->rkind == MAny || req->rkind == MAlign;
2070 i = find_nsegment_idx(startPoint);
2072 #if defined(VGO_solaris)
2073 # define UPDATE_INDEX(index) \
2074 (index)--; \
2075 if ((index) <= 0) \
2076 (index) = nsegments_used - 1;
2077 # define ADVISE_ADDRESS(segment) \
2078 VG_PGROUNDDN((segment)->end + 1 - reqLen)
2079 # define ADVISE_ADDRESS_ALIGNED(segment) \
2080 VG_ROUNDDN((segment)->end + 1 - reqLen, req->start)
2082 #else
2084 # define UPDATE_INDEX(index) \
2085 (index)++; \
2086 if ((index) >= nsegments_used) \
2087 (index) = 0;
2088 # define ADVISE_ADDRESS(segment) \
2089 (segment)->start
2090 # define ADVISE_ADDRESS_ALIGNED(segment) \
2091 VG_ROUNDUP((segment)->start, req->start)
2092 #endif /* VGO_solaris */
2094 /* Examine holes from index i back round to i-1. Record the
2095 index first fixed hole and the first floating hole which would
2096 satisfy the request. */
2097 for (j = 0; j < nsegments_used; j++) {
2099 if (nsegments[i].kind != SkFree) {
2100 UPDATE_INDEX(i);
2101 continue;
2104 holeStart = nsegments[i].start;
2105 holeEnd = nsegments[i].end;
2107 /* Stay sane .. */
2108 aspacem_assert(holeStart <= holeEnd);
2109 aspacem_assert(aspacem_minAddr <= holeStart);
2110 aspacem_assert(holeEnd <= aspacem_maxAddr);
2112 if (req->rkind == MAlign) {
2113 holeStart = VG_ROUNDUP(holeStart, req->start);
2114 if (holeStart >= holeEnd) {
2115 /* This hole can't be used. */
2116 UPDATE_INDEX(i);
2117 continue;
2121 /* See if it's any use to us. */
2122 holeLen = holeEnd - holeStart + 1;
2124 if (fixedIdx == -1 && holeStart <= reqStart && reqEnd <= holeEnd)
2125 fixedIdx = i;
2127 if (floatIdx == -1 && holeLen >= reqLen)
2128 floatIdx = i;
2130 /* Don't waste time searching once we've found what we wanted. */
2131 if ((fixed_not_required || fixedIdx >= 0) && floatIdx >= 0)
2132 break;
2134 UPDATE_INDEX(i);
2137 aspacem_assert(fixedIdx >= -1 && fixedIdx < nsegments_used);
2138 if (fixedIdx >= 0)
2139 aspacem_assert(nsegments[fixedIdx].kind == SkFree);
2141 aspacem_assert(floatIdx >= -1 && floatIdx < nsegments_used);
2142 if (floatIdx >= 0)
2143 aspacem_assert(nsegments[floatIdx].kind == SkFree);
2145 AM_SANITY_CHECK;
2147 /* Now see if we found anything which can satisfy the request. */
2148 switch (req->rkind) {
2149 case MFixed:
2150 if (fixedIdx >= 0) {
2151 *ok = True;
2152 return req->start;
2153 } else {
2154 *ok = False;
2155 return 0;
2157 break;
2158 case MHint:
2159 if (fixedIdx >= 0) {
2160 *ok = True;
2161 return req->start;
2163 if (floatIdx >= 0) {
2164 *ok = True;
2165 return ADVISE_ADDRESS(&nsegments[floatIdx]);
2167 *ok = False;
2168 return 0;
2169 case MAny:
2170 if (floatIdx >= 0) {
2171 *ok = True;
2172 return ADVISE_ADDRESS(&nsegments[floatIdx]);
2174 *ok = False;
2175 return 0;
2176 case MAlign:
2177 if (floatIdx >= 0) {
2178 *ok = True;
2179 return ADVISE_ADDRESS_ALIGNED(&nsegments[floatIdx]);
2181 *ok = False;
2182 return 0;
2183 default:
2184 break;
2187 /*NOTREACHED*/
2188 ML_(am_barf)("getAdvisory: unknown request kind");
2189 *ok = False;
2190 return 0;
2192 #undef UPDATE_INDEX
2193 #undef ADVISE_ADDRESS
2194 #undef ADVISE_ADDRESS_ALIGNED
2197 /* Convenience wrapper for VG_(am_get_advisory) for client floating or
2198 fixed requests. If start is zero, a floating request is issued; if
2199 nonzero, a fixed request at that address is issued. Same comments
2200 about return values apply. */
2202 Addr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len,
2203 /*OUT*/Bool* ok )
2205 MapRequest mreq;
2206 mreq.rkind = start==0 ? MAny : MFixed;
2207 mreq.start = start;
2208 mreq.len = len;
2209 return VG_(am_get_advisory)( &mreq, True/*forClient*/, ok );
2212 /* Similar to VG_(am_find_nsegment) but only returns free segments. */
2213 static NSegment const * VG_(am_find_free_nsegment) ( Addr a )
2215 Int i = find_nsegment_idx(a);
2216 aspacem_assert(i >= 0 && i < nsegments_used);
2217 aspacem_assert(nsegments[i].start <= a);
2218 aspacem_assert(a <= nsegments[i].end);
2219 if (nsegments[i].kind == SkFree)
2220 return &nsegments[i];
2221 else
2222 return NULL;
2225 Bool VG_(am_covered_by_single_free_segment)
2226 ( Addr start, SizeT len)
2228 NSegment const* segLo = VG_(am_find_free_nsegment)( start );
2229 NSegment const* segHi = VG_(am_find_free_nsegment)( start + len - 1 );
2231 return segLo != NULL && segHi != NULL && segLo == segHi;
2235 /* Notifies aspacem that the client completed an mmap successfully.
2236 The segment array is updated accordingly. If the returned Bool is
2237 True, the caller should immediately discard translations from the
2238 specified address range. */
2240 Bool
2241 VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
2242 Int fd, Off64T offset )
2244 HChar buf[VKI_PATH_MAX];
2245 ULong dev, ino;
2246 UInt mode;
2247 NSegment seg;
2248 Bool needDiscard;
2250 aspacem_assert(len > 0);
2251 aspacem_assert(VG_IS_PAGE_ALIGNED(a));
2252 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2253 aspacem_assert(VG_IS_PAGE_ALIGNED(offset));
2255 /* Discard is needed if any of the just-trashed range had T. */
2256 needDiscard = any_Ts_in_range( a, len );
2258 init_nsegment( &seg );
2259 seg.kind = (flags & (VKI_MAP_ANONYMOUS | VKI_MAP_STACK)) ? SkAnonC : SkFileC;
2260 seg.start = a;
2261 seg.end = a + len - 1;
2262 seg.hasR = toBool(prot & VKI_PROT_READ);
2263 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2264 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2265 if (!(flags & (VKI_MAP_ANONYMOUS | VKI_MAP_STACK))) {
2266 // Nb: We ignore offset requests in anonymous mmaps (see bug #126722)
2267 seg.offset = offset;
2268 if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
2269 seg.dev = dev;
2270 seg.ino = ino;
2271 seg.mode = mode;
2273 if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
2274 seg.fnIdx = ML_(am_allocate_segname)( buf );
2276 #if defined(VGO_freebsd)
2277 seg.isFF = (flags & VKI_MAP_FIXED);
2278 #endif
2280 add_segment( &seg );
2281 AM_SANITY_CHECK;
2282 return needDiscard;
2285 /* Notifies aspacem that the client completed a shmat successfully.
2286 The segment array is updated accordingly. If the returned Bool is
2287 True, the caller should immediately discard translations from the
2288 specified address range. */
2290 Bool
2291 VG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot )
2293 NSegment seg;
2294 Bool needDiscard;
2296 aspacem_assert(len > 0);
2297 aspacem_assert(VG_IS_PAGE_ALIGNED(a));
2298 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2300 /* Discard is needed if any of the just-trashed range had T. */
2301 needDiscard = any_Ts_in_range( a, len );
2303 init_nsegment( &seg );
2304 seg.kind = SkShmC;
2305 seg.start = a;
2306 seg.end = a + len - 1;
2307 seg.offset = 0;
2308 seg.hasR = toBool(prot & VKI_PROT_READ);
2309 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2310 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2311 add_segment( &seg );
2312 AM_SANITY_CHECK;
2313 return needDiscard;
2316 /* Notifies aspacem that an mprotect was completed successfully. The
2317 segment array is updated accordingly. Note, as with
2318 VG_(am_notify_munmap), it is not the job of this function to reject
2319 stupid mprotects, for example the client doing mprotect of
2320 non-client areas. Such requests should be intercepted earlier, by
2321 the syscall wrapper for mprotect. This function merely records
2322 whatever it is told. If the returned Bool is True, the caller
2323 should immediately discard translations from the specified address
2324 range. */
2326 Bool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot )
2328 Int i, iLo, iHi;
2329 Bool newR, newW, newX, needDiscard;
2331 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2332 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2334 if (len == 0)
2335 return False;
2337 newR = toBool(prot & VKI_PROT_READ);
2338 newW = toBool(prot & VKI_PROT_WRITE);
2339 newX = toBool(prot & VKI_PROT_EXEC);
2341 /* Discard is needed if we're dumping X permission */
2342 needDiscard = any_Ts_in_range( start, len ) && !newX;
2344 split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
2346 iLo = find_nsegment_idx(start);
2347 iHi = find_nsegment_idx(start + len - 1);
2349 for (i = iLo; i <= iHi; i++) {
2350 /* Apply the permissions to all relevant segments. */
2351 switch (nsegments[i].kind) {
2352 case SkAnonC: case SkAnonV: case SkFileC: case SkFileV: case SkShmC:
2353 nsegments[i].hasR = newR;
2354 nsegments[i].hasW = newW;
2355 nsegments[i].hasX = newX;
2356 aspacem_assert(sane_NSegment(&nsegments[i]));
2357 break;
2358 default:
2359 break;
2363 /* Changing permissions could have made previously un-mergable
2364 segments mergeable. Therefore have to re-preen them. */
2365 (void)preen_nsegments();
2366 AM_SANITY_CHECK;
2367 return needDiscard;
2371 /* Notifies aspacem that an munmap completed successfully. The
2372 segment array is updated accordingly. As with
2373 VG_(am_notify_mprotect), we merely record the given info, and don't
2374 check it for sensibleness. If the returned Bool is True, the
2375 caller should immediately discard translations from the specified
2376 address range. */
2378 Bool VG_(am_notify_munmap)( Addr start, SizeT len )
2380 NSegment seg;
2381 Bool needDiscard;
2382 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2383 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2385 if (len == 0)
2386 return False;
2388 needDiscard = any_Ts_in_range( start, len );
2390 init_nsegment( &seg );
2391 seg.start = start;
2392 seg.end = start + len - 1;
2394 /* The segment becomes unused (free). Segments from above
2395 aspacem_maxAddr were originally SkResvn and so we make them so
2396 again. Note, this isn't really right when the segment straddles
2397 the aspacem_maxAddr boundary - then really it should be split in
2398 two, the lower part marked as SkFree and the upper part as
2399 SkResvn. Ah well. */
2400 if (start > aspacem_maxAddr
2401 && /* check previous comparison is meaningful */
2402 aspacem_maxAddr < Addr_MAX)
2403 seg.kind = SkResvn;
2404 else
2405 /* Ditto for segments from below aspacem_minAddr. */
2406 if (seg.end < aspacem_minAddr && aspacem_minAddr > 0)
2407 seg.kind = SkResvn;
2408 else
2409 seg.kind = SkFree;
2411 add_segment( &seg );
2413 /* Unmapping could create two adjacent free segments, so a preen is
2414 needed. add_segment() will do that, so no need to here. */
2415 AM_SANITY_CHECK;
2416 return needDiscard;
2420 /*-----------------------------------------------------------------*/
2421 /*--- ---*/
2422 /*--- Handling mappings which do not arise directly from the ---*/
2423 /*--- simulation of the client. ---*/
2424 /*--- ---*/
2425 /*-----------------------------------------------------------------*/
2427 /* --- --- --- map, unmap, protect --- --- --- */
2429 /* Map a file at a fixed address for the client, and update the
2430 segment array accordingly. */
2432 SysRes VG_(am_mmap_file_fixed_client)
2433 ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset )
2435 UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
2436 return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
2437 fd, offset, NULL);
2440 SysRes VG_(am_mmap_file_fixed_client_flags)
2441 ( Addr start, SizeT length, UInt prot, UInt flags, Int fd, Off64T offset )
2443 return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
2444 fd, offset, NULL);
2447 SysRes VG_(am_mmap_named_file_fixed_client)
2448 ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name )
2450 UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
2451 return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
2452 fd, offset, name);
2455 SysRes VG_(am_mmap_named_file_fixed_client_flags)
2456 ( Addr start, SizeT length, UInt prot, UInt flags,
2457 Int fd, Off64T offset, const HChar *name )
2459 SysRes sres;
2460 NSegment seg;
2461 Addr advised;
2462 Bool ok;
2463 MapRequest req;
2464 ULong dev, ino;
2465 UInt mode;
2466 HChar buf[VKI_PATH_MAX];
2468 /* Not allowable. */
2469 if (length == 0
2470 || !VG_IS_PAGE_ALIGNED(start)
2471 || !VG_IS_PAGE_ALIGNED(offset))
2472 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2474 /* Ask for an advisory. If it's negative, fail immediately. */
2475 req.rkind = MFixed;
2476 req.start = start;
2477 req.len = length;
2478 advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
2479 if (!ok || advised != start)
2480 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2482 /* We have been advised that the mapping is allowable at the
2483 specified address. So hand it off to the kernel, and propagate
2484 any resulting failure immediately. */
2485 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
2486 sres = VG_(am_do_mmap_NO_NOTIFY)(
2487 start, length, prot, flags,
2488 fd, offset
2490 if (sr_isError(sres))
2491 return sres;
2493 if (sr_Res(sres) != start) {
2494 /* I don't think this can happen. It means the kernel made a
2495 fixed map succeed but not at the requested location. Try to
2496 repair the damage, then return saying the mapping failed. */
2497 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2498 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2501 /* Ok, the mapping succeeded. Now notify the interval map. */
2502 init_nsegment( &seg );
2503 seg.kind = SkFileC;
2504 seg.start = start;
2505 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2506 seg.offset = offset;
2507 seg.hasR = toBool(prot & VKI_PROT_READ);
2508 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2509 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2510 if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
2511 seg.dev = dev;
2512 seg.ino = ino;
2513 seg.mode = mode;
2515 if (name) {
2516 seg.fnIdx = ML_(am_allocate_segname)( name );
2517 } else if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
2518 seg.fnIdx = ML_(am_allocate_segname)( buf );
2520 #if defined(VGO_freebsd)
2521 seg.isFF = (flags & VKI_MAP_FIXED);
2522 #endif
2523 add_segment( &seg );
2525 AM_SANITY_CHECK;
2526 return sres;
2530 /* Map anonymously at a fixed address for the client, and update
2531 the segment array accordingly. */
2533 SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
2535 SysRes sres;
2536 NSegment seg;
2537 Addr advised;
2538 Bool ok;
2539 MapRequest req;
2541 /* Not allowable. */
2542 if (length == 0 || !VG_IS_PAGE_ALIGNED(start))
2543 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2545 /* Ask for an advisory. If it's negative, fail immediately. */
2546 req.rkind = MFixed;
2547 req.start = start;
2548 req.len = length;
2549 advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
2550 if (!ok || advised != start)
2551 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2553 /* We have been advised that the mapping is allowable at the
2554 specified address. So hand it off to the kernel, and propagate
2555 any resulting failure immediately. */
2556 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
2557 sres = VG_(am_do_mmap_NO_NOTIFY)(
2558 start, length, prot,
2559 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2560 0, 0
2562 if (sr_isError(sres))
2563 return sres;
2565 if (sr_Res(sres) != start) {
2566 /* I don't think this can happen. It means the kernel made a
2567 fixed map succeed but not at the requested location. Try to
2568 repair the damage, then return saying the mapping failed. */
2569 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2570 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2573 /* Ok, the mapping succeeded. Now notify the interval map. */
2574 init_nsegment( &seg );
2575 seg.kind = SkAnonC;
2576 seg.start = start;
2577 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2578 seg.hasR = toBool(prot & VKI_PROT_READ);
2579 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2580 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2581 add_segment( &seg );
2583 AM_SANITY_CHECK;
2584 return sres;
2588 /* Map anonymously at an unconstrained address for the client, and
2589 update the segment array accordingly. */
2591 static SysRes am_mmap_anon_float_client ( SizeT length, Int prot, Bool isCH )
2593 SysRes sres;
2594 NSegment seg;
2595 Addr advised;
2596 Bool ok;
2597 MapRequest req;
2599 /* Not allowable. */
2600 if (length == 0)
2601 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2603 /* Ask for an advisory. If it's negative, fail immediately. */
2604 req.rkind = MAny;
2605 req.start = 0;
2606 req.len = length;
2607 advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
2608 if (!ok)
2609 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2611 /* We have been advised that the mapping is allowable at the
2612 advised address. So hand it off to the kernel, and propagate
2613 any resulting failure immediately. */
2614 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
2615 sres = VG_(am_do_mmap_NO_NOTIFY)(
2616 advised, length, prot,
2617 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2618 0, 0
2620 if (sr_isError(sres))
2621 return sres;
2623 if (sr_Res(sres) != advised) {
2624 /* I don't think this can happen. It means the kernel made a
2625 fixed map succeed but not at the requested location. Try to
2626 repair the damage, then return saying the mapping failed. */
2627 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2628 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2631 /* Ok, the mapping succeeded. Now notify the interval map. */
2632 init_nsegment( &seg );
2633 seg.kind = SkAnonC;
2634 seg.start = advised;
2635 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2636 seg.hasR = toBool(prot & VKI_PROT_READ);
2637 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2638 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2639 seg.isCH = isCH;
2640 add_segment( &seg );
2642 AM_SANITY_CHECK;
2643 return sres;
2646 SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
2648 return am_mmap_anon_float_client (length, prot, False /* isCH */);
2651 /* Map anonymously at an unconstrained address for V, and update the
2652 segment array accordingly. This is fundamentally how V allocates
2653 itself more address space when needed. */
2655 SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
2657 SysRes sres;
2658 NSegment seg;
2659 Addr advised;
2660 Bool ok;
2661 MapRequest req;
2663 /* Not allowable. */
2664 if (length == 0)
2665 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2667 /* Ask for an advisory. If it's negative, fail immediately. */
2668 req.rkind = MAny;
2669 req.start = 0;
2670 req.len = length;
2671 advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
2672 if (!ok)
2673 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2675 // On Darwin, for anonymous maps you can pass in a tag which is used by
2676 // programs like vmmap for statistical purposes.
2677 #ifndef VM_TAG_VALGRIND
2678 # define VM_TAG_VALGRIND 0
2679 #endif
2681 /* We have been advised that the mapping is allowable at the
2682 specified address. So hand it off to the kernel, and propagate
2683 any resulting failure immediately. */
2684 /* GrP fixme darwin: use advisory as a hint only, otherwise syscall in
2685 another thread can pre-empt our spot. [At one point on the DARWIN
2686 branch the VKI_MAP_FIXED was commented out; unclear if this is
2687 necessary or not given the second Darwin-only call that immediately
2688 follows if this one fails. --njn]
2689 Also, an inner valgrind cannot observe the mmap syscalls done by
2690 the outer valgrind. The outer Valgrind might make the mmap
2691 fail here, as the inner valgrind believes that a segment is free,
2692 while it is in fact used by the outer valgrind.
2693 So, for an inner valgrind, similarly to DARWIN, if the fixed mmap
2694 fails, retry the mmap without map fixed.
2695 This is a kludge which on linux is only activated for the inner.
2696 The state of the inner aspacemgr is not made correct by this kludge
2697 and so a.o. VG_(am_do_sync_check) could fail.
2698 A proper solution implies a better collaboration between the
2699 inner and the outer (e.g. inner VG_(am_get_advisory) should do
2700 a client request to call the outer VG_(am_get_advisory). */
2701 sres = VG_(am_do_mmap_NO_NOTIFY)(
2702 advised, length,
2703 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
2704 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2705 VM_TAG_VALGRIND, 0
2707 #if defined(VGO_darwin) || defined(ENABLE_INNER)
2708 /* Kludge on Darwin and inner linux if the fixed mmap failed. */
2709 if (sr_isError(sres)) {
2710 /* try again, ignoring the advisory */
2711 sres = VG_(am_do_mmap_NO_NOTIFY)(
2712 0, length,
2713 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
2714 /*VKI_MAP_FIXED|*/VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2715 VM_TAG_VALGRIND, 0
2718 #endif
2719 if (sr_isError(sres))
2720 return sres;
2722 #if defined(VGO_linux) && !defined(ENABLE_INNER)
2723 /* Doing the check only in linux not inner, as the below
2724 check can fail when the kludge above has been used. */
2725 if (sr_Res(sres) != advised) {
2726 /* I don't think this can happen. It means the kernel made a
2727 fixed map succeed but not at the requested location. Try to
2728 repair the damage, then return saying the mapping failed. */
2729 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2730 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2732 #endif
2734 /* Ok, the mapping succeeded. Now notify the interval map. */
2735 init_nsegment( &seg );
2736 seg.kind = SkAnonV;
2737 seg.start = sr_Res(sres);
2738 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2739 seg.hasR = True;
2740 seg.hasW = True;
2741 seg.hasX = True;
2742 add_segment( &seg );
2744 AM_SANITY_CHECK;
2745 return sres;
2748 /* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
2750 SysRes VG_(am_shadow_alloc)(SizeT size)
2752 return VG_(am_mmap_anon_float_valgrind)( size );
2755 /* Map a file at an unconstrained address for V, and update the
2756 segment array accordingly. Use the provided flags */
2758 static SysRes VG_(am_mmap_file_float_valgrind_flags) ( SizeT length, UInt prot,
2759 UInt flags,
2760 Int fd, Off64T offset )
2762 SysRes sres;
2763 NSegment seg;
2764 Addr advised;
2765 Bool ok;
2766 MapRequest req;
2767 ULong dev, ino;
2768 UInt mode;
2769 HChar buf[VKI_PATH_MAX];
2771 /* Not allowable. */
2772 if (length == 0 || !VG_IS_PAGE_ALIGNED(offset))
2773 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2775 /* Ask for an advisory. If it's negative, fail immediately. */
2776 req.rkind = MAny;
2777 req.start = 0;
2778 #if defined(VGA_arm) || defined(VGA_arm64) \
2779 || defined(VGA_mips32) || defined(VGA_mips64) || defined(VGA_nanomips)
2780 aspacem_assert(VKI_SHMLBA >= VKI_PAGE_SIZE);
2781 #else
2782 aspacem_assert(VKI_SHMLBA == VKI_PAGE_SIZE);
2783 #endif
2784 if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags)) {
2785 /* arm-linux only. See ML_(generic_PRE_sys_shmat) and bug 290974 */
2786 req.len = length + VKI_SHMLBA - VKI_PAGE_SIZE;
2787 } else {
2788 req.len = length;
2790 advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
2791 if (!ok)
2792 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2793 if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags))
2794 advised = VG_ROUNDUP(advised, VKI_SHMLBA);
2796 /* We have been advised that the mapping is allowable at the
2797 specified address. So hand it off to the kernel, and propagate
2798 any resulting failure immediately. */
2799 sres = VG_(am_do_mmap_NO_NOTIFY)(
2800 advised, length, prot,
2801 flags,
2802 fd, offset
2804 if (sr_isError(sres))
2805 return sres;
2807 if (sr_Res(sres) != advised) {
2808 /* I don't think this can happen. It means the kernel made a
2809 fixed map succeed but not at the requested location. Try to
2810 repair the damage, then return saying the mapping failed. */
2811 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2812 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2815 /* Ok, the mapping succeeded. Now notify the interval map. */
2816 init_nsegment( &seg );
2817 seg.kind = SkFileV;
2818 seg.start = sr_Res(sres);
2819 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2820 seg.offset = offset;
2821 seg.hasR = toBool(prot & VKI_PROT_READ);
2822 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2823 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2824 if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
2825 seg.dev = dev;
2826 seg.ino = ino;
2827 seg.mode = mode;
2829 if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
2830 seg.fnIdx = ML_(am_allocate_segname)( buf );
2832 #if defined(VGO_freebsd)
2833 seg.isFF = (flags & VKI_MAP_FIXED);
2834 #endif
2835 add_segment( &seg );
2837 AM_SANITY_CHECK;
2838 return sres;
2840 /* Map privately a file at an unconstrained address for V, and update the
2841 segment array accordingly. This is used by V for transiently
2842 mapping in object files to read their debug info. */
2844 SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot,
2845 Int fd, Off64T offset )
2847 return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
2848 VKI_MAP_FIXED|VKI_MAP_PRIVATE,
2849 fd, offset );
2852 SysRes VG_(am_shared_mmap_file_float_valgrind)
2853 ( SizeT length, UInt prot, Int fd, Off64T offset )
2855 return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
2856 VKI_MAP_FIXED|VKI_MAP_SHARED,
2857 fd, offset );
2860 /* Similar to VG_(am_mmap_anon_float_client) but also
2861 marks the segment as containing the client heap. This is for the benefit
2862 of the leak checker which needs to be able to identify such segments
2863 so as not to use them as sources of roots during leak checks. */
2864 SysRes VG_(am_mmap_client_heap) ( SizeT length, Int prot )
2866 return am_mmap_anon_float_client (length, prot, True /* isCH */);
2869 /* --- --- munmap helper --- --- */
2871 static
2872 SysRes am_munmap_both_wrk ( /*OUT*/Bool* need_discard,
2873 Addr start, SizeT len, Bool forClient )
2875 Bool d;
2876 SysRes sres;
2878 /* Be safe with this regardless of return path. */
2879 *need_discard = False;
2881 if (!VG_IS_PAGE_ALIGNED(start))
2882 goto eINVAL;
2884 if (len == 0) {
2885 *need_discard = False;
2886 return VG_(mk_SysRes_Success)( 0 );
2889 if (start + len < len)
2890 goto eINVAL;
2892 len = VG_PGROUNDUP(len);
2893 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2894 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2896 if (forClient) {
2897 if (!VG_(am_is_valid_for_client_or_free_or_resvn)
2898 ( start, len, VKI_PROT_NONE ))
2899 goto eINVAL;
2900 } else {
2901 if (!VG_(am_is_valid_for_valgrind)
2902 ( start, len, VKI_PROT_NONE ))
2903 goto eINVAL;
2906 d = any_Ts_in_range( start, len );
2908 sres = ML_(am_do_munmap_NO_NOTIFY)( start, len );
2909 if (sr_isError(sres))
2910 return sres;
2912 VG_(am_notify_munmap)( start, len );
2913 AM_SANITY_CHECK;
2914 *need_discard = d;
2915 return sres;
2917 eINVAL:
2918 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2921 /* Unmap the given address range and update the segment array
2922 accordingly. This fails if the range isn't valid for the client.
2923 If *need_discard is True after a successful return, the caller
2924 should immediately discard translations from the specified address
2925 range. */
2927 SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
2928 Addr start, SizeT len )
2930 return am_munmap_both_wrk( need_discard, start, len, True/*client*/ );
2933 /* Unmap the given address range and update the segment array
2934 accordingly. This fails if the range isn't valid for valgrind. */
2936 SysRes VG_(am_munmap_valgrind)( Addr start, SizeT len )
2938 Bool need_discard;
2939 SysRes r = am_munmap_both_wrk( &need_discard,
2940 start, len, False/*valgrind*/ );
2941 /* If this assertion fails, it means we allowed translations to be
2942 made from a V-owned section. Which shouldn't happen. */
2943 if (!sr_isError(r))
2944 aspacem_assert(!need_discard);
2945 return r;
2948 /* Let (start,len) denote an area within a single Valgrind-owned
2949 segment (anon or file). Change the ownership of [start, start+len)
2950 to the client instead. Fails if (start,len) does not denote a
2951 suitable segment. */
2953 Bool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len )
2955 Int i, iLo, iHi;
2957 if (len == 0)
2958 return True;
2959 if (start + len < start)
2960 return False;
2961 if (!VG_IS_PAGE_ALIGNED(start) || !VG_IS_PAGE_ALIGNED(len))
2962 return False;
2964 i = find_nsegment_idx(start);
2965 if (nsegments[i].kind != SkFileV && nsegments[i].kind != SkAnonV)
2966 return False;
2967 if (start+len-1 > nsegments[i].end)
2968 return False;
2970 aspacem_assert(start >= nsegments[i].start);
2971 aspacem_assert(start+len-1 <= nsegments[i].end);
2973 /* This scheme is like how mprotect works: split the to-be-changed
2974 range into its own segment(s), then mess with them (it). There
2975 should be only one. */
2976 split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
2977 aspacem_assert(iLo == iHi);
2978 switch (nsegments[iLo].kind) {
2979 case SkFileV: nsegments[iLo].kind = SkFileC; break;
2980 case SkAnonV: nsegments[iLo].kind = SkAnonC; break;
2981 default: aspacem_assert(0); /* can't happen - guarded above */
2984 preen_nsegments();
2985 return True;
2988 /* Set the 'hasT' bit on the segment containing ADDR indicating that
2989 translations have or may have been taken from this segment. ADDR is
2990 expected to belong to a client segment. */
2991 void VG_(am_set_segment_hasT)( Addr addr )
2993 Int i = find_nsegment_idx(addr);
2994 SegKind kind = nsegments[i].kind;
2995 aspacem_assert(kind == SkAnonC || kind == SkFileC || kind == SkShmC);
2996 nsegments[i].hasT = True;
3000 /* --- --- --- reservations --- --- --- */
3002 /* Create a reservation from START .. START+LENGTH-1, with the given
3003 ShrinkMode. When checking whether the reservation can be created,
3004 also ensure that at least abs(EXTRA) extra free bytes will remain
3005 above (> 0) or below (< 0) the reservation.
3007 The reservation will only be created if it, plus the extra-zone,
3008 falls entirely within a single free segment. The returned Bool
3009 indicates whether the creation succeeded. */
3011 Bool VG_(am_create_reservation) ( Addr start, SizeT length,
3012 ShrinkMode smode, SSizeT extra )
3014 Int startI, endI;
3015 NSegment seg;
3017 /* start and end, not taking into account the extra space. */
3018 Addr start1 = start;
3019 Addr end1 = start + length - 1;
3021 /* start and end, taking into account the extra space. */
3022 Addr start2 = start1;
3023 Addr end2 = end1;
3025 if (extra < 0) start2 += extra; // this moves it down :-)
3026 if (extra > 0) end2 += extra;
3028 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
3029 aspacem_assert(VG_IS_PAGE_ALIGNED(start+length));
3030 aspacem_assert(VG_IS_PAGE_ALIGNED(start2));
3031 aspacem_assert(VG_IS_PAGE_ALIGNED(end2+1));
3033 startI = find_nsegment_idx( start2 );
3034 endI = find_nsegment_idx( end2 );
3036 /* If the start and end points don't fall within the same (free)
3037 segment, we're hosed. This does rely on the assumption that all
3038 mergeable adjacent segments can be merged, but add_segment()
3039 should ensure that. */
3040 if (startI != endI)
3041 return False;
3043 if (nsegments[startI].kind != SkFree)
3044 return False;
3046 /* Looks good - make the reservation. */
3047 aspacem_assert(nsegments[startI].start <= start2);
3048 aspacem_assert(end2 <= nsegments[startI].end);
3050 init_nsegment( &seg );
3051 seg.kind = SkResvn;
3052 seg.start = start1; /* NB: extra space is not included in the
3053 reservation. */
3054 seg.end = end1;
3055 seg.smode = smode;
3056 add_segment( &seg );
3058 AM_SANITY_CHECK;
3059 return True;
3063 /* ADDR is the start address of an anonymous client mapping. This fn extends
3064 the mapping by DELTA bytes, taking the space from a reservation section
3065 which must be adjacent. If DELTA is positive, the segment is
3066 extended forwards in the address space, and the reservation must be
3067 the next one along. If DELTA is negative, the segment is extended
3068 backwards in the address space and the reservation must be the
3069 previous one. DELTA must be page aligned. abs(DELTA) must not
3070 exceed the size of the reservation segment minus one page, that is,
3071 the reservation segment after the operation must be at least one
3072 page long. The function returns a pointer to the resized segment. */
3074 const NSegment *VG_(am_extend_into_adjacent_reservation_client)( Addr addr,
3075 SSizeT delta,
3076 Bool *overflow)
3078 Int segA, segR;
3079 UInt prot;
3080 SysRes sres;
3082 *overflow = False;
3084 segA = find_nsegment_idx(addr);
3085 aspacem_assert(nsegments[segA].kind == SkAnonC);
3087 if (delta == 0)
3088 return nsegments + segA;
3090 prot = (nsegments[segA].hasR ? VKI_PROT_READ : 0)
3091 | (nsegments[segA].hasW ? VKI_PROT_WRITE : 0)
3092 | (nsegments[segA].hasX ? VKI_PROT_EXEC : 0);
3094 aspacem_assert(VG_IS_PAGE_ALIGNED(delta<0 ? -delta : delta));
3096 if (delta > 0) {
3098 /* Extending the segment forwards. */
3099 segR = segA+1;
3100 if (segR >= nsegments_used
3101 || nsegments[segR].kind != SkResvn
3102 || nsegments[segR].smode != SmLower)
3103 return NULL;
3105 if (delta + VKI_PAGE_SIZE
3106 > (nsegments[segR].end - nsegments[segR].start + 1)) {
3107 *overflow = True;
3108 return NULL;
3111 /* Extend the kernel's mapping. */
3112 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
3113 sres = VG_(am_do_mmap_NO_NOTIFY)(
3114 nsegments[segR].start, delta,
3115 prot,
3116 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
3117 0, 0
3119 if (sr_isError(sres))
3120 return NULL; /* kernel bug if this happens? */
3121 if (sr_Res(sres) != nsegments[segR].start) {
3122 /* kernel bug if this happens? */
3123 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
3124 return NULL;
3127 /* Ok, success with the kernel. Update our structures. */
3128 nsegments[segR].start += delta;
3129 nsegments[segA].end += delta;
3130 aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
3132 } else {
3134 /* Extending the segment backwards. */
3135 delta = -delta;
3136 aspacem_assert(delta > 0);
3138 segR = segA-1;
3139 if (segR < 0
3140 || nsegments[segR].kind != SkResvn
3141 || nsegments[segR].smode != SmUpper)
3142 return NULL;
3144 if (delta + VKI_PAGE_SIZE
3145 > (nsegments[segR].end - nsegments[segR].start + 1)) {
3146 *overflow = True;
3147 return NULL;
3150 /* Extend the kernel's mapping. */
3151 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
3152 sres = VG_(am_do_mmap_NO_NOTIFY)(
3153 nsegments[segA].start-delta, delta,
3154 prot,
3155 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
3156 0, 0
3158 if (sr_isError(sres))
3159 return NULL; /* kernel bug if this happens? */
3160 if (sr_Res(sres) != nsegments[segA].start-delta) {
3161 /* kernel bug if this happens? */
3162 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
3163 return NULL;
3166 /* Ok, success with the kernel. Update our structures. */
3167 nsegments[segR].end -= delta;
3168 nsegments[segA].start -= delta;
3169 aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
3172 AM_SANITY_CHECK;
3173 return nsegments + segA;
3177 /* --- --- --- resizing/move a mapping --- --- --- */
3179 #if HAVE_MREMAP
3181 /* This function grows a client mapping in place into an adjacent free segment.
3182 ADDR is the client mapping's start address and DELTA, which must be page
3183 aligned, is the growth amount. The function returns a pointer to the
3184 resized segment. The function is used in support of mremap. */
3185 const NSegment *VG_(am_extend_map_client)( Addr addr, SizeT delta )
3187 Addr xStart;
3188 SysRes sres;
3190 if (0)
3191 VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) BEFORE");
3193 /* Get the client segment */
3194 Int ix = find_nsegment_idx(addr);
3195 aspacem_assert(ix >= 0 && ix < nsegments_used);
3197 NSegment *seg = nsegments + ix;
3199 aspacem_assert(seg->kind == SkFileC || seg->kind == SkAnonC ||
3200 seg->kind == SkShmC);
3201 aspacem_assert(delta > 0 && VG_IS_PAGE_ALIGNED(delta)) ;
3203 xStart = seg->end+1;
3204 aspacem_assert(xStart + delta >= delta); // no wrap-around
3206 /* The segment following the client segment must be a free segment and
3207 it must be large enough to cover the additional memory. */
3208 NSegment *segf = seg + 1;
3209 aspacem_assert(segf->kind == SkFree);
3210 aspacem_assert(segf->start == xStart);
3211 aspacem_assert(xStart + delta - 1 <= segf->end);
3213 SizeT seg_old_len = seg->end + 1 - seg->start;
3215 AM_SANITY_CHECK;
3216 sres = ML_(am_do_extend_mapping_NO_NOTIFY)( seg->start,
3217 seg_old_len,
3218 seg_old_len + delta );
3219 if (sr_isError(sres)) {
3220 AM_SANITY_CHECK;
3221 return NULL;
3222 } else {
3223 /* the area must not have moved */
3224 aspacem_assert(sr_Res(sres) == seg->start);
3227 NSegment seg_copy = *seg;
3228 seg_copy.end += delta;
3229 add_segment( &seg_copy );
3231 if (0)
3232 VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) AFTER");
3234 AM_SANITY_CHECK;
3235 return nsegments + find_nsegment_idx(addr);
3239 /* Remap the old address range to the new address range. Fails if any
3240 parameter is not page aligned, if the either size is zero, if any
3241 wraparound is implied, if the old address range does not fall
3242 entirely within a single segment, if the new address range overlaps
3243 with the old one, or if the old address range is not a valid client
3244 mapping. If *need_discard is True after a successful return, the
3245 caller should immediately discard translations from both specified
3246 address ranges. */
3248 Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
3249 Addr old_addr, SizeT old_len,
3250 Addr new_addr, SizeT new_len )
3252 Int iLo, iHi;
3253 SysRes sres;
3254 NSegment seg;
3256 if (old_len == 0 || new_len == 0)
3257 return False;
3259 if (!VG_IS_PAGE_ALIGNED(old_addr) || !VG_IS_PAGE_ALIGNED(old_len)
3260 || !VG_IS_PAGE_ALIGNED(new_addr) || !VG_IS_PAGE_ALIGNED(new_len))
3261 return False;
3263 if (old_addr + old_len < old_addr
3264 || new_addr + new_len < new_addr)
3265 return False;
3267 if (old_addr + old_len - 1 < new_addr
3268 || new_addr + new_len - 1 < old_addr) {
3269 /* no overlap */
3270 } else
3271 return False;
3273 iLo = find_nsegment_idx( old_addr );
3274 iHi = find_nsegment_idx( old_addr + old_len - 1 );
3275 if (iLo != iHi)
3276 return False;
3278 if (nsegments[iLo].kind != SkFileC && nsegments[iLo].kind != SkAnonC &&
3279 nsegments[iLo].kind != SkShmC)
3280 return False;
3282 sres = ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)
3283 ( old_addr, old_len, new_addr, new_len );
3284 if (sr_isError(sres)) {
3285 AM_SANITY_CHECK;
3286 return False;
3287 } else {
3288 aspacem_assert(sr_Res(sres) == new_addr);
3291 *need_discard = any_Ts_in_range( old_addr, old_len )
3292 || any_Ts_in_range( new_addr, new_len );
3294 seg = nsegments[iLo];
3296 /* Mark the new area based on the old seg. */
3297 if (seg.kind == SkFileC) {
3298 seg.offset += ((ULong)old_addr) - ((ULong)seg.start);
3300 seg.start = new_addr;
3301 seg.end = new_addr + new_len - 1;
3302 add_segment( &seg );
3304 /* Create a free hole in the old location. */
3305 init_nsegment( &seg );
3306 seg.start = old_addr;
3307 seg.end = old_addr + old_len - 1;
3308 /* See comments in VG_(am_notify_munmap) about this SkResvn vs
3309 SkFree thing. */
3310 if (old_addr > aspacem_maxAddr
3311 && /* check previous comparison is meaningful */
3312 aspacem_maxAddr < Addr_MAX)
3313 seg.kind = SkResvn;
3314 else
3315 seg.kind = SkFree;
3317 add_segment( &seg );
3319 AM_SANITY_CHECK;
3320 return True;
3323 #endif // HAVE_MREMAP
3326 #if defined(VGO_linux)
3328 /*-----------------------------------------------------------------*/
3329 /*--- ---*/
3330 /*--- A simple parser for /proc/self/maps on Linux 2.4.X/2.6.X. ---*/
3331 /*--- Almost completely independent of the stuff above. The ---*/
3332 /*--- only function it 'exports' to the code above this comment ---*/
3333 /*--- is parse_procselfmaps. ---*/
3334 /*--- ---*/
3335 /*-----------------------------------------------------------------*/
3337 /*------BEGIN-procmaps-parser-for-Linux--------------------------*/
3339 /* Size of a smallish table used to read /proc/self/map entries. */
3340 #define M_PROCMAP_BUF 100000
3342 /* static ... to keep it out of the stack frame. */
3343 static HChar procmap_buf[M_PROCMAP_BUF];
3345 /* Records length of /proc/self/maps read into procmap_buf. */
3346 static Int buf_n_tot;
3348 /* Helper fns. */
3350 static Int hexdigit ( HChar c )
3352 if (c >= '0' && c <= '9') return (Int)(c - '0');
3353 if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a');
3354 if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A');
3355 return -1;
3358 static Int decdigit ( HChar c )
3360 if (c >= '0' && c <= '9') return (Int)(c - '0');
3361 return -1;
3364 static Int readchar ( const HChar* buf, HChar* ch )
3366 if (*buf == 0) return 0;
3367 *ch = *buf;
3368 return 1;
3371 static Int readhex ( const HChar* buf, UWord* val )
3373 /* Read a word-sized hex number. */
3374 Int n = 0;
3375 *val = 0;
3376 while (hexdigit(*buf) >= 0) {
3377 *val = (*val << 4) + hexdigit(*buf);
3378 n++; buf++;
3380 return n;
3383 static Int readhex64 ( const HChar* buf, ULong* val )
3385 /* Read a potentially 64-bit hex number. */
3386 Int n = 0;
3387 *val = 0;
3388 while (hexdigit(*buf) >= 0) {
3389 *val = (*val << 4) + hexdigit(*buf);
3390 n++; buf++;
3392 return n;
3395 static Int readdec64 ( const HChar* buf, ULong* val )
3397 Int n = 0;
3398 *val = 0;
3399 while (decdigit(*buf) >= 0) {
3400 *val = (*val * 10) + decdigit(*buf);
3401 n++; buf++;
3403 return n;
3407 /* Get the contents of /proc/self/maps into a static buffer. If
3408 there's a syntax error, it won't fit, or other failure, just
3409 abort. */
3411 static void read_procselfmaps_into_buf ( void )
3413 Int n_chunk;
3414 SysRes fd;
3416 /* Read the initial memory mapping from the /proc filesystem. */
3417 fd = ML_(am_open)( "/proc/self/maps", VKI_O_RDONLY, 0 );
3418 if (sr_isError(fd))
3419 ML_(am_barf)("can't open /proc/self/maps");
3421 buf_n_tot = 0;
3422 do {
3423 n_chunk = ML_(am_read)( sr_Res(fd), &procmap_buf[buf_n_tot],
3424 M_PROCMAP_BUF - buf_n_tot );
3425 if (n_chunk >= 0)
3426 buf_n_tot += n_chunk;
3427 } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
3429 ML_(am_close)(sr_Res(fd));
3431 if (buf_n_tot >= M_PROCMAP_BUF-5)
3432 ML_(am_barf_toolow)("M_PROCMAP_BUF");
3433 if (buf_n_tot == 0)
3434 ML_(am_barf)("I/O error on /proc/self/maps");
3436 procmap_buf[buf_n_tot] = 0;
3439 /* Parse /proc/self/maps. For each map entry, call
3440 record_mapping, passing it, in this order:
3442 start address in memory
3443 length
3444 page protections (using the VKI_PROT_* flags)
3445 mapped file device and inode
3446 offset in file, or zero if no file
3447 filename, zero terminated, or NULL if no file
3448 ignore_offset, when the exact offset cannot be
3449 obtained
3451 So the sig of the called fn might be
3453 void (*record_mapping)( Addr start, SizeT size, UInt prot,
3454 UInt dev, UInt info,
3455 ULong foffset, UChar* filename,
3456 Bool ignore_offset )
3458 Note that the supplied filename is transiently stored; record_mapping
3459 should make a copy if it wants to keep it.
3461 Nb: it is important that this function does not alter the contents of
3462 procmap_buf!
3464 static void parse_procselfmaps (
3465 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
3466 ULong dev, ULong ino, Off64T offset,
3467 const HChar* filename, Bool ignore_offset ),
3468 void (*record_gap)( Addr addr, SizeT len )
3471 Int i, j, i_eol;
3472 Addr start, endPlusOne, gapStart;
3473 HChar* filename;
3474 HChar rr, ww, xx, pp, ch, tmp;
3475 UInt prot;
3476 UWord maj, min;
3477 ULong foffset, dev, ino;
3479 foffset = ino = 0; /* keep gcc-4.1.0 happy */
3481 read_procselfmaps_into_buf();
3483 aspacem_assert('\0' != procmap_buf[0] && 0 != buf_n_tot);
3485 if (0)
3486 VG_(debugLog)(0, "procselfmaps", "raw:\n%s\n", procmap_buf);
3488 /* Ok, it's safely aboard. Parse the entries. */
3489 i = 0;
3490 gapStart = Addr_MIN;
3491 while (True) {
3492 if (i >= buf_n_tot) break;
3494 /* Read (without fscanf :) the pattern %16x-%16x %c%c%c%c %16x %2x:%2x %d */
3495 j = readhex(&procmap_buf[i], &start);
3496 if (j > 0) i += j; else goto syntaxerror;
3497 j = readchar(&procmap_buf[i], &ch);
3498 if (j == 1 && ch == '-') i += j; else goto syntaxerror;
3499 j = readhex(&procmap_buf[i], &endPlusOne);
3500 if (j > 0) i += j; else goto syntaxerror;
3502 j = readchar(&procmap_buf[i], &ch);
3503 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3505 j = readchar(&procmap_buf[i], &rr);
3506 if (j == 1 && (rr == 'r' || rr == '-')) i += j; else goto syntaxerror;
3507 j = readchar(&procmap_buf[i], &ww);
3508 if (j == 1 && (ww == 'w' || ww == '-')) i += j; else goto syntaxerror;
3509 j = readchar(&procmap_buf[i], &xx);
3510 if (j == 1 && (xx == 'x' || xx == '-')) i += j; else goto syntaxerror;
3511 /* This field is the shared/private flag */
3512 j = readchar(&procmap_buf[i], &pp);
3513 if (j == 1 && (pp == 'p' || pp == '-' || pp == 's'))
3514 i += j; else goto syntaxerror;
3516 j = readchar(&procmap_buf[i], &ch);
3517 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3519 j = readhex64(&procmap_buf[i], &foffset);
3520 if (j > 0) i += j; else goto syntaxerror;
3522 j = readchar(&procmap_buf[i], &ch);
3523 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3525 j = readhex(&procmap_buf[i], &maj);
3526 if (j > 0) i += j; else goto syntaxerror;
3527 j = readchar(&procmap_buf[i], &ch);
3528 if (j == 1 && ch == ':') i += j; else goto syntaxerror;
3529 j = readhex(&procmap_buf[i], &min);
3530 if (j > 0) i += j; else goto syntaxerror;
3532 j = readchar(&procmap_buf[i], &ch);
3533 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3535 j = readdec64(&procmap_buf[i], &ino);
3536 if (j > 0) i += j; else goto syntaxerror;
3538 goto read_line_ok;
3540 syntaxerror:
3541 VG_(debugLog)(0, "Valgrind:",
3542 "FATAL: syntax error reading /proc/self/maps\n");
3543 { Int k, m;
3544 HChar buf50[51];
3545 m = 0;
3546 buf50[m] = 0;
3547 k = i - 50;
3548 if (k < 0) k = 0;
3549 for (; k <= i; k++) {
3550 buf50[m] = procmap_buf[k];
3551 buf50[m+1] = 0;
3552 if (m < 50-1) m++;
3554 VG_(debugLog)(0, "procselfmaps", "Last 50 chars: '%s'\n", buf50);
3556 ML_(am_exit)(1);
3558 read_line_ok:
3560 aspacem_assert(i < buf_n_tot);
3562 /* Try and find the name of the file mapped to this segment, if
3563 it exists. Note that file names can contain spaces. */
3565 // Move i to the next non-space char, which should be either a '/',
3566 // a '[', or a newline.
3567 while (procmap_buf[i] == ' ') i++;
3569 // Move i_eol to the end of the line.
3570 i_eol = i;
3571 while (procmap_buf[i_eol] != '\n') i_eol++;
3573 // If there's a filename...
3574 if (procmap_buf[i] == '/') {
3575 /* Minor hack: put a '\0' at the filename end for the call to
3576 'record_mapping', then restore the old char with 'tmp'. */
3577 filename = &procmap_buf[i];
3578 tmp = filename[i_eol - i];
3579 filename[i_eol - i] = '\0';
3580 } else {
3581 tmp = 0;
3582 filename = NULL;
3583 foffset = 0;
3586 prot = 0;
3587 if (rr == 'r') prot |= VKI_PROT_READ;
3588 if (ww == 'w') prot |= VKI_PROT_WRITE;
3589 if (xx == 'x') prot |= VKI_PROT_EXEC;
3591 /* Linux has two ways to encode a device number when it
3592 is exposed to user space (via fstat etc). The old way
3593 is the traditional unix scheme that produces a 16 bit
3594 device number with the top 8 being the major number and
3595 the bottom 8 the minor number.
3597 The new scheme allows for a 12 bit major number and
3598 a 20 bit minor number by using a 32 bit device number
3599 and putting the top 12 bits of the minor number into
3600 the top 12 bits of the device number thus leaving an
3601 extra 4 bits for the major number.
3603 If the minor and major number are both single byte
3604 values then both schemes give the same result so we
3605 use the new scheme here in case either number is
3606 outside the 0-255 range and then use fstat64 when
3607 available (or fstat on 64 bit systems) so that we
3608 should always have a new style device number and
3609 everything should match. */
3610 dev = (min & 0xff) | (maj << 8) | ((min & ~0xff) << 12);
3612 if (record_gap && gapStart < start)
3613 (*record_gap) ( gapStart, start-gapStart );
3615 if (record_mapping && start < endPlusOne)
3616 (*record_mapping) ( start, endPlusOne-start,
3617 prot, dev, ino,
3618 foffset, filename, False );
3620 if ('\0' != tmp) {
3621 filename[i_eol - i] = tmp;
3624 i = i_eol + 1;
3625 gapStart = endPlusOne;
3628 # if defined(VGP_arm_linux)
3629 /* ARM puts code at the end of memory that contains processor
3630 specific stuff (cmpxchg, getting the thread local storage, etc.)
3631 This isn't specified in /proc/self/maps, so do it here. This
3632 kludgery causes the view of memory, as presented to
3633 record_gap/record_mapping, to actually reflect reality. IMO
3634 (JRS, 2010-Jan-03) the fact that /proc/.../maps does not list
3635 the commpage should be regarded as a bug in the kernel. */
3636 { const Addr commpage_start = ARM_LINUX_FAKE_COMMPAGE_START;
3637 const Addr commpage_end1 = ARM_LINUX_FAKE_COMMPAGE_END1;
3638 if (gapStart < commpage_start) {
3639 if (record_gap)
3640 (*record_gap)( gapStart, commpage_start - gapStart );
3641 if (record_mapping)
3642 (*record_mapping)( commpage_start, commpage_end1 - commpage_start,
3643 VKI_PROT_READ|VKI_PROT_EXEC,
3644 0/*dev*/, 0/*ino*/, 0/*foffset*/,
3645 NULL, False);
3646 gapStart = commpage_end1;
3649 # endif
3651 if (record_gap && gapStart < Addr_MAX)
3652 (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
3655 /*------END-procmaps-parser-for-Linux----------------------------*/
3657 /*------BEGIN-procmaps-parser-for-Darwin-------------------------*/
3659 #elif defined(VGO_darwin)
3660 #include <mach/mach.h>
3661 #include <mach/mach_vm.h>
3663 static unsigned int mach2vki(unsigned int vm_prot)
3665 return
3666 ((vm_prot & VM_PROT_READ) ? VKI_PROT_READ : 0) |
3667 ((vm_prot & VM_PROT_WRITE) ? VKI_PROT_WRITE : 0) |
3668 ((vm_prot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC : 0) ;
3671 static UInt stats_machcalls = 0;
3673 static void parse_procselfmaps (
3674 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
3675 ULong dev, ULong ino, Off64T offset,
3676 const HChar* filename, Bool ignore_offset ),
3677 void (*record_gap)( Addr addr, SizeT len )
3680 vm_address_t iter;
3681 unsigned int depth;
3682 vm_address_t last;
3684 iter = 0;
3685 depth = 0;
3686 last = 0;
3687 while (1) {
3688 mach_vm_address_t addr = iter;
3689 mach_vm_size_t size;
3690 vm_region_submap_short_info_data_64_t info;
3691 kern_return_t kr;
3693 while (1) {
3694 mach_msg_type_number_t info_count
3695 = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
3696 stats_machcalls++;
3697 kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth,
3698 (vm_region_info_t)&info, &info_count);
3699 if (kr)
3700 return;
3701 if (info.is_submap) {
3702 depth++;
3703 continue;
3705 break;
3707 iter = addr + size;
3709 if (addr > last && record_gap) {
3710 (*record_gap)(last, addr - last);
3712 if (record_mapping) {
3713 (*record_mapping)(addr, size, mach2vki(info.protection),
3714 0, 0, info.offset, NULL, False);
3716 last = addr + size;
3719 if ((Addr)-1 > last && record_gap)
3720 (*record_gap)(last, (Addr)-1 - last);
3723 // Urr. So much for thread safety.
3724 static Bool css_overflowed;
3725 static ChangedSeg* css_local;
3726 static Int css_size_local;
3727 static Int css_used_local;
3729 static Addr Addr__max ( Addr a, Addr b ) { return a > b ? a : b; }
3730 static Addr Addr__min ( Addr a, Addr b ) { return a < b ? a : b; }
3732 static void add_mapping_callback(Addr addr, SizeT len, UInt prot,
3733 ULong dev, ULong ino, Off64T offset,
3734 const HChar *filename, Bool ignore_offset)
3736 // derived from sync_check_mapping_callback()
3738 /* JRS 2012-Mar-07: this all seems very dubious to me. It would be
3739 safer to see if we can find, in V's segment collection, one
3740 single segment that completely covers the range [addr, +len)
3741 (and possibly more), and that has the exact same other
3742 properties (prot, dev, ino, offset, etc) as the data presented
3743 here. If found, we just skip. Otherwise add the data presented
3744 here into css_local[]. */
3746 Int iLo, iHi, i;
3748 if (len == 0) return;
3750 /* The kernel should not give us wraparounds. */
3751 aspacem_assert(addr <= addr + len - 1);
3753 iLo = find_nsegment_idx( addr );
3754 iHi = find_nsegment_idx( addr + len - 1 );
3756 /* NSegments iLo .. iHi inclusive should agree with the presented
3757 data. */
3758 for (i = iLo; i <= iHi; i++) {
3760 UInt seg_prot;
3762 if (nsegments[i].kind == SkAnonV || nsegments[i].kind == SkFileV) {
3763 /* Ignore V regions */
3764 continue;
3766 else if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) {
3767 /* Add mapping for SkResvn regions */
3768 ChangedSeg* cs = &css_local[css_used_local];
3769 if (css_used_local < css_size_local) {
3770 cs->is_added = True;
3771 cs->start = addr;
3772 cs->end = addr + len - 1;
3773 cs->prot = prot;
3774 cs->offset = offset;
3775 css_used_local++;
3776 } else {
3777 css_overflowed = True;
3779 return;
3782 else if (nsegments[i].kind == SkAnonC ||
3783 nsegments[i].kind == SkFileC ||
3784 nsegments[i].kind == SkShmC)
3786 /* Check permissions on client regions */
3787 // GrP fixme
3788 seg_prot = 0;
3789 if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
3790 if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
3791 # if defined(VGA_x86)
3792 // GrP fixme sloppyXcheck
3793 // darwin: kernel X ignored and spuriously changes? (vm_copy)
3794 seg_prot |= (prot & VKI_PROT_EXEC);
3795 # else
3796 if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
3797 # endif
3798 if (seg_prot != prot) {
3799 if (VG_(clo_trace_syscalls))
3800 VG_(debugLog)(0,"aspacem","region %p..%p permission "
3801 "mismatch (kernel %x, V %x)\n",
3802 (void*)nsegments[i].start,
3803 (void*)(nsegments[i].end+1), prot, seg_prot);
3804 /* Add mapping for regions with protection changes */
3805 ChangedSeg* cs = &css_local[css_used_local];
3806 if (css_used_local < css_size_local) {
3807 cs->is_added = True;
3808 cs->start = addr;
3809 cs->end = addr + len - 1;
3810 cs->prot = prot;
3811 cs->offset = offset;
3812 css_used_local++;
3813 } else {
3814 css_overflowed = True;
3816 return;
3820 } else {
3821 aspacem_assert(0);
3826 static void remove_mapping_callback(Addr addr, SizeT len)
3828 // derived from sync_check_gap_callback()
3830 Int iLo, iHi, i;
3832 if (len == 0)
3833 return;
3835 /* The kernel should not give us wraparounds. */
3836 aspacem_assert(addr <= addr + len - 1);
3838 iLo = find_nsegment_idx( addr );
3839 iHi = find_nsegment_idx( addr + len - 1 );
3841 /* NSegments iLo .. iHi inclusive should agree with the presented data. */
3842 for (i = iLo; i <= iHi; i++) {
3843 if (nsegments[i].kind != SkFree && nsegments[i].kind != SkResvn) {
3844 /* V has a mapping, kernel doesn't. Add to css_local[],
3845 directives to chop off the part of the V mapping that
3846 falls within the gap that the kernel tells us is
3847 present. */
3848 ChangedSeg* cs = &css_local[css_used_local];
3849 if (css_used_local < css_size_local) {
3850 cs->is_added = False;
3851 cs->start = Addr__max(nsegments[i].start, addr);
3852 cs->end = Addr__min(nsegments[i].end, addr + len - 1);
3853 aspacem_assert(VG_IS_PAGE_ALIGNED(cs->start));
3854 aspacem_assert(VG_IS_PAGE_ALIGNED(cs->end+1));
3855 /* I don't think the following should fail. But if it
3856 does, just omit the css_used_local++ in the cases where
3857 it doesn't hold. */
3858 aspacem_assert(cs->start < cs->end);
3859 cs->prot = 0;
3860 cs->offset = 0;
3861 css_used_local++;
3862 } else {
3863 css_overflowed = True;
3870 // Returns False if 'css' wasn't big enough.
3871 Bool VG_(get_changed_segments)(
3872 const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css,
3873 Int css_size, /*OUT*/Int* css_used)
3875 static UInt stats_synccalls = 1;
3876 aspacem_assert(when && where);
3878 if (0)
3879 VG_(debugLog)(0,"aspacem",
3880 "[%u,%u] VG_(get_changed_segments)(%s, %s)\n",
3881 stats_synccalls++, stats_machcalls, when, where
3884 css_overflowed = False;
3885 css_local = css;
3886 css_size_local = css_size;
3887 css_used_local = 0;
3889 // Get the list of segs that need to be added/removed.
3890 parse_procselfmaps(&add_mapping_callback, &remove_mapping_callback);
3892 *css_used = css_used_local;
3894 if (css_overflowed) {
3895 aspacem_assert(css_used_local == css_size_local);
3898 return !css_overflowed;
3902 /*------END-procmaps-parser-for-Darwin---------------------------*/
3904 /*------BEGIN-procmaps-parser-for-Freebsd------------------------*/
3905 #elif defined(VGO_freebsd)
3908 * PJF 2023-09-23
3910 * This function is somewhat badly named for FreeBSD, where the
3911 * /proc filesystem is optional so we can't count on users
3912 * having it. Instead we use the KERN_PROC_VMMAP syscall.
3913 * So far so good.
3915 * This function is used in two contexts. The heaviest use is from
3916 * VG_(am_do_sync_check) as a sanity check that the contents of the
3917 * global nsegments array is consistent with what the OS reports
3918 * as being memory maps. No known problems with that.
3920 * The other use is at startup in order to get the mapping for the
3921 * tool itself. In this case we have a fairly big problem. There is
3922 * a difference in the mapping used when the kernel loads an exe
3923 * and when the link loader ldrt (or Valgrind which does the same
3924 * job for the guest exe. In the case of ldrt, all ELF PT_LOAD
3925 * sections get mmap'd. The kernel, however, does _not_ mmap
3926 * the RW PT_LOAD.
3928 * For instance, objdump -p for memcheck-amd64-freebsd contains
3929 * LOAD off 0x0000000000000000 vaddr 0x0000000038000000 paddr 0x0000000038000000 align 2**12
3930 * filesz 0x00000000000c5124 memsz 0x00000000000c5124 flags r--
3931 * LOAD off 0x00000000000c5130 vaddr 0x00000000380c6130 paddr 0x00000000380c6130 align 2**12
3932 * filesz 0x00000000001b10df memsz 0x00000000001b10df flags r-x
3933 * LOAD off 0x0000000000276210 vaddr 0x0000000038278210 paddr 0x0000000038278210 align 2**12
3934 * filesz 0x0000000000000a90 memsz 0x00000000025dd000 flags rw-
3936 * Running procstat -v on a running instance gives
3937 * 44814 0x38000000 0x380c6000 r-- 198 2558 2 0 CN--- vn /usr/home/paulf/scratch/valgrind/memcheck/memcheck-amd64-freebsd
3938 * 44814 0x380c6000 0x38278000 r-x 434 2558 2 0 CN--- vn /usr/home/paulf/scratch/valgrind/memcheck/memcheck-amd64-freebsd
3939 * 44814 0x38278000 0x3a856000 rw- 4590 4590 1 0 ----- df
3941 * Instead of mmap'ing the RW PT_LOAD the kernel has mmap'd anonymous swap and copied from the exe file.
3942 * See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=273956
3944 * So what can we do? We can reuse most of the info from the previous 'r-x' mapping.
3945 * The filename, dev and ino are all the same. That leaves the offset. We can
3946 * make a rough estimate of the value as being previous offset + previous size.
3947 * Since the addresses in memory will be page aligned it's not possible to
3948 * obtain the original offset. It isn't good enough for ML_(read_elf_object)
3949 * in readelf.c
3951 * As a hack of last resort we force ML_(read_elf_object) to accept this
3952 * mapping by adding an "ignore offset" flag. We can't be wrong that
3953 * there is something mapped roughly there - it's the global data of the
3954 * code that is executing on the CPU! Furthermore, this is not frequently
3955 * used. The main benefit is for Valgrind developers. Without this hack,
3956 * if Valgrind crashes or asserts it will print its own stack without
3957 * debuginfo, which is mostly useless. See the above FreeBSD bugzilla item
3958 * for an example.
3961 /* Size of a smallish table used to read /proc/self/map entries. */
3962 #define M_PROCMAP_BUF 10485760 /* 10M */
3964 /* static ... to keep it out of the stack frame. */
3965 static char procmap_buf[M_PROCMAP_BUF];
3967 static void parse_procselfmaps (
3968 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
3969 ULong dev, ULong ino, Off64T offset,
3970 const HChar* filename, Bool ignore_offset ),
3971 void (*record_gap)( Addr addr, SizeT len )
3974 Addr start, endPlusOne, gapStart;
3975 char* filename;
3976 char *p;
3977 UInt prot;
3978 ULong foffset, dev, ino;
3979 struct vki_kinfo_vmentry *kve;
3980 vki_size_t len;
3981 Int oid[4];
3982 SysRes sres;
3983 Int map_count = 0;
3984 // this assumes that compiling with clang uses ld.lld which produces 3 LOAD segements
3985 // and that compiling with GCC uses ld.bfd which produces 2 LOAD segments
3986 #if defined(__clang__)
3987 Int const rx_map = 1;
3988 Int const rw_map = 2;
3989 #elif defined(__GNUC__)
3990 Int const rx_map = 0;
3991 Int const rw_map = 1;
3992 #else
3993 #error("unsupported compiler")
3994 #endif
3995 // could copy the whole kinfo_vmentry but it is 1160 bytes
3996 char *rx_filename = NULL;
3997 ULong rx_dev = 0U;
3998 ULong rx_ino = 0U;
3999 ULong rx_foffset = 0U;
4000 Bool tool_read_maps = (record_mapping == read_maps_callback);
4002 foffset = ino = 0; /* keep gcc-4.1.0 happy */
4004 oid[0] = VKI_CTL_KERN;
4005 oid[1] = VKI_KERN_PROC;
4006 oid[2] = VKI_KERN_PROC_VMMAP;
4007 oid[3] = sr_Res(VG_(do_syscall0)(__NR_getpid));
4008 len = sizeof(procmap_buf);
4010 sres = VG_(do_syscall6)(__NR___sysctl, (UWord)oid, 4, (UWord)procmap_buf,
4011 (UWord)&len, 0, 0);
4012 if (sr_isError(sres)) {
4013 VG_(debugLog)(0, "procselfmaps", "sysctl %lu\n", sr_Err(sres));
4014 ML_(am_exit)(1);
4016 gapStart = Addr_MIN;
4017 p = procmap_buf;
4018 while (p < (char *)procmap_buf + len) {
4019 kve = (struct vki_kinfo_vmentry *)p;
4020 start = (UWord)kve->kve_start;
4021 endPlusOne = (UWord)kve->kve_end;
4022 foffset = kve->kve_offset;
4023 filename = kve->kve_path;
4024 dev = kve->kve_vn_fsid_freebsd11;
4025 ino = kve->kve_fileid;
4026 if (filename[0] != '/') {
4027 filename = NULL;
4028 foffset = 0;
4031 prot = 0;
4032 if (kve->kve_protection & VKI_KVME_PROT_READ) prot |= VKI_PROT_READ;
4033 if (kve->kve_protection & VKI_KVME_PROT_WRITE) prot |= VKI_PROT_WRITE;
4034 if (kve->kve_protection & VKI_KVME_PROT_EXEC) prot |= VKI_PROT_EXEC;
4036 map_count = (p - (char *)procmap_buf)/kve->kve_structsize;
4038 if (tool_read_maps && map_count == rw_map) {
4039 aspacem_assert((prot & (VKI_PROT_READ | VKI_PROT_WRITE)) == (VKI_PROT_READ | VKI_PROT_WRITE));
4040 filename = rx_filename;
4041 dev = rx_dev;
4042 ino = rx_ino;
4043 foffset = rx_foffset;
4046 if (record_gap && gapStart < start)
4047 (*record_gap) ( gapStart, start-gapStart );
4049 if (record_mapping && start < endPlusOne) {
4050 (*record_mapping) ( start, endPlusOne-start,
4051 prot, dev, ino,
4052 foffset, filename, tool_read_maps && map_count == 2 );
4055 if (tool_read_maps && map_count == rx_map) {
4056 aspacem_assert((prot & (VKI_PROT_READ | VKI_PROT_EXEC)) == (VKI_PROT_READ | VKI_PROT_EXEC));
4057 rx_filename = filename;
4058 rx_dev = dev;
4059 rx_ino = ino;
4060 /* this is only accurate to the page alignment */
4061 rx_foffset = foffset + endPlusOne - start;
4064 gapStart = endPlusOne;
4065 p += kve->kve_structsize;
4068 if (record_gap && gapStart < Addr_MAX)
4069 (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
4072 /*------END-procmaps-parser-for-Freebsd--------------------------*/
4074 /*------BEGIN-procmaps-parser-for-Solaris------------------------*/
4076 #elif defined(VGO_solaris)
4078 /* Note: /proc/self/xmap contains extended information about already
4079 materialized mappings whereas /proc/self/rmap contains information about
4080 all mappings including reserved but yet-to-materialize mappings (mmap'ed
4081 with MAP_NORESERVE flag, such as thread stacks). But /proc/self/rmap does
4082 not contain extended information found in /proc/self/xmap. Therefore
4083 information from both sources need to be combined.
4086 typedef struct
4088 Addr addr;
4089 SizeT size;
4090 UInt prot;
4091 ULong dev;
4092 ULong ino;
4093 Off64T foffset;
4094 HChar filename[VKI_PATH_MAX];
4095 } Mapping;
4097 static SizeT read_proc_file(const HChar *filename, HChar *buf,
4098 SizeT buf_size, const HChar *buf_size_name,
4099 SizeT entry_size)
4101 SysRes res = ML_(am_open)(filename, VKI_O_RDONLY, 0);
4102 if (sr_isError(res)) {
4103 HChar message[100];
4104 ML_(am_sprintf)(message, "Cannot open %s.", filename);
4105 ML_(am_barf)(message);
4107 Int fd = sr_Res(res);
4109 Int r = ML_(am_read)(fd, buf, buf_size);
4110 ML_(am_close)(fd);
4111 if (r < 0) {
4112 HChar message[100];
4113 ML_(am_sprintf)(message, "I/O error on %s.", filename);
4114 ML_(am_barf)(message);
4117 if (r >= buf_size)
4118 ML_(am_barf_toolow)(buf_size_name);
4120 if (r % entry_size != 0) {
4121 HChar message[100];
4122 ML_(am_sprintf)(message, "Bogus values read from %s.", filename);
4123 ML_(am_barf)(message);
4126 return r / entry_size;
4129 static Mapping *next_xmap(const HChar *buffer, SizeT entries, SizeT *idx,
4130 Mapping *mapping)
4132 aspacem_assert(idx);
4133 aspacem_assert(mapping);
4135 if (*idx >= entries)
4136 return NULL; /* No more entries */
4138 const vki_prxmap_t *map = (const vki_prxmap_t *)buffer + *idx;
4140 mapping->addr = map->pr_vaddr;
4141 mapping->size = map->pr_size;
4143 mapping->prot = 0;
4144 if (map->pr_mflags & VKI_MA_READ)
4145 mapping->prot |= VKI_PROT_READ;
4146 if (map->pr_mflags & VKI_MA_WRITE)
4147 mapping->prot |= VKI_PROT_WRITE;
4148 if (map->pr_mflags & VKI_MA_EXEC)
4149 mapping->prot |= VKI_PROT_EXEC;
4151 if (map->pr_dev != VKI_PRNODEV) {
4152 mapping->dev = map->pr_dev;
4153 mapping->ino = map->pr_ino;
4154 mapping->foffset = map->pr_offset;
4156 else {
4157 mapping->dev = 0;
4158 mapping->ino = 0;
4159 mapping->foffset = 0;
4162 /* Try to get the filename. */
4163 mapping->filename[0] = '\0';
4164 if (map->pr_mapname[0] != '\0') {
4165 ML_(am_sprintf)(mapping->filename, "/proc/self/path/%s",
4166 map->pr_mapname);
4167 Int r = ML_(am_readlink)(mapping->filename, mapping->filename,
4168 sizeof(mapping->filename) - 1);
4169 if (r == -1) {
4170 /* If Valgrind is executed in a non-global zone and the link in
4171 /proc/self/path/ represents a file that is available through lofs
4172 from a global zone then the kernel may not be able to resolve the
4173 link.
4175 In such a case, return a corresponding /proc/self/object/ file to
4176 allow Valgrind to read the file if it is necessary.
4178 This can create some discrepancy for the sanity check. For
4179 instance, if a client program mmaps some file then the address
4180 space manager will have a correct zone-local name of that file,
4181 but the sanity check will receive a different file name from this
4182 code. This currently does not represent a problem because the
4183 sanity check ignores the file names (it uses device and inode
4184 numbers for the comparison).
4186 ML_(am_sprintf)(mapping->filename, "/proc/self/object/%s",
4187 map->pr_mapname);
4189 else {
4190 aspacem_assert(r >= 0);
4191 mapping->filename[r] = '\0';
4195 *idx += 1;
4196 return mapping;
4199 static Mapping *next_rmap(const HChar *buffer, SizeT entries, SizeT *idx,
4200 Mapping *mapping)
4202 aspacem_assert(idx);
4203 aspacem_assert(mapping);
4205 if (*idx >= entries)
4206 return NULL; /* No more entries */
4208 const vki_prmap_t *map = (const vki_prmap_t *)buffer + *idx;
4210 mapping->addr = map->pr_vaddr;
4211 mapping->size = map->pr_size;
4213 mapping->prot = 0;
4214 if (map->pr_mflags & VKI_MA_READ)
4215 mapping->prot |= VKI_PROT_READ;
4216 if (map->pr_mflags & VKI_MA_WRITE)
4217 mapping->prot |= VKI_PROT_WRITE;
4218 if (map->pr_mflags & VKI_MA_EXEC)
4219 mapping->prot |= VKI_PROT_EXEC;
4221 mapping->dev = 0;
4222 mapping->ino = 0;
4223 mapping->foffset = 0;
4224 mapping->filename[0] = '\0';
4226 *idx += 1;
4227 return mapping;
4230 /* Used for two purposes:
4231 1. Establish initial mappings upon the process startup
4232 2. Check mappings during aspacemgr sanity check
4234 static void parse_procselfmaps (
4235 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
4236 ULong dev, ULong ino, Off64T offset,
4237 const HChar *filename, Bool ignore_offset ),
4238 void (*record_gap)( Addr addr, SizeT len )
4241 Addr start = Addr_MIN;
4242 Addr gap_start = Addr_MIN;
4244 #define M_XMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prxmap_t))
4245 /* Static to keep it out of stack frame... */
4246 static HChar xmap_buf[M_XMAP_BUF];
4247 const Mapping *xmap = NULL;
4248 SizeT xmap_index = 0; /* Current entry */
4249 SizeT xmap_entries;
4250 Mapping xmap_mapping;
4251 Bool advance_xmap;
4253 #define M_RMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prmap_t))
4254 static HChar rmap_buf[M_RMAP_BUF];
4255 const Mapping *rmap = NULL;
4256 SizeT rmap_index = 0; /* Current entry */
4257 SizeT rmap_entries;
4258 Mapping rmap_mapping;
4259 Bool advance_rmap;
4261 /* Read fully /proc/self/xmap and /proc/self/rmap. */
4262 xmap_entries = read_proc_file("/proc/self/xmap", xmap_buf, M_XMAP_BUF,
4263 "M_XMAP_BUF", sizeof(vki_prxmap_t));
4265 rmap_entries = read_proc_file("/proc/self/rmap", rmap_buf, M_RMAP_BUF,
4266 "M_RMAP_BUF", sizeof(vki_prmap_t));
4268 /* Get the first xmap and rmap. */
4269 advance_xmap = True;
4270 advance_rmap = True;
4272 while (1) {
4273 /* Get next xmap or rmap if necessary. */
4274 if (advance_xmap) {
4275 xmap = next_xmap(xmap_buf, xmap_entries, &xmap_index, &xmap_mapping);
4276 advance_xmap = False;
4278 if (advance_rmap) {
4279 rmap = next_rmap(rmap_buf, rmap_entries, &rmap_index, &rmap_mapping);
4280 advance_rmap = False;
4283 /* Check if the end has been reached. */
4284 if (rmap == NULL)
4285 break;
4287 /* Invariants */
4288 if (xmap != NULL) {
4289 aspacem_assert(start <= xmap->addr);
4290 aspacem_assert(rmap->addr <= xmap->addr);
4293 if (xmap != NULL && start == xmap->addr) {
4294 /* xmap mapping reached. */
4295 aspacem_assert(xmap->addr >= rmap->addr &&
4296 xmap->addr + xmap->size <= rmap->addr + rmap->size);
4297 aspacem_assert(xmap->prot == rmap->prot);
4299 if (record_mapping != NULL)
4300 (*record_mapping)(xmap->addr, xmap->size, xmap->prot, xmap->dev,
4301 xmap->ino, xmap->foffset,
4302 (xmap->filename[0] != '\0') ?
4303 xmap->filename : NULL, False);
4305 start = xmap->addr + xmap->size;
4306 advance_xmap = True;
4308 else if (start >= rmap->addr) {
4309 /* Reserved-only part. */
4310 /* First calculate size until the end of this reserved mapping... */
4311 SizeT size = rmap->addr + rmap->size - start;
4312 /* ... but shrink it if some xmap is in a way. */
4313 if (xmap != NULL && size > xmap->addr - start)
4314 size = xmap->addr - start;
4316 if (record_mapping != NULL)
4317 (*record_mapping)(start, size, rmap->prot, 0, 0, 0, NULL, False);
4318 start += size;
4320 else {
4321 /* Gap. */
4322 if (record_gap != NULL && gap_start < start)
4323 (*record_gap)(gap_start, start - gap_start);
4324 start = rmap->addr;
4327 if (rmap->addr + rmap->size <= start)
4328 advance_rmap = True;
4330 gap_start = start;
4333 if (record_gap != NULL && gap_start < Addr_MAX)
4334 (*record_gap)(gap_start, Addr_MAX - gap_start + 1);
4337 /* parse_procselfmaps() callbacks do not allow for easy thread safety. */
4338 static Addr found_addr;
4339 static SizeT found_size;
4340 static UInt found_prot;
4342 /* Reports a new mapping into variables above. */
4343 static void new_segment_found_callback(Addr addr, SizeT len, UInt prot,
4344 ULong dev, ULong ino, Off64T offset, const HChar *filename, Bool ignore_offset)
4346 aspacem_assert(addr <= addr + len - 1);
4348 Int iLo = find_nsegment_idx(addr);
4349 Int iHi = find_nsegment_idx(addr + len - 1);
4350 aspacem_assert(iLo <= iHi);
4351 aspacem_assert(nsegments[iLo].start <= addr);
4352 aspacem_assert(nsegments[iHi].end >= addr + len - 1);
4354 /* Do not perform any sanity checks. That is done in other places.
4355 Just find if a reported mapping is found in aspacemgr's book keeping. */
4356 for (Int i = iLo; i <= iHi; i++) {
4357 if ((nsegments[i].kind == SkFree) || (nsegments[i].kind == SkResvn)) {
4358 found_addr = addr;
4359 found_size = len;
4360 found_prot = prot;
4361 break;
4366 /* Returns True if a new segment was found. */
4367 Bool VG_(am_search_for_new_segment)(Addr *addr, SizeT *size, UInt *prot)
4369 found_addr = 0;
4370 parse_procselfmaps(new_segment_found_callback, NULL);
4372 if (found_addr != 0) {
4373 *addr = found_addr;
4374 *size = found_size;
4375 *prot = found_prot;
4376 return True;
4377 } else {
4378 return False;
4382 #endif // defined(VGO_solaris)
4384 /*------END-procmaps-parser-for-Solaris--------------------------*/
4386 #endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd)
4388 /*--------------------------------------------------------------------*/
4389 /*--- end ---*/
4390 /*--------------------------------------------------------------------*/