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