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