1 2 /*--------------------------------------------------------------------*/ 3 /*--- The address space manager: segment initialisation and ---*/ 4 /*--- tracking, stack operations ---*/ 5 /*--- ---*/ 6 /*--- Implementation for AIX5 m_aspacemgr-aix5.c ---*/ 7 /*--------------------------------------------------------------------*/ 8 9 /* 10 This file is part of Valgrind, a dynamic binary instrumentation 11 framework. 12 13 Copyright (C) 2006-2010 OpenWorks LLP 14 info (at) open-works.co.uk 15 16 This program is free software; you can redistribute it and/or 17 modify it under the terms of the GNU General Public License as 18 published by the Free Software Foundation; either version 2 of the 19 License, or (at your option) any later version. 20 21 This program is distributed in the hope that it will be useful, but 22 WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 General Public License for more details. 25 26 You should have received a copy of the GNU General Public License 27 along with this program; if not, write to the Free Software 28 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 29 02111-1307, USA. 30 31 The GNU General Public License is contained in the file COPYING. 32 33 Neither the names of the U.S. Department of Energy nor the 34 University of California nor the names of its contributors may be 35 used to endorse or promote products derived from this software 36 without prior written permission. 37 */ 38 39 #if defined(VGO_aix5) 40 41 /* ************************************************************* 42 DO NOT INCLUDE ANY OTHER FILES HERE. 43 ADD NEW INCLUDES ONLY TO priv_aspacemgr.h 44 AND THEN ONLY AFTER READING DIRE WARNINGS THERE TOO. 45 ************************************************************* */ 46 47 #include "priv_aspacemgr.h" 48 49 50 /* Note: many of the exported functions implemented below are 51 described more fully in comments in pub_core_aspacemgr.h. 52 */ 53 54 /* This provides a minimal address space management facility for AIX5. 55 It is not as comprehensive, robust or efficient as its Linux 56 counterpart. 57 58 It does implement the advise/notify concept described in 59 aspacemgr-linux.c, but minimally. It only keeps track of the 60 mappings belonging to Valgrind; the client can do what it likes so 61 long as it doesn't trash Valgrind's mappings. 62 63 This is unfortunate, but the root problem is that it is impossible 64 to find out on AIX what the complete set of mappings for a process 65 is. Sure, AIX does have /proc/pid/map, but it's weak compared to 66 Linux's: it just shows some small subset of the mappings, not all 67 of them. So it is not very useful: it can't be used to discover 68 the true initial process mapping state, and it can't be used to 69 cross-check Valgrind's internal mapping table, as is done at 70 --sanity-level=3 and above on Linux. 71 */ 72 73 74 /*-----------------------------------------------------------------*/ 75 /*--- ---*/ 76 /*--- The Address Space Manager's state. ---*/ 77 /*--- ---*/ 78 /*-----------------------------------------------------------------*/ 79 80 /* Describes AIX5-specific segment kinds */ 81 typedef 82 enum { 83 ASkFree=1, // free space 84 ASkMText, // module text (code) mapping 85 ASkMData, // module data (& bss) mapping 86 ASkFileV, // file mapping belonging to valgrind 87 ASkAnonC, // anonymous mapping belonging to the client 88 ASkAnonV, // anonymous mapping belonging to valgrind 89 ASkShmemC, // shm mapping belonging to the client 90 ASkPreAlloc // area preallocated from sbrk 91 } 92 AixSegKind; 93 94 /* Segment table entries, in summary: 95 96 ASkFree start end 97 ASkMText start end r w x sibling ismainexe fname mname 98 ASkMData start end r w x sibling 99 FileV start end r w x fname offset 100 AnonC start end r w x fromP isCH 101 AnonV start end r w x fromP 102 ShmemC start end r w x 103 PreAlloc start end 104 105 Entries are non-overlapping and cover the entire address space 106 exactly (as in the Linux aspacem). Unlike Linux there are no 107 alignment constraints, since we're just recording what's going on, 108 rather than controlling it. 109 110 MText/MData are XCOFF mapped modules, as determined by looking at 111 /proc/../map. MText is the primary entry and contains the text 112 range. MData contains the data range, if the module has a data 113 mapping (usually but not always). MText also holds the avma of the 114 corresponding data segment start, if any, (sibling field) so it can 115 be found and the two added/removed together. Similarly MData 116 contains the address of the corresponding MText (also sibling). 117 118 fname/mname only apply to MText. To find the fname/mname for MData 119 you have to look at the corresponding MText entry, which is 120 guaranteed to exist. MText may exist without a corresponding MData 121 but not vice versa. Kludge: in fact fname/mname have to be 122 allowed in MData, else read_procselfmap doesn't work. 123 124 MText may have a zero sibling pointer, indicating that there is no 125 corresponding MData. But MData must have a nonzero sibling pointer 126 since MData without MText is not allowed. Implication is that 127 neither MText nor MData may be mapped at zero as this would mess up 128 the representation, but I don't think that will ever happen since 129 AIX uses page zero as a readonly const-zero area. 130 131 For MData entries, the data section size acquired from /proc/../map 132 appears to also include the bss, so there is no need for any 133 further handling of that. 134 135 isCH indicates whether an AnonC area is part of the client heap 136 or not. May not be set for any other kind of area. 137 138 File and member names are entries into the string table. 139 140 fromP, for AnonC/AnonV, if True, indicates that the segment was 141 allocated from a PreAlloc area, and so should be returned to that 142 state upon deallocation. If False, indicates that the segment 143 should be unmapped on deallocation. 144 */ 145 typedef 146 struct { 147 AixSegKind kind; 148 149 /* ALL: extent */ 150 /* Note: zero-length segments are not allowed. That guarantees 151 that start <= end. */ 152 Addr start; // lowest addr in range (ALL) 153 Addr end; // highest addr in range (ALL) 154 155 /* ALL except Free */ 156 Bool hasR; 157 Bool hasW; 158 Bool hasX; 159 160 /* misc */ 161 Addr sibling; // MText, MData only: addr of MData/MText 162 Bool isMainExe; // MText only: is this the main executable? 163 Bool isCH; // AnonC only: is this part of the client's heap? 164 Bool fromP; // AnonC, AnonV only: originated from PreAlloc? 165 UChar* fname; // MText, FileV only: filename 166 UChar* mname; // MText only: member name if present 167 Off64T offset; // FileV only: file offset 168 } 169 AixSegment; 170 171 172 #define VG_N_ASEGMENTS 5000 173 174 typedef 175 struct { 176 AixSegment seg[VG_N_ASEGMENTS]; 177 Int used; 178 } 179 AixSegments; 180 181 182 /* ------ start of STATE for the address-space manager ------ */ 183 184 /* A table of zero-terminated strings (file names etc). This 185 is only ever added to. */ 186 187 #define VG_N_ASTRTAB 200000 188 static Int strtab_used = 0; 189 static UChar strtab[VG_N_ASTRTAB]; 190 191 #define Addr_MIN ((Addr)0) 192 #define Addr_MAX ((Addr)(-1ULL)) 193 194 /* The main array of AixSegments, in order as required. */ 195 196 static AixSegments asegs_pri; 197 198 /* and two auxiliary arrays. */ 199 200 static AixSegments asegs_tnew; 201 static AixSegments asegs_told; 202 203 /* The assumed size of the main thread's stack, so that we can add a 204 segment for it at startup. */ 205 206 #define N_FAKE_STACK_PAGES_MIN 4096 /* 16M fake stack */ /* default size */ 207 #define N_FAKE_STACK_PAGES_MAX 32768 /* 128M fake stack */ /* max size? */ 208 209 210 /* Hacks which are probably for AIX 'millicode'. Note: ensure 211 these stay page aligned. */ 212 213 #define MAGIC_PAGES_1_BASE 0x3000 214 #define MAGIC_PAGES_1_SIZE (2*0x1000) 215 216 #define MAGIC_PAGES_2_BASE 0xC000 217 #define MAGIC_PAGES_2_SIZE (4*0x1000) 218 219 220 #define AM_SANITY_CHECK(_who) \ 221 do { \ 222 if (VG_(clo_sanity_level >= 3)) { \ 223 Bool ok = sane_AixSegments(&asegs_pri); \ 224 if (!ok) \ 225 VG_(debugLog)(0,"aspace", "sanity check failed, " \ 226 "who = %s\n", _who); \ 227 aspacem_assert(ok); \ 228 } \ 229 } while (0) 230 231 /* When preallocating a block from sbrk-world, how much extra 232 should we pre-emptively acquire? */ 233 234 //#define AM_PREALLOC_EXTRA (512 * 1024) 235 //#define AM_PREALLOC_EXTRA 0x0800000 /* 8 M */ 236 #define AM_PREALLOC_EXTRA 0x4000000 /* 64 M */ 237 238 /* The AIX5 aspacem implementation needs to be told when it is and 239 isn't allowed to use sbrk to allocate memory. Hence: */ 240 Bool VG_(am_aix5_sbrk_allowed) = True; 241 242 /* ------ end of STATE for the address-space manager ------ */ 243 244 /* ------ Forwards decls ------ */ 245 static void parse_procselfmap ( /*OUT*/ AixSegments* ); 246 247 248 /*-----------------------------------------------------------------*/ 249 /*--- ---*/ 250 /*--- Stuff for 4K (small-page-size) rounding. ---*/ 251 /*--- ---*/ 252 /*-----------------------------------------------------------------*/ 253 254 #define AM_4K_PAGESZ 4096 255 256 static Bool AM_IS_4K_ALIGNED ( UWord w ) 257 { 258 UWord m = AM_4K_PAGESZ-1; 259 return toBool( (w & m) == 0 ); 260 } 261 262 static UWord AM_4K_ROUNDUP ( UWord w ) 263 { 264 UWord m = AM_4K_PAGESZ-1; 265 return (w+m) & (~m); 266 } 267 268 static UWord AM_64K_ROUNDUP ( UWord w ) 269 { 270 UWord m = 0x10000-1; 271 return (w+m) & (~m); 272 } 273 274 275 /*-----------------------------------------------------------------*/ 276 /*--- ---*/ 277 /*--- String table management. ---*/ 278 /*--- ---*/ 279 /*-----------------------------------------------------------------*/ 280 281 /* Add the given string into the string table (or find an existing 282 copy of it) and return a pointer to the in-table version. The 283 pointer will be valid for the entire rest of the run. */ 284 285 static UChar* add_to_strtab ( UChar* str ) 286 { 287 Int off, len; 288 /* First, look for the string. */ 289 off = 0; 290 while (off < strtab_used) { 291 if (0 == VG_(strcmp)(str, &strtab[off])) 292 return &strtab[off]; 293 off += VG_(strlen)(&strtab[off]) + 1; 294 } 295 /* not present? we'll have to copy it then. */ 296 len = VG_(strlen)(str); 297 if (len + 1 + strtab_used > VG_N_ASTRTAB) 298 ML_(am_barf_toolow)("VG_N_ASTRTAB"); 299 off = strtab_used; 300 for (; *str; str++) 301 strtab[strtab_used++] = *str; 302 strtab[strtab_used++] = 0; 303 aspacem_assert(strtab_used <= VG_N_ASTRTAB); 304 return &strtab[off]; 305 } 306 307 308 static Bool is_in_strtab ( UChar* str ) 309 { 310 if (str < &strtab[0]) 311 return False; 312 if (str >= &strtab[strtab_used]) 313 return False; 314 if (str > &strtab[0] && str[-1] != 0) 315 return False; 316 return True; 317 } 318 319 320 /*-----------------------------------------------------------------*/ 321 /*--- ---*/ 322 /*--- Low level AixSegment stuff. ---*/ 323 /*--- ---*/ 324 /*-----------------------------------------------------------------*/ 325 326 static void init_AixSegment ( AixSegment* s ) 327 { 328 s->kind = 0; /* invalid */ 329 s->start = 0; 330 s->end = 0; 331 s->hasR = False; 332 s->hasW = False; 333 s->hasX = False; 334 s->sibling = 0; 335 s->isMainExe = False; 336 s->isCH = False; 337 s->fromP = False; 338 s->fname = NULL; 339 s->mname = NULL; 340 s->offset = 0; 341 } 342 343 344 static HChar* name_of_AixSegKind ( AixSegKind sk ) 345 { 346 switch (sk) { 347 case ASkFree: return "Free "; 348 case ASkMText: return "MText"; 349 case ASkMData: return "MData"; 350 case ASkAnonV: return "AnonV"; 351 case ASkAnonC: return "AnonC"; 352 case ASkFileV: return "FileV"; 353 case ASkShmemC: return "ShmC "; 354 case ASkPreAlloc: return "PreAl"; 355 default: ML_(am_barf)("name_of_AixSegKind"); 356 /*NOTREACHED*/ 357 return NULL; 358 } 359 } 360 361 362 static 363 void show_AixSegment ( Int logLevel, Int segNo, AixSegment* seg ) 364 { 365 HChar* segName = name_of_AixSegKind( seg->kind ); 366 switch (seg->kind) { 367 case ASkFree: 368 VG_(debugLog)(logLevel, "aspacem", 369 "%3d: %s %010llx-%010llx\n", 370 segNo, /*segName*/" ", 371 (ULong)seg->start, (ULong)seg->end 372 ); 373 break; 374 case ASkMText: 375 VG_(debugLog)(logLevel, "aspacem", 376 "%3d: %s %010llx-%010llx %c%c%c-- (d %010llx) %s%s%s%s\n", 377 segNo, seg->isMainExe ? "MTEXT" : "MText", 378 (ULong)seg->start, (ULong)seg->end, 379 seg->hasR ? 'r' : '-', 380 seg->hasW ? 'w' : '-', 381 seg->hasX ? 'x' : '-', 382 (ULong)seg->sibling, 383 seg->fname, 384 seg->mname ? "(" : "", 385 seg->mname ? (HChar*)seg->mname : "", 386 seg->mname ? ")" : "" 387 ); 388 break; 389 case ASkMData: 390 VG_(debugLog)(logLevel, "aspacem", 391 "%3d: %s %010llx-%010llx %c%c%c-- (t %010llx)\n", 392 segNo, "MData", 393 (ULong)seg->start, (ULong)seg->end, 394 seg->hasR ? 'r' : '-', 395 seg->hasW ? 'w' : '-', 396 seg->hasX ? 'x' : '-', 397 (ULong)seg->sibling 398 ); 399 break; 400 case ASkFileV: 401 VG_(debugLog)(logLevel, "aspacem", 402 "%3d: %s %010llx-%010llx %c%c%c-- %6lld %s\n", 403 segNo, segName, 404 (ULong)seg->start, (ULong)seg->end, 405 seg->hasR ? 'r' : '-', 406 seg->hasW ? 'w' : '-', 407 seg->hasX ? 'x' : '-', 408 seg->offset, 409 seg->fname 410 ); 411 break; 412 case ASkAnonV: 413 case ASkAnonC: 414 case ASkShmemC: 415 VG_(debugLog)(logLevel, "aspacem", 416 "%3d: %s %010llx-%010llx %c%c%c%c%c\n", 417 segNo, segName, 418 (ULong)seg->start, (ULong)seg->end, 419 seg->hasR ? 'r' : '-', 420 seg->hasW ? 'w' : '-', 421 seg->hasX ? 'x' : '-', 422 seg->kind==ASkAnonC && seg->isCH ? 'H' : '-', 423 seg->fromP ? 'P' : '-' 424 ); 425 break; 426 case ASkPreAlloc: 427 VG_(debugLog)(logLevel, "aspacem", 428 "%3d: %s %010llx-%010llx %c%c%c-- (size %llu)\n", 429 segNo, segName, 430 (ULong)seg->start, (ULong)seg->end, 431 seg->hasR ? 'r' : '-', 432 seg->hasW ? 'w' : '-', 433 seg->hasX ? 'x' : '-', 434 (ULong)seg->end - (ULong)seg->start + 1 435 ); 436 break; 437 default: 438 VG_(debugLog)(logLevel, "aspacem", 439 "%3d: show_AixSegment: unknown segment\n", 440 segNo); 441 break; 442 } 443 } 444 445 446 static void init_AixSegments ( AixSegments* segs ) 447 { 448 segs->used = 1; 449 init_AixSegment( &segs->seg[0] ); 450 segs->seg[0].kind = ASkFree; 451 segs->seg[0].start = Addr_MIN; 452 segs->seg[0].end = Addr_MAX; 453 } 454 455 456 static 457 void show_AixSegments ( Int logLevel, HChar* who, AixSegments* segs ) 458 { 459 Int i; 460 VG_(debugLog)(logLevel, "aspacem", "<<< %s\n", who); 461 for (i = 0; i < segs->used; i++) 462 show_AixSegment( logLevel, i, &segs->seg[i] ); 463 VG_(debugLog)(logLevel, "aspacem", ">>>\n"); 464 } 465 466 467 static Bool sane_AixSegment ( AixSegment* seg ) 468 { 469 /* disallow zero and negative length segments */ 470 if (seg->end < seg->start) 471 return False; 472 473 switch (seg->kind) { 474 case ASkFree: 475 if (seg->hasR || seg->hasW || seg->hasX) 476 return False; 477 if (seg->isMainExe || seg->sibling != 0 || seg->offset != 0) 478 return False; 479 if (seg->fname || seg->mname) 480 return False; 481 if (seg->isCH || seg->fromP) 482 return False; 483 break; 484 case ASkMText: 485 if (!is_in_strtab(seg->fname)) 486 return False; 487 if (seg->mname && !is_in_strtab(seg->mname)) 488 return False; 489 if (seg->offset != 0) 490 return False; 491 if (seg->isCH || seg->fromP) 492 return False; 493 break; 494 case ASkMData: 495 if (seg->isMainExe || seg->sibling == 0 || seg->offset != 0) 496 return False; 497 /* fname/mname have to be allowed in MData, else 498 read_procselfmap doesn't work. Unfortunately. */ 499 /* 500 if (seg->fname || seg->mname) 501 return False; 502 */ 503 if (seg->isCH || seg->fromP) 504 return False; 505 break; 506 case ASkFileV: 507 if (!is_in_strtab(seg->fname)) 508 return False; 509 if (seg->mname != NULL) 510 return False; 511 if (seg->isMainExe || seg->sibling != 0) 512 return False; 513 if (seg->isCH || seg->fromP) 514 return False; 515 break; 516 case ASkShmemC: 517 case ASkAnonV: 518 case ASkAnonC: 519 if (seg->fname || seg->mname) 520 return False; 521 if (seg->isMainExe || seg->sibling != 0) 522 return False; 523 if (seg->offset != 0) 524 return False; 525 if (seg->kind != ASkAnonC && seg->isCH) 526 return False; 527 if ( (!(seg->kind == ASkAnonV || seg->kind == ASkAnonC)) 528 && seg->fromP) 529 return False; 530 break; 531 case ASkPreAlloc: 532 if (seg->fname || seg->mname) 533 return False; 534 if (seg->isMainExe || seg->sibling != 0) 535 return False; 536 if (seg->offset != 0) 537 return False; 538 if (seg->kind != ASkAnonC && seg->isCH) 539 return False; 540 if (seg->fromP) 541 return False; 542 if (!AM_IS_4K_ALIGNED(seg->start)) 543 return False; 544 if (!AM_IS_4K_ALIGNED(seg->end + 1)) 545 return False; 546 if (!(seg->hasR && seg->hasW && seg->hasX)) 547 return False; 548 break; 549 default: 550 return False; 551 } 552 return True; 553 } 554 555 556 /* Binary search the interval array for a given address. Since the 557 array covers the entire address space the search cannot fail. */ 558 static Int find_asegment_idx ( AixSegments* segs, Addr a ) 559 { 560 Addr a_mid_lo, a_mid_hi; 561 Int mid, 562 lo = 0, 563 hi = segs->used-1; 564 aspacem_assert(lo <= hi); 565 while (True) { 566 /* current unsearched space is from lo to hi, inclusive. */ 567 if (lo > hi) { 568 /* Not found. This can't happen. */ 569 ML_(am_barf)("find_nsegment_idx: not found"); 570 } 571 mid = (lo + hi) / 2; 572 a_mid_lo = segs->seg[mid].start; 573 a_mid_hi = segs->seg[mid].end; 574 575 if (a < a_mid_lo) { hi = mid-1; continue; } 576 if (a > a_mid_hi) { lo = mid+1; continue; } 577 aspacem_assert(a >= a_mid_lo && a <= a_mid_hi); 578 aspacem_assert(0 <= mid && mid < segs->used); 579 return mid; 580 } 581 } 582 583 584 static Bool sane_AixSegments ( AixSegments* segs ) 585 { 586 Int i; 587 588 /* Check endpoints */ 589 if (segs->used < 1 || segs->used > VG_N_ASEGMENTS) { 590 VG_(debugLog)(0, "aspacem", "sane_AixSegments: bad ->used"); 591 return False; 592 } 593 if (segs->seg[0].start != Addr_MIN 594 || segs->seg[segs->used-1].end != Addr_MAX) { 595 VG_(debugLog)(0, "aspacem", "sane_AixSegments: bad endpoints"); 596 return False; 597 } 598 599 /* Check each segment, and check entire range is covered. */ 600 for (i = 0; i < segs->used; i++) { 601 if (!sane_AixSegment( &segs->seg[i] )) { 602 VG_(debugLog)(0, "aspacem", 603 "sane_AixSegments: bad segment %d\n", i); 604 return False; 605 } 606 } 607 for (i = 1; i < segs->used; i++) { 608 if (segs->seg[i-1].end + 1 != segs->seg[i].start) { 609 VG_(debugLog)(0, "aspacem", 610 "sane_AixSegments: bad transition at %d/%d\n", i-1,i); 611 return False; 612 } 613 } 614 615 /* Now we know 'seg' is safe for use in find_asegment_idx(). 616 Check the sibling pointers for MText/MData. 617 618 Also check that the segment starting at address zero is neither 619 MText nor MData (since this would mess up the sibling pointer 620 representation; see comments above.) Failure of this is not per 621 se a logic failure, but it does indicate that the kernel 622 unexpectedly placed MText or MData at zero, and our 623 representation is therefore inadequate. 624 */ 625 if (segs->seg[0].kind == ASkMText || segs->seg[0].kind == ASkMData) { 626 VG_(debugLog)(0, "aspacem", 627 "sane_AixSegments: ASkMText/ASkMData at address zero\n"); 628 return False; 629 } 630 631 for (i = 0; i < segs->used-1; i++) { 632 633 AixSegment *s1, *s2; 634 635 s1 = &segs->seg[i]; 636 637 if (s1->kind == ASkMData) { 638 s2 = &segs->seg[ find_asegment_idx(segs, s1->sibling) ]; 639 if (s2->kind != ASkMText 640 || find_asegment_idx(segs, s2->sibling) != i) { 641 VG_(debugLog)(0, "aspacem", "sane_AixSegments: bad sibling " 642 "link(s) for ASkData\n"); 643 return False; 644 } 645 } 646 647 if (s1->kind == ASkMText && s1->sibling != 0) { 648 s2 = &segs->seg[ find_asegment_idx(segs, s1->sibling) ]; 649 if (s2->kind != ASkMData 650 || find_asegment_idx(segs, s2->sibling) != i) { 651 VG_(debugLog)(0, "aspacem", "sane_AixSegments: bad sibling " 652 "link(s) for ASkText\n"); 653 return False; 654 } 655 } 656 657 } 658 659 return True; 660 } 661 662 663 /* Try merging s2 into s1, if possible. If successful, s1 is 664 modified, and True is returned. Otherwise s1 is unchanged and 665 False is returned. */ 666 667 static Bool maybe_merge_asegments ( AixSegment* s1, AixSegment* s2 ) 668 { 669 if (s1->kind != s2->kind) 670 return False; 671 672 if (s1->end+1 != s2->start) 673 return False; 674 675 switch (s1->kind) { 676 677 case ASkFree: 678 s1->end = s2->end; 679 return True; 680 681 case ASkAnonC: 682 case ASkAnonV: 683 if (s1->hasR == s2->hasR && s1->hasW == s2->hasW 684 && s1->hasX == s2->hasX && s1->isCH == s2->isCH 685 && s1->fromP == s2->fromP) { 686 s1->end = s2->end; 687 return True; 688 } 689 break; 690 691 /* not really necessary, but .. */ 692 case SkFileV: 693 if (s1->hasR == s2->hasR 694 && s1->hasW == s2->hasW && s1->hasX == s2->hasX 695 && s1->fname == s2->fname 696 && s2->offset == s1->offset 697 + ((ULong)s2->start) - ((ULong)s1->start) ) { 698 s1->end = s2->end; 699 return True; 700 } 701 break; 702 703 /* it's important to merge PreAlloc's back together to avoid 704 fragmenting PreAlloc'd space unnecessarily */ 705 case ASkPreAlloc: 706 s1->end = s2->end; 707 return True; 708 709 default: 710 break; 711 } 712 713 return False; 714 } 715 716 717 /* Merge mergable segments in SEGS. */ 718 719 static void preen_asegments ( AixSegments* segs ) 720 { 721 Int r, w; 722 723 aspacem_assert(segs->used >= 1); 724 if (segs->used == 1) 725 return; 726 727 w = 0; 728 for (r = 1; r < segs->used; r++) { 729 if (maybe_merge_asegments(&segs->seg[w], &segs->seg[r])) { 730 /* nothing */ 731 } else { 732 w++; 733 if (w != r) 734 segs->seg[w] = segs->seg[r]; 735 } 736 } 737 w++; 738 aspacem_assert(w > 0 && w <= segs->used); 739 segs->used = w; 740 } 741 742 743 /*-----------------------------------------------------------------*/ 744 /*--- ---*/ 745 /*--- Modifying a segment array, and constructing segments. ---*/ 746 /*--- ---*/ 747 /*-----------------------------------------------------------------*/ 748 749 /* Split the segment containing 'a' into two, so that 'a' is 750 guaranteed to be the start of a new segment. If 'a' is already the 751 start of a segment, do nothing. */ 752 753 static void split_asegment_at ( AixSegments* segs, Addr a ) 754 { 755 Int i, j; 756 757 aspacem_assert(a > 0); 758 aspacem_assert(segs->used >= 1); 759 760 i = find_asegment_idx(segs, a); 761 aspacem_assert(i >= 0 && i < segs->used); 762 763 if (segs->seg[i].start == a) 764 /* 'a' is already the start point of a segment, so nothing to be 765 done. */ 766 return; 767 768 /* else we have to slide the segments upwards to make a hole */ 769 if (segs->used >= VG_N_ASEGMENTS) 770 ML_(am_barf_toolow)("VG_N_ASEGMENTS"); 771 for (j = segs->used-1; j > i; j--) 772 segs->seg[j+1] = segs->seg[j]; 773 segs->used++; 774 775 segs->seg[i+1] = segs->seg[i]; 776 segs->seg[i+1].start = a; 777 segs->seg[i].end = a-1; 778 779 if (segs->seg[i].kind == ASkFileV /* || segs->seg[i].kind == ASkFileC*/) 780 segs->seg[i+1].offset 781 += ((ULong)segs->seg[i+1].start) - ((ULong)segs->seg[i].start); 782 783 aspacem_assert(sane_AixSegment(&segs->seg[i])); 784 aspacem_assert(sane_AixSegment(&segs->seg[i+1])); 785 } 786 787 788 /* Do the minimum amount of segment splitting necessary to ensure that 789 sLo is the first address denoted by some segment and sHi is the 790 highest address denoted by some other segment. Returns the indices 791 of the lowest and highest segments in the range. */ 792 793 static 794 void split_asegments_lo_and_hi ( AixSegments* segs, 795 Addr sLo, Addr sHi, 796 /*OUT*/Int* iLo, 797 /*OUT*/Int* iHi ) 798 { 799 aspacem_assert(sLo < sHi); 800 801 if (sLo > 0) 802 split_asegment_at(segs, sLo); 803 if (sHi < Addr_MAX) 804 split_asegment_at(segs, sHi+1); 805 806 *iLo = find_asegment_idx(segs,sLo); 807 *iHi = find_asegment_idx(segs,sHi); 808 aspacem_assert(0 <= *iLo && *iLo < segs->used); 809 aspacem_assert(0 <= *iHi && *iHi < segs->used); 810 aspacem_assert(*iLo <= *iHi); 811 aspacem_assert(segs->seg[*iLo].start == sLo); 812 aspacem_assert(segs->seg[*iHi].end == sHi); 813 /* Not that I'm overly paranoid or anything, definitely not :-) */ 814 } 815 816 817 /* Add SEG to the collection, deleting/truncating any it overlaps. 818 This deals with all the tricky cases of splitting up segments as 819 needed. Contents of SEG are copied. */ 820 821 static void add_asegment ( AixSegments* segs, AixSegment* seg ) 822 { 823 Int i, iLo, iHi, delta; 824 Bool segment_is_sane; 825 826 Addr sStart = seg->start; 827 Addr sEnd = seg->end; 828 829 aspacem_assert(sStart <= sEnd); 830 831 segment_is_sane = sane_AixSegment(seg); 832 if (!segment_is_sane) show_AixSegment(0,0,seg); 833 aspacem_assert(segment_is_sane); 834 835 split_asegments_lo_and_hi( segs, sStart, sEnd, &iLo, &iHi ); 836 837 /* Now iLo .. iHi inclusive is the range of segment indices which 838 seg will replace. If we're replacing more than one segment, 839 slide those above the range down to fill the hole. */ 840 delta = iHi - iLo; 841 aspacem_assert(delta >= 0); 842 if (delta > 0) { 843 for (i = iLo; i < segs->used-delta; i++) 844 segs->seg[i] = segs->seg[i+delta]; 845 segs->used -= delta; 846 } 847 aspacem_assert(segs->used >= 1); 848 849 segs->seg[iLo] = *seg; 850 851 preen_asegments(segs); 852 if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)"); 853 } 854 855 856 /* Convert everything in SEG except MData and MText into Free, 857 then preen, so as to retain normalised form. */ 858 859 static void knockout_non_module_segs ( AixSegments* segs ) 860 { 861 Int i; 862 Addr s, e; 863 for (i = 0; i < segs->used; i++) { 864 if (segs->seg[i].kind == ASkFree 865 || segs->seg[i].kind == ASkMText 866 || segs->seg[i].kind == ASkMData) 867 continue; 868 s = segs->seg[i].start; 869 e = segs->seg[i].end; 870 init_AixSegment( &segs->seg[i] ); 871 segs->seg[i].start = s; 872 segs->seg[i].end = e; 873 segs->seg[i].kind = ASkFree; 874 } 875 preen_asegments(segs); 876 aspacem_assert( sane_AixSegments(segs) ); 877 } 878 879 880 /* Copy a segment array. */ 881 882 static void copy_asegments_d_s ( AixSegments* dst, AixSegments* src ) 883 { 884 Int i; 885 aspacem_assert(src->used >= 1 && src->used < VG_N_ASEGMENTS); 886 dst->used = src->used; 887 for (i = 0; i < src->used; i++) 888 dst->seg[i] = src->seg[i]; 889 } 890 891 892 /*-----------------------------------------------------------------*/ 893 /*--- ---*/ 894 /*--- Re-reading /proc/../map and updating MText/MData segments ---*/ 895 /*--- ---*/ 896 /*-----------------------------------------------------------------*/ 897 898 /* Find out the size of the AixCodeSegChange that must be 899 presented to VG_(am_aix5_reread_procmap). */ 900 901 Int VG_(am_aix5_reread_procmap_howmany_directives)(void) 902 { 903 /* In the worst imaginable case, all the tracked modules could have 904 disappeared and been replaced with different ones. Hence: */ 905 return 2 * VG_N_ASEGMENTS; 906 } 907 908 909 static 910 void add_pri_text_and_data_segs ( AixSegment* tnew, AixSegment* dnew ) 911 { 912 Bool dExists = (dnew->end - dnew->start + 1) != 0; 913 aspacem_assert(tnew->kind == ASkMText); 914 aspacem_assert(dnew->kind == ASkMData); 915 if (dExists) { 916 aspacem_assert(tnew->sibling == dnew->start); 917 aspacem_assert(dnew->sibling == tnew->start); 918 add_asegment(&asegs_pri, tnew); 919 add_asegment(&asegs_pri, dnew); 920 } else { 921 aspacem_assert(tnew->sibling == 0); 922 add_asegment(&asegs_pri, tnew); 923 } 924 } 925 926 static 927 void del_pri_text_and_data_segs ( AixSegment* told, AixSegment* dold ) 928 { 929 AixSegment fre; 930 Bool dExists = (dold->end - dold->start + 1) != 0; 931 aspacem_assert(told->kind == ASkMText); 932 aspacem_assert(dold->kind == ASkMData); 933 init_AixSegment( &fre ); 934 fre.kind = ASkFree; 935 if (dExists) { 936 aspacem_assert(told->sibling == dold->start); 937 aspacem_assert(dold->sibling == told->start); 938 fre.start = told->start; 939 fre.end = told->end; 940 add_asegment(&asegs_pri, &fre); 941 fre.start = dold->start; 942 fre.end = dold->end; 943 add_asegment(&asegs_pri, &fre); 944 } else { 945 aspacem_assert(told->sibling == 0); 946 fre.start = told->start; 947 fre.end = told->end; 948 add_asegment(&asegs_pri, &fre); 949 } 950 } 951 952 953 /* Tell aspacem that /proc/<pid>/map may have changed (eg following 954 __loadx) and so it should be re-read, and the code/data segment 955 list updated accordingly. The resulting array of AixCodeChangeSeg 956 directives are written to 'directives', and the number of entries 957 to *ndirectives. */ 958 959 void VG_(am_aix5_reread_procmap) 960 ( /*OUT*/AixCodeSegChange* directives, /*OUT*/Int* ndirectives ) 961 { 962 Int ixold, ixnew; 963 Bool done_old, done_new; 964 AixSegment *olds, *news; 965 966 /* First, read /proc/../map into asegs_tnew. Copy asegs_pri into 967 asegs_told, and remove everything except MData and MText, so as 968 to generate something we can sanely compare with asegs_tnew. 969 Walk asegs_told and asegs_tnew together, writing the differences 970 to 'directives', and modifying asegs_pri accordingly. */ 971 parse_procselfmap( &asegs_tnew ); 972 copy_asegments_d_s( &asegs_told, &asegs_pri ); 973 knockout_non_module_segs( &asegs_told ); 974 975 *ndirectives = 0; 976 977 # define MODIFY_PRI(_dir, _asegs, _ixt, _acquire) \ 978 do { \ 979 Int _ixd; \ 980 AixSegment *_segt, *_segd; \ 981 AixSegment _segd_dummy; \ 982 aspacem_assert(_ixt >= 0 && _ixt < _asegs.used); \ 983 _segt = &_asegs.seg[_ixt]; \ 984 aspacem_assert(_segt->kind == ASkMText); \ 985 if (_segt->sibling) { \ 986 _ixd = find_asegment_idx( &_asegs, _segt->sibling ); \ 987 _segd = &_asegs.seg[_ixd]; \ 988 aspacem_assert(_segd->kind == ASkMData); \ 989 aspacem_assert(_segt->sibling == _segd->start); \ 990 } else { \ 991 init_AixSegment( &_segd_dummy ); \ 992 _segd_dummy.kind = ASkMData; \ 993 _segd_dummy.start = 1; \ 994 _segd_dummy.end = 0; \ 995 _segd = &_segd_dummy; \ 996 } \ 997 if (_segd != &_segd_dummy) \ 998 aspacem_assert(_segd->sibling == _segt->start); \ 999 \ 1000 (_dir).code_start = (_segt)->start; \ 1001 (_dir).code_len = (_segt)->end - (_segt)->start + 1; \ 1002 (_dir).data_start = (_segd)->start; \ 1003 (_dir).data_len = (_segd)->end - (_segd)->start + 1; \ 1004 (_dir).file_name = (_segt)->fname; \ 1005 (_dir).mem_name = (_segt)->mname; \ 1006 (_dir).is_mainexe = (_acquire) ? (_segt)->isMainExe : False; \ 1007 (_dir).acquire = (_acquire); \ 1008 \ 1009 if (_acquire) { \ 1010 add_pri_text_and_data_segs( _segt, _segd ); \ 1011 } else { \ 1012 del_pri_text_and_data_segs( _segt, _segd ); \ 1013 } \ 1014 } while (0) 1015 1016 ixold = 0; /* indexes asegs_told */ 1017 ixnew = 0; /* indexes asegs_tnew */ 1018 1019 while (True) { 1020 1021 aspacem_assert(ixold >= 0 && ixold < asegs_told.used); 1022 aspacem_assert(ixnew >= 0 && ixnew < asegs_tnew.used); 1023 1024 /* Advance ixold and ixnew to the next MText in their 1025 respective arrays. */ 1026 while (ixold < asegs_told.used 1027 && asegs_told.seg[ixold].kind != ASkMText) { 1028 aspacem_assert(asegs_told.seg[ixold].kind == ASkFree 1029 || asegs_told.seg[ixold].kind == ASkMData); 1030 ixold++; 1031 } 1032 while (ixnew < asegs_tnew.used 1033 && asegs_tnew.seg[ixnew].kind != ASkMText) { 1034 aspacem_assert(asegs_tnew.seg[ixnew].kind == ASkFree 1035 || asegs_tnew.seg[ixnew].kind == ASkMData); 1036 ixnew++; 1037 } 1038 1039 aspacem_assert(ixold >= 0 && ixold <= asegs_told.used); 1040 aspacem_assert(ixnew >= 0 && ixnew <= asegs_tnew.used); 1041 1042 done_old = ixold == asegs_told.used; 1043 done_new = ixnew == asegs_tnew.used; 1044 1045 if (done_old && done_new) 1046 goto both_done; 1047 if (done_old && !done_new) 1048 goto finishup_new; 1049 if (done_new && !done_old) 1050 goto finishup_old; 1051 1052 olds = &asegs_told.seg[ixold]; 1053 news = &asegs_tnew.seg[ixnew]; 1054 1055 aspacem_assert(olds->kind == ASkMText); 1056 aspacem_assert(news->kind == ASkMText); 1057 1058 if (0) { 1059 show_AixSegment(0,ixold,&asegs_told.seg[ixold]); 1060 show_AixSegment(0,ixnew,&asegs_tnew.seg[ixnew]); 1061 VG_(debugLog)(0, "aspacem", "\n"); 1062 } 1063 1064 /* Here, if olds->start < news->start, then the old sequence has 1065 an entry which the new one doesn't, so a module has been 1066 unloaded. If news->start < olds->start then the new sequence 1067 has a module the old one doesn't, so a module has been 1068 loaded. If news->start ==olds->start then the module is 1069 unchanged. Except, we should check a bit more carefully in 1070 the zero case. */ 1071 if (olds->start == news->start) { 1072 if (olds->start == news->start 1073 && olds->end == news->end 1074 && olds->fname == news->fname 1075 && olds->mname == news->mname 1076 && olds->sibling == news->sibling 1077 && olds->isMainExe == news->isMainExe) { 1078 /* really identical, do nothing */ 1079 } else { 1080 /* Dubious; mark it as an unload of old and load of 1081 new. */ 1082 MODIFY_PRI(directives[*ndirectives], asegs_told, ixold, False); 1083 (*ndirectives)++; 1084 aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS); 1085 MODIFY_PRI(directives[*ndirectives], asegs_tnew, ixnew, True); 1086 (*ndirectives)++; 1087 aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS); 1088 } 1089 ixold++; 1090 ixnew++; 1091 continue; 1092 } 1093 1094 if (olds->start < news->start) { 1095 /* discard olds */ 1096 MODIFY_PRI(directives[*ndirectives], asegs_told, ixold, False); 1097 (*ndirectives)++; 1098 aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS); 1099 ixold++; 1100 continue; 1101 } 1102 1103 if (news->start < olds->start) { 1104 /* acquire news */ 1105 MODIFY_PRI(directives[*ndirectives], asegs_tnew, ixnew, True); 1106 (*ndirectives)++; 1107 aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS); 1108 ixnew++; 1109 continue; 1110 } 1111 /* NOTREACHED */ 1112 aspacem_assert(0); 1113 } 1114 1115 finishup_new: 1116 olds = NULL; 1117 aspacem_assert(ixold == asegs_told.used); 1118 aspacem_assert(ixnew < asegs_tnew.used); 1119 while (ixnew < asegs_tnew.used) { 1120 news = &asegs_tnew.seg[ixnew]; 1121 aspacem_assert(news->kind == ASkMText || news->kind == ASkMData 1122 || news->kind == ASkFree); 1123 if (news->kind == ASkMText) { 1124 MODIFY_PRI(directives[*ndirectives], asegs_tnew, ixnew, True); 1125 (*ndirectives)++; 1126 aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS); 1127 } 1128 ixnew++; 1129 } 1130 goto both_done; 1131 1132 finishup_old: 1133 news = NULL; 1134 aspacem_assert(ixnew == asegs_tnew.used); 1135 aspacem_assert(ixold < asegs_told.used); 1136 while (ixold < asegs_told.used) { 1137 olds = &asegs_told.seg[ixold]; 1138 aspacem_assert(olds->kind == ASkMText || olds->kind == ASkMData 1139 || olds->kind == ASkFree); 1140 if (olds->kind == ASkMText) { 1141 MODIFY_PRI(directives[*ndirectives], asegs_told, ixold, False); 1142 (*ndirectives)++; 1143 aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS); 1144 } 1145 ixold++; 1146 } 1147 goto both_done; 1148 1149 both_done: 1150 aspacem_assert(ixold == asegs_told.used); 1151 aspacem_assert(ixnew == asegs_tnew.used); 1152 1153 asegs_tnew.used = 0; 1154 asegs_told.used = 0; 1155 1156 aspacem_assert( sane_AixSegments(&asegs_pri) ); 1157 1158 # undef MODIFY_PRI 1159 } 1160 1161 1162 /* Set the initial stack segment. Contains kludgery. Also take the 1163 opportunity to create fake segs for the millicode areas. */ 1164 1165 void VG_(am_aix5_set_initial_client_sp)( Addr sp ) 1166 { 1167 static Bool done = False; 1168 AixSegment seg; 1169 Word n_fake_stack_pages; 1170 Word m1 = 1048576; 1171 1172 aspacem_assert(!done); 1173 done = True; 1174 1175 /* We are given the initial client SP (that of the root thread). 1176 Already on the stack are argv and env. How far up does it 1177 extend? We assume to the next 64k boundary. How far down does 1178 it extend? We assume N_FAKE_STACK_PAGES small pages - by 1179 default 16M. Establish those limits and add an AnonC rwx 1180 segment. */ 1181 1182 /* The 64k boundary is "justified" as follows. On 32-bit AIX 5.3, 1183 a typical initial SP is 0x2FF22xxx, but the accessible (rw) area 1184 beyond that extends up to 0x2FF2FFFF - the next 64k boundary. 1185 In 64-bit mode, a typical initial SP might be 1186 0xFFF'FFFF'FFFF'E920, and the accessible area extends to 1187 0xFFF'FFFF'FFFF'FFFF. So in both cases, (64k roundup of sp) - 1 1188 gives the end of the accessible area. */ 1189 VG_(debugLog)(1,"aspacem", "aix5_set_initial_client_sp( %p )\n", 1190 (void*)sp); 1191 1192 init_AixSegment( &seg ); 1193 seg.kind = ASkAnonC; 1194 seg.hasR = seg.hasW = seg.hasX = True; 1195 1196 if (sizeof(void*) == 4 1197 && ((sp & 0xFFFF0000) == 0x2FF20000 1198 || (sp & 0xFFFF0000) == 0x2FF10000)) { 1199 /* Gaaah. Special-case 32-bit mode. */ 1200 seg.end = 0x2FF2FFFF; 1201 } else { 1202 seg.end = AM_64K_ROUNDUP(sp) - 1; 1203 } 1204 1205 n_fake_stack_pages = N_FAKE_STACK_PAGES_MIN; 1206 if (VG_(clo_main_stacksize) > 0 1207 && ((m1+VG_(clo_main_stacksize)) / VKI_PAGE_SIZE) > n_fake_stack_pages) { 1208 n_fake_stack_pages = (m1+VG_(clo_main_stacksize)) / VKI_PAGE_SIZE; 1209 } 1210 if (n_fake_stack_pages > N_FAKE_STACK_PAGES_MAX) { 1211 /* Allocation of the stack failed. We have to stop. */ 1212 VG_(debugLog)( 1213 0, "aspacem", 1214 "valgrind: " 1215 "I failed to allocate space for the application's stack.\n"); 1216 VG_(debugLog)( 1217 0, "aspacem", 1218 "valgrind: " 1219 "This may be the result of a very large --max-stackframe=\n"); 1220 VG_(debugLog)( 1221 0, "aspacem", 1222 "valgrind: " 1223 "setting. Cannot continue. Sorry.\n\n"); 1224 ML_(am_exit)(0); 1225 } 1226 1227 seg.start = seg.end+1 - n_fake_stack_pages * VKI_PAGE_SIZE; 1228 1229 VG_(debugLog)(1,"aspacem", "aix5_set_initial_client_sp: stack seg:\n"); 1230 show_AixSegment(1,0, &seg); 1231 add_asegment( &asegs_pri, &seg ); 1232 1233 init_AixSegment( &seg ); 1234 seg.kind = ASkAnonC; 1235 seg.hasR = seg.hasX = True; 1236 seg.start = MAGIC_PAGES_1_BASE; 1237 seg.end = MAGIC_PAGES_1_BASE + MAGIC_PAGES_1_SIZE - 1; 1238 VG_(debugLog)(1,"aspacem", "am_aix5_set_initial_client_sp: FAKE1 seg:\n"); 1239 show_AixSegment(1,0, &seg); 1240 add_asegment( &asegs_pri, &seg ); 1241 1242 init_AixSegment( &seg ); 1243 seg.kind = ASkAnonC; 1244 seg.hasR = seg.hasX = True; 1245 seg.start = MAGIC_PAGES_2_BASE; 1246 seg.end = MAGIC_PAGES_2_BASE + MAGIC_PAGES_2_SIZE - 1; 1247 VG_(debugLog)(1,"aspacem", "am_aix5_set_initial_client_sp: FAKE2 seg:\n"); 1248 show_AixSegment(1,0, &seg); 1249 add_asegment( &asegs_pri, &seg ); 1250 } 1251 1252 1253 /*-----------------------------------------------------------------*/ 1254 /*--- ---*/ 1255 /*--- Getting segment-starts. ---*/ 1256 /*--- ---*/ 1257 /*-----------------------------------------------------------------*/ 1258 1259 /* Print out the segment array (debugging only!). */ 1260 void VG_(am_show_nsegments) ( Int logLevel, HChar* who ) 1261 { 1262 show_AixSegments( logLevel, who, &asegs_pri ); 1263 } 1264 1265 /* Get the filename corresponding to this segment, if known and if it 1266 has one. The returned name's storage cannot be assumed to be 1267 persistent, so the caller should immediately copy the name 1268 elsewhere. On AIX5, we don't know what this is (in general) 1269 so just return NULL. */ 1270 HChar* VG_(am_get_filename)( NSegment const* seg ) 1271 { 1272 return NULL; 1273 } 1274 1275 /* Collect up the start addresses of all non-free, non-resvn segments. 1276 The interface is a bit strange in order to avoid potential 1277 segment-creation races caused by dynamic allocation of the result 1278 buffer *starts. 1279 1280 The function first computes how many entries in the result 1281 buffer *starts will be needed. If this number <= nStarts, 1282 they are placed in starts[0..], and the number is returned. 1283 If nStarts is not large enough, nothing is written to 1284 starts[0..], and the negation of the size is returned. 1285 1286 Correct use of this function may mean calling it multiple times in 1287 order to establish a suitably-sized buffer. */ 1288 1289 Int VG_(am_get_segment_starts)( Addr* starts, Int nStarts ) 1290 { 1291 Int i, j, nSegs; 1292 1293 /* don't pass dumbass arguments */ 1294 aspacem_assert(nStarts >= 0); 1295 1296 nSegs = 0; 1297 for (i = 0; i < asegs_pri.used; i++) { 1298 if (asegs_pri.seg[i].kind == ASkFree 1299 || asegs_pri.seg[i].kind == ASkPreAlloc) 1300 continue; 1301 nSegs++; 1302 } 1303 1304 if (nSegs > nStarts) { 1305 /* The buffer isn't big enough. Tell the caller how big it needs 1306 to be. */ 1307 return -nSegs; 1308 } 1309 1310 /* There's enough space. So write into the result buffer. */ 1311 aspacem_assert(nSegs <= nStarts); 1312 1313 j = 0; 1314 for (i = 0; i < asegs_pri.used; i++) { 1315 if (asegs_pri.seg[i].kind == ASkFree 1316 || asegs_pri.seg[i].kind == ASkPreAlloc) 1317 continue; 1318 starts[j++] = asegs_pri.seg[i].start; 1319 } 1320 1321 aspacem_assert(j == nSegs); /* this should not fail */ 1322 return nSegs; 1323 } 1324 1325 1326 /*-----------------------------------------------------------------*/ 1327 /*--- ---*/ 1328 /*--- Sanity checking and preening of the segment array. ---*/ 1329 /*--- ---*/ 1330 /*-----------------------------------------------------------------*/ 1331 1332 Bool VG_(am_do_sync_check) ( const HChar* fn, 1333 const HChar* file, Int line ) 1334 { 1335 /* There's nothing we can do here; just return a dummy value. */ 1336 return False; /* placate gcc */ 1337 } 1338 1339 /* Hook to allow sanity checks to be done from aspacemgr-common.c. */ 1340 void ML_(am_do_sanity_check)( void ) 1341 { 1342 Bool ok = sane_AixSegments( &asegs_pri ); 1343 aspacem_assert(ok); 1344 } 1345 1346 1347 /*-----------------------------------------------------------------*/ 1348 /*--- ---*/ 1349 /*--- Finding segments. ---*/ 1350 /*--- ---*/ 1351 /*-----------------------------------------------------------------*/ 1352 1353 /* Finds the segment containing 'a'. Only returns file/anon/resvn 1354 segments. On AIX5 this is pretty bogus; we fake up an entry as 1355 best we can by snooping round for useful information in 1356 asegs_pri. */ 1357 1358 NSegment const* VG_(am_find_nsegment) ( Addr a ) 1359 { 1360 Int i; 1361 AixSegment* aseg; 1362 static NSegment bogus; 1363 1364 /* Fill in default info. */ 1365 bogus.kind = SkAnonC; 1366 bogus.start = 0; 1367 bogus.end = 0; 1368 bogus.smode = SmFixed; 1369 bogus.dev = 0; 1370 bogus.ino = 0; 1371 bogus.mode = 0; 1372 bogus.offset = 0; 1373 bogus.fnIdx = -1; 1374 bogus.hasR = bogus.hasW = bogus.hasX = False; 1375 bogus.hasT = False; 1376 bogus.isCH = False; 1377 bogus.mark = False; 1378 1379 /* Go look for it in the segment table. */ 1380 i = find_asegment_idx( &asegs_pri, a ); 1381 aspacem_assert(i >= 0 && i <= asegs_pri.used); 1382 1383 aseg = &asegs_pri.seg[i]; 1384 if (aseg->kind == ASkFree || aseg->kind == ASkPreAlloc) 1385 return NULL; 1386 1387 bogus.start = aseg->start; 1388 bogus.end = aseg->end; 1389 1390 /* Refine */ 1391 switch (aseg->kind) { 1392 case ASkMText: 1393 bogus.kind = SkAnonC; /* hmm, pretty darn bogus */ 1394 bogus.hasR = bogus.hasX = True; 1395 break; 1396 case ASkMData: 1397 bogus.kind = SkAnonC; /* hmm, pretty darn bogus */ 1398 bogus.hasR = bogus.hasW = True; 1399 break; 1400 case ASkShmemC: 1401 bogus.kind = SkShmC; 1402 bogus.hasR = aseg->hasR; 1403 bogus.hasW = aseg->hasW; 1404 bogus.hasX = aseg->hasX; 1405 break; 1406 case ASkAnonC: 1407 bogus.kind = SkAnonC; 1408 bogus.hasR = aseg->hasR; 1409 bogus.hasW = aseg->hasW; 1410 bogus.hasX = aseg->hasX; 1411 bogus.isCH = aseg->isCH; 1412 break; 1413 case ASkAnonV: 1414 bogus.kind = SkAnonV; 1415 bogus.hasR = aseg->hasR; 1416 bogus.hasW = aseg->hasW; 1417 bogus.hasX = aseg->hasX; 1418 break; 1419 case ASkFileV: 1420 bogus.kind = SkFileV; 1421 bogus.hasR = aseg->hasR; 1422 bogus.hasW = aseg->hasW; 1423 bogus.hasX = aseg->hasX; 1424 bogus.offset = aseg->offset; 1425 break; 1426 default: 1427 aspacem_assert(0); 1428 } 1429 1430 return &bogus; 1431 } 1432 1433 1434 /* Find the next segment along from 'here', if it is a file/anon/resvn 1435 segment. */ 1436 NSegment const* VG_(am_next_nsegment) ( NSegment* here, Bool fwds ) 1437 { 1438 ML_(am_barf)("unimplemented: VG_(am_next_nsegment)"); 1439 return NULL; /* placate gcc */ 1440 } 1441 1442 1443 /* Trivial fn: return the total amount of space in anonymous mappings, 1444 both for V and the client. Is used for printing stats in 1445 out-of-memory messages. */ 1446 ULong VG_(am_get_anonsize_total)( void ) 1447 { 1448 Int i; 1449 ULong total = 0; 1450 for (i = 0; i < asegs_pri.used; i++) { 1451 if (asegs_pri.seg[i].kind == ASkAnonC 1452 || asegs_pri.seg[i].kind == ASkAnonV) { 1453 total += (ULong)asegs_pri.seg[i].end 1454 - (ULong)asegs_pri.seg[i].start + 1ULL; 1455 } 1456 } 1457 return total; 1458 } 1459 1460 1461 /* Test if a piece of memory is addressable by the client with at 1462 least the "prot" protection permissions by examining the underlying 1463 segments. */ 1464 Bool VG_(am_is_valid_for_client)( Addr start, SizeT len, 1465 UInt prot ) 1466 { 1467 NSegment const * const fake = VG_(am_find_nsegment)(start); 1468 if (!fake) 1469 return False; 1470 aspacem_assert(fake->start <= start); 1471 aspacem_assert(start + len - 1 <= fake->end); 1472 if (fake->kind == SkAnonV || fake->kind == SkFileV) 1473 return False; 1474 if ((prot & VKI_PROT_READ) && !fake->hasR) 1475 return False; 1476 if ((prot & VKI_PROT_WRITE) && !fake->hasW) 1477 return False; 1478 if ((prot & VKI_PROT_EXEC) && !fake->hasX) 1479 return False; 1480 return True; 1481 } 1482 1483 /* Variant of VG_(am_is_valid_for_client) which allows free areas to 1484 be considered part of the client's addressable space. It also 1485 considers reservations to be allowable, since from the client's 1486 point of view they don't exist. */ 1487 Bool VG_(am_is_valid_for_client_or_free_or_resvn) 1488 ( Addr start, SizeT len, UInt prot ) 1489 { 1490 ML_(am_barf)("unimplemented: " 1491 "VG_(am_is_valid_for_client_or_free_or_resvn)"); 1492 /*NOTREACHED*/ 1493 return False; 1494 } 1495 1496 1497 /*-----------------------------------------------------------------*/ 1498 /*--- ---*/ 1499 /*--- Startup, including reading /proc/self/maps. ---*/ 1500 /*--- ---*/ 1501 /*-----------------------------------------------------------------*/ 1502 1503 /* Initialise the address space manager, setting up the initial 1504 segment list, and reading /proc/self/maps into it. This must 1505 be called before any other function. 1506 1507 Takes a pointer to the SP at the time V gained control. This is 1508 taken to be the highest usable address (more or less). Based on 1509 that (and general consultation of tea leaves, etc) return a 1510 suggested end address for the client's stack. */ 1511 1512 Addr VG_(am_startup) ( Addr sp_at_startup ) 1513 { 1514 aspacem_assert(sizeof(Word) == sizeof(void*)); 1515 aspacem_assert(sizeof(Addr) == sizeof(void*)); 1516 aspacem_assert(sizeof(SizeT) == sizeof(void*)); 1517 aspacem_assert(sizeof(SSizeT) == sizeof(void*)); 1518 1519 asegs_tnew.used = 0; 1520 asegs_told.used = 0; 1521 1522 asegs_pri.used = 1; 1523 init_AixSegments( &asegs_pri ); 1524 aspacem_assert( sane_AixSegments(&asegs_pri) ); 1525 1526 if (0) 1527 VG_(am_show_nsegments)(0,"AFTER VG_(am_startup)"); 1528 1529 /* We do not make an initial read of /proc/../map since doing so 1530 would leave us without a way to communicate the results to a 1531 caller. Hence we expect that the caller (m_main) will call 1532 VG_(am_aix5_reread_procmap) soon after this call so as to get 1533 the initial code/data segments recorded. */ 1534 1535 /* Return value is irrelevant since we don't lay out the 1536 client's stack; it is already done. */ 1537 return 0; 1538 } 1539 1540 1541 /*-----------------------------------------------------------------*/ 1542 /*--- ---*/ 1543 /*--- Preallocation (acquiring space from sbrk). ---*/ 1544 /*--- ---*/ 1545 /*-----------------------------------------------------------------*/ 1546 1547 static 1548 SysRes local_do_sbrk_NO_NOTIFY( Word delta ) 1549 { 1550 SysRes res; 1551 aspacem_assert(__NR_AIX5_sbrk != __NR_AIX5_UNKNOWN); 1552 res = VG_(do_syscall1)(__NR_AIX5_sbrk, (UWord)delta); 1553 /* kernel produces (-1, VKI_ENOMEM) on failure. I think that's 1554 ok. */ 1555 return res; 1556 } 1557 1558 1559 /* Find the ix of a prealloc section containing at least req_sz bytes, 1560 or -1 if not found. Uses best-fit. */ 1561 1562 static Int find_prealloc_idx ( SizeT req_sz ) 1563 { 1564 SizeT best_sz, this_sz; 1565 Int best_ix, i; 1566 aspacem_assert(sizeof(SizeT) == sizeof(Addr)); 1567 aspacem_assert(req_sz > 0); 1568 aspacem_assert(AM_IS_4K_ALIGNED(req_sz)); 1569 1570 best_sz = Addr_MAX; 1571 best_ix = -1; 1572 1573 for (i = 0; i < asegs_pri.used; i++) { 1574 AixSegment* s = &asegs_pri.seg[i]; 1575 if (s->kind != ASkPreAlloc) 1576 continue; 1577 this_sz 1578 = s->end + 1 - s->start; 1579 aspacem_assert(this_sz > 0); 1580 aspacem_assert(AM_IS_4K_ALIGNED(this_sz)); 1581 if (this_sz >= req_sz && this_sz < best_sz) { 1582 best_sz = this_sz; 1583 best_ix = i; 1584 } 1585 } 1586 1587 return best_ix; 1588 } 1589 1590 1591 /* Create a new prealloc section containing req_sz bytes. Returns 1592 False if failed, True on success. */ 1593 1594 static Bool new_prealloc ( SizeT req_sz ) 1595 { 1596 SysRes sres; 1597 AixSegment seg; 1598 Addr start; 1599 SSizeT delta; 1600 HChar* why = NULL; 1601 1602 aspacem_assert(req_sz > 0); 1603 aspacem_assert(AM_IS_4K_ALIGNED(req_sz)); 1604 1605 /* m_syswrap may have decided that it's not currently safe to allow 1606 allocations from sbrk-world. If so, we have to fail. */ 1607 if (0 && !VG_(am_aix5_sbrk_allowed)) { 1608 why = "sbrk disallowed"; 1609 goto fail; 1610 } 1611 1612 /* Get the current limit. */ 1613 sres = local_do_sbrk_NO_NOTIFY(0); 1614 if (sres.isError) { 1615 why = "initial sbrk failed"; 1616 goto fail; 1617 } 1618 1619 /* Get it page aligned */ 1620 delta = AM_4K_ROUNDUP(sres.res) - sres.res; 1621 aspacem_assert(delta >= 0 && delta < AM_4K_PAGESZ); 1622 if (delta > 0) { 1623 sres = local_do_sbrk_NO_NOTIFY(delta); 1624 if (sres.isError) { 1625 why = "aligning sbrk failed"; 1626 goto fail; 1627 } 1628 } 1629 1630 /* Now the brk is aligned. Try to acquire the block. */ 1631 sres = local_do_sbrk_NO_NOTIFY(0); 1632 if (sres.isError) 1633 return False; 1634 start = sres.res; 1635 aspacem_assert( AM_IS_4K_ALIGNED( start )); 1636 1637 sres = local_do_sbrk_NO_NOTIFY( req_sz ); 1638 if (sres.isError) { 1639 why = "main sbrk failed"; 1640 goto fail; 1641 } 1642 1643 /* If this fails, the kernel is acting strange. */ 1644 aspacem_assert( sres.res == start ); 1645 1646 init_AixSegment( &seg ); 1647 seg.start = start; 1648 seg.end = start + req_sz - 1; 1649 seg.kind = ASkPreAlloc; 1650 seg.hasR = seg.hasW = seg.hasX = True; /* presumably */ 1651 add_asegment( &asegs_pri, &seg ); 1652 1653 VG_(debugLog)( 1654 1, "aspacem", "new_prealloc: SUCCESS at 0x%llx size %lld\n", 1655 (ULong)start, (ULong)req_sz 1656 ); 1657 return True; 1658 1659 fail: 1660 VG_(debugLog)(1, "aspacem", "new_prealloc: FAILED: %s\n", why); 1661 return False; 1662 } 1663 1664 1665 /* Find the ix of a prealloc section capable of holding a block of 1666 size req_sz. If none exists, try to create one first. Returns -1 1667 on failure. */ 1668 1669 static Int find_or_create_prealloc_idx ( SizeT req_sz ) 1670 { 1671 Int ix; 1672 SizeT req_szX; 1673 Bool alloc_ok; 1674 1675 if (0) 1676 VG_(debugLog)(0, "zz", " find_or_create_prealloc_idx ( %lu )\n", 1677 req_sz); 1678 1679 aspacem_assert(sizeof(SizeT) == sizeof(Addr)); 1680 aspacem_assert(req_sz > 0); 1681 aspacem_assert(AM_IS_4K_ALIGNED(req_sz)); 1682 1683 ix = find_prealloc_idx ( req_sz ); 1684 if (ix >= 0 && ix < asegs_pri.used) 1685 return ix; 1686 1687 /* Not found. We'll have to allocate one. Allocate some extra at 1688 the same time, so as to give a reservoir from which to satisfy 1689 future requests. */ 1690 aspacem_assert(ix == -1); 1691 1692 req_szX = req_sz + AM_PREALLOC_EXTRA; 1693 aspacem_assert(req_szX > 0); 1694 aspacem_assert(AM_IS_4K_ALIGNED(req_szX)); 1695 1696 alloc_ok = new_prealloc( req_szX ); 1697 if (!alloc_ok) 1698 return -1; /* failed */ 1699 1700 /* We should now be able to find it in the segment table. */ 1701 ix = find_prealloc_idx( req_sz ); 1702 aspacem_assert(ix >= 0 && ix < asegs_pri.used); 1703 return ix; 1704 } 1705 1706 1707 /*-----------------------------------------------------------------*/ 1708 /*--- ---*/ 1709 /*--- The core query-notify mechanism. ---*/ 1710 /*--- ---*/ 1711 /*-----------------------------------------------------------------*/ 1712 1713 /* Query aspacem to ask where a mapping should go. */ 1714 1715 Addr VG_(am_get_advisory) ( MapRequest* req, 1716 Bool forClient, 1717 /*OUT*/Bool* ok ) 1718 { 1719 ML_(am_barf)("unimplemented: VG_(am_get_advisory)"); 1720 /*NOTREACHED*/ 1721 return 0; /* placate gcc -Wall */ 1722 } 1723 1724 1725 /* Convenience wrapper for VG_(am_get_advisory) for client floating or 1726 fixed requests. If start is zero, a floating request is issued; if 1727 nonzero, a fixed request at that address is issued. Same comments 1728 about return values apply. */ 1729 1730 Addr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len, 1731 /*OUT*/Bool* ok ) 1732 { 1733 ML_(am_barf)("unimplemented: VG_(am_get_advisory_client_simple)"); 1734 /*NOTREACHED*/ 1735 return 0; /* placate gcc -Wall */ 1736 } 1737 1738 1739 /* Notifies aspacem that the client completed an mmap successfully. 1740 The segment array is updated accordingly. If the returned Bool is 1741 True, the caller should immediately discard translations from the 1742 specified address range. */ 1743 1744 Bool 1745 VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags, 1746 Int fd, Off64T offset ) 1747 { 1748 AixSegment seg; 1749 Bool needDiscard; 1750 1751 if (len == 0) 1752 return False; 1753 1754 /* Discard is needed if any of the just-trashed range had T. */ 1755 needDiscard = True; /* conservative but safe */ 1756 1757 init_AixSegment( &seg ); 1758 seg.kind = ASkAnonC; /* XXX bogus: could be a file */ 1759 seg.start = a; 1760 seg.end = a + len - 1; 1761 seg.hasR = toBool(prot & VKI_PROT_READ); 1762 seg.hasW = toBool(prot & VKI_PROT_WRITE); 1763 seg.hasX = toBool(prot & VKI_PROT_EXEC); 1764 1765 if (0) 1766 VG_(debugLog)(0,"aspacem","notify mmap ( %p, %ld, %ld, %ld )\n", 1767 (void*)a, len, (UWord)prot, (UWord)flags); 1768 1769 add_asegment( &asegs_pri, &seg ); 1770 AM_SANITY_CHECK("am_notify_client_mmap"); 1771 return needDiscard; 1772 } 1773 1774 1775 /* Notifies aspacem that the client completed a shmat successfully. 1776 The segment array is updated accordingly. If the returned Bool is 1777 True, the caller should immediately discard translations from the 1778 specified address range. */ 1779 1780 Bool 1781 VG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot ) 1782 { 1783 AixSegment seg; 1784 init_AixSegment( &seg ); 1785 seg.kind = ASkShmemC; 1786 seg.start = a; 1787 seg.end = seg.start + len - 1; 1788 seg.hasR = (prot & VKI_PROT_READ) ? True : False; 1789 seg.hasW = (prot & VKI_PROT_WRITE) ? True : False; 1790 seg.hasX = (prot & VKI_PROT_EXEC) ? True : False; 1791 add_asegment( &asegs_pri, &seg ); 1792 AM_SANITY_CHECK("am_notify_client_shmat"); 1793 if (0) VG_(am_show_nsegments)(0, "after shmat"); 1794 return True; /* be paranoid */ 1795 } 1796 1797 1798 /* Notifies aspacem that an mprotect was completed successfully. The 1799 segment array is updated accordingly. Note, as with 1800 VG_(am_notify_munmap), it is not the job of this function to reject 1801 stupid mprotects, for example the client doing mprotect of 1802 non-client areas. Such requests should be intercepted earlier, by 1803 the syscall wrapper for mprotect. This function merely records 1804 whatever it is told. If the returned Bool is True, the caller 1805 should immediately discard translations from the specified address 1806 range. */ 1807 1808 Bool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot ) 1809 { 1810 Int i, iLo, iHi; 1811 Bool newR, newW, newX, needDiscard; 1812 1813 if (len == 0) 1814 return False; 1815 1816 newR = toBool(prot & VKI_PROT_READ); 1817 newW = toBool(prot & VKI_PROT_WRITE); 1818 newX = toBool(prot & VKI_PROT_EXEC); 1819 1820 /* Discard is needed if we're dumping X permission */ 1821 needDiscard = True; /* conservative but correct */ 1822 1823 split_asegments_lo_and_hi( &asegs_pri, start, start+len-1, &iLo, &iHi ); 1824 1825 iLo = find_asegment_idx(&asegs_pri, start); 1826 iHi = find_asegment_idx(&asegs_pri, start + len - 1); 1827 1828 for (i = iLo; i <= iHi; i++) { 1829 aspacem_assert(i >= 0 && i < asegs_pri.used); 1830 /* Apply the permissions to all relevant segments. */ 1831 if (asegs_pri.seg[i].kind != ASkFree) { 1832 asegs_pri.seg[i].hasR = newR; 1833 asegs_pri.seg[i].hasW = newW; 1834 asegs_pri.seg[i].hasX = newX; 1835 aspacem_assert(sane_AixSegment(&asegs_pri.seg[i])); 1836 } 1837 } 1838 if (0) 1839 VG_(debugLog)(0,"aspacem","notify mprotect ( %p, %ld, %ld )\n", 1840 (void*)start, len, (UWord)prot); 1841 /* Changing permissions could have made previously un-mergable 1842 segments mergeable. Therefore have to re-preen them. */ 1843 preen_asegments(&asegs_pri); 1844 AM_SANITY_CHECK("am_notify_mprotect"); 1845 return needDiscard; 1846 } 1847 1848 1849 /* Notifies aspacem that an munmap completed successfully. The 1850 segment array is updated accordingly. As with 1851 VG_(am_notify_munmap), we merely record the given info, and don't 1852 check it for sensibleness. If the returned Bool is True, the 1853 caller should immediately discard translations from the specified 1854 address range. */ 1855 1856 Bool VG_(am_notify_munmap)( Addr start, SizeT len ) 1857 { 1858 Bool needDiscard = True; /* conservative but safe */ 1859 AixSegment seg; 1860 1861 if (len == 0) 1862 return False; 1863 1864 init_AixSegment( &seg ); 1865 seg.kind = ASkFree; 1866 seg.start = start; 1867 seg.end = start + len - 1; 1868 add_asegment( &asegs_pri, &seg ); 1869 AM_SANITY_CHECK("am_notify_munmap"); 1870 1871 return needDiscard; 1872 } 1873 1874 1875 /*-----------------------------------------------------------------*/ 1876 /*--- ---*/ 1877 /*--- Handling mappings which do not arise directly from the ---*/ 1878 /*--- simulation of the client. ---*/ 1879 /*--- ---*/ 1880 /*-----------------------------------------------------------------*/ 1881 1882 /* --- --- --- map, unmap, protect --- --- --- */ 1883 1884 /* Map a file at a fixed address for the client, and update the 1885 segment array accordingly. */ 1886 1887 SysRes VG_(am_mmap_file_fixed_client) 1888 ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset ) 1889 { 1890 SysRes r = {0,0}; 1891 ML_(am_barf)("unimplemented: VG_(am_mmap_file_fixed_client)"); 1892 /*NOTREACHED*/ 1893 return r; 1894 } 1895 1896 1897 /* Map anonymously at a fixed address for the client, and update 1898 the segment array accordingly. */ 1899 1900 SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot ) 1901 { 1902 SysRes r = {0,0}; 1903 ML_(am_barf)("unimplemented: VG_(am_mmap_anon_fixed_client)"); 1904 /*NOTREACHED*/ 1905 return r; 1906 } 1907 1908 1909 /* Map anonymously at an unconstrained address for the client, and 1910 update the segment array accordingly. */ 1911 1912 SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot ) 1913 { 1914 SysRes sres; 1915 AixSegment seg; 1916 1917 /* Not allowable. */ 1918 if (length == 0) 1919 return VG_(mk_SysRes_Error)( VKI_EINVAL ); 1920 1921 /* AIX seems to demand fd == -1 in anonymous mappings. hence: */ 1922 sres = VG_(am_do_mmap_NO_NOTIFY)( 1923 0, length, 1924 prot, 1925 VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 1926 -1, 0 1927 ); 1928 1929 if (!sres.isError) { 1930 init_AixSegment( &seg ); 1931 seg.kind = ASkAnonC; 1932 seg.start = sres.res; 1933 seg.end = seg.start + length - 1; 1934 seg.hasR = toBool((prot & VKI_PROT_READ) > 0); 1935 seg.hasW = toBool((prot & VKI_PROT_WRITE) > 0); 1936 seg.hasX = toBool((prot & VKI_PROT_EXEC) > 0); 1937 seg.fromP = False; 1938 add_asegment( &asegs_pri, &seg ); 1939 VG_(debugLog)(2, "aspacem", "new AnonC from mmap, size %lu\n", 1940 length ); 1941 } 1942 1943 return sres; 1944 } 1945 1946 1947 /* Similarly, acquire new address space for the client but with 1948 considerable restrictions on what can be done with it: (1) the 1949 actual protections may exceed those stated in 'prot', (2) the 1950 area's protections cannot be later changed using any form of 1951 mprotect, and (3) the area cannot be freed using any form of 1952 munmap. On Linux this behaves the same as 1953 VG_(am_mmap_anon_float_client). On AIX5 this *may* allocate memory 1954 by using sbrk, so as to make use of large pages on AIX. */ 1955 1956 SysRes VG_(am_sbrk_anon_float_client) ( SizeT length, Int prot ) 1957 { 1958 Int ix; 1959 SysRes sres; 1960 AixSegment seg; 1961 SizeT lenX = AM_4K_ROUNDUP(length); 1962 1963 /* Not allowable. */ 1964 if (length == 0) 1965 return VG_(mk_SysRes_Error)( VKI_EINVAL ); 1966 1967 /* First see if we can get space from sbrk-world. */ 1968 ix = find_or_create_prealloc_idx ( lenX ); 1969 if (ix >= 0 && ix < asegs_pri.used) { 1970 init_AixSegment( &seg ); 1971 seg.kind = ASkAnonC; 1972 seg.start = asegs_pri.seg[ix].start; 1973 seg.end = seg.start + lenX - 1; 1974 seg.hasR = toBool((prot & VKI_PROT_READ) > 0); 1975 seg.hasW = toBool((prot & VKI_PROT_WRITE) > 0); 1976 seg.hasX = toBool((prot & VKI_PROT_EXEC) > 0); 1977 seg.fromP = True; 1978 add_asegment( &asegs_pri, &seg ); 1979 sres = VG_(mk_SysRes_Success)( seg.start ); 1980 VG_(debugLog)(2, "aspacem", "new AnonC from prealloc, size %lu\n", 1981 length ); 1982 return sres; 1983 } 1984 1985 /* That didn't work out. Try mmap-world instead. */ 1986 aspacem_assert(ix == -1); 1987 return VG_(am_mmap_anon_float_client)( length, prot ); 1988 } 1989 1990 1991 /* Map anonymously at an unconstrained address for V, and update the 1992 segment array accordingly. This is fundamentally how V allocates 1993 itself more address space when needed. */ 1994 1995 SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length ) 1996 { 1997 SysRes sres; 1998 AixSegment seg; 1999 2000 /* Not allowable. */ 2001 if (length == 0) 2002 return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2003 2004 /* AIX seems to demand fd == -1 in anonymous mappings. hence: */ 2005 sres = VG_(am_do_mmap_NO_NOTIFY)( 2006 0, length, 2007 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC, 2008 VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 2009 -1, 0 2010 ); 2011 2012 if (!sres.isError) { 2013 init_AixSegment( &seg ); 2014 seg.kind = ASkAnonV; 2015 seg.start = sres.res; 2016 seg.end = seg.start + length - 1; 2017 seg.hasR = seg.hasW = seg.hasX = True; 2018 seg.fromP = False; 2019 add_asegment( &asegs_pri, &seg ); 2020 VG_(debugLog)(2, "aspacem", "new AnonV from mmap, size %lu\n", 2021 length ); 2022 } 2023 2024 return sres; 2025 } 2026 2027 2028 /* Same comments apply as per VG_(am_sbrk_anon_float_client). On 2029 Linux this behaves the same as VG_(am_mmap_anon_float_valgrind). */ 2030 SysRes VG_(am_sbrk_anon_float_valgrind)( SizeT length ) 2031 { 2032 Int ix; 2033 SysRes sres; 2034 AixSegment seg; 2035 SizeT lenX = AM_4K_ROUNDUP(length); 2036 2037 /* Not allowable. */ 2038 if (length == 0) 2039 return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2040 2041 /* First see if we can get space from sbrk-world. */ 2042 ix = find_or_create_prealloc_idx ( lenX ); 2043 if (ix >= 0 && ix < asegs_pri.used) { 2044 init_AixSegment( &seg ); 2045 seg.kind = ASkAnonV; 2046 seg.start = asegs_pri.seg[ix].start; 2047 seg.end = seg.start + lenX - 1; 2048 seg.hasR = True; 2049 seg.hasW = True; 2050 seg.hasX = True; 2051 seg.fromP = True; 2052 add_asegment( &asegs_pri, &seg ); 2053 sres = VG_(mk_SysRes_Success)( seg.start ); 2054 VG_(debugLog)(2, "aspacem", "new AnonV from prealloc, size %lu\n", 2055 length ); 2056 return sres; 2057 } 2058 2059 /* That didn't work out. Try mmap-world instead. */ 2060 aspacem_assert(ix == -1); 2061 return VG_(am_mmap_anon_float_valgrind)( length ); 2062 } 2063 2064 2065 /* Really just a wrapper around VG_(am_sbrk_anon_float_valgrind). */ 2066 2067 void* VG_(am_shadow_alloc)(SizeT size) 2068 { 2069 SysRes sres = VG_(am_sbrk_anon_float_valgrind)( size ); 2070 return sres.isError ? NULL : (void*)sres.res; 2071 } 2072 2073 2074 /* Map a file at an unconstrained address for V, and update the 2075 segment array accordingly. This is used by V for transiently 2076 mapping in object files to read their debug info. */ 2077 2078 SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot, 2079 Int fd, Off64T offset ) 2080 { 2081 SysRes sres; 2082 2083 /* Not allowable. */ 2084 if (length == 0 || !VG_IS_PAGE_ALIGNED(offset)) 2085 return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2086 2087 sres = VG_(am_do_mmap_NO_NOTIFY)( 2088 0, length, 2089 prot, VKI_MAP_PRIVATE, 2090 fd, offset 2091 ); 2092 if (!sres.isError) { 2093 AixSegment seg; 2094 init_AixSegment( &seg ); 2095 seg.kind = SkFileV; 2096 seg.start = sres.res; 2097 seg.end = seg.start + length - 1; 2098 seg.hasR = toBool(prot & VKI_PROT_READ); 2099 seg.hasW = toBool(prot & VKI_PROT_WRITE); 2100 seg.hasX = toBool(prot & VKI_PROT_EXEC); 2101 seg.fname = add_to_strtab("(FileV-float, unknown name)"); 2102 add_asegment( &asegs_pri, &seg ); 2103 aspacem_assert( sane_AixSegments( &asegs_pri )); 2104 } 2105 return sres; 2106 } 2107 2108 2109 /* Unmap the given address range and update the segment array 2110 accordingly. This fails if the range isn't valid for the client. 2111 If *need_discard is True after a successful return, the caller 2112 should immediately discard translations from the specified address 2113 range. */ 2114 2115 SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard, 2116 Addr start, SizeT len ) 2117 { 2118 SysRes r = {0,0}; 2119 ML_(am_barf)("unimplemented: VG_(am_munmap_client)"); 2120 /*NOTREACHED*/ 2121 return r; 2122 } 2123 2124 2125 /* Unmap the given address range and update the segment array 2126 accordingly. This fails if the range isn't valid for valgrind. */ 2127 /* Also, if the specified range doesn't fall within a single segment, 2128 it barfs. This simplifies the implementation; we shouldn't need to 2129 deal with anything but the simplest cases. */ 2130 2131 SysRes VG_(am_munmap_valgrind)( Addr start, SizeT len ) 2132 { 2133 AixSegment* seg; 2134 AixSegment seg2; 2135 Addr end; 2136 SysRes sres; 2137 Int ixS, ixE; 2138 Bool debug = False; 2139 2140 if (debug) 2141 VG_(debugLog)(0,"aspacem", 2142 "am_munmap_valgrind(%p, %lu)\n", (void*)start, len); 2143 2144 if (len == 0) 2145 return VG_(mk_SysRes_Success)(0); 2146 2147 /* We have to be a bit careful here. If the area being unmapped is 2148 AnonV which originated from a preallocated area (hence from 2149 sbrk-land) then we will have to return it to the preallocated 2150 state, rather than unmapping it. */ 2151 end = start + len - 1; 2152 aspacem_assert(start <= end); // else have wraparound?! 2153 2154 ixS = find_asegment_idx( &asegs_pri, start ); 2155 ixE = find_asegment_idx( &asegs_pri, end ); 2156 2157 aspacem_assert(ixS >= 0 && ixS < asegs_pri.used); 2158 aspacem_assert(ixE >= 0 && ixE < asegs_pri.used); 2159 2160 /* Preconditions: See comment at start of fn */ 2161 aspacem_assert(ixS == ixE); 2162 2163 /* For the segment S denoted by ixS: 2164 2165 - if S is AnonV from prealloc and S entirely within start .. end, 2166 return it to prealloc 2167 2168 - if S is AnonV not from prealloc and S entirely within start .. end, 2169 munmap it 2170 2171 - if S is FileV and S entirely within start .. end, munmap it 2172 2173 Otherwise, leave it alone (too complex to handle). In theory 2174 this could cause a leak; in practice I don't think it will. 2175 */ 2176 seg = &asegs_pri.seg[ixS]; 2177 2178 if (debug) 2179 show_AixSegment( 0, ixS, seg ); 2180 2181 /* Invariants */ 2182 aspacem_assert(seg->start <= start); 2183 aspacem_assert(end <= seg->end); 2184 2185 if (seg->kind == ASkFileV 2186 || (seg->kind == ASkAnonV && (!seg->fromP))) { 2187 if (debug) 2188 VG_(debugLog)(0,"aspacem", "am_munmap_valgrind: !fromP: %p-%p\n", 2189 (void*)start, (void*)end); 2190 sres = ML_(am_do_munmap_NO_NOTIFY)( start, len ); 2191 if (sres.isError) 2192 goto bad; 2193 init_AixSegment( &seg2 ); 2194 seg2.start = start; 2195 seg2.end = end; 2196 seg2.kind = ASkFree; 2197 add_asegment( &asegs_pri, &seg2 ); 2198 } 2199 else 2200 if (seg->kind == ASkAnonV && seg->fromP) { 2201 if (debug) 2202 VG_(debugLog)(0,"aspacem", "am_munmap_valgrind: fromP: %p-%p\n", 2203 (void*)start, (void*)end); 2204 init_AixSegment( &seg2 ); 2205 seg2.start = start; 2206 seg2.end = end; 2207 seg2.kind = ASkPreAlloc; 2208 seg2.hasR = seg2.hasW = seg2.hasX = True; 2209 add_asegment( &asegs_pri, &seg2 ); 2210 } 2211 else { 2212 /* shouldn't be asked to handle any other cases */ 2213 aspacem_assert(0); 2214 } 2215 2216 aspacem_assert( sane_AixSegments( &asegs_pri )); 2217 return VG_(mk_SysRes_Success)(0); 2218 2219 bad: 2220 aspacem_assert( sane_AixSegments( &asegs_pri )); 2221 return VG_(mk_SysRes_Error)(VKI_EINVAL); 2222 } 2223 2224 2225 /* Let (start,len) denote an area within a single Valgrind-owned 2226 segment (anon or file). Change the ownership of [start, start+len) 2227 to the client instead. Fails if (start,len) does not denote a 2228 suitable segment. */ 2229 2230 Bool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len ) 2231 { 2232 return True; 2233 } 2234 2235 2236 /* 'seg' must be NULL or have been obtained from 2237 VG_(am_find_nsegment), and still valid. If non-NULL, and if it 2238 denotes a SkAnonC (anonymous client mapping) area, set the .isCH 2239 (is-client-heap) flag for that area. Otherwise do nothing. 2240 (Bizarre interface so that the same code works for both Linux and 2241 AIX and does not impose inefficiencies on the Linux version.) */ 2242 /* AIX: presumably this is a faked-up segment our VG_(am_find_segment) 2243 came up with. So we have to find the corresponding AixSegment. */ 2244 2245 void VG_(am_set_segment_isCH_if_SkAnonC)( NSegment* seg ) 2246 { 2247 Int i; 2248 if (seg == NULL) 2249 return; 2250 i = find_asegment_idx( &asegs_pri, seg->start ); 2251 aspacem_assert(i >= 0 && i < asegs_pri.used ); 2252 if (asegs_pri.seg[i].kind == ASkAnonC) { 2253 asegs_pri.seg[i].isCH = True; 2254 if (0) 2255 VG_(debugLog)(0,"aspacem","set isCH for %p\n", (void*)seg->start ); 2256 } else { 2257 aspacem_assert(asegs_pri.seg[i].isCH == False); 2258 } 2259 } 2260 2261 2262 /* Same idea as VG_(am_set_segment_isCH_if_SkAnonC), except set the 2263 segment's hasT bit (has-cached-code) if this is SkFileC or SkAnonC 2264 segment. */ 2265 /* AIX: we ignore these complexities by conservatively assuming that 2266 all segments had translations taken from them. Hence we can safely 2267 ignore this. */ 2268 void VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( NSegment* seg ) 2269 { 2270 } 2271 2272 2273 /* --- --- --- reservations --- --- --- */ 2274 2275 /* Create a reservation from START .. START+LENGTH-1, with the given 2276 ShrinkMode. When checking whether the reservation can be created, 2277 also ensure that at least abs(EXTRA) extra free bytes will remain 2278 above (> 0) or below (< 0) the reservation. 2279 2280 The reservation will only be created if it, plus the extra-zone, 2281 falls entirely within a single free segment. The returned Bool 2282 indicates whether the creation succeeded. */ 2283 2284 Bool VG_(am_create_reservation) ( Addr start, SizeT length, 2285 ShrinkMode smode, SSizeT extra ) 2286 { 2287 ML_(am_barf)("unimplemented: VG_(am_create_reservation)"); 2288 /*NOTREACHED*/ 2289 return False; 2290 } 2291 2292 2293 /* Let SEG be an anonymous client mapping. This fn extends the 2294 mapping by DELTA bytes, taking the space from a reservation section 2295 which must be adjacent. If DELTA is positive, the segment is 2296 extended forwards in the address space, and the reservation must be 2297 the next one along. If DELTA is negative, the segment is extended 2298 backwards in the address space and the reservation must be the 2299 previous one. DELTA must be page aligned. abs(DELTA) must not 2300 exceed the size of the reservation segment minus one page, that is, 2301 the reservation segment after the operation must be at least one 2302 page long. */ 2303 2304 Bool VG_(am_extend_into_adjacent_reservation_client) ( NSegment* seg, 2305 SSizeT delta ) 2306 { 2307 ML_(am_barf)("unimplemented: " 2308 "VG_(am_extend_into_adjacent_reservation_client)"); 2309 /*NOTREACHED*/ 2310 return False; 2311 } 2312 2313 2314 /* --- --- --- resizing/move a mapping --- --- --- */ 2315 2316 /* Let SEG be a client mapping (anonymous or file). This fn extends 2317 the mapping forwards only by DELTA bytes, and trashes whatever was 2318 in the new area. Fails if SEG is not a single client mapping or if 2319 the new area is not accessible to the client. Fails if DELTA is 2320 not page aligned. *seg is invalid after a successful return. If 2321 *need_discard is True after a successful return, the caller should 2322 immediately discard translations from the new area. */ 2323 2324 Bool VG_(am_extend_map_client)( /*OUT*/Bool* need_discard, 2325 NSegment* seg, SizeT delta ) 2326 { 2327 ML_(am_barf)("unimplemented: VG_(am_extend_map_client)"); 2328 /*NOTREACHED*/ 2329 return False; 2330 } 2331 2332 2333 /* Remap the old address range to the new address range. Fails if any 2334 parameter is not page aligned, if the either size is zero, if any 2335 wraparound is implied, if the old address range does not fall 2336 entirely within a single segment, if the new address range overlaps 2337 with the old one, or if the old address range is not a valid client 2338 mapping. If *need_discard is True after a successful return, the 2339 caller should immediately discard translations from both specified 2340 address ranges. */ 2341 2342 Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard, 2343 Addr old_addr, SizeT old_len, 2344 Addr new_addr, SizeT new_len ) 2345 { 2346 ML_(am_barf)("unimplemented: VG_(am_relocate_nooverlap_client)"); 2347 /*NOTREACHED*/ 2348 return False; 2349 } 2350 2351 2352 2353 /*-----------------------------------------------------------------*/ 2354 /*--- ---*/ 2355 /*--- A simple parser for /proc/<pid>/map on AIX5. ---*/ 2356 /*--- Almost completely independent of the stuff above. The ---*/ 2357 /*--- only function it 'exports' to the code above this comment ---*/ 2358 /*--- is parse_procselfmaps. ---*/ 2359 /*--- ---*/ 2360 /*-----------------------------------------------------------------*/ 2361 2362 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ 2363 #include <sys/procfs.h> 2364 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */ 2365 2366 2367 /* Size of a smallish table used to read /proc/<pid>/map entries. */ 2368 #define M_APROCMAP_BUF 100000 2369 2370 /* static ... to keep it out of the stack frame. */ 2371 static HChar procmap_buf[M_APROCMAP_BUF]; 2372 2373 /* Records length of /proc/<pid>/map read into procmap_buf. */ 2374 static Int buf_n_tot; 2375 2376 /* Helper fns. */ 2377 2378 /* Get the contents of /proc/<pid>/map into a static buffer. If 2379 there's a syntax error, it won't fit, or other failure, just 2380 abort. */ 2381 2382 static void read_procselfmap_into_buf ( void ) 2383 { 2384 Char fname[50]; 2385 Int n_chunk; 2386 SysRes fd; 2387 2388 ML_(am_sprintf)( fname, "/proc/%d/map", ML_(am_getpid)() ); 2389 2390 /* Read the initial memory mapping from the /proc filesystem. */ 2391 fd = ML_(am_open)( fname, VKI_O_RDONLY, 0 ); 2392 if (fd.isError) 2393 ML_(am_barf)("can't open /proc/<pid>/map"); 2394 2395 buf_n_tot = 0; 2396 do { 2397 n_chunk = ML_(am_read)( fd.res, &procmap_buf[buf_n_tot], 2398 M_APROCMAP_BUF - buf_n_tot ); 2399 buf_n_tot += n_chunk; 2400 } while ( n_chunk > 0 && buf_n_tot < M_APROCMAP_BUF ); 2401 2402 ML_(am_close)(fd.res); 2403 2404 if (buf_n_tot >= M_APROCMAP_BUF-5) 2405 ML_(am_barf_toolow)("M_APROCMAP_BUF"); 2406 if (buf_n_tot == 0) 2407 ML_(am_barf)("I/O error on /proc/<pid>/map"); 2408 2409 procmap_buf[buf_n_tot] = 0; 2410 } 2411 2412 2413 /* /proc/<pid>/map appears to give out a non-absolute path name for 2414 the main executable. Fortunately we can reliably identify the main 2415 executable via the MA_MAINEXEC bit, and if we find the path is 2416 non-absolute, replace it with /proc/<pid>/object/a.out instead. 2417 AIX guarantees the latter is another name for the main 2418 executable. */ 2419 2420 static HChar* kludge_exe_file_name ( HChar* file_name, prmap_t* map ) 2421 { 2422 static Int my_pid = -1; 2423 static HChar a_out_name[64]; 2424 if (file_name == NULL) 2425 return NULL; 2426 if (file_name[0] != '/' && (map->pr_mflags & MA_MAINEXEC)) { 2427 if (my_pid == -1) 2428 my_pid = ML_(am_getpid)(); 2429 ML_(am_sprintf)(a_out_name, "/proc/%d/object/a.out", my_pid); 2430 file_name = a_out_name; 2431 } 2432 return file_name; 2433 } 2434 2435 2436 2437 /* Parse /proc/<pid>/map, copying the entries in it into an 2438 AixSegments structure. Returns a properly formed AixSegments, with 2439 ASkMText/ASkMData entries, with sibling pointers set up, and 2440 ASkFree everywhere else. 2441 */ 2442 static void parse_procselfmap ( /*OUT*/AixSegments* segs ) 2443 { 2444 UChar rr, ww, xx, mm, ss; 2445 prmap_t* map; 2446 UChar* file_name; 2447 UChar* member_name; 2448 Bool show_map; 2449 Int off, i, j; 2450 AixSegment s; 2451 2452 const UInt valid_pr_mflags 2453 = MA_MAINEXEC | MA_KERNTEXT | MA_READ | MA_WRITE 2454 | MA_EXEC | MA_SHARED | MA_BREAK | MA_STACK; 2455 2456 segs->used = 1; 2457 init_AixSegments(segs); 2458 aspacem_assert( sane_AixSegments(segs) ); 2459 2460 read_procselfmap_into_buf(); 2461 2462 if (0) 2463 VG_(debugLog)(0, "procselfmaps", "got %d bytes\n", buf_n_tot); 2464 2465 off = 0; 2466 while (True) { 2467 2468 /* stay sane .. */ 2469 if (off + sizeof(prmap_t) > buf_n_tot) 2470 break; 2471 2472 map = (prmap_t*)&procmap_buf[off]; 2473 off += sizeof(prmap_t); 2474 2475 /* When should we stop reading the array? 2476 /usr/include/sys/procfs.h says that "Array entries continue 2477 until an entry with a pr_size field of 0 and invalid 2478 pr_mflags occurs." It unhelpfully fails to define what 2479 "invalid" means here. However, the following test _seems_ to 2480 work. */ 2481 if (map->pr_size == 0 2482 && (map->pr_mflags & valid_pr_mflags) == 0) 2483 break; 2484 2485 /* Ok, keep going, but ignore any zero-sized mappings: */ 2486 if (map->pr_size == 0) 2487 continue; 2488 2489 mm = (map->pr_mflags & MA_MAINEXEC) > 0; 2490 rr = (map->pr_mflags & MA_READ) > 0; 2491 ww = (map->pr_mflags & MA_WRITE) > 0; 2492 xx = (map->pr_mflags & MA_EXEC) > 0; 2493 ss = (map->pr_mflags & MA_SHARED) > 0; 2494 2495 if (map->pr_pathoff > 0) { 2496 file_name = &procmap_buf[map->pr_pathoff]; 2497 member_name = file_name + VG_(strlen)(file_name) + 1; 2498 if (*member_name == 0) 2499 member_name = NULL; 2500 } else { 2501 file_name = member_name = NULL; 2502 } 2503 file_name = kludge_exe_file_name( file_name, map ); 2504 2505 /* Now file_name and member_name are NULL or ordinary strings. 2506 Convert them to string-table resident strings. */ 2507 if (file_name) 2508 file_name = add_to_strtab(file_name); 2509 if (member_name) 2510 member_name = add_to_strtab(member_name); 2511 2512 /* Create a suitable kind of segment. Initially we will start 2513 with bogus sibling pointers, and allow ASkMData entries to 2514 have file names, since we cannot assume anything about the 2515 ordering of entries in the procmap file. In a second pass, 2516 we will set up the sibling pointers based on those file 2517 names, then remove the MData file names. */ 2518 init_AixSegment(&s); 2519 show_map = False; 2520 if (rr && (!ww) && xx) { 2521 if (map->pr_size > 0) { 2522 /* r-x segment; add bounds for a text area. */ 2523 s.kind = ASkMText; 2524 s.start = (Addr)map->pr_vaddr; 2525 s.end = (Addr)map->pr_vaddr + (Addr)map->pr_size - 1; 2526 s.isMainExe = mm; 2527 s.sibling = 0; 2528 s.fname = file_name; 2529 s.mname = member_name; 2530 s.hasR = rr; 2531 s.hasW = ww; 2532 s.hasX = xx; 2533 add_asegment(segs, &s); 2534 } 2535 } 2536 else 2537 if (rr && ww && (!xx)) { 2538 if (map->pr_size > 0) { 2539 /* rw- segment; add bounds for a data area. */ 2540 s.kind = ASkMData; 2541 s.start = (Addr)map->pr_vaddr; 2542 s.end = (Addr)map->pr_vaddr + (Addr)map->pr_size - 1; 2543 /* Set a bogus non-zero sibling pointer, since sanity 2544 checking will reject zero sibling pointers on MData. 2545 It doesn't matter since the loops following this one 2546 below fix up the sibling pointers. */ 2547 s.sibling = 1; 2548 s.fname = file_name; 2549 s.mname = member_name; 2550 s.hasR = rr; 2551 s.hasW = ww; 2552 s.hasX = xx; 2553 add_asegment(segs, &s); 2554 } 2555 } 2556 else { 2557 /* unclassifiable; we better complain. */ 2558 show_map = True; 2559 VG_(debugLog)(0, "aspacem", "parse_procselfmap: unclassifiable:\n"); 2560 } 2561 2562 if (show_map) 2563 VG_(debugLog)(1,"aspacem", 2564 " %010llx-%010llx %c%c%c%c%c %s%s%s%s\n", 2565 (ULong)map->pr_vaddr, 2566 (ULong)map->pr_vaddr + (ULong)map->pr_size, 2567 mm ? 'M' : '-', 2568 rr ? 'r' : '-', 2569 ww ? 'w' : '-', 2570 xx ? 'x' : '-', 2571 ss ? 'S' : '-', 2572 file_name ? file_name : (UChar*)"(none)", 2573 member_name ? "(" : "", 2574 member_name ? member_name : (UChar*)"", 2575 member_name ? ")" : "" 2576 ); 2577 2578 } 2579 2580 /* Set up sibling pointers. For each MData, find an MText with the 2581 same file/member names, or complain. This is really ugly in 2582 that it makes the process quadratic in the number of modules 2583 mapped in, but I can't think of a (simple) better way. */ 2584 2585 for (i = 0; i < segs->used; i++) { 2586 if (segs->seg[i].kind != ASkMData) 2587 continue; 2588 for (j = 0; j < segs->used; j++) { 2589 if (segs->seg[j].kind == ASkMText 2590 && segs->seg[j].fname == segs->seg[i].fname 2591 && segs->seg[j].mname == segs->seg[i].mname) 2592 break; 2593 } 2594 if (j == segs->used) { 2595 VG_(debugLog)(0, "aspacem", "parse_procselfmap: " 2596 "data segment with no associated text segment:\n"); 2597 VG_(debugLog)(0, "aspacem", "module = %s(%s)\n", 2598 segs->seg[i].fname, 2599 segs->seg[i].mname ? segs->seg[i].mname 2600 : (UChar*)"(none)"); 2601 aspacem_assert(0); 2602 } 2603 aspacem_assert(j >= 0 && j < segs->used && j != i); 2604 segs->seg[i].sibling = segs->seg[j].start; 2605 } 2606 2607 /* (Almost) dually, for each MText, find an MData with same 2608 file/member names, but don't complain if not present. */ 2609 2610 for (i = 0; i < segs->used; i++) { 2611 if (segs->seg[i].kind != ASkMText) 2612 continue; 2613 for (j = 0; j < segs->used; j++) { 2614 if (segs->seg[j].kind == ASkMData 2615 && segs->seg[j].fname == segs->seg[i].fname 2616 && segs->seg[j].mname == segs->seg[i].mname) 2617 break; 2618 } 2619 if (j == segs->used) { 2620 /* no corresponding MData found; harmless. */ 2621 } else { 2622 aspacem_assert(j >= 0 && j < segs->used && j != i); 2623 segs->seg[i].sibling = segs->seg[j].start; 2624 } 2625 } 2626 2627 /* Finally, get rid of fname/mname pointers on MDatas, so as to 2628 adhere to the necessary representational invariants. */ 2629 for (i = 0; i < segs->used; i++) { 2630 if (segs->seg[i].kind == ASkMData){ 2631 segs->seg[i].fname = segs->seg[i].mname = NULL; 2632 } 2633 } 2634 2635 aspacem_assert( sane_AixSegments(segs) ); 2636 if (0) 2637 show_AixSegments(0, "as read from procmap", segs); 2638 } 2639 2640 #endif // defined(VGO_aix5) 2641 2642 /*--------------------------------------------------------------------*/ 2643 /*--- end ---*/ 2644 /*--------------------------------------------------------------------*/ 2645