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