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@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
AM_IS_4K_ALIGNED(UWord w)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
AM_4K_ROUNDUP(UWord w)262 static UWord AM_4K_ROUNDUP ( UWord w )
263 {
264 UWord m = AM_4K_PAGESZ-1;
265 return (w+m) & (~m);
266 }
267
AM_64K_ROUNDUP(UWord w)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
add_to_strtab(UChar * str)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
is_in_strtab(UChar * str)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
init_AixSegment(AixSegment * s)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
name_of_AixSegKind(AixSegKind sk)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
show_AixSegment(Int logLevel,Int segNo,AixSegment * seg)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
init_AixSegments(AixSegments * segs)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
show_AixSegments(Int logLevel,HChar * who,AixSegments * segs)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
sane_AixSegment(AixSegment * seg)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. */
find_asegment_idx(AixSegments * segs,Addr a)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
sane_AixSegments(AixSegments * segs)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
maybe_merge_asegments(AixSegment * s1,AixSegment * s2)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
preen_asegments(AixSegments * segs)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
split_asegment_at(AixSegments * segs,Addr a)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
split_asegments_lo_and_hi(AixSegments * segs,Addr sLo,Addr sHi,Int * iLo,Int * iHi)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
add_asegment(AixSegments * segs,AixSegment * seg)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
knockout_non_module_segs(AixSegments * segs)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
copy_asegments_d_s(AixSegments * dst,AixSegments * src)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
VG_(am_aix5_reread_procmap_howmany_directives)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
add_pri_text_and_data_segs(AixSegment * tnew,AixSegment * dnew)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
del_pri_text_and_data_segs(AixSegment * told,AixSegment * dold)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
VG_(am_aix5_reread_procmap)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
VG_(am_aix5_set_initial_client_sp)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!). */
VG_(am_show_nsegments)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. */
VG_(am_get_filename)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
VG_(am_get_segment_starts)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
VG_(am_do_sync_check)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. */
ML_(am_do_sanity_check)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
VG_(am_find_nsegment)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. */
VG_(am_next_nsegment)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. */
VG_(am_get_anonsize_total)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. */
VG_(am_is_valid_for_client)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. */
VG_(am_is_valid_for_client_or_free_or_resvn)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
VG_(am_startup)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
local_do_sbrk_NO_NOTIFY(Word delta)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
find_prealloc_idx(SizeT req_sz)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
new_prealloc(SizeT req_sz)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
find_or_create_prealloc_idx(SizeT req_sz)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
VG_(am_get_advisory)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
VG_(am_get_advisory_client_simple)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
VG_(am_notify_client_mmap)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
VG_(am_notify_client_shmat)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
VG_(am_notify_mprotect)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
VG_(am_notify_munmap)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
VG_(am_mmap_file_fixed_client)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
VG_(am_mmap_anon_fixed_client)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
VG_(am_mmap_anon_float_client)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
VG_(am_sbrk_anon_float_client)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
VG_(am_mmap_anon_float_valgrind)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). */
VG_(am_sbrk_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
VG_(am_shadow_alloc)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
VG_(am_mmap_file_float_valgrind)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
VG_(am_munmap_client)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
VG_(am_munmap_valgrind)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
VG_(am_change_ownership_v_to_c)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
VG_(am_set_segment_isCH_if_SkAnonC)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. */
VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)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
VG_(am_create_reservation)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
VG_(am_extend_into_adjacent_reservation_client)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
VG_(am_extend_map_client)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
VG_(am_relocate_nooverlap_client)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
read_procselfmap_into_buf(void)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
kludge_exe_file_name(HChar * file_name,prmap_t * map)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 */
parse_procselfmap(AixSegments * segs)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