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 (at) 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 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 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 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 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 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!). */ 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. */ 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 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 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 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 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 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 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 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. */ 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)) 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 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. */ 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. */ 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. */ 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. */ 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 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. */ 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. */ 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 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 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. */ 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 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 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 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 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 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 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 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 */ 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 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 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. */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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. */ 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 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 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 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 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. */ 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 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 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. */ 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 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 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 3063 static Int decdigit ( HChar c ) 3064 { 3065 if (c >= '0' && c <= '9') return (Int)(c - '0'); 3066 return -1; 3067 } 3068 3069 static Int readchar ( const HChar* buf, HChar* ch ) 3070 { 3071 if (*buf == 0) return 0; 3072 *ch = *buf; 3073 return 1; 3074 } 3075 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 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 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 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 */ 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 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 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 3431 static Addr Addr__max ( Addr a, Addr b ) { return a > b ? a : b; } 3432 static Addr Addr__min ( Addr a, Addr b ) { return a < b ? a : b; } 3433 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 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. 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