• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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