Bug 498492 - none/tests/amd64/lzcnt64 crashes on FreeBSD compiled with clang
[valgrind.git] / coregrind / m_aspacemgr / aspacemgr-linux.c
blobbae4f781a82a3c915fb597cd63be04387fa17d61
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)
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 #elif defined(VGO_freebsd)
869 cmp_offsets
870 = nsegments[i].kind == SkFileC || nsegments[i].kind == SkFileV;
871 cmp_offsets &= ignore_offset;
873 cmp_devino
874 = nsegments[i].dev != 0 || nsegments[i].ino != 0;
875 cmp_devino &= ignore_offset;
876 #else
877 cmp_offsets
878 = nsegments[i].kind == SkFileC || nsegments[i].kind == SkFileV;
880 cmp_devino
881 = nsegments[i].dev != 0 || nsegments[i].ino != 0;
882 #endif
884 /* Consider other reasons to not compare dev/inode */
885 #if defined(VGO_linux)
886 /* bproc does some godawful hack on /dev/zero at process
887 migration, which changes the name of it, and its dev & ino */
888 if (filename && 0==VG_(strcmp)(filename, "/dev/zero (deleted)"))
889 cmp_devino = False;
891 /* hack apparently needed on MontaVista Linux */
892 if (filename && VG_(strstr)(filename, "/.lib-ro/"))
893 cmp_devino = False;
895 /* On linux systems we want to avoid dev/inode check on btrfs,
896 we can use the statfs call for that, except on nanomips
897 (which also doesn't have a sys_fstatfs syswrap).
898 See https://bugs.kde.org/show_bug.cgi?id=317127 */
899 #if !defined(VGP_nanomips_linux)
900 struct vki_statfs statfs = {0};
901 SysRes res = VG_(do_syscall2)(__NR_statfs, (UWord)filename,
902 (UWord)&statfs);
903 if (!sr_isError(res) && statfs.f_type == VKI_BTRFS_SUPER_MAGIC) {
904 cmp_devino = False;
906 #endif
907 #endif
909 /* If we are doing sloppy execute permission checks then we
910 allow segment to have X permission when we weren't expecting
911 it (but not vice versa) so if the kernel reported execute
912 permission then pretend that this segment has it regardless
913 of what we were expecting. */
914 if (sloppyXcheck && (prot & VKI_PROT_EXEC) != 0) {
915 seg_prot |= VKI_PROT_EXEC;
918 if (sloppyRcheck && (prot & (VKI_PROT_EXEC | VKI_PROT_READ)) ==
919 (VKI_PROT_EXEC | VKI_PROT_READ)) {
920 seg_prot |= VKI_PROT_READ;
923 same = same
924 && seg_prot == prot
925 && (cmp_devino
926 ? (nsegments[i].dev == dev && nsegments[i].ino == ino)
927 : True)
928 && (cmp_offsets
929 ? nsegments[i].start-nsegments[i].offset == addr-offset
930 : True);
931 if (!same) {
932 Addr start = addr;
933 Addr end = start + len - 1;
934 HChar len_buf[20];
935 show_len_concisely(len_buf, start, end);
937 sync_check_ok = False;
939 VG_(debugLog)(
940 0,"aspacem",
941 "segment mismatch: V's seg 1st, kernel's 2nd:\n");
942 show_nsegment_full( 0, i, &nsegments[i] );
943 VG_(debugLog)(0,"aspacem",
944 "...: .... %010lx-%010lx %s %c%c%c.. ....... "
945 "d=0x%03llx i=%-7llu o=%-7lld (.) m=. %s\n",
946 start, end, len_buf,
947 prot & VKI_PROT_READ ? 'r' : '-',
948 prot & VKI_PROT_WRITE ? 'w' : '-',
949 prot & VKI_PROT_EXEC ? 'x' : '-',
950 dev, ino, offset, filename ? filename : "(none)" );
952 return;
956 /* Looks harmless. Keep going. */
957 return;
960 static void sync_check_gap_callback ( Addr addr, SizeT len )
962 Int iLo, iHi, i;
964 /* If a problem has already been detected, don't continue comparing
965 segments, so as to avoid flooding the output with error
966 messages. */
967 #if !defined(VGO_darwin)
968 /* GrP fixme not */
969 if (!sync_check_ok)
970 return;
971 #endif
972 if (len == 0)
973 return;
975 /* The kernel should not give us wraparounds. */
976 aspacem_assert(addr <= addr + len - 1);
978 iLo = find_nsegment_idx( addr );
979 iHi = find_nsegment_idx( addr + len - 1 );
981 /* These 5 should be guaranteed by find_nsegment_idx. */
982 aspacem_assert(0 <= iLo && iLo < nsegments_used);
983 aspacem_assert(0 <= iHi && iHi < nsegments_used);
984 aspacem_assert(iLo <= iHi);
985 aspacem_assert(nsegments[iLo].start <= addr );
986 aspacem_assert(nsegments[iHi].end >= addr + len - 1 );
988 /* NSegments iLo .. iHi inclusive should agree with the presented
989 data. */
990 for (i = iLo; i <= iHi; i++) {
992 Bool same;
994 /* compare the kernel's offering against ours. */
995 same = nsegments[i].kind == SkFree
996 || nsegments[i].kind == SkResvn;
998 if (!same) {
999 Addr start = addr;
1000 Addr end = start + len - 1;
1001 HChar len_buf[20];
1002 show_len_concisely(len_buf, start, end);
1004 sync_check_ok = False;
1006 VG_(debugLog)(
1007 0,"aspacem",
1008 "segment mismatch: V's gap 1st, kernel's 2nd:\n");
1009 show_nsegment_full( 0, i, &nsegments[i] );
1010 VG_(debugLog)(0,"aspacem",
1011 " : .... %010lx-%010lx %s\n",
1012 start, end, len_buf);
1013 return;
1017 /* Looks harmless. Keep going. */
1018 return;
1022 /* Sanity check: check that Valgrind and the kernel agree on the
1023 address space layout. Prints offending segments and call point if
1024 a discrepancy is detected, but does not abort the system. Returned
1025 Bool is False if a discrepancy was found. */
1027 Bool VG_(am_do_sync_check) ( const HChar* fn,
1028 const HChar* file, Int line )
1030 sync_check_ok = True;
1031 if (0)
1032 VG_(debugLog)(0,"aspacem", "do_sync_check %s:%d\n", file,line);
1033 parse_procselfmaps( sync_check_mapping_callback,
1034 sync_check_gap_callback );
1035 if (!sync_check_ok) {
1036 VG_(debugLog)(0,"aspacem",
1037 "sync check at %s:%d (%s): FAILED\n",
1038 file, line, fn);
1039 VG_(debugLog)(0,"aspacem", "\n");
1041 # if 0
1043 HChar buf[100]; // large enough
1044 VG_(am_show_nsegments)(0,"post syncheck failure");
1045 VG_(sprintf)(buf, "/bin/cat /proc/%d/maps", VG_(getpid)());
1046 VG_(system)(buf);
1048 # endif
1051 return sync_check_ok;
1054 /* Hook to allow sanity checks to be done from aspacemgr-common.c. */
1055 void ML_(am_do_sanity_check)( void )
1057 AM_SANITY_CHECK;
1061 /*-----------------------------------------------------------------*/
1062 /*--- ---*/
1063 /*--- Low level access / modification of the segment array. ---*/
1064 /*--- ---*/
1065 /*-----------------------------------------------------------------*/
1067 /* Binary search the interval array for a given address. Since the
1068 array covers the entire address space the search cannot fail. The
1069 _WRK function does the real work. Its caller (just below) caches
1070 the results thereof, to save time. With N_CACHE of 63 we get a hit
1071 rate exceeding 90% when running OpenOffice.
1073 Re ">> 12", it doesn't matter that the page size of some targets
1074 might be different from 12. Really "(a >> 12) % N_CACHE" is merely
1075 a hash function, and the actual cache entry is always validated
1076 correctly against the selected cache entry before use.
1078 /* Don't call find_nsegment_idx_WRK; use find_nsegment_idx instead. */
1079 __attribute__((noinline))
1080 static Int find_nsegment_idx_WRK ( Addr a )
1082 Addr a_mid_lo, a_mid_hi;
1083 Int mid,
1084 lo = 0,
1085 hi = nsegments_used-1;
1086 while (True) {
1087 /* current unsearched space is from lo to hi, inclusive. */
1088 if (lo > hi) {
1089 /* Not found. This can't happen. */
1090 ML_(am_barf)("find_nsegment_idx: not found");
1092 mid = (lo + hi) / 2;
1093 a_mid_lo = nsegments[mid].start;
1094 a_mid_hi = nsegments[mid].end;
1096 if (a < a_mid_lo) { hi = mid-1; continue; }
1097 if (a > a_mid_hi) { lo = mid+1; continue; }
1098 aspacem_assert(a >= a_mid_lo && a <= a_mid_hi);
1099 aspacem_assert(0 <= mid && mid < nsegments_used);
1100 return mid;
1104 inline static Int find_nsegment_idx ( Addr a )
1106 # define N_CACHE 131 /*prime*/
1107 static Addr cache_pageno[N_CACHE];
1108 static Int cache_segidx[N_CACHE];
1109 static Bool cache_inited = False;
1111 # ifdef N_Q_M_STATS
1112 static UWord n_q = 0;
1113 static UWord n_m = 0;
1114 n_q++;
1115 if (0 == (n_q & 0xFFFF))
1116 VG_(debugLog)(0,"xxx","find_nsegment_idx: %lu %lu\n", n_q, n_m);
1117 # endif
1119 UWord ix;
1121 if (LIKELY(cache_inited)) {
1122 /* do nothing */
1123 } else {
1124 for (ix = 0; ix < N_CACHE; ix++) {
1125 cache_pageno[ix] = 0;
1126 cache_segidx[ix] = -1;
1128 cache_inited = True;
1131 ix = (a >> 12) % N_CACHE;
1133 if ((a >> 12) == cache_pageno[ix]
1134 && cache_segidx[ix] >= 0
1135 && cache_segidx[ix] < nsegments_used
1136 && nsegments[cache_segidx[ix]].start <= a
1137 && a <= nsegments[cache_segidx[ix]].end) {
1138 /* hit */
1139 /* aspacem_assert( cache_segidx[ix] == find_nsegment_idx_WRK(a) ); */
1140 return cache_segidx[ix];
1142 /* miss */
1143 # ifdef N_Q_M_STATS
1144 n_m++;
1145 # endif
1146 cache_segidx[ix] = find_nsegment_idx_WRK(a);
1147 cache_pageno[ix] = a >> 12;
1148 return cache_segidx[ix];
1149 # undef N_CACHE
1153 /* Finds the segment containing 'a'. Only returns non-SkFree segments. */
1154 NSegment const * VG_(am_find_nsegment) ( Addr a )
1156 Int i = find_nsegment_idx(a);
1157 aspacem_assert(i >= 0 && i < nsegments_used);
1158 aspacem_assert(nsegments[i].start <= a);
1159 aspacem_assert(a <= nsegments[i].end);
1160 if (nsegments[i].kind == SkFree)
1161 return NULL;
1162 else
1163 return &nsegments[i];
1166 /* Finds an anonymous segment containing 'a'. Returned pointer is read only. */
1167 NSegment const *VG_(am_find_anon_segment) ( Addr a )
1169 Int i = find_nsegment_idx(a);
1170 aspacem_assert(i >= 0 && i < nsegments_used);
1171 aspacem_assert(nsegments[i].start <= a);
1172 aspacem_assert(a <= nsegments[i].end);
1173 if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV)
1174 return &nsegments[i];
1175 else
1176 return NULL;
1179 /* Map segment pointer to segment index. */
1180 static Int segAddr_to_index ( const NSegment* seg )
1182 aspacem_assert(seg >= &nsegments[0] && seg < &nsegments[nsegments_used]);
1184 return seg - &nsegments[0];
1188 /* Find the next segment along from 'here', if it is a non-SkFree segment. */
1189 NSegment const * VG_(am_next_nsegment) ( const NSegment* here, Bool fwds )
1191 Int i = segAddr_to_index(here);
1193 if (fwds) {
1194 i++;
1195 if (i >= nsegments_used)
1196 return NULL;
1197 } else {
1198 i--;
1199 if (i < 0)
1200 return NULL;
1202 if (nsegments[i].kind == SkFree)
1203 return NULL;
1204 else
1205 return &nsegments[i];
1209 /* Trivial fn: return the total amount of space in anonymous mappings,
1210 both for V and the client. Is used for printing stats in
1211 out-of-memory messages. */
1212 ULong VG_(am_get_anonsize_total)( void )
1214 Int i;
1215 ULong total = 0;
1216 for (i = 0; i < nsegments_used; i++) {
1217 if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV) {
1218 total += (ULong)nsegments[i].end
1219 - (ULong)nsegments[i].start + 1ULL;
1222 return total;
1226 /* Test if a piece of memory is addressable by client or by valgrind with at
1227 least the "prot" protection permissions by examining the underlying
1228 segments. The KINDS argument specifies the allowed segments ADDR may
1229 belong to in order to be considered "valid".
1231 static
1232 Bool is_valid_for( UInt kinds, Addr start, SizeT len, UInt prot )
1234 Int i, iLo, iHi;
1235 Bool needR, needW, needX;
1237 if (len == 0)
1238 return True; /* somewhat dubious case */
1239 if (start + len < start)
1240 return False; /* reject wraparounds */
1242 needR = toBool(prot & VKI_PROT_READ);
1243 needW = toBool(prot & VKI_PROT_WRITE);
1244 needX = toBool(prot & VKI_PROT_EXEC);
1246 iLo = find_nsegment_idx(start);
1247 aspacem_assert(start >= nsegments[iLo].start);
1249 if (start+len-1 <= nsegments[iLo].end) {
1250 /* This is a speedup hack which avoids calling find_nsegment_idx
1251 a second time when possible. It is always correct to just
1252 use the "else" clause below, but is_valid_for_client is
1253 called a lot by the leak checker, so avoiding pointless calls
1254 to find_nsegment_idx, which can be expensive, is helpful. */
1255 iHi = iLo;
1256 } else {
1257 iHi = find_nsegment_idx(start + len - 1);
1260 for (i = iLo; i <= iHi; i++) {
1261 if ( (nsegments[i].kind & kinds) != 0
1262 && (needR ? nsegments[i].hasR : True)
1263 && (needW ? nsegments[i].hasW : True)
1264 && (needX ? nsegments[i].hasX : True) ) {
1265 /* ok */
1266 } else {
1267 return False;
1271 return True;
1274 /* Test if a piece of memory is addressable by the client with at
1275 least the "prot" protection permissions by examining the underlying
1276 segments. */
1277 Bool VG_(am_is_valid_for_client)( Addr start, SizeT len,
1278 UInt prot )
1280 const UInt kinds = SkFileC | SkAnonC | SkShmC;
1282 return is_valid_for(kinds, start, len, prot);
1285 /* Variant of VG_(am_is_valid_for_client) which allows free areas to
1286 be consider part of the client's addressable space. It also
1287 considers reservations to be allowable, since from the client's
1288 point of view they don't exist. */
1289 Bool VG_(am_is_valid_for_client_or_free_or_resvn)
1290 ( Addr start, SizeT len, UInt prot )
1292 const UInt kinds = SkFileC | SkAnonC | SkShmC | SkFree | SkResvn;
1294 return is_valid_for(kinds, start, len, prot);
1297 /* Checks if a piece of memory consists of either free or reservation
1298 segments. */
1299 Bool VG_(am_is_free_or_resvn)( Addr start, SizeT len )
1301 const UInt kinds = SkFree | SkResvn;
1303 return is_valid_for(kinds, start, len, 0);
1307 Bool VG_(am_is_valid_for_valgrind) ( Addr start, SizeT len, UInt prot )
1309 const UInt kinds = SkFileV | SkAnonV;
1311 return is_valid_for(kinds, start, len, prot);
1315 /* Returns True if any part of the address range is marked as having
1316 translations made from it. This is used to determine when to
1317 discard code, so if in doubt return True. */
1319 static Bool any_Ts_in_range ( Addr start, SizeT len )
1321 Int iLo, iHi, i;
1322 aspacem_assert(len > 0);
1323 aspacem_assert(start + len > start);
1324 iLo = find_nsegment_idx(start);
1325 iHi = find_nsegment_idx(start + len - 1);
1326 for (i = iLo; i <= iHi; i++) {
1327 if (nsegments[i].hasT)
1328 return True;
1330 return False;
1334 /* Check whether ADDR looks like an address or address-to-be located in an
1335 extensible client stack segment. Return true if
1336 (1) ADDR is located in an already mapped stack segment, OR
1337 (2) ADDR is located in a reservation segment into which an abutting SkAnonC
1338 segment can be extended. */
1339 Bool VG_(am_addr_is_in_extensible_client_stack)( Addr addr )
1341 const NSegment *seg = nsegments + find_nsegment_idx(addr);
1343 switch (seg->kind) {
1344 case SkFree:
1345 case SkAnonV:
1346 case SkFileV:
1347 case SkFileC:
1348 case SkShmC:
1349 return False;
1351 case SkResvn: {
1352 if (seg->smode != SmUpper) return False;
1353 /* If the abutting segment towards higher addresses is an SkAnonC
1354 segment, then ADDR is a future stack pointer. */
1355 const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ True);
1356 if (next == NULL || next->kind != SkAnonC) return False;
1358 /* OK; looks like a stack segment */
1359 return True;
1362 case SkAnonC: {
1363 /* If the abutting segment towards lower addresses is an SkResvn
1364 segment, then ADDR is a stack pointer into mapped memory. */
1365 const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ False);
1366 if (next == NULL || next->kind != SkResvn || next->smode != SmUpper)
1367 return False;
1369 /* OK; looks like a stack segment */
1370 return True;
1373 default:
1374 aspacem_assert(0); // should never happen
1378 /*-----------------------------------------------------------------*/
1379 /*--- ---*/
1380 /*--- Modifying the segment array, and constructing segments. ---*/
1381 /*--- ---*/
1382 /*-----------------------------------------------------------------*/
1384 /* Split the segment containing 'a' into two, so that 'a' is
1385 guaranteed to be the start of a new segment. If 'a' is already the
1386 start of a segment, do nothing. */
1388 static void split_nsegment_at ( Addr a )
1390 Int i, j;
1392 aspacem_assert(a > 0);
1393 aspacem_assert(VG_IS_PAGE_ALIGNED(a));
1395 i = find_nsegment_idx(a);
1396 aspacem_assert(i >= 0 && i < nsegments_used);
1398 if (nsegments[i].start == a)
1399 /* 'a' is already the start point of a segment, so nothing to be
1400 done. */
1401 return;
1403 /* else we have to slide the segments upwards to make a hole */
1404 if (nsegments_used >= VG_N_SEGMENTS)
1405 ML_(am_barf_toolow)("VG_N_SEGMENTS");
1406 for (j = nsegments_used-1; j > i; j--)
1407 nsegments[j+1] = nsegments[j];
1408 nsegments_used++;
1410 nsegments[i+1] = nsegments[i];
1411 nsegments[i+1].start = a;
1412 nsegments[i].end = a-1;
1414 if (nsegments[i].kind == SkFileV || nsegments[i].kind == SkFileC)
1415 nsegments[i+1].offset
1416 += ((ULong)nsegments[i+1].start) - ((ULong)nsegments[i].start);
1418 ML_(am_inc_refcount)(nsegments[i].fnIdx);
1420 aspacem_assert(sane_NSegment(&nsegments[i]));
1421 aspacem_assert(sane_NSegment(&nsegments[i+1]));
1425 /* Do the minimum amount of segment splitting necessary to ensure that
1426 sLo is the first address denoted by some segment and sHi is the
1427 highest address denoted by some other segment. Returns the indices
1428 of the lowest and highest segments in the range. */
1430 static
1431 void split_nsegments_lo_and_hi ( Addr sLo, Addr sHi,
1432 /*OUT*/Int* iLo,
1433 /*OUT*/Int* iHi )
1435 aspacem_assert(sLo < sHi);
1436 aspacem_assert(VG_IS_PAGE_ALIGNED(sLo));
1437 aspacem_assert(VG_IS_PAGE_ALIGNED(sHi+1));
1439 if (sLo > 0)
1440 split_nsegment_at(sLo);
1441 if (sHi < sHi+1)
1442 split_nsegment_at(sHi+1);
1444 *iLo = find_nsegment_idx(sLo);
1445 *iHi = find_nsegment_idx(sHi);
1446 aspacem_assert(0 <= *iLo && *iLo < nsegments_used);
1447 aspacem_assert(0 <= *iHi && *iHi < nsegments_used);
1448 aspacem_assert(*iLo <= *iHi);
1449 aspacem_assert(nsegments[*iLo].start == sLo);
1450 aspacem_assert(nsegments[*iHi].end == sHi);
1451 /* Not that I'm overly paranoid or anything, definitely not :-) */
1455 /* Add SEG to the collection, deleting/truncating any it overlaps.
1456 This deals with all the tricky cases of splitting up segments as
1457 needed. */
1459 static void add_segment ( const NSegment* seg )
1461 Int i, iLo, iHi, delta;
1462 Bool segment_is_sane;
1464 Addr sStart = seg->start;
1465 Addr sEnd = seg->end;
1467 aspacem_assert(sStart <= sEnd);
1468 aspacem_assert(VG_IS_PAGE_ALIGNED(sStart));
1469 aspacem_assert(VG_IS_PAGE_ALIGNED(sEnd+1));
1471 segment_is_sane = sane_NSegment(seg);
1472 if (!segment_is_sane) show_nsegment_full(0,-1,seg);
1473 aspacem_assert(segment_is_sane);
1475 split_nsegments_lo_and_hi( sStart, sEnd, &iLo, &iHi );
1477 /* Increase the reference count of SEG's name. We need to do this
1478 *before* decreasing the reference count of the names of the replaced
1479 segments. Consider the case where the segment name of SEG and one of
1480 the replaced segments are the same. If the refcount of that name is 1,
1481 then decrementing first would put the slot for that name on the free
1482 list. Attempting to increment the refcount later would then fail
1483 because the slot is no longer allocated. */
1484 ML_(am_inc_refcount)(seg->fnIdx);
1486 /* Now iLo .. iHi inclusive is the range of segment indices which
1487 seg will replace. If we're replacing more than one segment,
1488 slide those above the range down to fill the hole. Before doing
1489 that decrement the reference counters for the segments names of
1490 the replaced segments. */
1491 for (i = iLo; i <= iHi; ++i)
1492 ML_(am_dec_refcount)(nsegments[i].fnIdx);
1493 delta = iHi - iLo;
1494 aspacem_assert(delta >= 0);
1495 if (delta > 0) {
1496 for (i = iLo; i < nsegments_used-delta; i++)
1497 nsegments[i] = nsegments[i+delta];
1498 nsegments_used -= delta;
1501 nsegments[iLo] = *seg;
1503 (void)preen_nsegments();
1504 if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)");
1508 /* Clear out an NSegment record. */
1510 static void init_nsegment ( /*OUT*/NSegment* seg )
1512 seg->kind = SkFree;
1513 seg->start = 0;
1514 seg->end = 0;
1515 seg->smode = SmFixed;
1516 seg->dev = 0;
1517 seg->ino = 0;
1518 seg->mode = 0;
1519 seg->offset = 0;
1520 seg->fnIdx = -1;
1522 seg->hasR = seg->hasW = seg->hasX = seg->hasT
1523 = seg->isCH = False;
1524 #if defined(VGO_freebsd)
1525 seg->isFF = False;
1526 seg->ignore_offset = False;
1527 #endif
1531 /* Make an NSegment which holds a reservation. */
1533 static void init_resvn ( /*OUT*/NSegment* seg, Addr start, Addr end )
1535 aspacem_assert(start < end);
1536 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
1537 aspacem_assert(VG_IS_PAGE_ALIGNED(end+1));
1538 init_nsegment(seg);
1539 seg->kind = SkResvn;
1540 seg->start = start;
1541 seg->end = end;
1545 /*-----------------------------------------------------------------*/
1546 /*--- ---*/
1547 /*--- Startup, including reading /proc/self/maps. ---*/
1548 /*--- ---*/
1549 /*-----------------------------------------------------------------*/
1551 static void read_maps_callback ( Addr addr, SizeT len, UInt prot,
1552 ULong dev, ULong ino, Off64T offset,
1553 const HChar* filename, Bool ignore_offset )
1555 NSegment seg;
1556 init_nsegment( &seg );
1557 seg.start = addr;
1558 seg.end = addr+len-1;
1559 seg.dev = dev;
1560 seg.ino = ino;
1561 seg.offset = offset;
1562 #if defined(VGO_freebsd)
1563 seg.ignore_offset = ignore_offset;
1564 #endif
1565 seg.hasR = toBool(prot & VKI_PROT_READ);
1566 seg.hasW = toBool(prot & VKI_PROT_WRITE);
1567 seg.hasX = toBool(prot & VKI_PROT_EXEC);
1568 seg.hasT = False;
1570 /* A segment in the initial /proc/self/maps is considered a FileV
1571 segment if either it has a file name associated with it or both its
1572 device and inode numbers are != 0. See bug #124528. */
1573 seg.kind = SkAnonV;
1574 if (filename || (dev != 0 && ino != 0))
1575 seg.kind = SkFileV;
1577 # if defined(VGO_darwin)
1578 // GrP fixme no dev/ino on darwin
1579 if (offset != 0)
1580 seg.kind = SkFileV;
1581 # endif // defined(VGO_darwin)
1583 # if defined(VGP_arm_linux)
1584 /* The standard handling of entries read from /proc/self/maps will
1585 cause the faked up commpage segment to have type SkAnonV, which
1586 is a problem because it contains code we want the client to
1587 execute, and so later m_translate will segfault the client when
1588 it tries to go in there. Hence change the ownership of it here
1589 to the client (SkAnonC). The least-worst kludge I could think
1590 of. */
1591 if (addr == ARM_LINUX_FAKE_COMMPAGE_START
1592 && addr + len == ARM_LINUX_FAKE_COMMPAGE_END1
1593 && seg.kind == SkAnonV)
1594 seg.kind = SkAnonC;
1595 # endif // defined(VGP_arm_linux)
1597 if (filename)
1598 seg.fnIdx = ML_(am_allocate_segname)( filename );
1600 if (0) show_nsegment( 2,0, &seg );
1601 add_segment( &seg );
1604 Bool
1605 VG_(am_is_valid_for_aspacem_minAddr)( Addr addr, const HChar **errmsg )
1607 const Addr min = VKI_PAGE_SIZE;
1608 #if VG_WORDSIZE == 4
1609 const Addr max = 0x40000000; // 1Gb
1610 #else
1611 const Addr max = 0x200000000; // 8Gb
1612 #endif
1613 Bool ok = VG_IS_PAGE_ALIGNED(addr) && addr >= min && addr <= max;
1615 if (errmsg) {
1616 *errmsg = "";
1617 if (! ok) {
1618 const HChar fmt[] = "Must be a page aligned address between "
1619 "0x%lx and 0x%lx";
1620 static HChar buf[sizeof fmt + 2 * 16]; // large enough
1621 ML_(am_sprintf)(buf, fmt, min, max);
1622 *errmsg = buf;
1625 return ok;
1628 /* See description in pub_core_aspacemgr.h */
1629 Addr VG_(am_startup) ( Addr sp_at_startup )
1631 NSegment seg;
1632 Addr suggested_clstack_end;
1634 aspacem_assert(sizeof(Word) == sizeof(void*));
1635 aspacem_assert(sizeof(Addr) == sizeof(void*));
1636 aspacem_assert(sizeof(SizeT) == sizeof(void*));
1637 aspacem_assert(sizeof(SSizeT) == sizeof(void*));
1639 /* Initialise the string table for segment names. */
1640 ML_(am_segnames_init)();
1642 /* Check that we can store the largest imaginable dev, ino and
1643 offset numbers in an NSegment. */
1644 aspacem_assert(sizeof(seg.dev) == 8);
1645 aspacem_assert(sizeof(seg.ino) == 8);
1646 aspacem_assert(sizeof(seg.offset) == 8);
1647 aspacem_assert(sizeof(seg.mode) == 4);
1649 /* Add a single interval covering the entire address space. */
1650 init_nsegment(&seg);
1651 seg.kind = SkFree;
1652 seg.start = Addr_MIN;
1653 seg.end = Addr_MAX;
1654 nsegments[0] = seg;
1655 nsegments_used = 1;
1657 aspacem_minAddr = VG_(clo_aspacem_minAddr);
1659 // --- Darwin -------------------------------------------
1660 #if defined(VGO_darwin)
1662 # if VG_WORDSIZE == 4
1663 aspacem_maxAddr = (Addr) 0xffffffff;
1665 aspacem_cStart = aspacem_minAddr;
1666 aspacem_vStart = 0xf0000000; // 0xc0000000..0xf0000000 available
1667 # else
1668 aspacem_maxAddr = (Addr) 0x7fffffffffff;
1670 aspacem_cStart = aspacem_minAddr;
1671 aspacem_vStart = 0x700000000000; // 0x7000:00000000..0x7fff:5c000000 avail
1672 // 0x7fff:5c000000..0x7fff:ffe00000? is stack, dyld, shared cache
1673 # endif
1675 suggested_clstack_end = -1; // ignored; Mach-O specifies its stack
1677 // --- Freebsd ------------------------------------------
1678 #elif defined(VGO_freebsd)
1681 VG_(debugLog)(2, "aspacem",
1682 " sp_at_startup = 0x%010lx (supplied)\n",
1683 sp_at_startup );
1685 # if VG_WORDSIZE == 4
1687 aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1;
1688 # else
1689 aspacem_maxAddr = (Addr)0x2000000000ULL - 1; // 128G
1690 # ifdef ENABLE_INNER
1691 { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1;
1692 if (aspacem_maxAddr > cse)
1693 aspacem_maxAddr = cse;
1695 # endif // ENABLE_INNER
1696 # endif
1698 aspacem_cStart = aspacem_minAddr;
1699 aspacem_vStart = VG_PGROUNDUP((aspacem_minAddr + aspacem_maxAddr + 1) / 2);
1701 # ifdef ENABLE_INNER
1702 aspacem_vStart -= 0x10000000UL; // 512M
1703 # endif // ENABLE_INNER
1705 // starting with FreeBSD 10.4, the stack is created with a zone
1706 // that is marked MAP_GUARD. This zone is reserved but unmapped,
1707 // and fills the space up to the end of the segment
1708 // see man mmap
1710 // On x86 this is 0x3FE0000
1711 // And on amd64 it is 0x1FFE0000 (536739840)
1712 // There is less of an issue on amd64 as we just choose some arbitrary address rather then trying
1713 // to squeeze in just below the host stack
1715 // Some of this is in sys/vm/vm_map.c, for instance vm_map_stack and vm_map_stack_locked
1716 // These refer to the kernel global sgrowsiz, which seems to be the initial size
1717 // of the user stack, 128k on my system
1719 // This seems to be in the sysctl kern.sgrowsiz
1720 // Then there is kern.maxssiz which is the total stack size (grow size + guard area)
1721 // In other words guard area = maxssiz - sgrowsiz
1723 // Unfortunately there isn't a maxssiz32 for x86 on amd64
1724 // That means x86 on amd64 gets the amd64 stack size of 512M
1725 // which is really quite big for the x86 address space
1726 // so we can't use these syscalls. Maybe one day when all supported platforms
1727 // have them.
1729 #if 0
1730 // this block implements what is described above
1731 // note this needs
1732 // #include "pub_core_libcproc.h"
1733 SizeT kern_maxssiz;
1734 SizeT kern_sgrowsiz;
1735 SizeT sysctl_size = sizeof(SizeT);
1736 VG_(sysctlbyname)("kern.maxssiz", &kern_maxssiz, &sysctl_size, NULL, 0);
1737 VG_(sysctlbyname)("kern.sgrowsiz", &kern_sgrowsiz, &sysctl_size, NULL, 0);
1738 VG_(printf)("maxssiz %lx\n", kern_maxssiz);
1739 //suggested_clstack_end = aspacem_maxAddr - (kern_maxssiz - kern_sgrowsiz) + VKI_PAGE_SIZE;
1740 #endif
1742 // on amd64 we have oodles of space and just shove the new stack somewhere out of the way
1743 // x86 is far more constrained, and we put the new stack just below the stack passed in to V
1744 // except that it has stack space and the growth stack guard below it as decribed above
1745 // so we need to skip over the existing stack/growth area on x86
1747 # if VG_WORDSIZE == 4
1748 suggested_clstack_end = aspacem_maxAddr - 64*1024*1024UL
1749 + VKI_PAGE_SIZE;
1750 #else
1751 suggested_clstack_end = aspacem_maxAddr;
1752 #endif
1754 // --- Solaris ------------------------------------------
1755 #elif defined(VGO_solaris)
1756 # if VG_WORDSIZE == 4
1758 Intended address space partitioning:
1760 ,--------------------------------, 0x00000000
1762 |--------------------------------|
1763 | initial stack given to V by OS |
1764 |--------------------------------| 0x08000000
1765 | client text |
1766 |--------------------------------|
1769 |--------------------------------|
1770 | client stack |
1771 |--------------------------------| 0x58000000
1772 | V's text |
1773 |--------------------------------|
1776 |--------------------------------|
1777 | dynamic shared objects |
1778 '--------------------------------' 0xffffffff
1782 /* Anonymous pages need to fit under user limit (USERLIMIT32)
1783 which is 4KB + 16MB below the top of the 32-bit range. */
1784 # ifdef ENABLE_INNER
1785 aspacem_maxAddr = (Addr)0x4fffffff; // 1.25GB
1786 aspacem_vStart = (Addr)0x40000000; // 1GB
1787 # else
1788 aspacem_maxAddr = (Addr)0xfefff000 - 1; // 4GB - 16MB - 4KB
1789 aspacem_vStart = (Addr)0x50000000; // 1.25GB
1790 # endif
1791 # elif VG_WORDSIZE == 8
1793 Intended address space partitioning:
1795 ,--------------------------------, 0x00000000_00000000
1797 |--------------------------------| 0x00000000_00400000
1798 | client text |
1799 |--------------------------------|
1802 |--------------------------------|
1803 | client stack |
1804 |--------------------------------| 0x00000000_58000000
1805 | V's text |
1806 |--------------------------------|
1808 |--------------------------------|
1809 | dynamic shared objects |
1810 |--------------------------------| 0x0000001f_ffffffff
1813 |--------------------------------|
1814 | initial stack given to V by OS |
1815 '--------------------------------' 0xffffffff_ffffffff
1819 /* Kernel likes to place objects at the end of the address space.
1820 However accessing memory beyond 128GB makes memcheck slow
1821 (see memcheck/mc_main.c, internal representation). Therefore:
1822 - mmapobj() syscall is emulated so that libraries are subject to
1823 Valgrind's aspacemgr control
1824 - Kernel shared pages (such as schedctl and hrt) are left as they are
1825 because kernel cannot be told where they should be put */
1826 # ifdef ENABLE_INNER
1827 aspacem_maxAddr = (Addr) 0x0000000fffffffff; // 64GB
1828 aspacem_vStart = (Addr) 0x0000000800000000; // 32GB
1829 # else
1830 aspacem_maxAddr = (Addr) 0x0000001fffffffff; // 128GB
1831 aspacem_vStart = (Addr) 0x0000001000000000; // 64GB
1832 # endif
1833 # else
1834 # error "Unknown word size"
1835 # endif
1837 aspacem_cStart = aspacem_minAddr;
1838 # ifdef ENABLE_INNER
1839 suggested_clstack_end = (Addr) 0x37ff0000 - 1; // 64kB below V's text
1840 # else
1841 suggested_clstack_end = (Addr) 0x57ff0000 - 1; // 64kB below V's text
1842 # endif
1844 // --- Linux --------------------------------------------
1845 #else
1847 /* Establish address limits and block out unusable parts
1848 accordingly. */
1850 VG_(debugLog)(2, "aspacem",
1851 " sp_at_startup = 0x%010lx (supplied)\n",
1852 sp_at_startup );
1854 # if VG_WORDSIZE == 8
1855 aspacem_maxAddr = (Addr)0x2000000000ULL - 1; // 128G
1856 # ifdef ENABLE_INNER
1857 { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1;
1858 if (aspacem_maxAddr > cse)
1859 aspacem_maxAddr = cse;
1861 # endif
1862 # else
1863 aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1;
1864 # endif
1866 aspacem_cStart = aspacem_minAddr;
1867 aspacem_vStart = VG_PGROUNDUP(aspacem_minAddr
1868 + (aspacem_maxAddr - aspacem_minAddr + 1) / 2);
1869 # ifdef ENABLE_INNER
1870 aspacem_vStart -= 0x20000000; // 512M
1871 # endif
1873 suggested_clstack_end = aspacem_maxAddr - 16*1024*1024ULL
1874 + VKI_PAGE_SIZE;
1876 #endif /* #else of 'defined(VGO_solaris)' */
1877 // --- (end) --------------------------------------------
1879 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr));
1880 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1));
1881 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_cStart));
1882 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_vStart));
1883 aspacem_assert(VG_IS_PAGE_ALIGNED(suggested_clstack_end + 1));
1885 VG_(debugLog)(2, "aspacem",
1886 " minAddr = 0x%010lx (computed)\n",
1887 aspacem_minAddr);
1888 VG_(debugLog)(2, "aspacem",
1889 " maxAddr = 0x%010lx (computed)\n",
1890 aspacem_maxAddr);
1891 VG_(debugLog)(2, "aspacem",
1892 " cStart = 0x%010lx (computed)\n",
1893 aspacem_cStart);
1894 VG_(debugLog)(2, "aspacem",
1895 " vStart = 0x%010lx (computed)\n",
1896 aspacem_vStart);
1897 VG_(debugLog)(2, "aspacem",
1898 "suggested_clstack_end = 0x%010lx (computed)\n",
1899 suggested_clstack_end);
1901 if (aspacem_cStart > Addr_MIN) {
1902 init_resvn(&seg, Addr_MIN, aspacem_cStart-1);
1903 add_segment(&seg);
1905 if (aspacem_maxAddr < Addr_MAX) {
1906 init_resvn(&seg, aspacem_maxAddr+1, Addr_MAX);
1907 add_segment(&seg);
1910 /* Create a 1-page reservation at the notional initial
1911 client/valgrind boundary. This isn't strictly necessary, but
1912 because the advisor does first-fit and starts searches for
1913 valgrind allocations at the boundary, this is kind of necessary
1914 in order to get it to start allocating in the right place. */
1915 init_resvn(&seg, aspacem_vStart, aspacem_vStart + VKI_PAGE_SIZE - 1);
1916 add_segment(&seg);
1918 VG_(am_show_nsegments)(2, "Initial layout");
1920 VG_(debugLog)(2, "aspacem", "Reading /proc/self/maps\n");
1921 parse_procselfmaps( read_maps_callback, NULL );
1922 /* NB: on arm-linux, parse_procselfmaps automagically kludges up
1923 (iow, hands to its callbacks) a description of the ARM Commpage,
1924 since that's not listed in /proc/self/maps (kernel bug IMO). We
1925 have to fake up its existence in parse_procselfmaps and not
1926 merely add it here as an extra segment, because doing the latter
1927 causes sync checking to fail: we see we have an extra segment in
1928 the segments array, which isn't listed in /proc/self/maps.
1929 Hence we must make it appear that /proc/self/maps contained this
1930 segment all along. Sigh. */
1932 VG_(am_show_nsegments)(2, "With contents of /proc/self/maps");
1934 AM_SANITY_CHECK;
1935 return suggested_clstack_end;
1939 /*-----------------------------------------------------------------*/
1940 /*--- ---*/
1941 /*--- The core query-notify mechanism. ---*/
1942 /*--- ---*/
1943 /*-----------------------------------------------------------------*/
1945 /* Query aspacem to ask where a mapping should go. */
1947 Addr VG_(am_get_advisory) ( const MapRequest* req,
1948 Bool forClient,
1949 /*OUT*/Bool* ok )
1951 /* This function implements allocation policy.
1953 The nature of the allocation request is determined by req, which
1954 specifies the start and length of the request and indicates
1955 whether the start address is mandatory, a hint, or irrelevant,
1956 and by forClient, which says whether this is for the client or
1957 for V.
1959 Return values: the request can be vetoed (*ok is set to False),
1960 in which case the caller should not attempt to proceed with
1961 making the mapping. Otherwise, *ok is set to True, the caller
1962 may proceed, and the preferred address at which the mapping
1963 should happen is returned.
1965 Note that this is an advisory system only: the kernel can in
1966 fact do whatever it likes as far as placement goes, and we have
1967 no absolute control over it.
1969 Allocations will never be granted in a reserved area.
1971 The Default Policy is:
1973 Search the address space for two free intervals: one of them
1974 big enough to contain the request without regard to the
1975 specified address (viz, as if it was a floating request) and
1976 the other being able to contain the request at the specified
1977 address (viz, as if were a fixed request). Then, depending on
1978 the outcome of the search and the kind of request made, decide
1979 whether the request is allowable and what address to advise.
1981 The Default Policy is overridden by Policy Exception #1:
1983 If the request is for a fixed client map, we are prepared to
1984 grant it providing all areas inside the request are either
1985 free, reservations, or mappings belonging to the client. In
1986 other words we are prepared to let the client trash its own
1987 mappings if it wants to.
1989 The Default Policy is overridden by Policy Exception #2:
1991 If the request is for a hinted client map, we are prepared to
1992 grant it providing all areas inside the request are either
1993 free or reservations. In other words we are prepared to let
1994 the client have a hinted mapping anywhere it likes provided
1995 it does not trash either any of its own mappings or any of
1996 valgrind's mappings.
1998 Int i, j;
1999 Addr holeStart, holeEnd, holeLen;
2000 Bool fixed_not_required;
2002 #if defined(VGO_solaris)
2003 Addr startPoint = forClient ? aspacem_vStart - 1 : aspacem_maxAddr - 1;
2004 #else
2005 Addr startPoint = forClient ? aspacem_cStart : aspacem_vStart;
2006 #endif /* VGO_solaris */
2008 Addr reqStart = req->rkind==MFixed || req->rkind==MHint ? req->start : 0;
2009 Addr reqEnd = reqStart + req->len - 1;
2010 Addr reqLen = req->len;
2012 /* These hold indices for segments found during search, or -1 if not
2013 found. */
2014 Int floatIdx = -1;
2015 Int fixedIdx = -1;
2017 aspacem_assert(nsegments_used > 0);
2019 if (0) {
2020 VG_(am_show_nsegments)(0,"getAdvisory");
2021 VG_(debugLog)(0,"aspacem", "getAdvisory 0x%lx %lu\n",
2022 req->start, req->len);
2025 /* Reject zero-length requests */
2026 if (req->len == 0) {
2027 *ok = False;
2028 return 0;
2031 /* Reject wraparounds */
2032 if (req->start + req->len < req->start) {
2033 *ok = False;
2034 return 0;
2037 /* ------ Implement Policy Exception #1 ------ */
2039 if (forClient && req->rkind == MFixed) {
2040 Int iLo = find_nsegment_idx(reqStart);
2041 Int iHi = find_nsegment_idx(reqEnd);
2042 Bool allow = True;
2043 for (i = iLo; i <= iHi; i++) {
2044 if (nsegments[i].kind == SkFree
2045 || nsegments[i].kind == SkFileC
2046 || nsegments[i].kind == SkAnonC
2047 || nsegments[i].kind == SkShmC
2048 || nsegments[i].kind == SkResvn) {
2049 /* ok */
2050 } else {
2051 allow = False;
2052 break;
2055 if (allow) {
2056 /* Acceptable. Granted. */
2057 *ok = True;
2058 return reqStart;
2060 /* Not acceptable. Fail. */
2061 *ok = False;
2062 return 0;
2065 /* ------ Implement Policy Exception #2 ------ */
2067 if (forClient && req->rkind == MHint) {
2068 Int iLo = find_nsegment_idx(reqStart);
2069 Int iHi = find_nsegment_idx(reqEnd);
2070 Bool allow = True;
2071 for (i = iLo; i <= iHi; i++) {
2072 if (nsegments[i].kind == SkFree
2073 || nsegments[i].kind == SkResvn) {
2074 /* ok */
2075 } else {
2076 allow = False;
2077 break;
2080 if (allow) {
2081 /* Acceptable. Granted. */
2082 *ok = True;
2083 return reqStart;
2085 /* Not acceptable. Fall through to the default policy. */
2088 /* ------ Implement the Default Policy ------ */
2090 /* Don't waste time looking for a fixed match if not requested to. */
2091 fixed_not_required = req->rkind == MAny || req->rkind == MAlign;
2093 i = find_nsegment_idx(startPoint);
2095 #if defined(VGO_solaris)
2096 # define UPDATE_INDEX(index) \
2097 (index)--; \
2098 if ((index) <= 0) \
2099 (index) = nsegments_used - 1;
2100 # define ADVISE_ADDRESS(segment) \
2101 VG_PGROUNDDN((segment)->end + 1 - reqLen)
2102 # define ADVISE_ADDRESS_ALIGNED(segment) \
2103 VG_ROUNDDN((segment)->end + 1 - reqLen, req->start)
2105 #else
2107 # define UPDATE_INDEX(index) \
2108 (index)++; \
2109 if ((index) >= nsegments_used) \
2110 (index) = 0;
2111 # define ADVISE_ADDRESS(segment) \
2112 (segment)->start
2113 # define ADVISE_ADDRESS_ALIGNED(segment) \
2114 VG_ROUNDUP((segment)->start, req->start)
2115 #endif /* VGO_solaris */
2117 /* Examine holes from index i back round to i-1. Record the
2118 index first fixed hole and the first floating hole which would
2119 satisfy the request. */
2120 for (j = 0; j < nsegments_used; j++) {
2122 if (nsegments[i].kind != SkFree) {
2123 UPDATE_INDEX(i);
2124 continue;
2127 holeStart = nsegments[i].start;
2128 holeEnd = nsegments[i].end;
2130 /* Stay sane .. */
2131 aspacem_assert(holeStart <= holeEnd);
2132 aspacem_assert(aspacem_minAddr <= holeStart);
2133 aspacem_assert(holeEnd <= aspacem_maxAddr);
2135 if (req->rkind == MAlign) {
2136 holeStart = VG_ROUNDUP(holeStart, req->start);
2137 if (holeStart >= holeEnd) {
2138 /* This hole can't be used. */
2139 UPDATE_INDEX(i);
2140 continue;
2144 /* See if it's any use to us. */
2145 holeLen = holeEnd - holeStart + 1;
2147 if (fixedIdx == -1 && holeStart <= reqStart && reqEnd <= holeEnd)
2148 fixedIdx = i;
2150 if (floatIdx == -1 && holeLen >= reqLen)
2151 floatIdx = i;
2153 /* Don't waste time searching once we've found what we wanted. */
2154 if ((fixed_not_required || fixedIdx >= 0) && floatIdx >= 0)
2155 break;
2157 UPDATE_INDEX(i);
2160 aspacem_assert(fixedIdx >= -1 && fixedIdx < nsegments_used);
2161 if (fixedIdx >= 0)
2162 aspacem_assert(nsegments[fixedIdx].kind == SkFree);
2164 aspacem_assert(floatIdx >= -1 && floatIdx < nsegments_used);
2165 if (floatIdx >= 0)
2166 aspacem_assert(nsegments[floatIdx].kind == SkFree);
2168 AM_SANITY_CHECK;
2170 /* Now see if we found anything which can satisfy the request. */
2171 switch (req->rkind) {
2172 case MFixed:
2173 if (fixedIdx >= 0) {
2174 *ok = True;
2175 return req->start;
2176 } else {
2177 *ok = False;
2178 return 0;
2180 break;
2181 case MHint:
2182 if (fixedIdx >= 0) {
2183 *ok = True;
2184 return req->start;
2186 if (floatIdx >= 0) {
2187 *ok = True;
2188 return ADVISE_ADDRESS(&nsegments[floatIdx]);
2190 *ok = False;
2191 return 0;
2192 case MAny:
2193 if (floatIdx >= 0) {
2194 *ok = True;
2195 return ADVISE_ADDRESS(&nsegments[floatIdx]);
2197 *ok = False;
2198 return 0;
2199 case MAlign:
2200 if (floatIdx >= 0) {
2201 *ok = True;
2202 return ADVISE_ADDRESS_ALIGNED(&nsegments[floatIdx]);
2204 *ok = False;
2205 return 0;
2206 default:
2207 break;
2210 /*NOTREACHED*/
2211 ML_(am_barf)("getAdvisory: unknown request kind");
2212 *ok = False;
2213 return 0;
2215 #undef UPDATE_INDEX
2216 #undef ADVISE_ADDRESS
2217 #undef ADVISE_ADDRESS_ALIGNED
2220 /* Convenience wrapper for VG_(am_get_advisory) for client floating or
2221 fixed requests. If start is zero, a floating request is issued; if
2222 nonzero, a fixed request at that address is issued. Same comments
2223 about return values apply. */
2225 Addr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len,
2226 /*OUT*/Bool* ok )
2228 MapRequest mreq;
2229 mreq.rkind = start==0 ? MAny : MFixed;
2230 mreq.start = start;
2231 mreq.len = len;
2232 return VG_(am_get_advisory)( &mreq, True/*forClient*/, ok );
2235 /* Similar to VG_(am_find_nsegment) but only returns free segments. */
2236 static NSegment const * VG_(am_find_free_nsegment) ( Addr a )
2238 Int i = find_nsegment_idx(a);
2239 aspacem_assert(i >= 0 && i < nsegments_used);
2240 aspacem_assert(nsegments[i].start <= a);
2241 aspacem_assert(a <= nsegments[i].end);
2242 if (nsegments[i].kind == SkFree)
2243 return &nsegments[i];
2244 else
2245 return NULL;
2248 Bool VG_(am_covered_by_single_free_segment)
2249 ( Addr start, SizeT len)
2251 NSegment const* segLo = VG_(am_find_free_nsegment)( start );
2252 NSegment const* segHi = VG_(am_find_free_nsegment)( start + len - 1 );
2254 return segLo != NULL && segHi != NULL && segLo == segHi;
2258 /* Notifies aspacem that the client completed an mmap successfully.
2259 The segment array is updated accordingly. If the returned Bool is
2260 True, the caller should immediately discard translations from the
2261 specified address range. */
2263 Bool
2264 VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
2265 Int fd, Off64T offset )
2267 HChar buf[VKI_PATH_MAX];
2268 ULong dev, ino;
2269 UInt mode;
2270 NSegment seg;
2271 Bool needDiscard;
2273 aspacem_assert(len > 0);
2274 aspacem_assert(VG_IS_PAGE_ALIGNED(a));
2275 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2276 aspacem_assert(VG_IS_PAGE_ALIGNED(offset));
2278 /* Discard is needed if any of the just-trashed range had T. */
2279 needDiscard = any_Ts_in_range( a, len );
2281 init_nsegment( &seg );
2282 seg.kind = (flags & (VKI_MAP_ANONYMOUS | VKI_MAP_STACK)) ? SkAnonC : SkFileC;
2283 seg.start = a;
2284 seg.end = a + len - 1;
2285 seg.hasR = toBool(prot & VKI_PROT_READ);
2286 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2287 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2288 if (!(flags & (VKI_MAP_ANONYMOUS | VKI_MAP_STACK))) {
2289 // Nb: We ignore offset requests in anonymous mmaps (see bug #126722)
2290 seg.offset = offset;
2291 if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
2292 seg.dev = dev;
2293 seg.ino = ino;
2294 seg.mode = mode;
2296 if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
2297 seg.fnIdx = ML_(am_allocate_segname)( buf );
2299 #if defined(VGO_freebsd)
2300 seg.isFF = (flags & VKI_MAP_FIXED);
2301 #endif
2303 add_segment( &seg );
2304 AM_SANITY_CHECK;
2305 return needDiscard;
2308 /* Notifies aspacem that the client completed a shmat successfully.
2309 The segment array is updated accordingly. If the returned Bool is
2310 True, the caller should immediately discard translations from the
2311 specified address range. */
2313 Bool
2314 VG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot )
2316 NSegment seg;
2317 Bool needDiscard;
2319 aspacem_assert(len > 0);
2320 aspacem_assert(VG_IS_PAGE_ALIGNED(a));
2321 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2323 /* Discard is needed if any of the just-trashed range had T. */
2324 needDiscard = any_Ts_in_range( a, len );
2326 init_nsegment( &seg );
2327 seg.kind = SkShmC;
2328 seg.start = a;
2329 seg.end = a + len - 1;
2330 seg.offset = 0;
2331 seg.hasR = toBool(prot & VKI_PROT_READ);
2332 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2333 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2334 add_segment( &seg );
2335 AM_SANITY_CHECK;
2336 return needDiscard;
2339 /* Notifies aspacem that an mprotect was completed successfully. The
2340 segment array is updated accordingly. Note, as with
2341 VG_(am_notify_munmap), it is not the job of this function to reject
2342 stupid mprotects, for example the client doing mprotect of
2343 non-client areas. Such requests should be intercepted earlier, by
2344 the syscall wrapper for mprotect. This function merely records
2345 whatever it is told. If the returned Bool is True, the caller
2346 should immediately discard translations from the specified address
2347 range. */
2349 Bool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot )
2351 Int i, iLo, iHi;
2352 Bool newR, newW, newX, needDiscard;
2354 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2355 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2357 if (len == 0)
2358 return False;
2360 newR = toBool(prot & VKI_PROT_READ);
2361 newW = toBool(prot & VKI_PROT_WRITE);
2362 newX = toBool(prot & VKI_PROT_EXEC);
2364 /* Discard is needed if we're dumping X permission */
2365 needDiscard = any_Ts_in_range( start, len ) && !newX;
2367 split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
2369 iLo = find_nsegment_idx(start);
2370 iHi = find_nsegment_idx(start + len - 1);
2372 for (i = iLo; i <= iHi; i++) {
2373 /* Apply the permissions to all relevant segments. */
2374 switch (nsegments[i].kind) {
2375 case SkAnonC: case SkAnonV: case SkFileC: case SkFileV: case SkShmC:
2376 nsegments[i].hasR = newR;
2377 nsegments[i].hasW = newW;
2378 nsegments[i].hasX = newX;
2379 aspacem_assert(sane_NSegment(&nsegments[i]));
2380 break;
2381 default:
2382 break;
2386 /* Changing permissions could have made previously un-mergable
2387 segments mergeable. Therefore have to re-preen them. */
2388 (void)preen_nsegments();
2389 AM_SANITY_CHECK;
2390 return needDiscard;
2394 /* Notifies aspacem that an munmap completed successfully. The
2395 segment array is updated accordingly. As with
2396 VG_(am_notify_mprotect), we merely record the given info, and don't
2397 check it for sensibleness. If the returned Bool is True, the
2398 caller should immediately discard translations from the specified
2399 address range. */
2401 Bool VG_(am_notify_munmap)( Addr start, SizeT len )
2403 NSegment seg;
2404 Bool needDiscard;
2405 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2406 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2408 if (len == 0)
2409 return False;
2411 needDiscard = any_Ts_in_range( start, len );
2413 init_nsegment( &seg );
2414 seg.start = start;
2415 seg.end = start + len - 1;
2417 /* The segment becomes unused (free). Segments from above
2418 aspacem_maxAddr were originally SkResvn and so we make them so
2419 again. Note, this isn't really right when the segment straddles
2420 the aspacem_maxAddr boundary - then really it should be split in
2421 two, the lower part marked as SkFree and the upper part as
2422 SkResvn. Ah well. */
2423 if (start > aspacem_maxAddr
2424 && /* check previous comparison is meaningful */
2425 aspacem_maxAddr < Addr_MAX)
2426 seg.kind = SkResvn;
2427 else
2428 /* Ditto for segments from below aspacem_minAddr. */
2429 if (seg.end < aspacem_minAddr && aspacem_minAddr > 0)
2430 seg.kind = SkResvn;
2431 else
2432 seg.kind = SkFree;
2434 add_segment( &seg );
2436 /* Unmapping could create two adjacent free segments, so a preen is
2437 needed. add_segment() will do that, so no need to here. */
2438 AM_SANITY_CHECK;
2439 return needDiscard;
2443 /*-----------------------------------------------------------------*/
2444 /*--- ---*/
2445 /*--- Handling mappings which do not arise directly from the ---*/
2446 /*--- simulation of the client. ---*/
2447 /*--- ---*/
2448 /*-----------------------------------------------------------------*/
2450 /* --- --- --- map, unmap, protect --- --- --- */
2452 /* Map a file at a fixed address for the client, and update the
2453 segment array accordingly. */
2455 SysRes VG_(am_mmap_file_fixed_client)
2456 ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset )
2458 UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
2459 return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
2460 fd, offset, NULL);
2463 SysRes VG_(am_mmap_file_fixed_client_flags)
2464 ( Addr start, SizeT length, UInt prot, UInt flags, Int fd, Off64T offset )
2466 return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
2467 fd, offset, NULL);
2470 SysRes VG_(am_mmap_named_file_fixed_client)
2471 ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name )
2473 UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
2474 return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
2475 fd, offset, name);
2478 SysRes VG_(am_mmap_named_file_fixed_client_flags)
2479 ( Addr start, SizeT length, UInt prot, UInt flags,
2480 Int fd, Off64T offset, const HChar *name )
2482 SysRes sres;
2483 NSegment seg;
2484 Addr advised;
2485 Bool ok;
2486 MapRequest req;
2487 ULong dev, ino;
2488 UInt mode;
2489 HChar buf[VKI_PATH_MAX];
2491 /* Not allowable. */
2492 if (length == 0
2493 || !VG_IS_PAGE_ALIGNED(start)
2494 || !VG_IS_PAGE_ALIGNED(offset))
2495 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2497 /* Ask for an advisory. If it's negative, fail immediately. */
2498 req.rkind = MFixed;
2499 req.start = start;
2500 req.len = length;
2501 advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
2502 if (!ok || advised != start)
2503 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2505 /* We have been advised that the mapping is allowable at the
2506 specified address. So hand it off to the kernel, and propagate
2507 any resulting failure immediately. */
2508 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
2509 sres = VG_(am_do_mmap_NO_NOTIFY)(
2510 start, length, prot, flags,
2511 fd, offset
2513 if (sr_isError(sres))
2514 return sres;
2516 if (sr_Res(sres) != start) {
2517 /* I don't think this can happen. It means the kernel made a
2518 fixed map succeed but not at the requested location. Try to
2519 repair the damage, then return saying the mapping failed. */
2520 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2521 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2524 /* Ok, the mapping succeeded. Now notify the interval map. */
2525 init_nsegment( &seg );
2526 seg.kind = SkFileC;
2527 seg.start = start;
2528 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2529 seg.offset = offset;
2530 seg.hasR = toBool(prot & VKI_PROT_READ);
2531 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2532 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2533 if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
2534 seg.dev = dev;
2535 seg.ino = ino;
2536 seg.mode = mode;
2538 if (name) {
2539 seg.fnIdx = ML_(am_allocate_segname)( name );
2540 } else if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
2541 seg.fnIdx = ML_(am_allocate_segname)( buf );
2543 #if defined(VGO_freebsd)
2544 seg.isFF = (flags & VKI_MAP_FIXED);
2545 #endif
2546 add_segment( &seg );
2548 AM_SANITY_CHECK;
2549 return sres;
2553 /* Map anonymously at a fixed address for the client, and update
2554 the segment array accordingly. */
2556 SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
2558 SysRes sres;
2559 NSegment seg;
2560 Addr advised;
2561 Bool ok;
2562 MapRequest req;
2564 /* Not allowable. */
2565 if (length == 0 || !VG_IS_PAGE_ALIGNED(start))
2566 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2568 /* Ask for an advisory. If it's negative, fail immediately. */
2569 req.rkind = MFixed;
2570 req.start = start;
2571 req.len = length;
2572 advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
2573 if (!ok || advised != start)
2574 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2576 /* We have been advised that the mapping is allowable at the
2577 specified address. So hand it off to the kernel, and propagate
2578 any resulting failure immediately. */
2579 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
2580 sres = VG_(am_do_mmap_NO_NOTIFY)(
2581 start, length, prot,
2582 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2583 0, 0
2585 if (sr_isError(sres))
2586 return sres;
2588 if (sr_Res(sres) != start) {
2589 /* I don't think this can happen. It means the kernel made a
2590 fixed map succeed but not at the requested location. Try to
2591 repair the damage, then return saying the mapping failed. */
2592 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2593 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2596 /* Ok, the mapping succeeded. Now notify the interval map. */
2597 init_nsegment( &seg );
2598 seg.kind = SkAnonC;
2599 seg.start = start;
2600 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2601 seg.hasR = toBool(prot & VKI_PROT_READ);
2602 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2603 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2604 add_segment( &seg );
2606 AM_SANITY_CHECK;
2607 return sres;
2611 /* Map anonymously at an unconstrained address for the client, and
2612 update the segment array accordingly. */
2614 static SysRes am_mmap_anon_float_client ( SizeT length, Int prot, Bool isCH )
2616 SysRes sres;
2617 NSegment seg;
2618 Addr advised;
2619 Bool ok;
2620 MapRequest req;
2622 /* Not allowable. */
2623 if (length == 0)
2624 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2626 /* Ask for an advisory. If it's negative, fail immediately. */
2627 req.rkind = MAny;
2628 req.start = 0;
2629 req.len = length;
2630 advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
2631 if (!ok)
2632 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2634 /* We have been advised that the mapping is allowable at the
2635 advised address. So hand it off to the kernel, and propagate
2636 any resulting failure immediately. */
2637 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
2638 sres = VG_(am_do_mmap_NO_NOTIFY)(
2639 advised, length, prot,
2640 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2641 0, 0
2643 if (sr_isError(sres))
2644 return sres;
2646 if (sr_Res(sres) != advised) {
2647 /* I don't think this can happen. It means the kernel made a
2648 fixed map succeed but not at the requested location. Try to
2649 repair the damage, then return saying the mapping failed. */
2650 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2651 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2654 /* Ok, the mapping succeeded. Now notify the interval map. */
2655 init_nsegment( &seg );
2656 seg.kind = SkAnonC;
2657 seg.start = advised;
2658 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2659 seg.hasR = toBool(prot & VKI_PROT_READ);
2660 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2661 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2662 seg.isCH = isCH;
2663 add_segment( &seg );
2665 AM_SANITY_CHECK;
2666 return sres;
2669 SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
2671 return am_mmap_anon_float_client (length, prot, False /* isCH */);
2674 /* Map anonymously at an unconstrained address for V, and update the
2675 segment array accordingly. This is fundamentally how V allocates
2676 itself more address space when needed. */
2678 SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
2680 SysRes sres;
2681 NSegment seg;
2682 Addr advised;
2683 Bool ok;
2684 MapRequest req;
2686 /* Not allowable. */
2687 if (length == 0)
2688 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2690 /* Ask for an advisory. If it's negative, fail immediately. */
2691 req.rkind = MAny;
2692 req.start = 0;
2693 req.len = length;
2694 advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
2695 if (!ok)
2696 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2698 // On Darwin, for anonymous maps you can pass in a tag which is used by
2699 // programs like vmmap for statistical purposes.
2700 #ifndef VM_TAG_VALGRIND
2701 # define VM_TAG_VALGRIND 0
2702 #endif
2704 /* We have been advised that the mapping is allowable at the
2705 specified address. So hand it off to the kernel, and propagate
2706 any resulting failure immediately. */
2707 /* GrP fixme darwin: use advisory as a hint only, otherwise syscall in
2708 another thread can pre-empt our spot. [At one point on the DARWIN
2709 branch the VKI_MAP_FIXED was commented out; unclear if this is
2710 necessary or not given the second Darwin-only call that immediately
2711 follows if this one fails. --njn]
2712 Also, an inner valgrind cannot observe the mmap syscalls done by
2713 the outer valgrind. The outer Valgrind might make the mmap
2714 fail here, as the inner valgrind believes that a segment is free,
2715 while it is in fact used by the outer valgrind.
2716 So, for an inner valgrind, similarly to DARWIN, if the fixed mmap
2717 fails, retry the mmap without map fixed.
2718 This is a kludge which on linux is only activated for the inner.
2719 The state of the inner aspacemgr is not made correct by this kludge
2720 and so a.o. VG_(am_do_sync_check) could fail.
2721 A proper solution implies a better collaboration between the
2722 inner and the outer (e.g. inner VG_(am_get_advisory) should do
2723 a client request to call the outer VG_(am_get_advisory). */
2724 sres = VG_(am_do_mmap_NO_NOTIFY)(
2725 advised, length,
2726 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
2727 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2728 VM_TAG_VALGRIND, 0
2730 #if defined(VGO_darwin) || defined(ENABLE_INNER)
2731 /* Kludge on Darwin and inner linux if the fixed mmap failed. */
2732 if (sr_isError(sres)) {
2733 /* try again, ignoring the advisory */
2734 sres = VG_(am_do_mmap_NO_NOTIFY)(
2735 0, length,
2736 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
2737 /*VKI_MAP_FIXED|*/VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2738 VM_TAG_VALGRIND, 0
2741 #endif
2742 if (sr_isError(sres))
2743 return sres;
2745 #if defined(VGO_linux) && !defined(ENABLE_INNER)
2746 /* Doing the check only in linux not inner, as the below
2747 check can fail when the kludge above has been used. */
2748 if (sr_Res(sres) != advised) {
2749 /* I don't think this can happen. It means the kernel made a
2750 fixed map succeed but not at the requested location. Try to
2751 repair the damage, then return saying the mapping failed. */
2752 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2753 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2755 #endif
2757 /* Ok, the mapping succeeded. Now notify the interval map. */
2758 init_nsegment( &seg );
2759 seg.kind = SkAnonV;
2760 seg.start = sr_Res(sres);
2761 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2762 seg.hasR = True;
2763 seg.hasW = True;
2764 seg.hasX = True;
2765 add_segment( &seg );
2767 AM_SANITY_CHECK;
2768 return sres;
2771 /* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
2773 SysRes VG_(am_shadow_alloc)(SizeT size)
2775 return VG_(am_mmap_anon_float_valgrind)( size );
2778 /* Map a file at an unconstrained address for V, and update the
2779 segment array accordingly. Use the provided flags */
2781 static SysRes VG_(am_mmap_file_float_valgrind_flags) ( SizeT length, UInt prot,
2782 UInt flags,
2783 Int fd, Off64T offset )
2785 SysRes sres;
2786 NSegment seg;
2787 Addr advised;
2788 Bool ok;
2789 MapRequest req;
2790 ULong dev, ino;
2791 UInt mode;
2792 HChar buf[VKI_PATH_MAX];
2794 /* Not allowable. */
2795 if (length == 0 || !VG_IS_PAGE_ALIGNED(offset))
2796 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2798 /* Ask for an advisory. If it's negative, fail immediately. */
2799 req.rkind = MAny;
2800 req.start = 0;
2801 #if defined(VGA_arm) || defined(VGA_arm64) \
2802 || defined(VGA_mips32) || defined(VGA_mips64) || defined(VGA_nanomips)
2803 aspacem_assert(VKI_SHMLBA >= VKI_PAGE_SIZE);
2804 #else
2805 aspacem_assert(VKI_SHMLBA == VKI_PAGE_SIZE);
2806 #endif
2807 if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags)) {
2808 /* arm-linux only. See ML_(generic_PRE_sys_shmat) and bug 290974 */
2809 req.len = length + VKI_SHMLBA - VKI_PAGE_SIZE;
2810 } else {
2811 req.len = length;
2813 advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
2814 if (!ok)
2815 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2816 if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags))
2817 advised = VG_ROUNDUP(advised, VKI_SHMLBA);
2819 /* We have been advised that the mapping is allowable at the
2820 specified address. So hand it off to the kernel, and propagate
2821 any resulting failure immediately. */
2822 sres = VG_(am_do_mmap_NO_NOTIFY)(
2823 advised, length, prot,
2824 flags,
2825 fd, offset
2827 if (sr_isError(sres))
2828 return sres;
2830 if (sr_Res(sres) != advised) {
2831 /* I don't think this can happen. It means the kernel made a
2832 fixed map succeed but not at the requested location. Try to
2833 repair the damage, then return saying the mapping failed. */
2834 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
2835 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2838 /* Ok, the mapping succeeded. Now notify the interval map. */
2839 init_nsegment( &seg );
2840 seg.kind = SkFileV;
2841 seg.start = sr_Res(sres);
2842 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2843 seg.offset = offset;
2844 seg.hasR = toBool(prot & VKI_PROT_READ);
2845 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2846 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2847 if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
2848 seg.dev = dev;
2849 seg.ino = ino;
2850 seg.mode = mode;
2852 if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
2853 seg.fnIdx = ML_(am_allocate_segname)( buf );
2855 #if defined(VGO_freebsd)
2856 seg.isFF = (flags & VKI_MAP_FIXED);
2857 #endif
2858 add_segment( &seg );
2860 AM_SANITY_CHECK;
2861 return sres;
2863 /* Map privately a file at an unconstrained address for V, and update the
2864 segment array accordingly. This is used by V for transiently
2865 mapping in object files to read their debug info. */
2867 SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot,
2868 Int fd, Off64T offset )
2870 return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
2871 VKI_MAP_FIXED|VKI_MAP_PRIVATE,
2872 fd, offset );
2875 SysRes VG_(am_shared_mmap_file_float_valgrind)
2876 ( SizeT length, UInt prot, Int fd, Off64T offset )
2878 return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
2879 VKI_MAP_FIXED|VKI_MAP_SHARED,
2880 fd, offset );
2883 /* Similar to VG_(am_mmap_anon_float_client) but also
2884 marks the segment as containing the client heap. This is for the benefit
2885 of the leak checker which needs to be able to identify such segments
2886 so as not to use them as sources of roots during leak checks. */
2887 SysRes VG_(am_mmap_client_heap) ( SizeT length, Int prot )
2889 return am_mmap_anon_float_client (length, prot, True /* isCH */);
2892 /* --- --- munmap helper --- --- */
2894 static
2895 SysRes am_munmap_both_wrk ( /*OUT*/Bool* need_discard,
2896 Addr start, SizeT len, Bool forClient )
2898 Bool d;
2899 SysRes sres;
2901 /* Be safe with this regardless of return path. */
2902 *need_discard = False;
2904 if (!VG_IS_PAGE_ALIGNED(start))
2905 goto eINVAL;
2907 if (len == 0) {
2908 *need_discard = False;
2909 return VG_(mk_SysRes_Success)( 0 );
2912 if (start + len < len)
2913 goto eINVAL;
2915 len = VG_PGROUNDUP(len);
2916 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2917 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2919 if (forClient) {
2920 if (!VG_(am_is_valid_for_client_or_free_or_resvn)
2921 ( start, len, VKI_PROT_NONE ))
2922 goto eINVAL;
2923 } else {
2924 if (!VG_(am_is_valid_for_valgrind)
2925 ( start, len, VKI_PROT_NONE ))
2926 goto eINVAL;
2929 d = any_Ts_in_range( start, len );
2931 sres = ML_(am_do_munmap_NO_NOTIFY)( start, len );
2932 if (sr_isError(sres))
2933 return sres;
2935 VG_(am_notify_munmap)( start, len );
2936 AM_SANITY_CHECK;
2937 *need_discard = d;
2938 return sres;
2940 eINVAL:
2941 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2944 /* Unmap the given address range and update the segment array
2945 accordingly. This fails if the range isn't valid for the client.
2946 If *need_discard is True after a successful return, the caller
2947 should immediately discard translations from the specified address
2948 range. */
2950 SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
2951 Addr start, SizeT len )
2953 return am_munmap_both_wrk( need_discard, start, len, True/*client*/ );
2956 /* Unmap the given address range and update the segment array
2957 accordingly. This fails if the range isn't valid for valgrind. */
2959 SysRes VG_(am_munmap_valgrind)( Addr start, SizeT len )
2961 Bool need_discard;
2962 SysRes r = am_munmap_both_wrk( &need_discard,
2963 start, len, False/*valgrind*/ );
2964 /* If this assertion fails, it means we allowed translations to be
2965 made from a V-owned section. Which shouldn't happen. */
2966 if (!sr_isError(r))
2967 aspacem_assert(!need_discard);
2968 return r;
2971 /* Let (start,len) denote an area within a single Valgrind-owned
2972 segment (anon or file). Change the ownership of [start, start+len)
2973 to the client instead. Fails if (start,len) does not denote a
2974 suitable segment. */
2976 Bool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len )
2978 Int i, iLo, iHi;
2980 if (len == 0)
2981 return True;
2982 if (start + len < start)
2983 return False;
2984 if (!VG_IS_PAGE_ALIGNED(start) || !VG_IS_PAGE_ALIGNED(len))
2985 return False;
2987 i = find_nsegment_idx(start);
2988 if (nsegments[i].kind != SkFileV && nsegments[i].kind != SkAnonV)
2989 return False;
2990 if (start+len-1 > nsegments[i].end)
2991 return False;
2993 aspacem_assert(start >= nsegments[i].start);
2994 aspacem_assert(start+len-1 <= nsegments[i].end);
2996 /* This scheme is like how mprotect works: split the to-be-changed
2997 range into its own segment(s), then mess with them (it). There
2998 should be only one. */
2999 split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
3000 aspacem_assert(iLo == iHi);
3001 switch (nsegments[iLo].kind) {
3002 case SkFileV: nsegments[iLo].kind = SkFileC; break;
3003 case SkAnonV: nsegments[iLo].kind = SkAnonC; break;
3004 default: aspacem_assert(0); /* can't happen - guarded above */
3007 preen_nsegments();
3008 return True;
3011 /* Set the 'hasT' bit on the segment containing ADDR indicating that
3012 translations have or may have been taken from this segment. ADDR is
3013 expected to belong to a client segment. */
3014 void VG_(am_set_segment_hasT)( Addr addr )
3016 Int i = find_nsegment_idx(addr);
3017 SegKind kind = nsegments[i].kind;
3018 aspacem_assert(kind == SkAnonC || kind == SkFileC || kind == SkShmC);
3019 nsegments[i].hasT = True;
3023 /* --- --- --- reservations --- --- --- */
3025 /* Create a reservation from START .. START+LENGTH-1, with the given
3026 ShrinkMode. When checking whether the reservation can be created,
3027 also ensure that at least abs(EXTRA) extra free bytes will remain
3028 above (> 0) or below (< 0) the reservation.
3030 The reservation will only be created if it, plus the extra-zone,
3031 falls entirely within a single free segment. The returned Bool
3032 indicates whether the creation succeeded. */
3034 Bool VG_(am_create_reservation) ( Addr start, SizeT length,
3035 ShrinkMode smode, SSizeT extra )
3037 Int startI, endI;
3038 NSegment seg;
3040 /* start and end, not taking into account the extra space. */
3041 Addr start1 = start;
3042 Addr end1 = start + length - 1;
3044 /* start and end, taking into account the extra space. */
3045 Addr start2 = start1;
3046 Addr end2 = end1;
3048 if (extra < 0) start2 += extra; // this moves it down :-)
3049 if (extra > 0) end2 += extra;
3051 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
3052 aspacem_assert(VG_IS_PAGE_ALIGNED(start+length));
3053 aspacem_assert(VG_IS_PAGE_ALIGNED(start2));
3054 aspacem_assert(VG_IS_PAGE_ALIGNED(end2+1));
3056 startI = find_nsegment_idx( start2 );
3057 endI = find_nsegment_idx( end2 );
3059 /* If the start and end points don't fall within the same (free)
3060 segment, we're hosed. This does rely on the assumption that all
3061 mergeable adjacent segments can be merged, but add_segment()
3062 should ensure that. */
3063 if (startI != endI)
3064 return False;
3066 if (nsegments[startI].kind != SkFree)
3067 return False;
3069 /* Looks good - make the reservation. */
3070 aspacem_assert(nsegments[startI].start <= start2);
3071 aspacem_assert(end2 <= nsegments[startI].end);
3073 init_nsegment( &seg );
3074 seg.kind = SkResvn;
3075 seg.start = start1; /* NB: extra space is not included in the
3076 reservation. */
3077 seg.end = end1;
3078 seg.smode = smode;
3079 add_segment( &seg );
3081 AM_SANITY_CHECK;
3082 return True;
3086 /* ADDR is the start address of an anonymous client mapping. This fn extends
3087 the mapping by DELTA bytes, taking the space from a reservation section
3088 which must be adjacent. If DELTA is positive, the segment is
3089 extended forwards in the address space, and the reservation must be
3090 the next one along. If DELTA is negative, the segment is extended
3091 backwards in the address space and the reservation must be the
3092 previous one. DELTA must be page aligned. abs(DELTA) must not
3093 exceed the size of the reservation segment minus one page, that is,
3094 the reservation segment after the operation must be at least one
3095 page long. The function returns a pointer to the resized segment. */
3097 const NSegment *VG_(am_extend_into_adjacent_reservation_client)( Addr addr,
3098 SSizeT delta,
3099 Bool *overflow)
3101 Int segA, segR;
3102 UInt prot;
3103 SysRes sres;
3105 *overflow = False;
3107 segA = find_nsegment_idx(addr);
3108 aspacem_assert(nsegments[segA].kind == SkAnonC);
3110 if (delta == 0)
3111 return nsegments + segA;
3113 prot = (nsegments[segA].hasR ? VKI_PROT_READ : 0)
3114 | (nsegments[segA].hasW ? VKI_PROT_WRITE : 0)
3115 | (nsegments[segA].hasX ? VKI_PROT_EXEC : 0);
3117 aspacem_assert(VG_IS_PAGE_ALIGNED(delta<0 ? -delta : delta));
3119 if (delta > 0) {
3121 /* Extending the segment forwards. */
3122 segR = segA+1;
3123 if (segR >= nsegments_used
3124 || nsegments[segR].kind != SkResvn
3125 || nsegments[segR].smode != SmLower)
3126 return NULL;
3128 if (delta + VKI_PAGE_SIZE
3129 > (nsegments[segR].end - nsegments[segR].start + 1)) {
3130 *overflow = True;
3131 return NULL;
3134 /* Extend the kernel's mapping. */
3135 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
3136 sres = VG_(am_do_mmap_NO_NOTIFY)(
3137 nsegments[segR].start, delta,
3138 prot,
3139 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
3140 0, 0
3142 if (sr_isError(sres))
3143 return NULL; /* kernel bug if this happens? */
3144 if (sr_Res(sres) != nsegments[segR].start) {
3145 /* kernel bug if this happens? */
3146 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
3147 return NULL;
3150 /* Ok, success with the kernel. Update our structures. */
3151 nsegments[segR].start += delta;
3152 nsegments[segA].end += delta;
3153 aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
3155 } else {
3157 /* Extending the segment backwards. */
3158 delta = -delta;
3159 aspacem_assert(delta > 0);
3161 segR = segA-1;
3162 if (segR < 0
3163 || nsegments[segR].kind != SkResvn
3164 || nsegments[segR].smode != SmUpper)
3165 return NULL;
3167 if (delta + VKI_PAGE_SIZE
3168 > (nsegments[segR].end - nsegments[segR].start + 1)) {
3169 *overflow = True;
3170 return NULL;
3173 /* Extend the kernel's mapping. */
3174 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
3175 sres = VG_(am_do_mmap_NO_NOTIFY)(
3176 nsegments[segA].start-delta, delta,
3177 prot,
3178 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
3179 0, 0
3181 if (sr_isError(sres))
3182 return NULL; /* kernel bug if this happens? */
3183 if (sr_Res(sres) != nsegments[segA].start-delta) {
3184 /* kernel bug if this happens? */
3185 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
3186 return NULL;
3189 /* Ok, success with the kernel. Update our structures. */
3190 nsegments[segR].end -= delta;
3191 nsegments[segA].start -= delta;
3192 aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
3195 AM_SANITY_CHECK;
3196 return nsegments + segA;
3200 /* --- --- --- resizing/move a mapping --- --- --- */
3202 #if HAVE_MREMAP
3204 /* This function grows a client mapping in place into an adjacent free segment.
3205 ADDR is the client mapping's start address and DELTA, which must be page
3206 aligned, is the growth amount. The function returns a pointer to the
3207 resized segment. The function is used in support of mremap. */
3208 const NSegment *VG_(am_extend_map_client)( Addr addr, SizeT delta )
3210 Addr xStart;
3211 SysRes sres;
3213 if (0)
3214 VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) BEFORE");
3216 /* Get the client segment */
3217 Int ix = find_nsegment_idx(addr);
3218 aspacem_assert(ix >= 0 && ix < nsegments_used);
3220 NSegment *seg = nsegments + ix;
3222 aspacem_assert(seg->kind == SkFileC || seg->kind == SkAnonC ||
3223 seg->kind == SkShmC);
3224 aspacem_assert(delta > 0 && VG_IS_PAGE_ALIGNED(delta)) ;
3226 xStart = seg->end+1;
3227 aspacem_assert(xStart + delta >= delta); // no wrap-around
3229 /* The segment following the client segment must be a free segment and
3230 it must be large enough to cover the additional memory. */
3231 NSegment *segf = seg + 1;
3232 aspacem_assert(segf->kind == SkFree);
3233 aspacem_assert(segf->start == xStart);
3234 aspacem_assert(xStart + delta - 1 <= segf->end);
3236 SizeT seg_old_len = seg->end + 1 - seg->start;
3238 AM_SANITY_CHECK;
3239 sres = ML_(am_do_extend_mapping_NO_NOTIFY)( seg->start,
3240 seg_old_len,
3241 seg_old_len + delta );
3242 if (sr_isError(sres)) {
3243 AM_SANITY_CHECK;
3244 return NULL;
3245 } else {
3246 /* the area must not have moved */
3247 aspacem_assert(sr_Res(sres) == seg->start);
3250 NSegment seg_copy = *seg;
3251 seg_copy.end += delta;
3252 add_segment( &seg_copy );
3254 if (0)
3255 VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) AFTER");
3257 AM_SANITY_CHECK;
3258 return nsegments + find_nsegment_idx(addr);
3262 /* Remap the old address range to the new address range. Fails if any
3263 parameter is not page aligned, if the either size is zero, if any
3264 wraparound is implied, if the old address range does not fall
3265 entirely within a single segment, if the new address range overlaps
3266 with the old one, or if the old address range is not a valid client
3267 mapping. If *need_discard is True after a successful return, the
3268 caller should immediately discard translations from both specified
3269 address ranges. */
3271 Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
3272 Addr old_addr, SizeT old_len,
3273 Addr new_addr, SizeT new_len )
3275 Int iLo, iHi;
3276 SysRes sres;
3277 NSegment seg;
3279 if (old_len == 0 || new_len == 0)
3280 return False;
3282 if (!VG_IS_PAGE_ALIGNED(old_addr) || !VG_IS_PAGE_ALIGNED(old_len)
3283 || !VG_IS_PAGE_ALIGNED(new_addr) || !VG_IS_PAGE_ALIGNED(new_len))
3284 return False;
3286 if (old_addr + old_len < old_addr
3287 || new_addr + new_len < new_addr)
3288 return False;
3290 if (old_addr + old_len - 1 < new_addr
3291 || new_addr + new_len - 1 < old_addr) {
3292 /* no overlap */
3293 } else
3294 return False;
3296 iLo = find_nsegment_idx( old_addr );
3297 iHi = find_nsegment_idx( old_addr + old_len - 1 );
3298 if (iLo != iHi)
3299 return False;
3301 if (nsegments[iLo].kind != SkFileC && nsegments[iLo].kind != SkAnonC &&
3302 nsegments[iLo].kind != SkShmC)
3303 return False;
3305 sres = ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)
3306 ( old_addr, old_len, new_addr, new_len );
3307 if (sr_isError(sres)) {
3308 AM_SANITY_CHECK;
3309 return False;
3310 } else {
3311 aspacem_assert(sr_Res(sres) == new_addr);
3314 *need_discard = any_Ts_in_range( old_addr, old_len )
3315 || any_Ts_in_range( new_addr, new_len );
3317 seg = nsegments[iLo];
3319 /* Mark the new area based on the old seg. */
3320 if (seg.kind == SkFileC) {
3321 seg.offset += ((ULong)old_addr) - ((ULong)seg.start);
3323 seg.start = new_addr;
3324 seg.end = new_addr + new_len - 1;
3325 add_segment( &seg );
3327 /* Create a free hole in the old location. */
3328 init_nsegment( &seg );
3329 seg.start = old_addr;
3330 seg.end = old_addr + old_len - 1;
3331 /* See comments in VG_(am_notify_munmap) about this SkResvn vs
3332 SkFree thing. */
3333 if (old_addr > aspacem_maxAddr
3334 && /* check previous comparison is meaningful */
3335 aspacem_maxAddr < Addr_MAX)
3336 seg.kind = SkResvn;
3337 else
3338 seg.kind = SkFree;
3340 add_segment( &seg );
3342 AM_SANITY_CHECK;
3343 return True;
3346 #endif // HAVE_MREMAP
3349 #if defined(VGO_linux)
3351 /*-----------------------------------------------------------------*/
3352 /*--- ---*/
3353 /*--- A simple parser for /proc/self/maps on Linux 2.4.X/2.6.X. ---*/
3354 /*--- Almost completely independent of the stuff above. The ---*/
3355 /*--- only function it 'exports' to the code above this comment ---*/
3356 /*--- is parse_procselfmaps. ---*/
3357 /*--- ---*/
3358 /*-----------------------------------------------------------------*/
3360 /*------BEGIN-procmaps-parser-for-Linux--------------------------*/
3362 /* Size of a smallish table used to read /proc/self/map entries. */
3363 #define M_PROCMAP_BUF 100000
3365 /* static ... to keep it out of the stack frame. */
3366 static HChar procmap_buf[M_PROCMAP_BUF];
3368 /* Records length of /proc/self/maps read into procmap_buf. */
3369 static Int buf_n_tot;
3371 /* Helper fns. */
3373 static Int hexdigit ( HChar c )
3375 if (c >= '0' && c <= '9') return (Int)(c - '0');
3376 if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a');
3377 if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A');
3378 return -1;
3381 static Int decdigit ( HChar c )
3383 if (c >= '0' && c <= '9') return (Int)(c - '0');
3384 return -1;
3387 static Int readchar ( const HChar* buf, HChar* ch )
3389 if (*buf == 0) return 0;
3390 *ch = *buf;
3391 return 1;
3394 static Int readhex ( const HChar* buf, UWord* val )
3396 /* Read a word-sized hex number. */
3397 Int n = 0;
3398 *val = 0;
3399 while (hexdigit(*buf) >= 0) {
3400 *val = (*val << 4) + hexdigit(*buf);
3401 n++; buf++;
3403 return n;
3406 static Int readhex64 ( const HChar* buf, ULong* val )
3408 /* Read a potentially 64-bit hex number. */
3409 Int n = 0;
3410 *val = 0;
3411 while (hexdigit(*buf) >= 0) {
3412 *val = (*val << 4) + hexdigit(*buf);
3413 n++; buf++;
3415 return n;
3418 static Int readdec64 ( const HChar* buf, ULong* val )
3420 Int n = 0;
3421 *val = 0;
3422 while (decdigit(*buf) >= 0) {
3423 *val = (*val * 10) + decdigit(*buf);
3424 n++; buf++;
3426 return n;
3430 /* Get the contents of /proc/self/maps into a static buffer. If
3431 there's a syntax error, it won't fit, or other failure, just
3432 abort. */
3434 static void read_procselfmaps_into_buf ( void )
3436 Int n_chunk;
3437 SysRes fd;
3439 /* Read the initial memory mapping from the /proc filesystem. */
3440 fd = ML_(am_open)( "/proc/self/maps", VKI_O_RDONLY, 0 );
3441 if (sr_isError(fd))
3442 ML_(am_barf)("can't open /proc/self/maps");
3444 buf_n_tot = 0;
3445 do {
3446 n_chunk = ML_(am_read)( sr_Res(fd), &procmap_buf[buf_n_tot],
3447 M_PROCMAP_BUF - buf_n_tot );
3448 if (n_chunk >= 0)
3449 buf_n_tot += n_chunk;
3450 } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
3452 ML_(am_close)(sr_Res(fd));
3454 if (buf_n_tot >= M_PROCMAP_BUF-5)
3455 ML_(am_barf_toolow)("M_PROCMAP_BUF");
3456 if (buf_n_tot == 0)
3457 ML_(am_barf)("I/O error on /proc/self/maps");
3459 procmap_buf[buf_n_tot] = 0;
3462 /* Parse /proc/self/maps. For each map entry, call
3463 record_mapping, passing it, in this order:
3465 start address in memory
3466 length
3467 page protections (using the VKI_PROT_* flags)
3468 mapped file device and inode
3469 offset in file, or zero if no file
3470 filename, zero terminated, or NULL if no file
3471 ignore_offset, when the exact offset cannot be
3472 obtained
3474 So the sig of the called fn might be
3476 void (*record_mapping)( Addr start, SizeT size, UInt prot,
3477 UInt dev, UInt info,
3478 ULong foffset, UChar* filename,
3479 Bool ignore_offset )
3481 Note that the supplied filename is transiently stored; record_mapping
3482 should make a copy if it wants to keep it.
3484 Nb: it is important that this function does not alter the contents of
3485 procmap_buf!
3487 static void parse_procselfmaps (
3488 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
3489 ULong dev, ULong ino, Off64T offset,
3490 const HChar* filename, Bool ignore_offset ),
3491 void (*record_gap)( Addr addr, SizeT len )
3494 Int i, j, i_eol;
3495 Addr start, endPlusOne, gapStart;
3496 HChar* filename;
3497 HChar rr, ww, xx, pp, ch, tmp;
3498 UInt prot;
3499 UWord maj, min;
3500 ULong foffset, dev, ino;
3502 foffset = ino = 0; /* keep gcc-4.1.0 happy */
3504 read_procselfmaps_into_buf();
3506 aspacem_assert('\0' != procmap_buf[0] && 0 != buf_n_tot);
3508 if (0)
3509 VG_(debugLog)(0, "procselfmaps", "raw:\n%s\n", procmap_buf);
3511 /* Ok, it's safely aboard. Parse the entries. */
3512 i = 0;
3513 gapStart = Addr_MIN;
3514 while (True) {
3515 if (i >= buf_n_tot) break;
3517 /* Read (without fscanf :) the pattern %16x-%16x %c%c%c%c %16x %2x:%2x %d */
3518 j = readhex(&procmap_buf[i], &start);
3519 if (j > 0) i += j; else goto syntaxerror;
3520 j = readchar(&procmap_buf[i], &ch);
3521 if (j == 1 && ch == '-') i += j; else goto syntaxerror;
3522 j = readhex(&procmap_buf[i], &endPlusOne);
3523 if (j > 0) i += j; else goto syntaxerror;
3525 j = readchar(&procmap_buf[i], &ch);
3526 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3528 j = readchar(&procmap_buf[i], &rr);
3529 if (j == 1 && (rr == 'r' || rr == '-')) i += j; else goto syntaxerror;
3530 j = readchar(&procmap_buf[i], &ww);
3531 if (j == 1 && (ww == 'w' || ww == '-')) i += j; else goto syntaxerror;
3532 j = readchar(&procmap_buf[i], &xx);
3533 if (j == 1 && (xx == 'x' || xx == '-')) i += j; else goto syntaxerror;
3534 /* This field is the shared/private flag */
3535 j = readchar(&procmap_buf[i], &pp);
3536 if (j == 1 && (pp == 'p' || pp == '-' || pp == 's'))
3537 i += j; else goto syntaxerror;
3539 j = readchar(&procmap_buf[i], &ch);
3540 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3542 j = readhex64(&procmap_buf[i], &foffset);
3543 if (j > 0) i += j; else goto syntaxerror;
3545 j = readchar(&procmap_buf[i], &ch);
3546 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3548 j = readhex(&procmap_buf[i], &maj);
3549 if (j > 0) i += j; else goto syntaxerror;
3550 j = readchar(&procmap_buf[i], &ch);
3551 if (j == 1 && ch == ':') i += j; else goto syntaxerror;
3552 j = readhex(&procmap_buf[i], &min);
3553 if (j > 0) i += j; else goto syntaxerror;
3555 j = readchar(&procmap_buf[i], &ch);
3556 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3558 j = readdec64(&procmap_buf[i], &ino);
3559 if (j > 0) i += j; else goto syntaxerror;
3561 goto read_line_ok;
3563 syntaxerror:
3564 VG_(debugLog)(0, "Valgrind:",
3565 "FATAL: syntax error reading /proc/self/maps\n");
3566 { Int k, m;
3567 HChar buf50[51];
3568 m = 0;
3569 buf50[m] = 0;
3570 k = i - 50;
3571 if (k < 0) k = 0;
3572 for (; k <= i; k++) {
3573 buf50[m] = procmap_buf[k];
3574 buf50[m+1] = 0;
3575 if (m < 50-1) m++;
3577 VG_(debugLog)(0, "procselfmaps", "Last 50 chars: '%s'\n", buf50);
3579 ML_(am_exit)(1);
3581 read_line_ok:
3583 aspacem_assert(i < buf_n_tot);
3585 /* Try and find the name of the file mapped to this segment, if
3586 it exists. Note that file names can contain spaces. */
3588 // Move i to the next non-space char, which should be either a '/',
3589 // a '[', or a newline.
3590 while (procmap_buf[i] == ' ') i++;
3592 // Move i_eol to the end of the line.
3593 i_eol = i;
3594 while (procmap_buf[i_eol] != '\n') i_eol++;
3596 // If there's a filename...
3597 if (procmap_buf[i] == '/') {
3598 /* Minor hack: put a '\0' at the filename end for the call to
3599 'record_mapping', then restore the old char with 'tmp'. */
3600 filename = &procmap_buf[i];
3601 tmp = filename[i_eol - i];
3602 filename[i_eol - i] = '\0';
3603 } else {
3604 tmp = 0;
3605 filename = NULL;
3606 foffset = 0;
3609 prot = 0;
3610 if (rr == 'r') prot |= VKI_PROT_READ;
3611 if (ww == 'w') prot |= VKI_PROT_WRITE;
3612 if (xx == 'x') prot |= VKI_PROT_EXEC;
3614 /* Linux has two ways to encode a device number when it
3615 is exposed to user space (via fstat etc). The old way
3616 is the traditional unix scheme that produces a 16 bit
3617 device number with the top 8 being the major number and
3618 the bottom 8 the minor number.
3620 The new scheme allows for a 12 bit major number and
3621 a 20 bit minor number by using a 32 bit device number
3622 and putting the top 12 bits of the minor number into
3623 the top 12 bits of the device number thus leaving an
3624 extra 4 bits for the major number.
3626 If the minor and major number are both single byte
3627 values then both schemes give the same result so we
3628 use the new scheme here in case either number is
3629 outside the 0-255 range and then use fstat64 when
3630 available (or fstat on 64 bit systems) so that we
3631 should always have a new style device number and
3632 everything should match. */
3633 dev = (min & 0xff) | (maj << 8) | ((min & ~0xff) << 12);
3635 if (record_gap && gapStart < start)
3636 (*record_gap) ( gapStart, start-gapStart );
3638 if (record_mapping && start < endPlusOne)
3639 (*record_mapping) ( start, endPlusOne-start,
3640 prot, dev, ino,
3641 foffset, filename, False );
3643 if ('\0' != tmp) {
3644 filename[i_eol - i] = tmp;
3647 i = i_eol + 1;
3648 gapStart = endPlusOne;
3651 # if defined(VGP_arm_linux)
3652 /* ARM puts code at the end of memory that contains processor
3653 specific stuff (cmpxchg, getting the thread local storage, etc.)
3654 This isn't specified in /proc/self/maps, so do it here. This
3655 kludgery causes the view of memory, as presented to
3656 record_gap/record_mapping, to actually reflect reality. IMO
3657 (JRS, 2010-Jan-03) the fact that /proc/.../maps does not list
3658 the commpage should be regarded as a bug in the kernel. */
3659 { const Addr commpage_start = ARM_LINUX_FAKE_COMMPAGE_START;
3660 const Addr commpage_end1 = ARM_LINUX_FAKE_COMMPAGE_END1;
3661 if (gapStart < commpage_start) {
3662 if (record_gap)
3663 (*record_gap)( gapStart, commpage_start - gapStart );
3664 if (record_mapping)
3665 (*record_mapping)( commpage_start, commpage_end1 - commpage_start,
3666 VKI_PROT_READ|VKI_PROT_EXEC,
3667 0/*dev*/, 0/*ino*/, 0/*foffset*/,
3668 NULL, False);
3669 gapStart = commpage_end1;
3672 # endif
3674 if (record_gap && gapStart < Addr_MAX)
3675 (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
3678 /*------END-procmaps-parser-for-Linux----------------------------*/
3680 /*------BEGIN-procmaps-parser-for-Darwin-------------------------*/
3682 #elif defined(VGO_darwin)
3683 #include <mach/mach.h>
3684 #include <mach/mach_vm.h>
3686 static unsigned int mach2vki(unsigned int vm_prot)
3688 return
3689 ((vm_prot & VM_PROT_READ) ? VKI_PROT_READ : 0) |
3690 ((vm_prot & VM_PROT_WRITE) ? VKI_PROT_WRITE : 0) |
3691 ((vm_prot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC : 0) ;
3694 static UInt stats_machcalls = 0;
3696 static void parse_procselfmaps (
3697 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
3698 ULong dev, ULong ino, Off64T offset,
3699 const HChar* filename, Bool ignore_offset ),
3700 void (*record_gap)( Addr addr, SizeT len )
3703 vm_address_t iter;
3704 unsigned int depth;
3705 vm_address_t last;
3707 iter = 0;
3708 depth = 0;
3709 last = 0;
3710 while (1) {
3711 mach_vm_address_t addr = iter;
3712 mach_vm_size_t size;
3713 vm_region_submap_short_info_data_64_t info;
3714 kern_return_t kr;
3716 while (1) {
3717 mach_msg_type_number_t info_count
3718 = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
3719 stats_machcalls++;
3720 kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth,
3721 (vm_region_info_t)&info, &info_count);
3722 if (kr)
3723 return;
3724 if (info.is_submap) {
3725 depth++;
3726 continue;
3728 break;
3730 iter = addr + size;
3732 if (addr > last && record_gap) {
3733 (*record_gap)(last, addr - last);
3735 if (record_mapping) {
3736 (*record_mapping)(addr, size, mach2vki(info.protection),
3737 0, 0, info.offset, NULL, False);
3739 last = addr + size;
3742 if ((Addr)-1 > last && record_gap)
3743 (*record_gap)(last, (Addr)-1 - last);
3746 // Urr. So much for thread safety.
3747 static Bool css_overflowed;
3748 static ChangedSeg* css_local;
3749 static Int css_size_local;
3750 static Int css_used_local;
3752 static Addr Addr__max ( Addr a, Addr b ) { return a > b ? a : b; }
3753 static Addr Addr__min ( Addr a, Addr b ) { return a < b ? a : b; }
3755 static void add_mapping_callback(Addr addr, SizeT len, UInt prot,
3756 ULong dev, ULong ino, Off64T offset,
3757 const HChar *filename, Bool ignore_offset)
3759 // derived from sync_check_mapping_callback()
3761 /* JRS 2012-Mar-07: this all seems very dubious to me. It would be
3762 safer to see if we can find, in V's segment collection, one
3763 single segment that completely covers the range [addr, +len)
3764 (and possibly more), and that has the exact same other
3765 properties (prot, dev, ino, offset, etc) as the data presented
3766 here. If found, we just skip. Otherwise add the data presented
3767 here into css_local[]. */
3769 Int iLo, iHi, i;
3771 if (len == 0) return;
3773 /* The kernel should not give us wraparounds. */
3774 aspacem_assert(addr <= addr + len - 1);
3776 iLo = find_nsegment_idx( addr );
3777 iHi = find_nsegment_idx( addr + len - 1 );
3779 /* NSegments iLo .. iHi inclusive should agree with the presented
3780 data. */
3781 for (i = iLo; i <= iHi; i++) {
3783 UInt seg_prot;
3785 if (nsegments[i].kind == SkAnonV || nsegments[i].kind == SkFileV) {
3786 /* Ignore V regions */
3787 continue;
3789 else if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) {
3790 /* Add mapping for SkResvn regions */
3791 ChangedSeg* cs = &css_local[css_used_local];
3792 if (css_used_local < css_size_local) {
3793 cs->is_added = True;
3794 cs->start = addr;
3795 cs->end = addr + len - 1;
3796 cs->prot = prot;
3797 cs->offset = offset;
3798 css_used_local++;
3799 } else {
3800 css_overflowed = True;
3802 return;
3805 else if (nsegments[i].kind == SkAnonC ||
3806 nsegments[i].kind == SkFileC ||
3807 nsegments[i].kind == SkShmC)
3809 /* Check permissions on client regions */
3810 // GrP fixme
3811 seg_prot = 0;
3812 if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
3813 if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
3814 # if defined(VGA_x86)
3815 // GrP fixme sloppyXcheck
3816 // darwin: kernel X ignored and spuriously changes? (vm_copy)
3817 seg_prot |= (prot & VKI_PROT_EXEC);
3818 # else
3819 if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
3820 # endif
3821 if (seg_prot != prot) {
3822 if (VG_(clo_trace_syscalls))
3823 VG_(debugLog)(0,"aspacem","region %p..%p permission "
3824 "mismatch (kernel %x, V %x)\n",
3825 (void*)nsegments[i].start,
3826 (void*)(nsegments[i].end+1), prot, seg_prot);
3827 /* Add mapping for regions with protection changes */
3828 ChangedSeg* cs = &css_local[css_used_local];
3829 if (css_used_local < css_size_local) {
3830 cs->is_added = True;
3831 cs->start = addr;
3832 cs->end = addr + len - 1;
3833 cs->prot = prot;
3834 cs->offset = offset;
3835 css_used_local++;
3836 } else {
3837 css_overflowed = True;
3839 return;
3843 } else {
3844 aspacem_assert(0);
3849 static void remove_mapping_callback(Addr addr, SizeT len)
3851 // derived from sync_check_gap_callback()
3853 Int iLo, iHi, i;
3855 if (len == 0)
3856 return;
3858 /* The kernel should not give us wraparounds. */
3859 aspacem_assert(addr <= addr + len - 1);
3861 iLo = find_nsegment_idx( addr );
3862 iHi = find_nsegment_idx( addr + len - 1 );
3864 /* NSegments iLo .. iHi inclusive should agree with the presented data. */
3865 for (i = iLo; i <= iHi; i++) {
3866 if (nsegments[i].kind != SkFree && nsegments[i].kind != SkResvn) {
3867 /* V has a mapping, kernel doesn't. Add to css_local[],
3868 directives to chop off the part of the V mapping that
3869 falls within the gap that the kernel tells us is
3870 present. */
3871 ChangedSeg* cs = &css_local[css_used_local];
3872 if (css_used_local < css_size_local) {
3873 cs->is_added = False;
3874 cs->start = Addr__max(nsegments[i].start, addr);
3875 cs->end = Addr__min(nsegments[i].end, addr + len - 1);
3876 aspacem_assert(VG_IS_PAGE_ALIGNED(cs->start));
3877 aspacem_assert(VG_IS_PAGE_ALIGNED(cs->end+1));
3878 /* I don't think the following should fail. But if it
3879 does, just omit the css_used_local++ in the cases where
3880 it doesn't hold. */
3881 aspacem_assert(cs->start < cs->end);
3882 cs->prot = 0;
3883 cs->offset = 0;
3884 css_used_local++;
3885 } else {
3886 css_overflowed = True;
3893 // Returns False if 'css' wasn't big enough.
3894 Bool VG_(get_changed_segments)(
3895 const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css,
3896 Int css_size, /*OUT*/Int* css_used)
3898 static UInt stats_synccalls = 1;
3899 aspacem_assert(when && where);
3901 if (0)
3902 VG_(debugLog)(0,"aspacem",
3903 "[%u,%u] VG_(get_changed_segments)(%s, %s)\n",
3904 stats_synccalls++, stats_machcalls, when, where
3907 css_overflowed = False;
3908 css_local = css;
3909 css_size_local = css_size;
3910 css_used_local = 0;
3912 // Get the list of segs that need to be added/removed.
3913 parse_procselfmaps(&add_mapping_callback, &remove_mapping_callback);
3915 *css_used = css_used_local;
3917 if (css_overflowed) {
3918 aspacem_assert(css_used_local == css_size_local);
3921 return !css_overflowed;
3925 /*------END-procmaps-parser-for-Darwin---------------------------*/
3927 /*------BEGIN-procmaps-parser-for-Freebsd------------------------*/
3928 #elif defined(VGO_freebsd)
3931 * Some more nasty hacks.
3933 * On FreeBSD mmap with MAP_STACK will result in TWO adjacent areas being mapped.
3934 * Assuming a grow down stack, the one in the lower address is a growth guard
3935 * area. The one in the higher area is the stack. The kernel will automatically
3936 * extend the stack into the growth guard. Valgrind doesn't see any of that.
3937 * When we see mapped memory like that, we need to try to merge them so that
3938 * they match the mmap that Valgrind saw and recorded.
3940 * There is also the initial stack. Valgrind will have already recorded that
3941 * with parse_procselfmaps. So we don't want to merge that.
3943 static char* maybe_merge_procmap_stack(char* p, struct vki_kinfo_vmentry *kve, Addr* pEndPlusOne, UInt* pProt)
3945 static Bool sgrowsiz_read = False;
3946 static SizeT kern_sgrowsiz;
3947 if (!sgrowsiz_read) {
3948 SizeT sysctl_size = sizeof(SizeT);
3949 VG_(sysctlbyname)("kern.sgrowsiz", &kern_sgrowsiz, &sysctl_size, NULL, 0);
3950 sgrowsiz_read = True;
3952 char* p_next = p + kve->kve_structsize;
3953 struct vki_kinfo_vmentry *kve_next = (struct vki_kinfo_vmentry *)(p_next);
3955 #if defined(VGP_amd64_freebsd)
3956 // I think that this is the stacksize rlimit
3957 // I could use sysctl kern.maxssiz for this
3958 if ( *pEndPlusOne + kern_sgrowsiz - kve->kve_start == 512ULL*1024ULL*1024ULL) {
3959 return p;
3961 #elif defined(VGP_x86_freebsd)
3962 // sysctl kern.maxssiz OK for x86 on x86 but not x86 on amd64
3963 if ( *pEndPlusOne + kern_sgrowsiz - kve->kve_start == 64ULL*1024ULL*1024ULL) {
3964 return p;
3966 #elif defined(VGP_arm64_freebsd)
3967 if ( *pEndPlusOne + kern_sgrowsiz - kve->kve_start == 1024ULL*1024ULL*1024ULL) {
3968 return p;
3970 #else
3971 # error Unknown platform
3972 #endif
3974 while (kve_next->kve_protection & VKI_KVME_PROT_READ &&
3975 kve_next->kve_protection & VKI_KVME_PROT_WRITE &&
3976 kve_next->kve_flags & VKI_KVME_FLAG_GROWS_DOWN &&
3977 kve_next->kve_end - kve_next->kve_start == kern_sgrowsiz) {
3980 *pEndPlusOne += kern_sgrowsiz;
3981 if (kve_next->kve_protection & VKI_KVME_PROT_READ) {
3982 *pProt |= VKI_PROT_READ;
3984 if (kve_next->kve_protection & VKI_KVME_PROT_WRITE) {
3985 *pProt |= VKI_PROT_WRITE;
3987 if (kve_next->kve_protection & VKI_KVME_PROT_EXEC) {
3988 *pProt |= VKI_PROT_EXEC;
3990 p_next += kve->kve_structsize;
3991 kve_next = (struct vki_kinfo_vmentry *)(p_next);
3993 p_next -= kve->kve_structsize;
3994 return p_next;
3999 * PJF 2023-09-23
4001 * This function is somewhat badly named for FreeBSD, where the
4002 * /proc filesystem is optional so we can't count on users
4003 * having it. Instead we use the KERN_PROC_VMMAP syscall.
4004 * So far so good.
4006 * This function is used in two contexts. The heaviest use is from
4007 * VG_(am_do_sync_check) as a sanity check that the contents of the
4008 * global nsegments array is consistent with what the OS reports
4009 * as being memory maps. No known problems with that.
4011 * The other use is at startup in order to get the mapping for the
4012 * tool itself. In this case we have a fairly big problem. There is
4013 * a difference in the mapping used when the kernel loads an exe
4014 * and when the link loader ldrt (or Valgrind which does the same
4015 * job for the guest exe. In the case of ldrt, all ELF PT_LOAD
4016 * sections get mmap'd. The kernel, however, does _not_ mmap
4017 * the RW PT_LOAD.
4019 * For instance, objdump -p for memcheck-amd64-freebsd contains
4020 * LOAD off 0x0000000000000000 vaddr 0x0000000038000000 paddr 0x0000000038000000 align 2**12
4021 * filesz 0x00000000000c5124 memsz 0x00000000000c5124 flags r--
4022 * LOAD off 0x00000000000c5130 vaddr 0x00000000380c6130 paddr 0x00000000380c6130 align 2**12
4023 * filesz 0x00000000001b10df memsz 0x00000000001b10df flags r-x
4024 * LOAD off 0x0000000000276210 vaddr 0x0000000038278210 paddr 0x0000000038278210 align 2**12
4025 * filesz 0x0000000000000a90 memsz 0x00000000025dd000 flags rw-
4027 * Running procstat -v on a running instance gives
4028 * 44814 0x38000000 0x380c6000 r-- 198 2558 2 0 CN--- vn /usr/home/paulf/scratch/valgrind/memcheck/memcheck-amd64-freebsd
4029 * 44814 0x380c6000 0x38278000 r-x 434 2558 2 0 CN--- vn /usr/home/paulf/scratch/valgrind/memcheck/memcheck-amd64-freebsd
4030 * 44814 0x38278000 0x3a856000 rw- 4590 4590 1 0 ----- df
4032 * Instead of mmap'ing the RW PT_LOAD the kernel has mmap'd anonymous swap and copied from the exe file.
4033 * See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=273956
4035 * So what can we do? We can reuse most of the info from the previous 'r-x' mapping.
4036 * The filename, dev and ino are all the same. That leaves the offset. We can
4037 * make a rough estimate of the value as being previous offset + previous size.
4038 * Since the addresses in memory will be page aligned it's not possible to
4039 * obtain the original offset. It isn't good enough for ML_(read_elf_object)
4040 * in readelf.c
4042 * As a hack of last resort we force ML_(read_elf_object) to accept this
4043 * mapping by adding an "ignore offset" flag. We can't be wrong that
4044 * there is something mapped roughly there - it's the global data of the
4045 * code that is executing on the CPU! Furthermore, this is not frequently
4046 * used. The main benefit is for Valgrind developers. Without this hack,
4047 * if Valgrind crashes or asserts it will print its own stack without
4048 * debuginfo, which is mostly useless. See the above FreeBSD bugzilla item
4049 * for an example.
4052 /* Size of a smallish table used to read /proc/self/map entries. */
4053 #define M_PROCMAP_BUF 10485760 /* 10M */
4055 /* static ... to keep it out of the stack frame. */
4056 static char procmap_buf[M_PROCMAP_BUF];
4058 static void parse_procselfmaps (
4059 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
4060 ULong dev, ULong ino, Off64T offset,
4061 const HChar* filename, Bool ignore_offset ),
4062 void (*record_gap)( Addr addr, SizeT len )
4065 Addr start, endPlusOne, gapStart;
4066 char* filename;
4067 char *p;
4068 UInt prot;
4069 ULong foffset, dev, ino;
4070 struct vki_kinfo_vmentry *kve;
4071 vki_size_t len;
4072 Int oid[4];
4073 SysRes sres;
4074 Int map_count = 0;
4075 // this assumes that compiling with clang uses ld.lld which produces 3 LOAD segements
4076 // and that compiling with GCC uses ld.bfd which produces 2 LOAD segments
4077 #if defined(__clang__)
4078 Int const rx_map = 1;
4079 Int const rw_map = 2;
4080 #elif defined(__GNUC__)
4081 Int const rx_map = 0;
4082 Int const rw_map = 1;
4083 #else
4084 #error("unsupported compiler")
4085 #endif
4086 // could copy the whole kinfo_vmentry but it is 1160 bytes
4087 char *rx_filename = NULL;
4088 ULong rx_dev = 0U;
4089 ULong rx_ino = 0U;
4090 ULong rx_foffset = 0U;
4091 Bool tool_read_maps = (record_mapping == read_maps_callback);
4093 foffset = ino = 0; /* keep gcc-4.1.0 happy */
4095 oid[0] = VKI_CTL_KERN;
4096 oid[1] = VKI_KERN_PROC;
4097 oid[2] = VKI_KERN_PROC_VMMAP;
4098 oid[3] = sr_Res(VG_(do_syscall0)(__NR_getpid));
4099 len = sizeof(procmap_buf);
4101 sres = VG_(do_syscall6)(__NR___sysctl, (UWord)oid, 4, (UWord)procmap_buf,
4102 (UWord)&len, 0, 0);
4103 if (sr_isError(sres)) {
4104 VG_(debugLog)(0, "procselfmaps", "sysctl %lu\n", sr_Err(sres));
4105 ML_(am_exit)(1);
4107 gapStart = Addr_MIN;
4108 p = procmap_buf;
4109 while (p < (char *)procmap_buf + len) {
4110 kve = (struct vki_kinfo_vmentry *)p;
4111 start = (UWord)kve->kve_start;
4112 endPlusOne = (UWord)kve->kve_end;
4113 foffset = kve->kve_offset;
4114 filename = kve->kve_path;
4115 dev = kve->kve_vn_fsid_freebsd11;
4116 ino = kve->kve_fileid;
4117 if (filename[0] != '/') {
4118 filename = NULL;
4119 foffset = 0;
4122 prot = 0;
4123 if (kve->kve_protection & VKI_KVME_PROT_READ) prot |= VKI_PROT_READ;
4124 if (kve->kve_protection & VKI_KVME_PROT_WRITE) prot |= VKI_PROT_WRITE;
4125 if (kve->kve_protection & VKI_KVME_PROT_EXEC) prot |= VKI_PROT_EXEC;
4127 map_count = (p - (char *)procmap_buf)/kve->kve_structsize;
4129 if (tool_read_maps && map_count == rw_map) {
4130 aspacem_assert((prot & (VKI_PROT_READ | VKI_PROT_WRITE)) == (VKI_PROT_READ | VKI_PROT_WRITE));
4131 filename = rx_filename;
4132 dev = rx_dev;
4133 ino = rx_ino;
4134 foffset = rx_foffset;
4137 if (record_gap && gapStart < start)
4138 (*record_gap) ( gapStart, start-gapStart );
4140 if (kve->kve_type == VKI_KVME_TYPE_GUARD &&
4141 record_mapping == sync_check_mapping_callback &&
4142 VG_(clo_sanity_level) >= 3) {
4143 p = maybe_merge_procmap_stack(p, kve, &endPlusOne, &prot);
4146 if (record_mapping && start < endPlusOne) {
4147 (*record_mapping) ( start, endPlusOne-start,
4148 prot, dev, ino,
4149 foffset, filename, tool_read_maps && map_count == 2 );
4152 if (tool_read_maps && map_count == rx_map) {
4153 aspacem_assert((prot & (VKI_PROT_READ | VKI_PROT_EXEC)) == (VKI_PROT_READ | VKI_PROT_EXEC));
4154 rx_filename = filename;
4155 rx_dev = dev;
4156 rx_ino = ino;
4157 /* this is only accurate to the page alignment */
4158 rx_foffset = foffset + endPlusOne - start;
4161 gapStart = endPlusOne;
4162 // PJF I think that we need to walk this based on each entry's kve_structsize
4163 // because sysctl kern.coredump_pack_fileinfo (on by default) can cause this
4164 // array to be packed (for core dumps)
4165 // the packing consists of only storing the used part of kve_path rather than
4166 // the full 1024 bytes
4167 p += kve->kve_structsize;
4170 if (record_gap && gapStart < Addr_MAX)
4171 (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
4174 /*------END-procmaps-parser-for-Freebsd--------------------------*/
4176 /*------BEGIN-procmaps-parser-for-Solaris------------------------*/
4178 #elif defined(VGO_solaris)
4180 /* Note: /proc/self/xmap contains extended information about already
4181 materialized mappings whereas /proc/self/rmap contains information about
4182 all mappings including reserved but yet-to-materialize mappings (mmap'ed
4183 with MAP_NORESERVE flag, such as thread stacks). But /proc/self/rmap does
4184 not contain extended information found in /proc/self/xmap. Therefore
4185 information from both sources need to be combined.
4188 typedef struct
4190 Addr addr;
4191 SizeT size;
4192 UInt prot;
4193 ULong dev;
4194 ULong ino;
4195 Off64T foffset;
4196 HChar filename[VKI_PATH_MAX];
4197 } Mapping;
4199 static SizeT read_proc_file(const HChar *filename, HChar *buf,
4200 SizeT buf_size, const HChar *buf_size_name,
4201 SizeT entry_size)
4203 SysRes res = ML_(am_open)(filename, VKI_O_RDONLY, 0);
4204 if (sr_isError(res)) {
4205 HChar message[100];
4206 ML_(am_sprintf)(message, "Cannot open %s.", filename);
4207 ML_(am_barf)(message);
4209 Int fd = sr_Res(res);
4211 Int r = ML_(am_read)(fd, buf, buf_size);
4212 ML_(am_close)(fd);
4213 if (r < 0) {
4214 HChar message[100];
4215 ML_(am_sprintf)(message, "I/O error on %s.", filename);
4216 ML_(am_barf)(message);
4219 if (r >= buf_size)
4220 ML_(am_barf_toolow)(buf_size_name);
4222 if (r % entry_size != 0) {
4223 HChar message[100];
4224 ML_(am_sprintf)(message, "Bogus values read from %s.", filename);
4225 ML_(am_barf)(message);
4228 return r / entry_size;
4231 static Mapping *next_xmap(const HChar *buffer, SizeT entries, SizeT *idx,
4232 Mapping *mapping)
4234 aspacem_assert(idx);
4235 aspacem_assert(mapping);
4237 if (*idx >= entries)
4238 return NULL; /* No more entries */
4240 const vki_prxmap_t *map = (const vki_prxmap_t *)buffer + *idx;
4242 mapping->addr = map->pr_vaddr;
4243 mapping->size = map->pr_size;
4245 mapping->prot = 0;
4246 if (map->pr_mflags & VKI_MA_READ)
4247 mapping->prot |= VKI_PROT_READ;
4248 if (map->pr_mflags & VKI_MA_WRITE)
4249 mapping->prot |= VKI_PROT_WRITE;
4250 if (map->pr_mflags & VKI_MA_EXEC)
4251 mapping->prot |= VKI_PROT_EXEC;
4253 if (map->pr_dev != VKI_PRNODEV) {
4254 mapping->dev = map->pr_dev;
4255 mapping->ino = map->pr_ino;
4256 mapping->foffset = map->pr_offset;
4258 else {
4259 mapping->dev = 0;
4260 mapping->ino = 0;
4261 mapping->foffset = 0;
4264 /* Try to get the filename. */
4265 mapping->filename[0] = '\0';
4266 if (map->pr_mapname[0] != '\0') {
4267 ML_(am_sprintf)(mapping->filename, "/proc/self/path/%s",
4268 map->pr_mapname);
4269 Int r = ML_(am_readlink)(mapping->filename, mapping->filename,
4270 sizeof(mapping->filename) - 1);
4271 if (r == -1) {
4272 /* If Valgrind is executed in a non-global zone and the link in
4273 /proc/self/path/ represents a file that is available through lofs
4274 from a global zone then the kernel may not be able to resolve the
4275 link.
4277 In such a case, return a corresponding /proc/self/object/ file to
4278 allow Valgrind to read the file if it is necessary.
4280 This can create some discrepancy for the sanity check. For
4281 instance, if a client program mmaps some file then the address
4282 space manager will have a correct zone-local name of that file,
4283 but the sanity check will receive a different file name from this
4284 code. This currently does not represent a problem because the
4285 sanity check ignores the file names (it uses device and inode
4286 numbers for the comparison).
4288 ML_(am_sprintf)(mapping->filename, "/proc/self/object/%s",
4289 map->pr_mapname);
4291 else {
4292 aspacem_assert(r >= 0);
4293 mapping->filename[r] = '\0';
4297 *idx += 1;
4298 return mapping;
4301 static Mapping *next_rmap(const HChar *buffer, SizeT entries, SizeT *idx,
4302 Mapping *mapping)
4304 aspacem_assert(idx);
4305 aspacem_assert(mapping);
4307 if (*idx >= entries)
4308 return NULL; /* No more entries */
4310 const vki_prmap_t *map = (const vki_prmap_t *)buffer + *idx;
4312 mapping->addr = map->pr_vaddr;
4313 mapping->size = map->pr_size;
4315 mapping->prot = 0;
4316 if (map->pr_mflags & VKI_MA_READ)
4317 mapping->prot |= VKI_PROT_READ;
4318 if (map->pr_mflags & VKI_MA_WRITE)
4319 mapping->prot |= VKI_PROT_WRITE;
4320 if (map->pr_mflags & VKI_MA_EXEC)
4321 mapping->prot |= VKI_PROT_EXEC;
4323 mapping->dev = 0;
4324 mapping->ino = 0;
4325 mapping->foffset = 0;
4326 mapping->filename[0] = '\0';
4328 *idx += 1;
4329 return mapping;
4332 /* Used for two purposes:
4333 1. Establish initial mappings upon the process startup
4334 2. Check mappings during aspacemgr sanity check
4336 static void parse_procselfmaps (
4337 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
4338 ULong dev, ULong ino, Off64T offset,
4339 const HChar *filename, Bool ignore_offset ),
4340 void (*record_gap)( Addr addr, SizeT len )
4343 Addr start = Addr_MIN;
4344 Addr gap_start = Addr_MIN;
4346 #define M_XMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prxmap_t))
4347 /* Static to keep it out of stack frame... */
4348 static HChar xmap_buf[M_XMAP_BUF];
4349 const Mapping *xmap = NULL;
4350 SizeT xmap_index = 0; /* Current entry */
4351 SizeT xmap_entries;
4352 Mapping xmap_mapping;
4353 Bool advance_xmap;
4355 #define M_RMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prmap_t))
4356 static HChar rmap_buf[M_RMAP_BUF];
4357 const Mapping *rmap = NULL;
4358 SizeT rmap_index = 0; /* Current entry */
4359 SizeT rmap_entries;
4360 Mapping rmap_mapping;
4361 Bool advance_rmap;
4363 /* Read fully /proc/self/xmap and /proc/self/rmap. */
4364 xmap_entries = read_proc_file("/proc/self/xmap", xmap_buf, M_XMAP_BUF,
4365 "M_XMAP_BUF", sizeof(vki_prxmap_t));
4367 rmap_entries = read_proc_file("/proc/self/rmap", rmap_buf, M_RMAP_BUF,
4368 "M_RMAP_BUF", sizeof(vki_prmap_t));
4370 /* Get the first xmap and rmap. */
4371 advance_xmap = True;
4372 advance_rmap = True;
4374 while (1) {
4375 /* Get next xmap or rmap if necessary. */
4376 if (advance_xmap) {
4377 xmap = next_xmap(xmap_buf, xmap_entries, &xmap_index, &xmap_mapping);
4378 advance_xmap = False;
4380 if (advance_rmap) {
4381 rmap = next_rmap(rmap_buf, rmap_entries, &rmap_index, &rmap_mapping);
4382 advance_rmap = False;
4385 /* Check if the end has been reached. */
4386 if (rmap == NULL)
4387 break;
4389 /* Invariants */
4390 if (xmap != NULL) {
4391 aspacem_assert(start <= xmap->addr);
4392 aspacem_assert(rmap->addr <= xmap->addr);
4395 if (xmap != NULL && start == xmap->addr) {
4396 /* xmap mapping reached. */
4397 aspacem_assert(xmap->addr >= rmap->addr &&
4398 xmap->addr + xmap->size <= rmap->addr + rmap->size);
4399 aspacem_assert(xmap->prot == rmap->prot);
4401 if (record_mapping != NULL)
4402 (*record_mapping)(xmap->addr, xmap->size, xmap->prot, xmap->dev,
4403 xmap->ino, xmap->foffset,
4404 (xmap->filename[0] != '\0') ?
4405 xmap->filename : NULL, False);
4407 start = xmap->addr + xmap->size;
4408 advance_xmap = True;
4410 else if (start >= rmap->addr) {
4411 /* Reserved-only part. */
4412 /* First calculate size until the end of this reserved mapping... */
4413 SizeT size = rmap->addr + rmap->size - start;
4414 /* ... but shrink it if some xmap is in a way. */
4415 if (xmap != NULL && size > xmap->addr - start)
4416 size = xmap->addr - start;
4418 if (record_mapping != NULL)
4419 (*record_mapping)(start, size, rmap->prot, 0, 0, 0, NULL, False);
4420 start += size;
4422 else {
4423 /* Gap. */
4424 if (record_gap != NULL && gap_start < start)
4425 (*record_gap)(gap_start, start - gap_start);
4426 start = rmap->addr;
4429 if (rmap->addr + rmap->size <= start)
4430 advance_rmap = True;
4432 gap_start = start;
4435 if (record_gap != NULL && gap_start < Addr_MAX)
4436 (*record_gap)(gap_start, Addr_MAX - gap_start + 1);
4439 /* parse_procselfmaps() callbacks do not allow for easy thread safety. */
4440 static Addr found_addr;
4441 static SizeT found_size;
4442 static UInt found_prot;
4444 /* Reports a new mapping into variables above. */
4445 static void new_segment_found_callback(Addr addr, SizeT len, UInt prot,
4446 ULong dev, ULong ino, Off64T offset, const HChar *filename, Bool ignore_offset)
4448 aspacem_assert(addr <= addr + len - 1);
4450 Int iLo = find_nsegment_idx(addr);
4451 Int iHi = find_nsegment_idx(addr + len - 1);
4452 aspacem_assert(iLo <= iHi);
4453 aspacem_assert(nsegments[iLo].start <= addr);
4454 aspacem_assert(nsegments[iHi].end >= addr + len - 1);
4456 /* Do not perform any sanity checks. That is done in other places.
4457 Just find if a reported mapping is found in aspacemgr's book keeping. */
4458 for (Int i = iLo; i <= iHi; i++) {
4459 if ((nsegments[i].kind == SkFree) || (nsegments[i].kind == SkResvn)) {
4460 found_addr = addr;
4461 found_size = len;
4462 found_prot = prot;
4463 break;
4468 /* Returns True if a new segment was found. */
4469 Bool VG_(am_search_for_new_segment)(Addr *addr, SizeT *size, UInt *prot)
4471 found_addr = 0;
4472 parse_procselfmaps(new_segment_found_callback, NULL);
4474 if (found_addr != 0) {
4475 *addr = found_addr;
4476 *size = found_size;
4477 *prot = found_prot;
4478 return True;
4479 } else {
4480 return False;
4484 #endif // defined(VGO_solaris)
4486 /*------END-procmaps-parser-for-Solaris--------------------------*/
4488 #endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd)
4490 /*--------------------------------------------------------------------*/
4491 /*--- end ---*/
4492 /*--------------------------------------------------------------------*/