~bkerensa/ubuntu/raring/valgrind/merge-from-deb

« back to all changes in this revision

Viewing changes to coregrind/m_aspacemgr/aspacemgr-aix5.c

  • Committer: Bazaar Package Importer
  • Author(s): Andrés Roldán
  • Date: 2008-06-13 02:31:40 UTC
  • mto: (1.4.1 upstream) (2.2.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: james.westby@ubuntu.com-20080613023140-iwk33rz9rhvfkr96
Import upstream version 3.3.1

Show diffs side-by-side

added added

removed removed

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