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