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