2
/*--------------------------------------------------------------------*/
3
/*--- The address space manager: segment initialisation and ---*/
4
/*--- tracking, stack operations ---*/
6
/*--- Implementation for AIX5 m_aspacemgr-aix5.c ---*/
7
/*--------------------------------------------------------------------*/
10
This file is part of Valgrind, a dynamic binary instrumentation
13
Copyright (C) 2006-2007 OpenWorks LLP
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.
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.
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
31
The GNU General Public License is contained in the file COPYING.
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.
39
/* *************************************************************
40
DO NOT INCLUDE ANY OTHER FILES HERE.
41
ADD NEW INCLUDES ONLY TO priv_aspacemgr.h
42
AND THEN ONLY AFTER READING DIRE WARNINGS THERE TOO.
43
************************************************************* */
45
#include "priv_aspacemgr.h"
48
/* Note: many of the exported functions implemented below are
49
described more fully in comments in pub_core_aspacemgr.h.
52
/* This provides a minimal address space management facility for AIX5.
53
It is not as comprehensive, robust or efficient as its Linux
56
It does implement the advise/notify concept described in
57
aspacemgr-linux.c, but minimally. It only keeps track of the
58
mappings belonging to Valgrind; the client can do what it likes so
59
long as it doesn't trash Valgrind's mappings.
61
This is unfortunate, but the root problem is that it is impossible
62
to find out on AIX what the complete set of mappings for a process
63
is. Sure, AIX does have /proc/pid/map, but it's weak compared to
64
Linux's: it just shows some small subset of the mappings, not all
65
of them. So it is not very useful: it can't be used to discover
66
the true initial process mapping state, and it can't be used to
67
cross-check Valgrind's internal mapping table, as is done at
68
--sanity-level=3 and above on Linux.
72
/*-----------------------------------------------------------------*/
74
/*--- The Address Space Manager's state. ---*/
76
/*-----------------------------------------------------------------*/
78
/* Describes AIX5-specific segment kinds */
81
ASkFree=1, // free space
82
ASkMText, // module text (code) mapping
83
ASkMData, // module data (& bss) mapping
84
ASkFileV, // file mapping belonging to valgrind
85
ASkAnonC, // anonymous mapping belonging to the client
86
ASkAnonV, // anonymous mapping belonging to valgrind
87
ASkShmemC, // shm mapping belonging to the client
88
ASkPreAlloc // area preallocated from sbrk
92
/* Segment table entries, in summary:
95
ASkMText start end r w x sibling ismainexe fname mname
96
ASkMData start end r w x sibling
97
FileV start end r w x fname offset
98
AnonC start end r w x fromP isCH
99
AnonV start end r w x fromP
100
ShmemC start end r w x
103
Entries are non-overlapping and cover the entire address space
104
exactly (as in the Linux aspacem). Unlike Linux there are no
105
alignment constraints, since we're just recording what's going on,
106
rather than controlling it.
108
MText/MData are XCOFF mapped modules, as determined by looking at
109
/proc/../map. MText is the primary entry and contains the text
110
range. MData contains the data range, if the module has a data
111
mapping (usually but not always). MText also holds the avma of the
112
corresponding data segment start, if any, (sibling field) so it can
113
be found and the two added/removed together. Similarly MData
114
contains the address of the corresponding MText (also sibling).
116
fname/mname only apply to MText. To find the fname/mname for MData
117
you have to look at the corresponding MText entry, which is
118
guaranteed to exist. MText may exist without a corresponding MData
119
but not vice versa. Kludge: in fact fname/mname have to be
120
allowed in MData, else read_procselfmap doesn't work.
122
MText may have a zero sibling pointer, indicating that there is no
123
corresponding MData. But MData must have a nonzero sibling pointer
124
since MData without MText is not allowed. Implication is that
125
neither MText nor MData may be mapped at zero as this would mess up
126
the representation, but I don't think that will ever happen since
127
AIX uses page zero as a readonly const-zero area.
129
For MData entries, the data section size acquired from /proc/../map
130
appears to also include the bss, so there is no need for any
131
further handling of that.
133
isCH indicates whether an AnonC area is part of the client heap
134
or not. May not be set for any other kind of area.
136
File and member names are entries into the string table.
138
fromP, for AnonC/AnonV, if True, indicates that the segment was
139
allocated from a PreAlloc area, and so should be returned to that
140
state upon deallocation. If False, indicates that the segment
141
should be unmapped on deallocation.
148
/* Note: zero-length segments are not allowed. That guarantees
149
that start <= end. */
150
Addr start; // lowest addr in range (ALL)
151
Addr end; // highest addr in range (ALL)
153
/* ALL except Free */
159
Addr sibling; // MText, MData only: addr of MData/MText
160
Bool isMainExe; // MText only: is this the main executable?
161
Bool isCH; // AnonC only: is this part of the client's heap?
162
Bool fromP; // AnonC, AnonV only: originated from PreAlloc?
163
UChar* fname; // MText, FileV only: filename
164
UChar* mname; // MText only: member name if present
165
ULong offset; // FileV only: file offset
170
#define VG_N_ASEGMENTS 5000
174
AixSegment seg[VG_N_ASEGMENTS];
180
/* ------ start of STATE for the address-space manager ------ */
182
/* A table of zero-terminated strings (file names etc). This
183
is only ever added to. */
185
#define VG_N_ASTRTAB 200000
186
static Int strtab_used = 0;
187
static UChar strtab[VG_N_ASTRTAB];
189
#define Addr_MIN ((Addr)0)
190
#define Addr_MAX ((Addr)(-1ULL))
192
/* The main array of AixSegments, in order as required. */
194
static AixSegments asegs_pri;
196
/* and two auxiliary arrays. */
198
static AixSegments asegs_tnew;
199
static AixSegments asegs_told;
201
/* The assumed size of the main thread's stack, so that we can add a
202
segment for it at startup. */
204
#define N_FAKE_STACK_PAGES 4096 /* 16M fake stack */
206
/* Hacks which are probably for AIX 'millicode'. Note: ensure
207
these stay page aligned. */
209
#define MAGIC_PAGES_1_BASE 0x3000
210
#define MAGIC_PAGES_1_SIZE (2*0x1000)
212
#define MAGIC_PAGES_2_BASE 0xC000
213
#define MAGIC_PAGES_2_SIZE (4*0x1000)
216
#define AM_SANITY_CHECK(_who) \
218
if (VG_(clo_sanity_level >= 3)) { \
219
Bool ok = sane_AixSegments(&asegs_pri); \
221
VG_(debugLog)(0,"aspace", "sanity check failed, " \
222
"who = %s\n", _who); \
223
aspacem_assert(ok); \
227
/* When preallocating a block from sbrk-world, how much extra
228
should we pre-emptively acquire? */
230
//#define AM_PREALLOC_EXTRA (512 * 1024)
231
//#define AM_PREALLOC_EXTRA 0x0800000 /* 8 M */
232
#define AM_PREALLOC_EXTRA 0x4000000 /* 64 M */
234
/* The AIX5 aspacem implementation needs to be told when it is and
235
isn't allowed to use sbrk to allocate memory. Hence: */
236
Bool VG_(am_aix5_sbrk_allowed) = True;
238
/* ------ end of STATE for the address-space manager ------ */
240
/* ------ Forwards decls ------ */
241
static void parse_procselfmap ( /*OUT*/ AixSegments* );
244
/*-----------------------------------------------------------------*/
246
/*--- Stuff for 4K (small-page-size) rounding. ---*/
248
/*-----------------------------------------------------------------*/
250
#define AM_4K_PAGESZ 4096
252
static Bool AM_IS_4K_ALIGNED ( UWord w )
254
UWord m = AM_4K_PAGESZ-1;
255
return toBool( (w & m) == 0 );
258
static UWord AM_4K_ROUNDUP ( UWord w )
260
UWord m = AM_4K_PAGESZ-1;
264
static UWord AM_64K_ROUNDUP ( UWord w )
271
/*-----------------------------------------------------------------*/
273
/*--- String table management. ---*/
275
/*-----------------------------------------------------------------*/
277
/* Add the given string into the string table (or find an existing
278
copy of it) and return a pointer to the in-table version. The
279
pointer will be valid for the entire rest of the run. */
281
static UChar* add_to_strtab ( UChar* str )
284
/* First, look for the string. */
286
while (off < strtab_used) {
287
if (0 == VG_(strcmp)(str, &strtab[off]))
289
off += VG_(strlen)(&strtab[off]) + 1;
291
/* not present? we'll have to copy it then. */
292
len = VG_(strlen)(str);
293
if (len + 1 + strtab_used > VG_N_ASTRTAB)
294
ML_(am_barf_toolow)("VG_N_ASTRTAB");
297
strtab[strtab_used++] = *str;
298
strtab[strtab_used++] = 0;
299
aspacem_assert(strtab_used <= VG_N_ASTRTAB);
304
static Bool is_in_strtab ( UChar* str )
306
if (str < &strtab[0])
308
if (str >= &strtab[strtab_used])
310
if (str > &strtab[0] && str[-1] != 0)
316
/*-----------------------------------------------------------------*/
318
/*--- Low level AixSegment stuff. ---*/
320
/*-----------------------------------------------------------------*/
322
static void init_AixSegment ( AixSegment* s )
324
s->kind = 0; /* invalid */
331
s->isMainExe = False;
340
static HChar* name_of_AixSegKind ( AixSegKind sk )
343
case ASkFree: return "Free ";
344
case ASkMText: return "MText";
345
case ASkMData: return "MData";
346
case ASkAnonV: return "AnonV";
347
case ASkAnonC: return "AnonC";
348
case ASkFileV: return "FileV";
349
case ASkShmemC: return "ShmC ";
350
case ASkPreAlloc: return "PreAl";
351
default: ML_(am_barf)("name_of_AixSegKind");
359
void show_AixSegment ( Int logLevel, Int segNo, AixSegment* seg )
361
HChar* segName = name_of_AixSegKind( seg->kind );
364
VG_(debugLog)(logLevel, "aspacem",
365
"%3d: %s %010llx-%010llx\n",
366
segNo, /*segName*/" ",
367
(ULong)seg->start, (ULong)seg->end
371
VG_(debugLog)(logLevel, "aspacem",
372
"%3d: %s %010llx-%010llx %c%c%c-- (d %010llx) %s%s%s%s\n",
373
segNo, seg->isMainExe ? "MTEXT" : "MText",
374
(ULong)seg->start, (ULong)seg->end,
375
seg->hasR ? 'r' : '-',
376
seg->hasW ? 'w' : '-',
377
seg->hasX ? 'x' : '-',
380
seg->mname ? "(" : "",
381
seg->mname ? (HChar*)seg->mname : "",
382
seg->mname ? ")" : ""
386
VG_(debugLog)(logLevel, "aspacem",
387
"%3d: %s %010llx-%010llx %c%c%c-- (t %010llx)\n",
389
(ULong)seg->start, (ULong)seg->end,
390
seg->hasR ? 'r' : '-',
391
seg->hasW ? 'w' : '-',
392
seg->hasX ? 'x' : '-',
397
VG_(debugLog)(logLevel, "aspacem",
398
"%3d: %s %010llx-%010llx %c%c%c-- %6lld %s\n",
400
(ULong)seg->start, (ULong)seg->end,
401
seg->hasR ? 'r' : '-',
402
seg->hasW ? 'w' : '-',
403
seg->hasX ? 'x' : '-',
411
VG_(debugLog)(logLevel, "aspacem",
412
"%3d: %s %010llx-%010llx %c%c%c%c%c\n",
414
(ULong)seg->start, (ULong)seg->end,
415
seg->hasR ? 'r' : '-',
416
seg->hasW ? 'w' : '-',
417
seg->hasX ? 'x' : '-',
418
seg->kind==ASkAnonC && seg->isCH ? 'H' : '-',
419
seg->fromP ? 'P' : '-'
423
VG_(debugLog)(logLevel, "aspacem",
424
"%3d: %s %010llx-%010llx %c%c%c-- (size %llu)\n",
426
(ULong)seg->start, (ULong)seg->end,
427
seg->hasR ? 'r' : '-',
428
seg->hasW ? 'w' : '-',
429
seg->hasX ? 'x' : '-',
430
(ULong)seg->end - (ULong)seg->start + 1
434
VG_(debugLog)(logLevel, "aspacem",
435
"%3d: show_AixSegment: unknown segment\n",
442
static void init_AixSegments ( AixSegments* segs )
445
init_AixSegment( &segs->seg[0] );
446
segs->seg[0].kind = ASkFree;
447
segs->seg[0].start = Addr_MIN;
448
segs->seg[0].end = Addr_MAX;
453
void show_AixSegments ( Int logLevel, HChar* who, AixSegments* segs )
456
VG_(debugLog)(logLevel, "aspacem", "<<< %s\n", who);
457
for (i = 0; i < segs->used; i++)
458
show_AixSegment( logLevel, i, &segs->seg[i] );
459
VG_(debugLog)(logLevel, "aspacem", ">>>\n");
463
static Bool sane_AixSegment ( AixSegment* seg )
465
/* disallow zero and negative length segments */
466
if (seg->end < seg->start)
471
if (seg->hasR || seg->hasW || seg->hasX)
473
if (seg->isMainExe || seg->sibling != 0 || seg->offset != 0)
475
if (seg->fname || seg->mname)
477
if (seg->isCH || seg->fromP)
481
if (!is_in_strtab(seg->fname))
483
if (seg->mname && !is_in_strtab(seg->mname))
485
if (seg->offset != 0)
487
if (seg->isCH || seg->fromP)
491
if (seg->isMainExe || seg->sibling == 0 || seg->offset != 0)
493
/* fname/mname have to be allowed in MData, else
494
read_procselfmap doesn't work. Unfortunately. */
496
if (seg->fname || seg->mname)
499
if (seg->isCH || seg->fromP)
503
if (!is_in_strtab(seg->fname))
505
if (seg->mname != NULL)
507
if (seg->isMainExe || seg->sibling != 0)
509
if (seg->isCH || seg->fromP)
515
if (seg->fname || seg->mname)
517
if (seg->isMainExe || seg->sibling != 0)
519
if (seg->offset != 0)
521
if (seg->kind != ASkAnonC && seg->isCH)
523
if ( (!(seg->kind == ASkAnonV || seg->kind == ASkAnonC))
528
if (seg->fname || seg->mname)
530
if (seg->isMainExe || seg->sibling != 0)
532
if (seg->offset != 0)
534
if (seg->kind != ASkAnonC && seg->isCH)
538
if (!AM_IS_4K_ALIGNED(seg->start))
540
if (!AM_IS_4K_ALIGNED(seg->end + 1))
542
if (!(seg->hasR && seg->hasW && seg->hasX))
552
/* Binary search the interval array for a given address. Since the
553
array covers the entire address space the search cannot fail. */
554
static Int find_asegment_idx ( AixSegments* segs, Addr a )
556
Addr a_mid_lo, a_mid_hi;
560
aspacem_assert(lo <= hi);
562
/* current unsearched space is from lo to hi, inclusive. */
564
/* Not found. This can't happen. */
565
ML_(am_barf)("find_nsegment_idx: not found");
568
a_mid_lo = segs->seg[mid].start;
569
a_mid_hi = segs->seg[mid].end;
571
if (a < a_mid_lo) { hi = mid-1; continue; }
572
if (a > a_mid_hi) { lo = mid+1; continue; }
573
aspacem_assert(a >= a_mid_lo && a <= a_mid_hi);
574
aspacem_assert(0 <= mid && mid < segs->used);
580
static Bool sane_AixSegments ( AixSegments* segs )
584
/* Check endpoints */
585
if (segs->used < 1 || segs->used > VG_N_ASEGMENTS) {
586
VG_(debugLog)(0, "aspacem", "sane_AixSegments: bad ->used");
589
if (segs->seg[0].start != Addr_MIN
590
|| segs->seg[segs->used-1].end != Addr_MAX) {
591
VG_(debugLog)(0, "aspacem", "sane_AixSegments: bad endpoints");
595
/* Check each segment, and check entire range is covered. */
596
for (i = 0; i < segs->used; i++) {
597
if (!sane_AixSegment( &segs->seg[i] )) {
598
VG_(debugLog)(0, "aspacem",
599
"sane_AixSegments: bad segment %d\n", i);
603
for (i = 1; i < segs->used; i++) {
604
if (segs->seg[i-1].end + 1 != segs->seg[i].start) {
605
VG_(debugLog)(0, "aspacem",
606
"sane_AixSegments: bad transition at %d/%d\n", i-1,i);
611
/* Now we know 'seg' is safe for use in find_asegment_idx().
612
Check the sibling pointers for MText/MData.
614
Also check that the segment starting at address zero is neither
615
MText nor MData (since this would mess up the sibling pointer
616
representation; see comments above.) Failure of this is not per
617
se a logic failure, but it does indicate that the kernel
618
unexpectedly placed MText or MData at zero, and our
619
representation is therefore inadequate.
621
if (segs->seg[0].kind == ASkMText || segs->seg[0].kind == ASkMData) {
622
VG_(debugLog)(0, "aspacem",
623
"sane_AixSegments: ASkMText/ASkMData at address zero\n");
627
for (i = 0; i < segs->used-1; i++) {
633
if (s1->kind == ASkMData) {
634
s2 = &segs->seg[ find_asegment_idx(segs, s1->sibling) ];
635
if (s2->kind != ASkMText
636
|| find_asegment_idx(segs, s2->sibling) != i) {
637
VG_(debugLog)(0, "aspacem", "sane_AixSegments: bad sibling "
638
"link(s) for ASkData\n");
643
if (s1->kind == ASkMText && s1->sibling != 0) {
644
s2 = &segs->seg[ find_asegment_idx(segs, s1->sibling) ];
645
if (s2->kind != ASkMData
646
|| find_asegment_idx(segs, s2->sibling) != i) {
647
VG_(debugLog)(0, "aspacem", "sane_AixSegments: bad sibling "
648
"link(s) for ASkText\n");
659
/* Try merging s2 into s1, if possible. If successful, s1 is
660
modified, and True is returned. Otherwise s1 is unchanged and
661
False is returned. */
663
static Bool maybe_merge_asegments ( AixSegment* s1, AixSegment* s2 )
665
if (s1->kind != s2->kind)
668
if (s1->end+1 != s2->start)
679
if (s1->hasR == s2->hasR && s1->hasW == s2->hasW
680
&& s1->hasX == s2->hasX && s1->isCH == s2->isCH
681
&& s1->fromP == s2->fromP) {
687
/* not really necessary, but .. */
689
if (s1->hasR == s2->hasR
690
&& s1->hasW == s2->hasW && s1->hasX == s2->hasX
691
&& s1->fname == s2->fname
692
&& s2->offset == s1->offset
693
+ ((ULong)s2->start) - ((ULong)s1->start) ) {
699
/* it's important to merge PreAlloc's back together to avoid
700
fragmenting PreAlloc'd space unnecessarily */
713
/* Merge mergable segments in SEGS. */
715
static void preen_asegments ( AixSegments* segs )
719
aspacem_assert(segs->used >= 1);
724
for (r = 1; r < segs->used; r++) {
725
if (maybe_merge_asegments(&segs->seg[w], &segs->seg[r])) {
730
segs->seg[w] = segs->seg[r];
734
aspacem_assert(w > 0 && w <= segs->used);
739
/*-----------------------------------------------------------------*/
741
/*--- Modifying a segment array, and constructing segments. ---*/
743
/*-----------------------------------------------------------------*/
745
/* Split the segment containing 'a' into two, so that 'a' is
746
guaranteed to be the start of a new segment. If 'a' is already the
747
start of a segment, do nothing. */
749
static void split_asegment_at ( AixSegments* segs, Addr a )
753
aspacem_assert(a > 0);
754
aspacem_assert(segs->used >= 1);
756
i = find_asegment_idx(segs, a);
757
aspacem_assert(i >= 0 && i < segs->used);
759
if (segs->seg[i].start == a)
760
/* 'a' is already the start point of a segment, so nothing to be
764
/* else we have to slide the segments upwards to make a hole */
765
if (segs->used >= VG_N_ASEGMENTS)
766
ML_(am_barf_toolow)("VG_N_ASEGMENTS");
767
for (j = segs->used-1; j > i; j--)
768
segs->seg[j+1] = segs->seg[j];
771
segs->seg[i+1] = segs->seg[i];
772
segs->seg[i+1].start = a;
773
segs->seg[i].end = a-1;
775
if (segs->seg[i].kind == ASkFileV /* || segs->seg[i].kind == ASkFileC*/)
776
segs->seg[i+1].offset
777
+= ((ULong)segs->seg[i+1].start) - ((ULong)segs->seg[i].start);
779
aspacem_assert(sane_AixSegment(&segs->seg[i]));
780
aspacem_assert(sane_AixSegment(&segs->seg[i+1]));
784
/* Do the minimum amount of segment splitting necessary to ensure that
785
sLo is the first address denoted by some segment and sHi is the
786
highest address denoted by some other segment. Returns the indices
787
of the lowest and highest segments in the range. */
790
void split_asegments_lo_and_hi ( AixSegments* segs,
795
aspacem_assert(sLo < sHi);
798
split_asegment_at(segs, sLo);
800
split_asegment_at(segs, sHi+1);
802
*iLo = find_asegment_idx(segs,sLo);
803
*iHi = find_asegment_idx(segs,sHi);
804
aspacem_assert(0 <= *iLo && *iLo < segs->used);
805
aspacem_assert(0 <= *iHi && *iHi < segs->used);
806
aspacem_assert(*iLo <= *iHi);
807
aspacem_assert(segs->seg[*iLo].start == sLo);
808
aspacem_assert(segs->seg[*iHi].end == sHi);
809
/* Not that I'm overly paranoid or anything, definitely not :-) */
813
/* Add SEG to the collection, deleting/truncating any it overlaps.
814
This deals with all the tricky cases of splitting up segments as
815
needed. Contents of SEG are copied. */
817
static void add_asegment ( AixSegments* segs, AixSegment* seg )
819
Int i, iLo, iHi, delta;
820
Bool segment_is_sane;
822
Addr sStart = seg->start;
823
Addr sEnd = seg->end;
825
aspacem_assert(sStart <= sEnd);
827
segment_is_sane = sane_AixSegment(seg);
828
if (!segment_is_sane) show_AixSegment(0,0,seg);
829
aspacem_assert(segment_is_sane);
831
split_asegments_lo_and_hi( segs, sStart, sEnd, &iLo, &iHi );
833
/* Now iLo .. iHi inclusive is the range of segment indices which
834
seg will replace. If we're replacing more than one segment,
835
slide those above the range down to fill the hole. */
837
aspacem_assert(delta >= 0);
839
for (i = iLo; i < segs->used-delta; i++)
840
segs->seg[i] = segs->seg[i+delta];
843
aspacem_assert(segs->used >= 1);
845
segs->seg[iLo] = *seg;
847
preen_asegments(segs);
848
if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)");
852
/* Convert everything in SEG except MData and MText into Free,
853
then preen, so as to retain normalised form. */
855
static void knockout_non_module_segs ( AixSegments* segs )
859
for (i = 0; i < segs->used; i++) {
860
if (segs->seg[i].kind == ASkFree
861
|| segs->seg[i].kind == ASkMText
862
|| segs->seg[i].kind == ASkMData)
864
s = segs->seg[i].start;
865
e = segs->seg[i].end;
866
init_AixSegment( &segs->seg[i] );
867
segs->seg[i].start = s;
868
segs->seg[i].end = e;
869
segs->seg[i].kind = ASkFree;
871
preen_asegments(segs);
872
aspacem_assert( sane_AixSegments(segs) );
876
/* Copy a segment array. */
878
static void copy_asegments_d_s ( AixSegments* dst, AixSegments* src )
881
aspacem_assert(src->used >= 1 && src->used < VG_N_ASEGMENTS);
882
dst->used = src->used;
883
for (i = 0; i < src->used; i++)
884
dst->seg[i] = src->seg[i];
888
/*-----------------------------------------------------------------*/
890
/*--- Re-reading /proc/../map and updating MText/MData segments ---*/
892
/*-----------------------------------------------------------------*/
894
/* Find out the size of the AixCodeSegChange that must be
895
presented to VG_(am_aix5_reread_procmap). */
897
Int VG_(am_aix5_reread_procmap_howmany_directives)(void)
899
/* In the worst imaginable case, all the tracked modules could have
900
disappeared and been replaced with different ones. Hence: */
901
return 2 * VG_N_ASEGMENTS;
906
void add_pri_text_and_data_segs ( AixSegment* tnew, AixSegment* dnew )
908
Bool dExists = (dnew->end - dnew->start + 1) != 0;
909
aspacem_assert(tnew->kind == ASkMText);
910
aspacem_assert(dnew->kind == ASkMData);
912
aspacem_assert(tnew->sibling == dnew->start);
913
aspacem_assert(dnew->sibling == tnew->start);
914
add_asegment(&asegs_pri, tnew);
915
add_asegment(&asegs_pri, dnew);
917
aspacem_assert(tnew->sibling == 0);
918
add_asegment(&asegs_pri, tnew);
923
void del_pri_text_and_data_segs ( AixSegment* told, AixSegment* dold )
926
Bool dExists = (dold->end - dold->start + 1) != 0;
927
aspacem_assert(told->kind == ASkMText);
928
aspacem_assert(dold->kind == ASkMData);
929
init_AixSegment( &fre );
932
aspacem_assert(told->sibling == dold->start);
933
aspacem_assert(dold->sibling == told->start);
934
fre.start = told->start;
936
add_asegment(&asegs_pri, &fre);
937
fre.start = dold->start;
939
add_asegment(&asegs_pri, &fre);
941
aspacem_assert(told->sibling == 0);
942
fre.start = told->start;
944
add_asegment(&asegs_pri, &fre);
949
/* Tell aspacem that /proc/<pid>/map may have changed (eg following
950
__loadx) and so it should be re-read, and the code/data segment
951
list updated accordingly. The resulting array of AixCodeChangeSeg
952
directives are written to 'directives', and the number of entries
955
void VG_(am_aix5_reread_procmap)
956
( /*OUT*/AixCodeSegChange* directives, /*OUT*/Int* ndirectives )
959
Bool done_old, done_new;
960
AixSegment *olds, *news;
962
/* First, read /proc/../map into asegs_tnew. Copy asegs_pri into
963
asegs_told, and remove everything except MData and MText, so as
964
to generate something we can sanely compare with asegs_tnew.
965
Walk asegs_told and asegs_tnew together, writing the differences
966
to 'directives', and modifying asegs_pri accordingly. */
967
parse_procselfmap( &asegs_tnew );
968
copy_asegments_d_s( &asegs_told, &asegs_pri );
969
knockout_non_module_segs( &asegs_told );
973
# define MODIFY_PRI(_dir, _asegs, _ixt, _acquire) \
976
AixSegment *_segt, *_segd; \
977
AixSegment _segd_dummy; \
978
aspacem_assert(_ixt >= 0 && _ixt < _asegs.used); \
979
_segt = &_asegs.seg[_ixt]; \
980
aspacem_assert(_segt->kind == ASkMText); \
981
if (_segt->sibling) { \
982
_ixd = find_asegment_idx( &_asegs, _segt->sibling ); \
983
_segd = &_asegs.seg[_ixd]; \
984
aspacem_assert(_segd->kind == ASkMData); \
985
aspacem_assert(_segt->sibling == _segd->start); \
987
init_AixSegment( &_segd_dummy ); \
988
_segd_dummy.kind = ASkMData; \
989
_segd_dummy.start = 1; \
990
_segd_dummy.end = 0; \
991
_segd = &_segd_dummy; \
993
if (_segd != &_segd_dummy) \
994
aspacem_assert(_segd->sibling == _segt->start); \
996
(_dir).code_start = (_segt)->start; \
997
(_dir).code_len = (_segt)->end - (_segt)->start + 1; \
998
(_dir).data_start = (_segd)->start; \
999
(_dir).data_len = (_segd)->end - (_segd)->start + 1; \
1000
(_dir).file_name = (_segt)->fname; \
1001
(_dir).mem_name = (_segt)->mname; \
1002
(_dir).is_mainexe = (_acquire) ? (_segt)->isMainExe : False; \
1003
(_dir).acquire = (_acquire); \
1006
add_pri_text_and_data_segs( _segt, _segd ); \
1008
del_pri_text_and_data_segs( _segt, _segd ); \
1012
ixold = 0; /* indexes asegs_told */
1013
ixnew = 0; /* indexes asegs_tnew */
1017
aspacem_assert(ixold >= 0 && ixold < asegs_told.used);
1018
aspacem_assert(ixnew >= 0 && ixnew < asegs_tnew.used);
1020
/* Advance ixold and ixnew to the next MText in their
1021
respective arrays. */
1022
while (ixold < asegs_told.used
1023
&& asegs_told.seg[ixold].kind != ASkMText) {
1024
aspacem_assert(asegs_told.seg[ixold].kind == ASkFree
1025
|| asegs_told.seg[ixold].kind == ASkMData);
1028
while (ixnew < asegs_tnew.used
1029
&& asegs_tnew.seg[ixnew].kind != ASkMText) {
1030
aspacem_assert(asegs_tnew.seg[ixnew].kind == ASkFree
1031
|| asegs_tnew.seg[ixnew].kind == ASkMData);
1035
aspacem_assert(ixold >= 0 && ixold <= asegs_told.used);
1036
aspacem_assert(ixnew >= 0 && ixnew <= asegs_tnew.used);
1038
done_old = ixold == asegs_told.used;
1039
done_new = ixnew == asegs_tnew.used;
1041
if (done_old && done_new)
1043
if (done_old && !done_new)
1045
if (done_new && !done_old)
1048
olds = &asegs_told.seg[ixold];
1049
news = &asegs_tnew.seg[ixnew];
1051
aspacem_assert(olds->kind == ASkMText);
1052
aspacem_assert(news->kind == ASkMText);
1055
show_AixSegment(0,ixold,&asegs_told.seg[ixold]);
1056
show_AixSegment(0,ixnew,&asegs_tnew.seg[ixnew]);
1057
VG_(debugLog)(0, "aspacem", "\n");
1060
/* Here, if olds->start < news->start, then the old sequence has
1061
an entry which the new one doesn't, so a module has been
1062
unloaded. If news->start < olds->start then the new sequence
1063
has a module the old one doesn't, so a module has been
1064
loaded. If news->start ==olds->start then the module is
1065
unchanged. Except, we should check a bit more carefully in
1067
if (olds->start == news->start) {
1068
if (olds->start == news->start
1069
&& olds->end == news->end
1070
&& olds->fname == news->fname
1071
&& olds->mname == news->mname
1072
&& olds->sibling == news->sibling
1073
&& olds->isMainExe == news->isMainExe) {
1074
/* really identical, do nothing */
1076
/* Dubious; mark it as an unload of old and load of
1078
MODIFY_PRI(directives[*ndirectives], asegs_told, ixold, False);
1080
aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS);
1081
MODIFY_PRI(directives[*ndirectives], asegs_tnew, ixnew, True);
1083
aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS);
1090
if (olds->start < news->start) {
1092
MODIFY_PRI(directives[*ndirectives], asegs_told, ixold, False);
1094
aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS);
1099
if (news->start < olds->start) {
1101
MODIFY_PRI(directives[*ndirectives], asegs_tnew, ixnew, True);
1103
aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS);
1113
aspacem_assert(ixold == asegs_told.used);
1114
aspacem_assert(ixnew < asegs_tnew.used);
1115
while (ixnew < asegs_tnew.used) {
1116
news = &asegs_tnew.seg[ixnew];
1117
aspacem_assert(news->kind == ASkMText || news->kind == ASkMData
1118
|| news->kind == ASkFree);
1119
if (news->kind == ASkMText) {
1120
MODIFY_PRI(directives[*ndirectives], asegs_tnew, ixnew, True);
1122
aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS);
1130
aspacem_assert(ixnew == asegs_tnew.used);
1131
aspacem_assert(ixold < asegs_told.used);
1132
while (ixold < asegs_told.used) {
1133
olds = &asegs_told.seg[ixold];
1134
aspacem_assert(olds->kind == ASkMText || olds->kind == ASkMData
1135
|| olds->kind == ASkFree);
1136
if (olds->kind == ASkMText) {
1137
MODIFY_PRI(directives[*ndirectives], asegs_told, ixold, False);
1139
aspacem_assert(*ndirectives <= 2 * VG_N_ASEGMENTS);
1146
aspacem_assert(ixold == asegs_told.used);
1147
aspacem_assert(ixnew == asegs_tnew.used);
1149
asegs_tnew.used = 0;
1150
asegs_told.used = 0;
1152
aspacem_assert( sane_AixSegments(&asegs_pri) );
1158
/* Set the initial stack segment. Contains kludgery. Also take the
1159
opportunity to create fake segs for the millicode areas. */
1161
void VG_(am_aix5_set_initial_client_sp)( Addr sp )
1163
static Bool done = False;
1166
aspacem_assert(!done);
1169
/* We are given the initial client SP (that of the root thread).
1170
Already on the stack are argv and env. How far up does it
1171
extend? We assume to the next 64k boundary. How far down does
1172
it extend? We assume N_FAKE_STACK_PAGES small pages - by
1173
default 16M. Establish those limits and add an AnonC rwx
1176
/* The 64k boundary is "justified" as follows. On 32-bit AIX 5.3,
1177
a typical initial SP is 0x2FF22xxx, but the accessible (rw) area
1178
beyond that extends up to 0x2FF2FFFF - the next 64k boundary.
1179
In 64-bit mode, a typical initial SP might be
1180
0xFFF'FFFF'FFFF'E920, and the accessible area extends to
1181
0xFFF'FFFF'FFFF'FFFF. So in both cases, (64k roundup of sp) - 1
1182
gives the end of the accessible area. */
1184
VG_(debugLog)(1,"aspacem", "aix5_set_initial_client_sp( %p )\n",
1187
init_AixSegment( &seg );
1188
seg.kind = ASkAnonC;
1189
seg.hasR = seg.hasW = seg.hasX = True;
1191
if (sizeof(void*) == 4
1192
&& ((sp & 0xFFFF0000) == 0x2FF20000
1193
|| (sp & 0xFFFF0000) == 0x2FF10000)) {
1194
/* Gaaah. Special-case 32-bit mode. */
1195
seg.end = 0x2FF2FFFF;
1197
seg.end = AM_64K_ROUNDUP(sp) - 1;
1200
seg.start = seg.end+1 - N_FAKE_STACK_PAGES * VKI_PAGE_SIZE;
1202
VG_(debugLog)(1,"aspacem", "aix5_set_initial_client_sp: stack seg:\n");
1203
show_AixSegment(1,0, &seg);
1204
add_asegment( &asegs_pri, &seg );
1206
init_AixSegment( &seg );
1207
seg.kind = ASkAnonC;
1208
seg.hasR = seg.hasX = True;
1209
seg.start = MAGIC_PAGES_1_BASE;
1210
seg.end = MAGIC_PAGES_1_BASE + MAGIC_PAGES_1_SIZE - 1;
1211
VG_(debugLog)(1,"aspacem", "am_aix5_set_initial_client_sp: FAKE1 seg:\n");
1212
show_AixSegment(1,0, &seg);
1213
add_asegment( &asegs_pri, &seg );
1215
init_AixSegment( &seg );
1216
seg.kind = ASkAnonC;
1217
seg.hasR = seg.hasX = True;
1218
seg.start = MAGIC_PAGES_2_BASE;
1219
seg.end = MAGIC_PAGES_2_BASE + MAGIC_PAGES_2_SIZE - 1;
1220
VG_(debugLog)(1,"aspacem", "am_aix5_set_initial_client_sp: FAKE2 seg:\n");
1221
show_AixSegment(1,0, &seg);
1222
add_asegment( &asegs_pri, &seg );
1226
/*-----------------------------------------------------------------*/
1228
/*--- Getting segment-starts. ---*/
1230
/*-----------------------------------------------------------------*/
1232
/* Print out the segment array (debugging only!). */
1233
void VG_(am_show_nsegments) ( Int logLevel, HChar* who )
1235
show_AixSegments( logLevel, who, &asegs_pri );
1238
/* Get the filename corresponding to this segment, if known and if it
1239
has one. The returned name's storage cannot be assumed to be
1240
persistent, so the caller should immediately copy the name
1242
HChar* VG_(am_get_filename)( NSegment* seg )
1244
ML_(am_barf)("unimplemented: VG_(am_get_filename)");
1245
return NULL; /* placate gcc -Wall */
1248
/* Collect up the start addresses of all non-free, non-resvn segments.
1249
The interface is a bit strange in order to avoid potential
1250
segment-creation races caused by dynamic allocation of the result
1253
The function first computes how many entries in the result
1254
buffer *starts will be needed. If this number <= nStarts,
1255
they are placed in starts[0..], and the number is returned.
1256
If nStarts is not large enough, nothing is written to
1257
starts[0..], and the negation of the size is returned.
1259
Correct use of this function may mean calling it multiple times in
1260
order to establish a suitably-sized buffer. */
1262
Int VG_(am_get_segment_starts)( Addr* starts, Int nStarts )
1266
/* don't pass dumbass arguments */
1267
aspacem_assert(nStarts >= 0);
1270
for (i = 0; i < asegs_pri.used; i++) {
1271
if (asegs_pri.seg[i].kind == ASkFree
1272
|| asegs_pri.seg[i].kind == ASkPreAlloc)
1277
if (nSegs > nStarts) {
1278
/* The buffer isn't big enough. Tell the caller how big it needs
1283
/* There's enough space. So write into the result buffer. */
1284
aspacem_assert(nSegs <= nStarts);
1287
for (i = 0; i < asegs_pri.used; i++) {
1288
if (asegs_pri.seg[i].kind == ASkFree
1289
|| asegs_pri.seg[i].kind == ASkPreAlloc)
1291
starts[j++] = asegs_pri.seg[i].start;
1294
aspacem_assert(j == nSegs); /* this should not fail */
1299
/*-----------------------------------------------------------------*/
1301
/*--- Sanity checking and preening of the segment array. ---*/
1303
/*-----------------------------------------------------------------*/
1305
Bool VG_(am_do_sync_check) ( const HChar* fn,
1306
const HChar* file, Int line )
1308
/* There's nothing we can do here; just return a dummy value. */
1309
return False; /* placate gcc */
1312
/* Hook to allow sanity checks to be done from aspacemgr-common.c. */
1313
void ML_(am_do_sanity_check)( void )
1315
Bool ok = sane_AixSegments( &asegs_pri );
1320
/*-----------------------------------------------------------------*/
1322
/*--- Finding segments. ---*/
1324
/*-----------------------------------------------------------------*/
1326
/* Finds the segment containing 'a'. Only returns file/anon/resvn
1327
segments. On AIX5 this is pretty bogus; we fake up an entry as
1328
best we can by snooping round for useful information in
1331
NSegment const* VG_(am_find_nsegment) ( Addr a )
1335
static NSegment bogus;
1337
/* Fill in default info. */
1338
bogus.kind = SkAnonC;
1341
bogus.smode = SmFixed;
1347
bogus.hasR = bogus.hasW = bogus.hasX = False;
1352
/* Go look for it in the segment table. */
1353
i = find_asegment_idx( &asegs_pri, a );
1354
aspacem_assert(i >= 0 && i <= asegs_pri.used);
1356
aseg = &asegs_pri.seg[i];
1357
if (aseg->kind == ASkFree || aseg->kind == ASkPreAlloc)
1360
bogus.start = aseg->start;
1361
bogus.end = aseg->end;
1364
switch (aseg->kind) {
1366
bogus.kind = SkAnonC; /* hmm, pretty darn bogus */
1367
bogus.hasR = bogus.hasX = True;
1370
bogus.kind = SkAnonC; /* hmm, pretty darn bogus */
1371
bogus.hasR = bogus.hasW = True;
1374
bogus.kind = SkShmC;
1375
bogus.hasR = aseg->hasR;
1376
bogus.hasW = aseg->hasW;
1377
bogus.hasX = aseg->hasX;
1380
bogus.kind = SkAnonC;
1381
bogus.hasR = aseg->hasR;
1382
bogus.hasW = aseg->hasW;
1383
bogus.hasX = aseg->hasX;
1384
bogus.isCH = aseg->isCH;
1387
bogus.kind = SkAnonV;
1388
bogus.hasR = aseg->hasR;
1389
bogus.hasW = aseg->hasW;
1390
bogus.hasX = aseg->hasX;
1393
bogus.kind = SkFileV;
1394
bogus.hasR = aseg->hasR;
1395
bogus.hasW = aseg->hasW;
1396
bogus.hasX = aseg->hasX;
1397
bogus.offset = aseg->offset;
1407
/* Find the next segment along from 'here', if it is a file/anon/resvn
1409
NSegment const* VG_(am_next_nsegment) ( NSegment* here, Bool fwds )
1411
ML_(am_barf)("unimplemented: VG_(am_next_nsegment)");
1412
return NULL; /* placate gcc */
1416
/* Trivial fn: return the total amount of space in anonymous mappings,
1417
both for V and the client. Is used for printing stats in
1418
out-of-memory messages. */
1419
ULong VG_(am_get_anonsize_total)( void )
1423
for (i = 0; i < asegs_pri.used; i++) {
1424
if (asegs_pri.seg[i].kind == ASkAnonC
1425
|| asegs_pri.seg[i].kind == ASkAnonV) {
1426
total += (ULong)asegs_pri.seg[i].end
1427
- (ULong)asegs_pri.seg[i].start + 1ULL;
1434
/* Test if a piece of memory is addressable by the client with at
1435
least the "prot" protection permissions by examining the underlying
1437
Bool VG_(am_is_valid_for_client)( Addr start, SizeT len,
1440
NSegment const * const fake = VG_(am_find_nsegment)(start);
1443
aspacem_assert(fake->start <= start);
1444
aspacem_assert(start + len - 1 <= fake->end);
1445
if (fake->kind == SkAnonV || fake->kind == SkFileV)
1447
if ((prot & VKI_PROT_READ) && !fake->hasR)
1449
if ((prot & VKI_PROT_WRITE) && !fake->hasW)
1451
if ((prot & VKI_PROT_EXEC) && !fake->hasX)
1456
/* Variant of VG_(am_is_valid_for_client) which allows free areas to
1457
be considered part of the client's addressable space. It also
1458
considers reservations to be allowable, since from the client's
1459
point of view they don't exist. */
1460
Bool VG_(am_is_valid_for_client_or_free_or_resvn)
1461
( Addr start, SizeT len, UInt prot )
1463
ML_(am_barf)("unimplemented: "
1464
"VG_(am_is_valid_for_client_or_free_or_resvn)");
1470
/*-----------------------------------------------------------------*/
1472
/*--- Startup, including reading /proc/self/maps. ---*/
1474
/*-----------------------------------------------------------------*/
1476
/* Initialise the address space manager, setting up the initial
1477
segment list, and reading /proc/self/maps into it. This must
1478
be called before any other function.
1480
Takes a pointer to the SP at the time V gained control. This is
1481
taken to be the highest usable address (more or less). Based on
1482
that (and general consultation of tea leaves, etc) return a
1483
suggested end address for the client's stack. */
1485
Addr VG_(am_startup) ( Addr sp_at_startup )
1487
aspacem_assert(sizeof(Word) == sizeof(void*));
1488
aspacem_assert(sizeof(Addr) == sizeof(void*));
1489
aspacem_assert(sizeof(SizeT) == sizeof(void*));
1490
aspacem_assert(sizeof(SSizeT) == sizeof(void*));
1492
asegs_tnew.used = 0;
1493
asegs_told.used = 0;
1496
init_AixSegments( &asegs_pri );
1497
aspacem_assert( sane_AixSegments(&asegs_pri) );
1500
VG_(am_show_nsegments)(0,"AFTER VG_(am_startup)");
1502
/* We do not make an initial read of /proc/../map since doing so
1503
would leave us without a way to communicate the results to a
1504
caller. Hence we expect that the caller (m_main) will call
1505
VG_(am_aix5_reread_procmap) soon after this call so as to get
1506
the initial code/data segments recorded. */
1508
/* Return value is irrelevant since we don't lay out the
1509
client's stack; it is already done. */
1514
/*-----------------------------------------------------------------*/
1516
/*--- Preallocation (acquiring space from sbrk). ---*/
1518
/*-----------------------------------------------------------------*/
1521
SysRes local_do_sbrk_NO_NOTIFY( Word delta )
1524
aspacem_assert(__NR_AIX5_sbrk != __NR_AIX5_UNKNOWN);
1525
res = VG_(do_syscall1)(__NR_AIX5_sbrk, (UWord)delta);
1526
/* kernel produces (-1, VKI_ENOMEM) on failure. I think that's
1532
/* Find the ix of a prealloc section containing at least req_sz bytes,
1533
or -1 if not found. Uses best-fit. */
1535
static Int find_prealloc_idx ( SizeT req_sz )
1537
SizeT best_sz, this_sz;
1539
aspacem_assert(sizeof(SizeT) == sizeof(Addr));
1540
aspacem_assert(req_sz > 0);
1541
aspacem_assert(AM_IS_4K_ALIGNED(req_sz));
1546
for (i = 0; i < asegs_pri.used; i++) {
1547
AixSegment* s = &asegs_pri.seg[i];
1548
if (s->kind != ASkPreAlloc)
1551
= s->end + 1 - s->start;
1552
aspacem_assert(this_sz > 0);
1553
aspacem_assert(AM_IS_4K_ALIGNED(this_sz));
1554
if (this_sz >= req_sz && this_sz < best_sz) {
1564
/* Create a new prealloc section containing req_sz bytes. Returns
1565
False if failed, True on success. */
1567
static Bool new_prealloc ( SizeT req_sz )
1575
aspacem_assert(req_sz > 0);
1576
aspacem_assert(AM_IS_4K_ALIGNED(req_sz));
1578
/* m_syswrap may have decided that it's not currently safe to allow
1579
allocations from sbrk-world. If so, we have to fail. */
1580
if (0 && !VG_(am_aix5_sbrk_allowed)) {
1581
why = "sbrk disallowed";
1585
/* Get the current limit. */
1586
sres = local_do_sbrk_NO_NOTIFY(0);
1588
why = "initial sbrk failed";
1592
/* Get it page aligned */
1593
delta = AM_4K_ROUNDUP(sres.res) - sres.res;
1594
aspacem_assert(delta >= 0 && delta < AM_4K_PAGESZ);
1596
sres = local_do_sbrk_NO_NOTIFY(delta);
1598
why = "aligning sbrk failed";
1603
/* Now the brk is aligned. Try to acquire the block. */
1604
sres = local_do_sbrk_NO_NOTIFY(0);
1608
aspacem_assert( AM_IS_4K_ALIGNED( start ));
1610
sres = local_do_sbrk_NO_NOTIFY( req_sz );
1612
why = "main sbrk failed";
1616
/* If this fails, the kernel is acting strange. */
1617
aspacem_assert( sres.res == start );
1619
init_AixSegment( &seg );
1621
seg.end = start + req_sz - 1;
1622
seg.kind = ASkPreAlloc;
1623
seg.hasR = seg.hasW = seg.hasX = True; /* presumably */
1624
add_asegment( &asegs_pri, &seg );
1627
1, "aspacem", "new_prealloc: SUCCESS at 0x%llx size %lld\n",
1628
(ULong)start, (ULong)req_sz
1633
VG_(debugLog)(1, "aspacem", "new_prealloc: FAILED: %s\n", why);
1638
/* Find the ix of a prealloc section capable of holding a block of
1639
size req_sz. If none exists, try to create one first. Returns -1
1642
static Int find_or_create_prealloc_idx ( SizeT req_sz )
1649
VG_(debugLog)(0, "zz", " find_or_create_prealloc_idx ( %lu )\n",
1652
aspacem_assert(sizeof(SizeT) == sizeof(Addr));
1653
aspacem_assert(req_sz > 0);
1654
aspacem_assert(AM_IS_4K_ALIGNED(req_sz));
1656
ix = find_prealloc_idx ( req_sz );
1657
if (ix >= 0 && ix < asegs_pri.used)
1660
/* Not found. We'll have to allocate one. Allocate some extra at
1661
the same time, so as to give a reservoir from which to satisfy
1663
aspacem_assert(ix == -1);
1665
req_szX = req_sz + AM_PREALLOC_EXTRA;
1666
aspacem_assert(req_szX > 0);
1667
aspacem_assert(AM_IS_4K_ALIGNED(req_szX));
1669
alloc_ok = new_prealloc( req_szX );
1671
return -1; /* failed */
1673
/* We should now be able to find it in the segment table. */
1674
ix = find_prealloc_idx( req_sz );
1675
aspacem_assert(ix >= 0 && ix < asegs_pri.used);
1680
/*-----------------------------------------------------------------*/
1682
/*--- The core query-notify mechanism. ---*/
1684
/*-----------------------------------------------------------------*/
1686
/* Query aspacem to ask where a mapping should go. */
1688
Addr VG_(am_get_advisory) ( MapRequest* req,
1692
ML_(am_barf)("unimplemented: VG_(am_get_advisory)");
1694
return 0; /* placate gcc -Wall */
1698
/* Convenience wrapper for VG_(am_get_advisory) for client floating or
1699
fixed requests. If start is zero, a floating request is issued; if
1700
nonzero, a fixed request at that address is issued. Same comments
1701
about return values apply. */
1703
Addr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len,
1706
ML_(am_barf)("unimplemented: VG_(am_get_advisory_client_simple)");
1708
return 0; /* placate gcc -Wall */
1712
/* Notifies aspacem that the client completed an mmap successfully.
1713
The segment array is updated accordingly. If the returned Bool is
1714
True, the caller should immediately discard translations from the
1715
specified address range. */
1718
VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
1719
Int fd, Off64T offset )
1727
/* Discard is needed if any of the just-trashed range had T. */
1728
needDiscard = True; /* conservative but safe */
1730
init_AixSegment( &seg );
1731
seg.kind = ASkAnonC; /* XXX bogus: could be a file */
1733
seg.end = a + len - 1;
1734
seg.hasR = toBool(prot & VKI_PROT_READ);
1735
seg.hasW = toBool(prot & VKI_PROT_WRITE);
1736
seg.hasX = toBool(prot & VKI_PROT_EXEC);
1739
VG_(debugLog)(0,"aspacem","notify mmap ( %p, %ld, %ld, %ld )\n",
1740
(void*)a, len, (UWord)prot, (UWord)flags);
1742
add_asegment( &asegs_pri, &seg );
1743
AM_SANITY_CHECK("am_notify_client_mmap");
1748
/* Notifies aspacem that the client completed a shmat successfully.
1749
The segment array is updated accordingly. If the returned Bool is
1750
True, the caller should immediately discard translations from the
1751
specified address range. */
1754
VG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot )
1757
init_AixSegment( &seg );
1758
seg.kind = ASkShmemC;
1760
seg.end = seg.start + len - 1;
1761
seg.hasR = (prot & VKI_PROT_READ) ? True : False;
1762
seg.hasW = (prot & VKI_PROT_WRITE) ? True : False;
1763
seg.hasX = (prot & VKI_PROT_EXEC) ? True : False;
1764
add_asegment( &asegs_pri, &seg );
1765
AM_SANITY_CHECK("am_notify_client_shmat");
1766
if (0) VG_(am_show_nsegments)(0, "after shmat");
1767
return True; /* be paranoid */
1771
/* Notifies aspacem that an mprotect was completed successfully. The
1772
segment array is updated accordingly. Note, as with
1773
VG_(am_notify_munmap), it is not the job of this function to reject
1774
stupid mprotects, for example the client doing mprotect of
1775
non-client areas. Such requests should be intercepted earlier, by
1776
the syscall wrapper for mprotect. This function merely records
1777
whatever it is told. If the returned Bool is True, the caller
1778
should immediately discard translations from the specified address
1781
Bool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot )
1784
Bool newR, newW, newX, needDiscard;
1789
newR = toBool(prot & VKI_PROT_READ);
1790
newW = toBool(prot & VKI_PROT_WRITE);
1791
newX = toBool(prot & VKI_PROT_EXEC);
1793
/* Discard is needed if we're dumping X permission */
1794
needDiscard = True; /* conservative but correct */
1796
split_asegments_lo_and_hi( &asegs_pri, start, start+len-1, &iLo, &iHi );
1798
iLo = find_asegment_idx(&asegs_pri, start);
1799
iHi = find_asegment_idx(&asegs_pri, start + len - 1);
1801
for (i = iLo; i <= iHi; i++) {
1802
aspacem_assert(i >= 0 && i < asegs_pri.used);
1803
/* Apply the permissions to all relevant segments. */
1804
if (asegs_pri.seg[i].kind != ASkFree) {
1805
asegs_pri.seg[i].hasR = newR;
1806
asegs_pri.seg[i].hasW = newW;
1807
asegs_pri.seg[i].hasX = newX;
1808
aspacem_assert(sane_AixSegment(&asegs_pri.seg[i]));
1812
VG_(debugLog)(0,"aspacem","notify mprotect ( %p, %ld, %ld )\n",
1813
(void*)start, len, (UWord)prot);
1814
/* Changing permissions could have made previously un-mergable
1815
segments mergeable. Therefore have to re-preen them. */
1816
preen_asegments(&asegs_pri);
1817
AM_SANITY_CHECK("am_notify_mprotect");
1822
/* Notifies aspacem that an munmap completed successfully. The
1823
segment array is updated accordingly. As with
1824
VG_(am_notify_munmap), we merely record the given info, and don't
1825
check it for sensibleness. If the returned Bool is True, the
1826
caller should immediately discard translations from the specified
1829
Bool VG_(am_notify_munmap)( Addr start, SizeT len )
1831
Bool needDiscard = True; /* conservative but safe */
1837
init_AixSegment( &seg );
1840
seg.end = start + len - 1;
1841
add_asegment( &asegs_pri, &seg );
1842
AM_SANITY_CHECK("am_notify_munmap");
1848
/*-----------------------------------------------------------------*/
1850
/*--- Handling mappings which do not arise directly from the ---*/
1851
/*--- simulation of the client. ---*/
1853
/*-----------------------------------------------------------------*/
1855
/* --- --- --- map, unmap, protect --- --- --- */
1857
/* Map a file at a fixed address for the client, and update the
1858
segment array accordingly. */
1860
SysRes VG_(am_mmap_file_fixed_client)
1861
( Addr start, SizeT length, UInt prot, Int fd, Off64T offset )
1864
ML_(am_barf)("unimplemented: VG_(am_mmap_file_fixed_client)");
1870
/* Map anonymously at a fixed address for the client, and update
1871
the segment array accordingly. */
1873
SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
1876
ML_(am_barf)("unimplemented: VG_(am_mmap_anon_fixed_client)");
1882
/* Map anonymously at an unconstrained address for the client, and
1883
update the segment array accordingly. */
1885
SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
1890
/* Not allowable. */
1892
return VG_(mk_SysRes_Error)( VKI_EINVAL );
1894
/* AIX seems to demand fd == -1 in anonymous mappings. hence: */
1895
sres = VG_(am_do_mmap_NO_NOTIFY)(
1898
VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
1902
if (!sres.isError) {
1903
init_AixSegment( &seg );
1904
seg.kind = ASkAnonC;
1905
seg.start = sres.res;
1906
seg.end = seg.start + length - 1;
1907
seg.hasR = toBool((prot & VKI_PROT_READ) > 0);
1908
seg.hasW = toBool((prot & VKI_PROT_WRITE) > 0);
1909
seg.hasX = toBool((prot & VKI_PROT_EXEC) > 0);
1911
add_asegment( &asegs_pri, &seg );
1912
VG_(debugLog)(2, "aspacem", "new AnonC from mmap, size %lu\n",
1920
/* Similarly, acquire new address space for the client but with
1921
considerable restrictions on what can be done with it: (1) the
1922
actual protections may exceed those stated in 'prot', (2) the
1923
area's protections cannot be later changed using any form of
1924
mprotect, and (3) the area cannot be freed using any form of
1925
munmap. On Linux this behaves the same as
1926
VG_(am_mmap_anon_float_client). On AIX5 this *may* allocate memory
1927
by using sbrk, so as to make use of large pages on AIX. */
1929
SysRes VG_(am_sbrk_anon_float_client) ( SizeT length, Int prot )
1934
SizeT lenX = AM_4K_ROUNDUP(length);
1936
/* Not allowable. */
1938
return VG_(mk_SysRes_Error)( VKI_EINVAL );
1940
/* First see if we can get space from sbrk-world. */
1941
ix = find_or_create_prealloc_idx ( lenX );
1942
if (ix >= 0 && ix < asegs_pri.used) {
1943
init_AixSegment( &seg );
1944
seg.kind = ASkAnonC;
1945
seg.start = asegs_pri.seg[ix].start;
1946
seg.end = seg.start + lenX - 1;
1947
seg.hasR = toBool((prot & VKI_PROT_READ) > 0);
1948
seg.hasW = toBool((prot & VKI_PROT_WRITE) > 0);
1949
seg.hasX = toBool((prot & VKI_PROT_EXEC) > 0);
1951
add_asegment( &asegs_pri, &seg );
1952
sres = VG_(mk_SysRes_Success)( seg.start );
1953
VG_(debugLog)(2, "aspacem", "new AnonC from prealloc, size %lu\n",
1958
/* That didn't work out. Try mmap-world instead. */
1959
aspacem_assert(ix == -1);
1960
return VG_(am_mmap_anon_float_client)( length, prot );
1964
/* Map anonymously at an unconstrained address for V, and update the
1965
segment array accordingly. This is fundamentally how V allocates
1966
itself more address space when needed. */
1968
SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
1973
/* Not allowable. */
1975
return VG_(mk_SysRes_Error)( VKI_EINVAL );
1977
/* AIX seems to demand fd == -1 in anonymous mappings. hence: */
1978
sres = VG_(am_do_mmap_NO_NOTIFY)(
1980
VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
1981
VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
1985
if (!sres.isError) {
1986
init_AixSegment( &seg );
1987
seg.kind = ASkAnonV;
1988
seg.start = sres.res;
1989
seg.end = seg.start + length - 1;
1990
seg.hasR = seg.hasW = seg.hasX = True;
1992
add_asegment( &asegs_pri, &seg );
1993
VG_(debugLog)(2, "aspacem", "new AnonV from mmap, size %lu\n",
2001
/* Same comments apply as per VG_(am_sbrk_anon_float_client). On
2002
Linux this behaves the same as VG_(am_mmap_anon_float_valgrind). */
2003
SysRes VG_(am_sbrk_anon_float_valgrind)( SizeT length )
2008
SizeT lenX = AM_4K_ROUNDUP(length);
2010
/* Not allowable. */
2012
return VG_(mk_SysRes_Error)( VKI_EINVAL );
2014
/* First see if we can get space from sbrk-world. */
2015
ix = find_or_create_prealloc_idx ( lenX );
2016
if (ix >= 0 && ix < asegs_pri.used) {
2017
init_AixSegment( &seg );
2018
seg.kind = ASkAnonV;
2019
seg.start = asegs_pri.seg[ix].start;
2020
seg.end = seg.start + lenX - 1;
2025
add_asegment( &asegs_pri, &seg );
2026
sres = VG_(mk_SysRes_Success)( seg.start );
2027
VG_(debugLog)(2, "aspacem", "new AnonV from prealloc, size %lu\n",
2032
/* That didn't work out. Try mmap-world instead. */
2033
aspacem_assert(ix == -1);
2034
return VG_(am_mmap_anon_float_valgrind)( length );
2038
/* Really just a wrapper around VG_(am_sbrk_anon_float_valgrind). */
2040
void* VG_(am_shadow_alloc)(SizeT size)
2042
SysRes sres = VG_(am_sbrk_anon_float_valgrind)( size );
2043
return sres.isError ? NULL : (void*)sres.res;
2047
/* Map a file at an unconstrained address for V, and update the
2048
segment array accordingly. This is used by V for transiently
2049
mapping in object files to read their debug info. */
2051
SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot,
2052
Int fd, Off64T offset )
2056
/* Not allowable. */
2057
if (length == 0 || !VG_IS_PAGE_ALIGNED(offset))
2058
return VG_(mk_SysRes_Error)( VKI_EINVAL );
2060
sres = VG_(am_do_mmap_NO_NOTIFY)(
2062
prot, VKI_MAP_PRIVATE,
2065
if (!sres.isError) {
2067
init_AixSegment( &seg );
2069
seg.start = sres.res;
2070
seg.end = seg.start + length - 1;
2071
seg.hasR = toBool(prot & VKI_PROT_READ);
2072
seg.hasW = toBool(prot & VKI_PROT_WRITE);
2073
seg.hasX = toBool(prot & VKI_PROT_EXEC);
2074
seg.fname = add_to_strtab("(FileV-float, unknown name)");
2075
add_asegment( &asegs_pri, &seg );
2076
aspacem_assert( sane_AixSegments( &asegs_pri ));
2082
/* Unmap the given address range and update the segment array
2083
accordingly. This fails if the range isn't valid for the client.
2084
If *need_discard is True after a successful return, the caller
2085
should immediately discard translations from the specified address
2088
SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
2089
Addr start, SizeT len )
2092
ML_(am_barf)("unimplemented: VG_(am_munmap_client)");
2098
/* Unmap the given address range and update the segment array
2099
accordingly. This fails if the range isn't valid for valgrind. */
2100
/* Also, if the specified range doesn't fall within a single segment,
2101
it barfs. This simplifies the implementation; we shouldn't need to
2102
deal with anything but the simplest cases. */
2104
SysRes VG_(am_munmap_valgrind)( Addr start, SizeT len )
2114
VG_(debugLog)(0,"aspacem",
2115
"am_munmap_valgrind(%p, %lu)\n", (void*)start, len);
2118
return VG_(mk_SysRes_Success)(0);
2120
/* We have to be a bit careful here. If the area being unmapped is
2121
AnonV which originated from a preallocated area (hence from
2122
sbrk-land) then we will have to return it to the preallocated
2123
state, rather than unmapping it. */
2124
end = start + len - 1;
2125
aspacem_assert(start <= end); // else have wraparound?!
2127
ixS = find_asegment_idx( &asegs_pri, start );
2128
ixE = find_asegment_idx( &asegs_pri, end );
2130
aspacem_assert(ixS >= 0 && ixS < asegs_pri.used);
2131
aspacem_assert(ixE >= 0 && ixE < asegs_pri.used);
2133
/* Preconditions: See comment at start of fn */
2134
aspacem_assert(ixS == ixE);
2136
/* For the segment S denoted by ixS:
2138
- if S is AnonV from prealloc and S entirely within start .. end,
2139
return it to prealloc
2141
- if S is AnonV not from prealloc and S entirely within start .. end,
2144
- if S is FileV and S entirely within start .. end, munmap it
2146
Otherwise, leave it alone (too complex to handle). In theory
2147
this could cause a leak; in practice I don't think it will.
2149
seg = &asegs_pri.seg[ixS];
2152
show_AixSegment( 0, ixS, seg );
2155
aspacem_assert(seg->start <= start);
2156
aspacem_assert(end <= seg->end);
2158
if (seg->kind == ASkFileV
2159
|| (seg->kind == ASkAnonV && (!seg->fromP))) {
2161
VG_(debugLog)(0,"aspacem", "am_munmap_valgrind: !fromP: %p-%p\n",
2162
(void*)start, (void*)end);
2163
sres = ML_(am_do_munmap_NO_NOTIFY)( start, len );
2166
init_AixSegment( &seg2 );
2169
seg2.kind = ASkFree;
2170
add_asegment( &asegs_pri, &seg2 );
2173
if (seg->kind == ASkAnonV && seg->fromP) {
2175
VG_(debugLog)(0,"aspacem", "am_munmap_valgrind: fromP: %p-%p\n",
2176
(void*)start, (void*)end);
2177
init_AixSegment( &seg2 );
2180
seg2.kind = ASkPreAlloc;
2181
seg2.hasR = seg2.hasW = seg2.hasX = True;
2182
add_asegment( &asegs_pri, &seg2 );
2185
/* shouldn't be asked to handle any other cases */
2189
aspacem_assert( sane_AixSegments( &asegs_pri ));
2190
return VG_(mk_SysRes_Success)(0);
2193
aspacem_assert( sane_AixSegments( &asegs_pri ));
2194
return VG_(mk_SysRes_Error)(VKI_EINVAL);
2198
/* Let (start,len) denote an area within a single Valgrind-owned
2199
segment (anon or file). Change the ownership of [start, start+len)
2200
to the client instead. Fails if (start,len) does not denote a
2201
suitable segment. */
2203
Bool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len )
2209
/* 'seg' must be NULL or have been obtained from
2210
VG_(am_find_nsegment), and still valid. If non-NULL, and if it
2211
denotes a SkAnonC (anonymous client mapping) area, set the .isCH
2212
(is-client-heap) flag for that area. Otherwise do nothing.
2213
(Bizarre interface so that the same code works for both Linux and
2214
AIX and does not impose inefficiencies on the Linux version.) */
2215
/* AIX: presumably this is a faked-up segment our VG_(am_find_segment)
2216
came up with. So we have to find the corresponding AixSegment. */
2218
void VG_(am_set_segment_isCH_if_SkAnonC)( NSegment* seg )
2223
i = find_asegment_idx( &asegs_pri, seg->start );
2224
aspacem_assert(i >= 0 && i < asegs_pri.used );
2225
if (asegs_pri.seg[i].kind == ASkAnonC) {
2226
asegs_pri.seg[i].isCH = True;
2228
VG_(debugLog)(0,"aspacem","set isCH for %p\n", (void*)seg->start );
2230
aspacem_assert(asegs_pri.seg[i].isCH == False);
2235
/* Same idea as VG_(am_set_segment_isCH_if_SkAnonC), except set the
2236
segment's hasT bit (has-cached-code) if this is SkFileC or SkAnonC
2238
/* AIX: we ignore these complexities by conservatively assuming that
2239
all segments had translations taken from them. Hence we can safely
2241
void VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( NSegment* seg )
2246
/* --- --- --- reservations --- --- --- */
2248
/* Create a reservation from START .. START+LENGTH-1, with the given
2249
ShrinkMode. When checking whether the reservation can be created,
2250
also ensure that at least abs(EXTRA) extra free bytes will remain
2251
above (> 0) or below (< 0) the reservation.
2253
The reservation will only be created if it, plus the extra-zone,
2254
falls entirely within a single free segment. The returned Bool
2255
indicates whether the creation succeeded. */
2257
Bool VG_(am_create_reservation) ( Addr start, SizeT length,
2258
ShrinkMode smode, SSizeT extra )
2260
ML_(am_barf)("unimplemented: VG_(am_create_reservation)");
2266
/* Let SEG be an anonymous client mapping. This fn extends the
2267
mapping by DELTA bytes, taking the space from a reservation section
2268
which must be adjacent. If DELTA is positive, the segment is
2269
extended forwards in the address space, and the reservation must be
2270
the next one along. If DELTA is negative, the segment is extended
2271
backwards in the address space and the reservation must be the
2272
previous one. DELTA must be page aligned. abs(DELTA) must not
2273
exceed the size of the reservation segment minus one page, that is,
2274
the reservation segment after the operation must be at least one
2277
Bool VG_(am_extend_into_adjacent_reservation_client) ( NSegment* seg,
2280
ML_(am_barf)("unimplemented: "
2281
"VG_(am_extend_into_adjacent_reservation_client)");
2287
/* --- --- --- resizing/move a mapping --- --- --- */
2289
/* Let SEG be a client mapping (anonymous or file). This fn extends
2290
the mapping forwards only by DELTA bytes, and trashes whatever was
2291
in the new area. Fails if SEG is not a single client mapping or if
2292
the new area is not accessible to the client. Fails if DELTA is
2293
not page aligned. *seg is invalid after a successful return. If
2294
*need_discard is True after a successful return, the caller should
2295
immediately discard translations from the new area. */
2297
Bool VG_(am_extend_map_client)( /*OUT*/Bool* need_discard,
2298
NSegment* seg, SizeT delta )
2300
ML_(am_barf)("unimplemented: VG_(am_extend_map_client)");
2306
/* Remap the old address range to the new address range. Fails if any
2307
parameter is not page aligned, if the either size is zero, if any
2308
wraparound is implied, if the old address range does not fall
2309
entirely within a single segment, if the new address range overlaps
2310
with the old one, or if the old address range is not a valid client
2311
mapping. If *need_discard is True after a successful return, the
2312
caller should immediately discard translations from both specified
2315
Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
2316
Addr old_addr, SizeT old_len,
2317
Addr new_addr, SizeT new_len )
2319
ML_(am_barf)("unimplemented: VG_(am_relocate_nooverlap_client)");
2326
/*-----------------------------------------------------------------*/
2328
/*--- A simple parser for /proc/<pid>/map on AIX5. ---*/
2329
/*--- Almost completely independent of the stuff above. The ---*/
2330
/*--- only function it 'exports' to the code above this comment ---*/
2331
/*--- is parse_procselfmaps. ---*/
2333
/*-----------------------------------------------------------------*/
2335
/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
2336
#include <sys/procfs.h>
2337
/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
2340
/* Size of a smallish table used to read /proc/<pid>/map entries. */
2341
#define M_APROCMAP_BUF 100000
2343
/* static ... to keep it out of the stack frame. */
2344
static HChar procmap_buf[M_APROCMAP_BUF];
2346
/* Records length of /proc/<pid>/map read into procmap_buf. */
2347
static Int buf_n_tot;
2351
/* Get the contents of /proc/<pid>/map into a static buffer. If
2352
there's a syntax error, it won't fit, or other failure, just
2355
static void read_procselfmap_into_buf ( void )
2361
ML_(am_sprintf)( fname, "/proc/%d/map", ML_(am_getpid)() );
2363
/* Read the initial memory mapping from the /proc filesystem. */
2364
fd = ML_(am_open)( fname, VKI_O_RDONLY, 0 );
2366
ML_(am_barf)("can't open /proc/<pid>/map");
2370
n_chunk = ML_(am_read)( fd.res, &procmap_buf[buf_n_tot],
2371
M_APROCMAP_BUF - buf_n_tot );
2372
buf_n_tot += n_chunk;
2373
} while ( n_chunk > 0 && buf_n_tot < M_APROCMAP_BUF );
2375
ML_(am_close)(fd.res);
2377
if (buf_n_tot >= M_APROCMAP_BUF-5)
2378
ML_(am_barf_toolow)("M_APROCMAP_BUF");
2380
ML_(am_barf)("I/O error on /proc/<pid>/map");
2382
procmap_buf[buf_n_tot] = 0;
2386
/* /proc/<pid>/map appears to give out a non-absolute path name for
2387
the main executable. Fortunately we can reliably identify the main
2388
executable via the MA_MAINEXEC bit, and if we find the path is
2389
non-absolute, replace it with /proc/<pid>/object/a.out instead.
2390
AIX guarantees the latter is another name for the main
2393
static HChar* kludge_exe_file_name ( HChar* file_name, prmap_t* map )
2395
static Int my_pid = -1;
2396
static HChar a_out_name[64];
2397
if (file_name == NULL)
2399
if (file_name[0] != '/' && (map->pr_mflags & MA_MAINEXEC)) {
2401
my_pid = ML_(am_getpid)();
2402
ML_(am_sprintf)(a_out_name, "/proc/%d/object/a.out", my_pid);
2403
file_name = a_out_name;
2410
/* Parse /proc/<pid>/map, copying the entries in it into an
2411
AixSegments structure. Returns a properly formed AixSegments, with
2412
ASkMText/ASkMData entries, with sibling pointers set up, and
2413
ASkFree everywhere else.
2415
static void parse_procselfmap ( /*OUT*/AixSegments* segs )
2417
UChar rr, ww, xx, mm, ss;
2425
const UInt valid_pr_mflags
2426
= MA_MAINEXEC | MA_KERNTEXT | MA_READ | MA_WRITE
2427
| MA_EXEC | MA_SHARED | MA_BREAK | MA_STACK;
2430
init_AixSegments(segs);
2431
aspacem_assert( sane_AixSegments(segs) );
2433
read_procselfmap_into_buf();
2436
VG_(debugLog)(0, "procselfmaps", "got %d bytes\n", buf_n_tot);
2442
if (off + sizeof(prmap_t) > buf_n_tot)
2445
map = (prmap_t*)&procmap_buf[off];
2446
off += sizeof(prmap_t);
2448
/* When should we stop reading the array?
2449
/usr/include/sys/procfs.h says that "Array entries continue
2450
until an entry with a pr_size field of 0 and invalid
2451
pr_mflags occurs." It unhelpfully fails to define what
2452
"invalid" means here. However, the following test _seems_ to
2454
if (map->pr_size == 0
2455
&& (map->pr_mflags & valid_pr_mflags) == 0)
2458
/* Ok, keep going, but ignore any zero-sized mappings: */
2459
if (map->pr_size == 0)
2462
mm = (map->pr_mflags & MA_MAINEXEC) > 0;
2463
rr = (map->pr_mflags & MA_READ) > 0;
2464
ww = (map->pr_mflags & MA_WRITE) > 0;
2465
xx = (map->pr_mflags & MA_EXEC) > 0;
2466
ss = (map->pr_mflags & MA_SHARED) > 0;
2468
if (map->pr_pathoff > 0) {
2469
file_name = &procmap_buf[map->pr_pathoff];
2470
member_name = file_name + VG_(strlen)(file_name) + 1;
2471
if (*member_name == 0)
2474
file_name = member_name = NULL;
2476
file_name = kludge_exe_file_name( file_name, map );
2478
/* Now file_name and member_name are NULL or ordinary strings.
2479
Convert them to string-table resident strings. */
2481
file_name = add_to_strtab(file_name);
2483
member_name = add_to_strtab(member_name);
2485
/* Create a suitable kind of segment. Initially we will start
2486
with bogus sibling pointers, and allow ASkMData entries to
2487
have file names, since we cannot assume anything about the
2488
ordering of entries in the procmap file. In a second pass,
2489
we will set up the sibling pointers based on those file
2490
names, then remove the MData file names. */
2491
init_AixSegment(&s);
2493
if (rr && (!ww) && xx) {
2494
if (map->pr_size > 0) {
2495
/* r-x segment; add bounds for a text area. */
2497
s.start = (Addr)map->pr_vaddr;
2498
s.end = (Addr)map->pr_vaddr + (Addr)map->pr_size - 1;
2501
s.fname = file_name;
2502
s.mname = member_name;
2506
add_asegment(segs, &s);
2510
if (rr && ww && (!xx)) {
2511
if (map->pr_size > 0) {
2512
/* rw- segment; add bounds for a data area. */
2514
s.start = (Addr)map->pr_vaddr;
2515
s.end = (Addr)map->pr_vaddr + (Addr)map->pr_size - 1;
2516
/* Set a bogus non-zero sibling pointer, since sanity
2517
checking will reject zero sibling pointers on MData.
2518
It doesn't matter since the loops following this one
2519
below fix up the sibling pointers. */
2521
s.fname = file_name;
2522
s.mname = member_name;
2526
add_asegment(segs, &s);
2530
/* unclassifiable; we better complain. */
2532
VG_(debugLog)(0, "aspacem", "parse_procselfmap: unclassifiable:\n");
2536
VG_(debugLog)(1,"aspacem",
2537
" %010llx-%010llx %c%c%c%c%c %s%s%s%s\n",
2538
(ULong)map->pr_vaddr,
2539
(ULong)map->pr_vaddr + (ULong)map->pr_size,
2545
file_name ? file_name : (UChar*)"(none)",
2546
member_name ? "(" : "",
2547
member_name ? member_name : (UChar*)"",
2548
member_name ? ")" : ""
2553
/* Set up sibling pointers. For each MData, find an MText with the
2554
same file/member names, or complain. This is really ugly in
2555
that it makes the process quadratic in the number of modules
2556
mapped in, but I can't think of a (simple) better way. */
2558
for (i = 0; i < segs->used; i++) {
2559
if (segs->seg[i].kind != ASkMData)
2561
for (j = 0; j < segs->used; j++) {
2562
if (segs->seg[j].kind == ASkMText
2563
&& segs->seg[j].fname == segs->seg[i].fname
2564
&& segs->seg[j].mname == segs->seg[i].mname)
2567
if (j == segs->used) {
2568
VG_(debugLog)(0, "aspacem", "parse_procselfmap: "
2569
"data segment with no associated text segment:\n");
2570
VG_(debugLog)(0, "aspacem", "module = %s(%s)\n",
2572
segs->seg[i].mname ? segs->seg[i].mname
2573
: (UChar*)"(none)");
2576
aspacem_assert(j >= 0 && j < segs->used && j != i);
2577
segs->seg[i].sibling = segs->seg[j].start;
2580
/* (Almost) dually, for each MText, find an MData with same
2581
file/member names, but don't complain if not present. */
2583
for (i = 0; i < segs->used; i++) {
2584
if (segs->seg[i].kind != ASkMText)
2586
for (j = 0; j < segs->used; j++) {
2587
if (segs->seg[j].kind == ASkMData
2588
&& segs->seg[j].fname == segs->seg[i].fname
2589
&& segs->seg[j].mname == segs->seg[i].mname)
2592
if (j == segs->used) {
2593
/* no corresponding MData found; harmless. */
2595
aspacem_assert(j >= 0 && j < segs->used && j != i);
2596
segs->seg[i].sibling = segs->seg[j].start;
2600
/* Finally, get rid of fname/mname pointers on MDatas, so as to
2601
adhere to the necessary representational invariants. */
2602
for (i = 0; i < segs->used; i++) {
2603
if (segs->seg[i].kind == ASkMData){
2604
segs->seg[i].fname = segs->seg[i].mname = NULL;
2608
aspacem_assert( sane_AixSegments(segs) );
2610
show_AixSegments(0, "as read from procmap", segs);
2614
/*--------------------------------------------------------------------*/
2616
/*--------------------------------------------------------------------*/