]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_debuginfo/readxcoff.c
Inital import
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / m_debuginfo / readxcoff.c
1
2 /*--------------------------------------------------------------------*/
3 /*--- Read XCOFF debug info.                           readxcoff.c ---*/
4 /*--------------------------------------------------------------------*/
5
6 /*
7    This file is part of Valgrind, a dynamic binary instrumentation
8    framework.
9
10    Copyright (C) 2006-2010 OpenWorks LLP
11       info@open-works.co.uk
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of the
16    License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful, but
19    WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26    02111-1307, USA.
27
28    The GNU General Public License is contained in the file COPYING.
29
30    Neither the names of the U.S. Department of Energy nor the
31    University of California nor the names of its contributors may be
32    used to endorse or promote products derived from this software
33    without prior written permission.
34 */
35
36 #if defined(VGO_aix5)
37
38 /* This file reads XCOFF symbol tables and debug info.
39    Known limitations:
40
41    * only one text section per object file is handled
42
43    * C_BINCL/C_EINCL handling is wrong, so functions defined in files
44      included from other files will end up with the wrong file name
45      and possibly line numbers.  Fixable.
46
47    * The line number reader leans heavily on the fact that the generic
48      line number canonicaliser in storage.c truncates overlapping
49      ranges.
50 */
51
52 #include "pub_core_basics.h"
53 #include "pub_core_vki.h"          /* struct vki_stat et al */
54 #include "pub_core_libcbase.h"
55 #include "pub_core_libcassert.h"
56 #include "pub_core_libcprint.h"
57 #include "pub_core_libcfile.h"     /* stat, open, close */
58 #include "pub_core_aspacemgr.h"    /* for mmaping debuginfo files */
59 #include "pub_core_options.h"      /* VG_(clo_trace_symtab) */
60 #include "pub_core_xarray.h"
61 #include "priv_misc.h"
62 #include "priv_tytypes.h"
63 #include "pub_tool_debuginfo.h"
64 #include "priv_d3basics.h"
65 #include "priv_storage.h"
66 #include "priv_readxcoff.h"        /* self */
67
68 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
69 #if defined(VGP_ppc32_aix5)
70 # define __XCOFF32__ 1
71 # undef  __XCOFF64__
72 #elif defined(VGP_ppc64_aix5)
73 # define __XCOFF64__ 1
74 # undef  __XCOFF32__
75 #else
76 # error "This file should only be compiled on AIX"
77 #endif
78 #include <xcoff.h>
79
80 #undef __AR_SMALL__
81 #define __AR_BIG__ 1
82 #include <ar.h>
83 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
84
85 /* Debug stuff */
86 #define SHOW_LD_STRTAB 1   /* loader string tables */
87 #define SHOW_LD_SYMTAB 1   /* loader symbol table */
88 #define SHOW_LD_RELTAB 1   /* loader reloc table */
89 #define SHOW_STRTAB 1      /* main string table */
90 #define SHOW_SYMS_P1 1     /* P1: find text sym starts */
91 #define SHOW_SYMS_P2 1     /* P2: find text sym ends */
92 #define SHOW_SYMS_P3 1     /* P3: src filenames & fn start/end line #s */
93 #define SHOW_SYMS_P4 1     /* P4: line numbers */
94 #define SHOW_SYMS_P5 1     /* P5: find TOC pointers */
95 #define SHOW_SYMS_P6 1     /* P6: finalise symbol info */
96
97 #define SHOW_AR_DETAILS 0  /* show details of .a file internals */
98
99 #define SHOW  di->trace_symtab
100
101 /* A small stack of filenames is maintained for dealing
102    with BINCL/EINCL symbol table entries. */
103
104 #define N_FILENAME_STACK 16
105
106 /* Phase 5 (find TOC pointers) has two implementations, the official
107    version, which involves reading the data segment symbols, and the
108    kludgey version, which basically scans the (actual loaded) data
109    segment to find structs which look like function descriptors. */
110
111 #if 1
112 # undef OFFICIAL_PHASE5
113 #else
114 # define OFFICIAL_PHASE5 1
115 #endif
116
117 /*------------------------------------------------------------*/
118 /*--- Read XCOFF format debug info.                        ---*/
119 /*------------------------------------------------------------*/
120
121
122 /* COFF uses a strange way to represent symbol names.  A symbol is an
123    eight-byte field.
124
125    In 32-bit mode: if the first four bytes are zero, then the second
126    four bytes give the offset into the string table where the string
127    really is.  Otherwise, the whole 8-byte thing is itself the name.
128
129    In 64-bit mode: a four-byte field at offset 8 is always interpreted
130    as an offset into the string table.
131
132    For a symbol of length 8, in 32-bit mode, there is no obvious way
133    to zero-terminate it.  One solution is to copy the name into
134    dynamically allocated memory, but that complicates storage
135    management.
136
137    An alternative solution, used here, is to represent a name as a
138    (data, length) pair instead of the traditional zero-terminated
139    string.  Such a pair can be constructed for any XCOFF symbol name,
140    and has the advantages that (1) no dynamic memory is required, and
141    (2) the name is guaranteed to be accessible as long as the object
142    image is mapped in.
143
144    What the .vec points at must not be modified; if you want to do
145    that, copy it elsewhere first.
146 */
147
148 typedef
149    struct {
150       UChar* vec; /* the text of the name */
151       UInt   len; /* length of the text */
152    }
153    Name;
154
155 static Name maybeDerefStrTab( SYMENT* sym,
156                               UChar* oi_strtab, UWord oi_n_strtab)
157 {
158    Name res;
159    static UChar* bogus 
160       = (UChar*)"**_Error_Dereferencing_COFF_String_Table_**";
161    UChar* bytes = (UChar*)sym;
162
163 #  if defined(VGP_ppc32_aix5)
164    if (bytes[0]==0 && bytes[1]==0 && bytes[2]==0 && bytes[3]==0) {
165       UInt off = *(UInt*)&bytes[4];
166       if (oi_strtab && oi_n_strtab > 0 && off < oi_n_strtab) {
167          res.vec = &oi_strtab[off];
168          res.len = VG_(strlen)(res.vec);
169          return res;
170       } else
171          goto bad;
172    } else {
173       Int i;
174       res.vec = bytes;
175       res.len = 8;
176       for (i = 0; i < 8; i++)
177          if (bytes[i] == 0)
178             res.len--;
179       return res;
180    }
181
182 #  elif defined(VGP_ppc64_aix5)
183    ULong off = (ULong)( *(UInt*)&bytes[8] );
184    if (oi_strtab && oi_n_strtab > 0 && off < oi_n_strtab) {
185       res.vec = &oi_strtab[off];
186       res.len = VG_(strlen)(res.vec);
187       return res;
188    } else
189       goto bad;
190
191 #  else
192 #    error "Unknown platform"
193 #  endif
194
195   bad:
196    res.vec = bogus;
197    res.len = VG_(strlen)(bogus);
198    return res;
199 }
200
201
202 /* Similar scheme for extracting names from C_FILE auxiliary entries,
203    except that the 32-bit scheme appears to be always used, even for
204    XCOFF64. */
205
206 static Name maybeDerefStrTab_fname ( UChar* bytes,
207                                      UChar* oi_strtab, UWord oi_n_strtab)
208 {
209    Name res;
210    static UChar* bogus 
211       = (UChar*)"**_Error_Dereferencing_COFF_String_Table_**";
212
213    if (bytes[0]==0 && bytes[1]==0 && bytes[2]==0 && bytes[3]==0) {
214       UInt off = *(UInt*)&bytes[4];
215       if (oi_strtab && oi_n_strtab > 0 && off < oi_n_strtab) {
216          res.vec = &oi_strtab[off];
217          res.len = VG_(strlen)(res.vec);
218          return res;
219       } else
220          goto bad;
221    } else {
222       Int i;
223       res.vec = bytes;
224       res.len = 8;
225       for (i = 0; i < 8; i++)
226          if (bytes[i] == 0)
227             res.len--;
228       return res;
229    }
230
231   bad:
232    res.vec = bogus;
233    res.len = VG_(strlen)(bogus);
234    return res;
235 }
236
237
238 static Name mk_const_Name ( HChar* str )
239 {
240    Name res;
241    res.vec = str;
242    res.len = VG_(strlen)(res.vec);
243    return res;
244 }
245
246 static Name mk_empty_Name ( void )
247 {
248    Name res;
249    res.vec = "";
250    res.len = 0;
251    return res;
252 }
253
254 static Bool is_empty_Name ( Name name )
255 {
256    return name.len == 0;
257 }
258
259 static Bool eq_string_Name ( Name name, UChar* str )
260 {
261    UInt i;
262    for (i = 0; i < name.len; i++) {
263       if (str[i] == 0)
264          return False;
265       if (str[i] != name.vec[i])
266          return False;
267    }
268    if (str[name.len] == 0)
269       return True;
270    else
271       return False;
272 }
273
274 static Int cmp_Names ( Name n1, Name n2 )
275 {
276    UInt i = 0;
277    while (1) {
278       vg_assert(i >= 0 && i <= n1.len);
279       vg_assert(i >= 0 && i <= n2.len);
280       if (i == n1.len && i == n2.len)
281          return 0;
282       if (i == n1.len && i < n2.len)
283          return -1;
284       if (i < n1.len && i == n2.len)
285          return 1;
286       if (n1.vec[i] < n2.vec[i])
287          return -1;
288       if (n1.vec[i] > n2.vec[i])
289          return 1;
290       i++;
291    }
292 }
293
294 static void print_Name ( Name name )
295 {
296    UInt i;
297    for (i = 0; i < name.len; i++)
298       VG_(printf)("%c", name.vec[i]);
299 }
300
301
302 static UChar sanitiseChar ( UChar c )
303 {
304    if (c < 32 || c > 127)
305       c = '?';
306    return c;
307 }
308
309 static HChar* name_of_filhdr_f_magic ( Int magic )
310 {
311    switch (magic) {
312       case 0x01DF: return "xcoff32";
313       case 0x01EF: return "xcoff64-upto-aix43";
314       case 0x01F7: return "xcoff64-from-aix51";
315       default:     return "unknown-xcoff-header-magic";
316    }
317 }
318
319 static HChar* name_of_scnhdr_s_flags ( Int flags )
320 {
321    switch (flags & 0xFFFF) {
322       case STYP_REG:    return "\"regular\"";
323       case STYP_PAD:    return "\"padding\"";
324       case STYP_TEXT:   return "text only";
325       case STYP_DATA:   return "data only";
326       case STYP_BSS:    return "bss only";
327       case STYP_EXCEPT: return "Exception";
328       case STYP_INFO:   return "Comment";
329       case STYP_LOADER: return "Loader";
330       case STYP_DEBUG:  return "Debug";
331       case STYP_TYPCHK: return "Typecheck";
332       case STYP_OVRFLO: return "Overflow";
333       default: return "unknown-section-header-name";
334    }
335 }
336
337 static HChar* name_of_syment_n_sclass ( Int sclass )
338 {
339    static HChar buf[10];
340    switch (sclass) {
341       /* dbx ones (>= 0x80) */
342       case C_GSYM:    return "gsym";
343       case C_LSYM:    return "lsym";
344       case C_PSYM:    return "psym";
345       case C_RSYM:    return "rsym";
346       case C_RPSYM:   return "rpsym";
347       case C_STSYM:   return "stsym";
348       case C_DECL:    return "decl";
349       case C_FUN:     return "fun";
350       case C_BSTAT:   return "bstat";
351       case C_ESTAT:   return "estat";
352       /* non-dbx ones (< 0x80) */
353       case C_STAT:    return "STAT";
354       case C_FILE:    return "FILE";
355       case C_HIDEXT:  return "HIDEXT";
356       case C_EXT:     return "EXT";
357       case C_FCN:     return "FCN";
358       case C_BINCL:   return "BINCL";
359       case C_EINCL:   return "EINCL";
360       case C_BLOCK:   return "BLOCK";
361       case C_WEAKEXT: return "WEAKEXT";
362       default:
363          VG_(sprintf)(buf, "??%d??", sclass);
364          return buf;
365    }
366 }
367
368 typedef 
369    struct {
370       Name   name;    /* symbol's name */
371       Addr   first;   /* first address; always known */
372       Addr   last;    /* last address; may be an overestimate */
373
374       Name   fname;   /* source file name, if known */
375       Int    slnno;   /* starting line #, or 0 if unknown */
376       Int    elnno;   /* ending line #, or 0 if unknown */
377
378       UWord  r2value; /* what r2 should be for this fn (tocptr) */
379       Bool   r2known; /* do we have a r2 value? */
380    } 
381    XCoffSym;
382
383 static void init_XCoffSym( XCoffSym* sym )
384 {
385    sym->name    = mk_empty_Name();
386    sym->first   = 0;
387    sym->last    = 0;
388    sym->fname   = mk_empty_Name();
389    sym->slnno   = 0;
390    sym->elnno   = 0;
391    sym->r2known = False;
392    sym->r2value = False;
393 }
394
395 /* Compare XCoffSyms by their start address. */
396 static Int cmp_XCoffSym_by_start ( void* v1, void* v2 )
397 {
398    XCoffSym* s1 = (XCoffSym*)v1;
399    XCoffSym* s2 = (XCoffSym*)v2;
400    if (s1->first < s2->first) return -1;
401    if (s1->first > s2->first) return 1;
402    return 0;
403 }
404
405 /* Compare XCoffSyms by a slightly weaker ordering, returning zero
406    (equivalence) for any overlap, and -1 or 1 otherwise. */
407 static Int cmp_XCoffSym_by_overlap ( void* v1, void* v2 )
408 {
409    XCoffSym* s1 = (XCoffSym*)v1;
410    XCoffSym* s2 = (XCoffSym*)v2;
411    if (s1->last < s2->first) return -1;
412    if (s2->last < s1->first) return 1;
413    return 0;
414 }
415
416 /* Compare XCoffSyms by their start address, and for equal addresses,
417    use the name as a secondary sort key. */
418 static Int cmp_XCoffSym_by_start_then_name ( void* v1, void* v2 )
419 {
420    XCoffSym* s1 = (XCoffSym*)v1;
421    XCoffSym* s2 = (XCoffSym*)v2;
422    if (s1->first < s2->first) return -1;
423    if (s1->first > s2->first) return 1;
424    return cmp_Names(s1->name, s2->name);
425 }
426
427
428 /* csect_idx is an index in the symbol table (start, n_entries) to a
429    symbol defining a csect.  If possible, find the bounds of the csect
430    and assign them to *first and *last, and return True; else return
431    False.  sntext_1based_if_known is the 1-based number of the text
432    section.  Note: computes stated VMAs, not actual VMAs. */
433
434 #if defined(VGP_ppc32_aix5)
435 # define SMTYP_SMTYP(x)  ((x) & 0x7)     /* symbol type */
436 # define CSECT(PP)       (((AUXENT*)(PP))->x_csect)
437 # define CSECT_LEN(PP)   (CSECT(PP).x_scnlen)
438 # define CSECT_ALIGN(PP) (SMTYP_ALIGN(CSECT(PP).x_smtyp))
439 # define CSECT_SMTYP(PP) (SMTYP_SMTYP(CSECT(PP).x_smtyp))
440 # define CSECT_SCLAS(PP) (CSECT(PP).x_smclas)
441
442 #elif defined(VGP_ppc64_aix5)
443 # define SMTYP_SMTYP(x)  ((x) & 0x7)     /* symbol type */
444 # define CSECT(PP)       (((AUXENT*)(PP))->x_csect)
445 # define CSECT_LEN(PP)   ((((ULong)(CSECT(PP).x_scnlen_hi)) << 32) \
446                           | ((ULong)(CSECT(PP).x_scnlen_lo)))
447 # define CSECT_ALIGN(PP) (SMTYP_ALIGN(CSECT(PP).x_smtyp))
448 # define CSECT_SMTYP(PP) (SMTYP_SMTYP(CSECT(PP).x_smtyp))
449 # define CSECT_SCLAS(PP) (CSECT(PP).x_smclas)
450
451 #else
452 # error "Unknown platform"
453
454 #endif
455
456
457 #define SYM_IX(_tab,_n) ((SYMENT*)(((UChar*)(_tab)) + SYMESZ * (_n)))
458
459 static 
460 Bool get_csect_bounds ( UChar* start, UWord n_entries,
461                         UWord csect_idx, 
462                         Int sntext_1based_if_known,
463                         /*OUT*/UChar** first, /*OUT*/UChar** last )
464 {
465    Bool    is_text;
466    SYMENT* cssym;
467    AUXENT* csaux;
468
469    vg_assert(SYMESZ == 18); /* both for XCOFF32 and XCOFF64 */
470
471    if (n_entries < 2)
472       return False;
473    if (csect_idx+1 >= n_entries)
474       return False;
475    cssym = (SYMENT*)SYM_IX(start, csect_idx);
476    csaux = (AUXENT*)SYM_IX(start, csect_idx+1);
477    is_text = sntext_1based_if_known != -1
478              && (Int)cssym->n_scnum == sntext_1based_if_known;
479
480    if (!is_text)
481       return False;
482
483    if (cssym->n_sclass == C_EXT || cssym->n_sclass == C_HIDEXT) {
484       if (cssym->n_numaux == 1) {
485          if (CSECT_SMTYP(csaux) == XTY_SD) {
486             if (0) VG_(printf)("GCB: SD: len is %lld\n", (Long)CSECT_LEN(csaux));
487             *first = (UChar*)(cssym->n_value);
488             *last = *first + CSECT_LEN(csaux)-1;
489            return True;
490          }
491       } else {
492          /* Possibly complain or take evasive action here.  In fact
493             I've yet to see a case where a csect definition symbol has
494             n_numaux != 1. */
495       }
496    }
497    return False;
498 }
499
500 /* Read symbol and line number info for the given text section.  (This
501    is the central routine for XCOFF reading.)  Returns NULL on
502    success, or the text of an error message otherwise. */
503 static 
504 HChar* read_symbol_table ( 
505           /*MOD*/struct _DebugInfo* di,
506
507           /* location of symbol table */
508           UChar* oi_symtab, UWord oi_nent_symtab,
509
510           /* location of string table */
511           UChar* oi_strtab, UWord oi_n_strtab,
512
513           /* location of debug section (stabs strings, if any) */
514           UChar* oi_debug, UWord oi_n_debug,
515
516           /* location of line number info, if any */
517           UChar* oi_lnos, UWord oi_nent_lnos,
518
519           /* section indices */
520           Int sntext_1based_if_known,
521           Int sndata_1based_if_known,
522
523           /* where the mapped data section is */
524           /* Now in di->data_avma:   Addr data_avma, */
525           /* Now in di->data_size:   UWord data_alen, */
526           UWord data_alen_from_auxhdr,
527
528           /* where the mapped toc is (in the data section,
529              presumably), if known */
530           Addr toc_avma,
531
532           /* stated-to-actual VMA offsets */ 
533           Word text_bias,
534           Word data_bias 
535        )
536 {
537    SYMENT* sym;
538    SYMENT* aux;
539    UInt    i, j, nsyms, k, m;
540    Name    name;
541    Bool    is_text, is_data;
542    XArray* syms = NULL; /* XArray of XCoffSyms */
543
544    /* If the TOC avma is obviously bogus, get rid of it */
545    { 
546      UWord data_maxlen = di->data_size;
547      if (data_maxlen < data_alen_from_auxhdr)
548         data_maxlen = data_alen_from_auxhdr;
549
550      //VG_(printf)(" toc_avma %p\n", toc_avma);
551      //VG_(printf)("data_avma %p\n", data_avma);
552      //VG_(printf)("dxxx_avma %p\n", data_avma + data_maxlen);
553
554      if (toc_avma != 0
555          && (toc_avma < di->data_avma 
556              || toc_avma >= di->data_avma + data_maxlen))
557         toc_avma = 0;
558      //VG_(printf)("2toc_avma %p\n", toc_avma);
559    }
560
561    /* We can't just treat this as an array of SYMENTs, because C
562       thinks they have size 20 whereas the spec says they have size 18
563       (alignment padding) so doing the obvious thing screws up.  Hence
564       we have to calculate the offset of each entry manually. */
565
566    if (0) VG_(printf)("size of SYMENT = %ld\n", sizeof(SYMENT));
567
568    /* ----------------------------------------------------------
569       Phase 1: first make a pass through the symbols, looking for
570       stuff in the text segment.  Calculate their actual VMAs,
571       dump any outside the text segment actual VMA bounds, and 
572       add the rest to 'syms'.
573       ---------------------------------------------------------- */
574
575    syms = VG_(newXA)( ML_(dinfo_zalloc), "di.readxcoff.rst.1", 
576                       ML_(dinfo_free), sizeof(XCoffSym) );
577
578    if (SHOW && SHOW_SYMS_P1) {
579       VG_(printf)("--- BEGIN Phase1 (find text symbol starts) ---\n");
580       VG_(printf)("--- note: shown addresses are STATED VMAs ---\n");
581    }
582
583    i = 0;
584    while (1) {
585
586       if (i >= oi_nent_symtab)
587          break;
588
589       sym = SYM_IX(oi_symtab, i);
590       is_text = sntext_1based_if_known != -1
591                 && (Int)sym->n_scnum == sntext_1based_if_known;
592       is_data = sndata_1based_if_known != -1
593                 && (Int)sym->n_scnum == sndata_1based_if_known;
594
595       if (SHOW && SHOW_SYMS_P1)
596          VG_(printf)("Phase1: %5d+%d  ", i, (Int)sym->n_numaux);
597
598       name = mk_const_Name("(unknown)");
599       if (sym->n_scnum == N_DEBUG && sym->n_sclass == C_FUN)
600          name = maybeDerefStrTab( sym, oi_debug, oi_n_debug );
601       else 
602       if (sym->n_sclass & DBXMASK)
603          name = mk_const_Name("(dbxstr)");
604       else
605          name = maybeDerefStrTab( sym, oi_strtab, oi_n_strtab);
606
607       if (SHOW && SHOW_SYMS_P1) {
608          VG_(printf)("%5s(%2d)  %6s  0x%016llx ", 
609                      is_text ? "text" : is_data ? "data" : "other",
610                      (Int)sym->n_scnum, 
611                      name_of_syment_n_sclass(sym->n_sclass), 
612                      (ULong)sym->n_value);
613          print_Name(name);
614          VG_(printf)("\n");
615       }
616
617       i++;
618       i += sym->n_numaux;
619
620       if (!is_text)
621          continue;
622
623       /* --- BEGIN regular(ish) symbol --- */
624       if ((sym->n_sclass == C_EXT || sym->n_sclass == C_HIDEXT)
625           && (sym->n_numaux == 1 || sym->n_numaux == 2)) {
626          /* Dealing with a symbol with a csect entry.  By convention
627             (according to IBM docs) the csect entry is the last
628             auxiliary for this symbol, if there is more than one
629             auxiliary present; hence "SYM_IX(oi_symtab, i-1)" below. */
630
631          aux = SYM_IX(oi_symtab, i-1);
632          if (0) VG_(printf)("symtype is %d\n", CSECT_SMTYP(aux));
633
634          if (CSECT_SMTYP(aux) == XTY_SD) {
635             /* Aux is a csect definition.  This is relatively rare,
636                but at least it is simple: the CSECT_LEN(aux) field
637                contains it's length, so we just heave that into the
638                pot for phase 2. */
639             XCoffSym cand;
640             if (0) VG_(printf)("SD: len is %d\n", (Int)CSECT_LEN(aux));
641             if (0) VG_(printf)("SD: proposed %#llx\n", (ULong)sym->n_value);
642             init_XCoffSym(&cand);
643             cand.first = sym->n_value;
644             cand.last = cand.first + (UWord)CSECT_LEN(aux) - 1;
645
646             cand.first += text_bias;
647             cand.last += text_bias;
648             cand.name = name;
649
650             if (cand.last < di->text_avma 
651                 || cand.first >= di->text_avma + di->text_size)
652                continue;
653             if (cand.last < cand.first)
654                continue;
655             if (is_empty_Name(name))
656                continue;
657             (void)VG_(addToXA)(syms, &cand);
658          }
659
660          if (CSECT_SMTYP(aux) == XTY_LD) {
661             /* Aux is a label definition.  This is the common case. */
662             XCoffSym cand;
663             Bool ok;
664             UChar *csect_first, *csect_last;
665             /* x_scnlen contains the symbol table entry of the
666                containing csect.  Use the symbol's stated vma and csect
667                end as the initial approximation of this symbol's start
668                and length.  The length will get revised downwards in
669                Phase 2. */
670             init_XCoffSym(&cand);
671             ok = get_csect_bounds( oi_symtab, oi_nent_symtab, 
672                                    CSECT_LEN(aux), 
673                                    sntext_1based_if_known,
674                                    &csect_first, &csect_last );
675             if (0 && ok)
676                VG_(printf)("new csect svma %p %p\n", csect_first, csect_last);
677             if (ok && ((UWord)csect_first) <= ((UWord)sym->n_value)
678                    && ((UWord)sym->n_value) <= ((UWord)csect_last)) {
679                if (0) {
680                   VG_(printf)("LD: in a csect %p %p\n", 
681                               csect_first, csect_last);
682                   VG_(printf)("CAND: %p .. %p  %s\n", 
683                               (void*)sym->n_value, (void*)csect_last, 
684                               "fixme-Name-printing(1)" /*name*/);
685                }
686                cand.first = sym->n_value;
687                cand.last = (Addr)csect_last;
688             } else {
689                if (0) {
690                   VG_(printf)("LD: can't compute csect bounds?!\n");
691                   VG_(printf)("CAND: %p .. %p  %s\n", 
692                               (HChar*)sym->n_value,
693                               (HChar*)sym->n_value+1,
694                                "fixme-Name-printing(2)" /*name*/);
695                }
696                cand.first = sym->n_value;
697                cand.last = cand.first + 1;
698             }
699
700             /* cand.first is a stated VMA; turn it into an actual VMA
701                and ignore it if not in the actual text segment. */
702
703             cand.first += text_bias;
704             cand.last += text_bias;
705             cand.name = name;
706
707             if (cand.last < di->text_avma 
708                 || cand.first >= di->text_avma + di->text_size)
709                continue;
710             if (cand.last < cand.first)
711                continue;
712             if (is_empty_Name(name))
713                continue;
714
715             (void)VG_(addToXA)(syms, &cand);
716          }
717       }
718       /* --- END regular(ish) symbol --- */
719
720    }
721
722    /* ----------------------------------------------------------
723       Phase 2: suitable text symbols have been put into 'syms'.  Their
724       start addresses are correct, but end addresses are those of the
725       containing csect, which is in general way too long.  This phase
726       clips the ends so that the ranges no longer overlap, and thereby
727       constrains each symbol's range to something which, for the most
728       part, is correct.
729       ---------------------------------------------------------- */
730
731    nsyms = VG_(sizeXA)(syms);
732
733    if (SHOW && SHOW_SYMS_P1)
734       VG_(printf)("Phase1 acquired %d text symbols\n", nsyms);
735
736    if (SHOW && SHOW_SYMS_P2) {
737       VG_(printf)("--- BEGIN Phase2 (find text symbol ends) ---\n");
738       VG_(printf)("--- note: shown addresses are ACTUAL VMAs ---\n");
739    }
740
741    VG_(setCmpFnXA)(syms, cmp_XCoffSym_by_start_then_name);
742    VG_(sortXA)(syms);
743
744    /* We only know for sure the start addresses (actual VMAs) of
745       symbols, and an overestimation of their end addresses.  So sort
746       by start address, then clip each symbol so that its end address
747       does not overlap with the next one along.
748
749       There is a small refinement: if a group of symbols have the same
750       address, treat them as a group: find the next symbol along that
751       has a higher start address, and clip all of the group
752       accordingly.  This clips the group as a whole so as not to
753       overlap following symbols.  This leaves prefersym() in
754       storage.c, which is not XCOFF-specific, to later decide which of
755       the symbols in the group to keep. 
756
757       Another refinement is that we need to get rid of symbols which,
758       after clipping, have identical starts, ends, and names.  So the
759       sorting uses the name as a secondary key.
760    */
761
762    for (i = 0; i < nsyms; i++) {
763       for (k = i+1; 
764            k < nsyms 
765              && ((XCoffSym*)VG_(indexXA)(syms,i))->first 
766                  == ((XCoffSym*)VG_(indexXA)(syms,k))->first; 
767            k++)
768          ;
769       /* So now [i .. k-1] is a group all with the same start address.
770          Clip their ending addresses so they don't overlap [k].  In
771          the normal case (no overlaps), k == i+1. */
772       if (k < nsyms) {
773          XCoffSym* next = (XCoffSym*)VG_(indexXA)(syms,k);
774          for (m = i; m < k; m++) {
775             XCoffSym* here = (XCoffSym*)VG_(indexXA)(syms,m);
776             vg_assert(here->first < next->first);
777             if (here->last >= next->first)
778                here->last = next->first-1;
779          }
780       }
781       i = k-1;
782       vg_assert(i <= nsyms);
783    }
784
785    j = 0;
786    if (nsyms > 0) {
787       j = 1;
788       for (i = 1; i < nsyms; i++) {
789          vg_assert(j <= i);
790          XCoffSym* s_j1 = (XCoffSym*)VG_(indexXA)(syms, j-1);
791          XCoffSym* s_j  = (XCoffSym*)VG_(indexXA)(syms, j);
792          XCoffSym* s_i  = (XCoffSym*)VG_(indexXA)(syms, i);
793          if (s_i->first != s_j1->first
794              || s_i->last != s_j1->last
795              || 0 != cmp_Names(s_i->name, s_j1->name)) {
796             *s_j = *s_i;
797             j++;
798          } else {
799             if (SHOW && SHOW_SYMS_P2) {
800                VG_(printf)("Phase2: dump duplicate "); 
801                print_Name(s_i->name);
802                VG_(printf)("\n");
803             }
804          }
805       }
806    }
807    vg_assert(j >= 0 && j <= nsyms);
808    VG_(dropTailXA)(syms, nsyms - j);
809    nsyms = j;
810
811    if (1) {
812       for (i = 0; i < nsyms; i++) {
813          XCoffSym* s = (XCoffSym*)VG_(indexXA)(syms, i);
814          if (SHOW && SHOW_SYMS_P2) {
815             VG_(printf)("Phase2: %d 0x%lx 0x%lx ", 
816                         i, s->first, s->last);
817             print_Name(s->name);
818             VG_(printf)("\n");
819          }
820       }
821    }
822
823    /* ----------------------------------------------------------
824       Phase 3: rescan the symbol table, looking for info on function
825       start/end line numbers and source file names.  Generally
826       this will be absent for sources compiled without -g.
827       ---------------------------------------------------------- */
828
829    if (SHOW && SHOW_SYMS_P3) {
830       VG_(printf)("--- BEGIN Phase3 (find src filenames "
831                   "& fn start/end line #s) ---\n");
832       VG_(printf)("--- note: shown addresses are STATED VMAs ---\n");
833    }
834
835    /* The lookupXAs in the C_FUN(.bf) part have to operate by
836       inclusion.  Hence: */
837    VG_(setCmpFnXA)(syms, cmp_XCoffSym_by_overlap);
838    VG_(sortXA)(syms);
839
840    /* In this loop, p3currsym is maintained as a pointer to the most
841       recent XCoffSym identified as FCN(.bf) (function start).
842       Subsequent FCN(.ef) (function end) indications are compared
843       against said symbol.  This assumes that function start/end
844       indications are not nested. */
845
846    XCoffSym* p3currsym = NULL;
847
848    /* Maintain a stack of filenames.  We allow the stack pointer to go
849       beyond the end, but obviously nothing is stored in this
850       imaginary part of the stack. */
851    Name filenames[N_FILENAME_STACK];
852    Int  filenames_used = 1;
853
854    Name name_unknown  = mk_empty_Name();
855    Name name_overflow = mk_const_Name("(filename_stack_overflow)");
856
857    for (i = 0; i < N_FILENAME_STACK; i++)
858       filenames[i] = name_unknown;
859
860 #  define FNAME_PUSH(_fname) \
861       do { \
862          vg_assert(filenames_used >= 1);\
863          if (filenames_used < N_FILENAME_STACK)\
864             filenames[filenames_used] = (_fname);\
865          filenames_used++;\
866       } while (0)
867
868 #  define FNAME_POP \
869       do {\
870          vg_assert(filenames_used >= 1);\
871          if (filenames_used > 1 && filenames_used <= N_FILENAME_STACK) \
872             filenames[filenames_used-1] = name_unknown; \
873          if (filenames_used > 1)\
874             filenames_used--;\
875       } while (0)
876
877 #  define FNAME_GET_TOP \
878       (filenames_used > N_FILENAME_STACK  \
879          ? name_overflow \
880          : filenames[filenames_used-1])
881
882 #  define FNAME_SET_TOP(_fname) \
883       do {\
884          vg_assert(filenames_used >= 1);\
885          filenames[filenames_used-1] = (_fname);\
886       } while (0)
887
888
889    i = 0;
890    while (1) {
891
892       if (i >= oi_nent_symtab)
893          break;
894
895       sym = SYM_IX(oi_symtab, i);
896       is_text = sntext_1based_if_known != -1
897                 && (Int)sym->n_scnum == sntext_1based_if_known;
898       is_data = sndata_1based_if_known != -1
899                 && (Int)sym->n_scnum == sndata_1based_if_known;
900
901       if (0 && SHOW && SHOW_SYMS_P3)
902          VG_(printf)("Phase3: %5d+%d  ", i, (Int)sym->n_numaux);
903
904       name = mk_const_Name("(unknown)");
905       if (sym->n_scnum == N_DEBUG && sym->n_sclass == C_FUN)
906          name = maybeDerefStrTab( sym, oi_debug, oi_n_debug );
907       else 
908       if (sym->n_sclass & DBXMASK)
909          name = mk_const_Name("(dbxstr)");
910       else
911          name = maybeDerefStrTab( sym, oi_strtab, oi_n_strtab);
912
913       if (0 && SHOW && SHOW_SYMS_P3) {
914          VG_(printf)("%5s(%2d)  %6s  0x%016llx ", 
915                      is_text ? "text" : is_data ? "data" : "other",
916                      (Int)sym->n_scnum, 
917                      name_of_syment_n_sclass(sym->n_sclass), 
918                      (ULong)sym->n_value);
919          print_Name(name);
920          VG_(printf)("\n");
921       }
922
923       i++;
924       i += sym->n_numaux;
925
926       /* --- BEGIN C_FILE [source file] --- */
927       /* There are two variants of C_FILE: a simple one with n_numaux
928          == 0, where the primary name is what we're after, and another
929          variant with n_numaux == 3, in which we have to hunt around
930          in the auxiliary entries to find the file name.  gcc produces
931          exclusively the first kind, and xlc a mixture of both. */
932       if (sym->n_sclass == C_FILE && sym->n_numaux == 0) {
933          if (!is_empty_Name(name))
934             FNAME_SET_TOP(name);
935          if (SHOW && SHOW_SYMS_P3) {
936             VG_(printf)("Phase3: %5d+%d  FILE      ",
937                         i-1-sym->n_numaux, (Int)sym->n_numaux );
938             print_Name(name);
939             VG_(printf)("\n");
940          }
941          continue;
942       }
943       if (sym->n_sclass == C_FILE && sym->n_numaux > 1 
944                                   && sym->n_numaux <= 5 /*stay sane*/) {
945          for (k = 0; k < sym->n_numaux; k++) {
946             aux = SYM_IX(oi_symtab, i - sym->n_numaux + k);
947             Name fname
948                = maybeDerefStrTab_fname( 
949                     (UChar*)&((AUXENT*)aux)->x_file.x_fname,
950                     oi_strtab, oi_n_strtab);
951             if (((AUXENT*)aux)->x_file._x.x_ftype == XFT_FN) {
952                if (!is_empty_Name(fname))
953                   FNAME_SET_TOP(fname);
954                if (SHOW && SHOW_SYMS_P3) {
955                   VG_(printf)("Phase3: %5d+%d  FILE      ",
956                               i-1-sym->n_numaux, (Int)sym->n_numaux );
957                   print_Name(fname);
958                   VG_(printf)("\n");
959                }
960                break;
961             }
962          }
963          continue;
964       }
965       /* --- END C_FILE [source file] --- */
966
967       /* --- BEGIN C_BINCL [beginning of include] --- */
968       if (sym->n_sclass == C_BINCL && sym->n_numaux == 0) {
969          FNAME_PUSH(name);
970          if (SHOW && SHOW_SYMS_P3)
971             VG_(printf)("Phase3: %5d+%d  BINCL     %s\n",
972                          i-1-sym->n_numaux, (Int)sym->n_numaux, 
973                          "fixme-Name-printing(3)" /*name*/ );
974          continue;
975       }
976       /* --- END C_BINCL [beginning of include] --- */
977
978       /* --- BEGIN C_EINCL [end of include] --- */
979       if (sym->n_sclass == C_EINCL && sym->n_numaux == 0) {
980          FNAME_POP;
981          if (SHOW && SHOW_SYMS_P3)
982             VG_(printf)("Phase3: %5d+%d  EINCL     %s\n",
983                          i-1-sym->n_numaux, (Int)sym->n_numaux, 
984                          "fixme-Name-printing(4)" /*name*/ );
985          continue;
986       }
987       /* --- END C_EINCL [end of include] --- */
988
989       /* everything else that is interesting is in the text
990          section. */
991       if (!is_text)
992          continue;
993  
994       /* --- BEGIN C_FCN(.bf) [function begin mark] --- */
995       if (sym->n_sclass == C_FCN 
996           && sym->n_numaux == 1 
997           && eq_string_Name(name, ".bf")) {
998          /* aux is BLOCK */
999          aux = SYM_IX(oi_symtab, i-1);
1000          Addr fn_start_avma = ((Addr)sym->n_value) + text_bias;
1001          Int  fn_start_lnno = ((AUXENT*)aux)->x_sym.x_misc.x_lnsz.x_lnno;
1002          /* Look in 'syms' to see if we have anything for address
1003             fn_avma. */
1004          XCoffSym key;
1005          VG_(memset)(&key, 0, sizeof(key));
1006          key.first = fn_start_avma;
1007          key.last  = fn_start_avma;
1008          Word ix_lo, ix_hi;
1009
1010          /* Search for all symbols intersecting fn_start_avma. */
1011          Bool found = VG_(lookupXA)(syms, &key, &ix_lo, &ix_hi);
1012          if (found) {
1013             /* All the 'syms' entries from ix_lo to ix_hi match. */
1014
1015             for (k = ix_lo; k <= ix_hi; k++) {
1016                XCoffSym* tsym = (XCoffSym*)VG_(indexXA)(syms,k);
1017
1018                /* note the start line number */
1019                if (tsym->slnno == 0 && fn_start_lnno > 0)
1020                   tsym->slnno = fn_start_lnno;
1021
1022                /* also the current filename, if we know it */
1023                if (is_empty_Name(tsym->fname) 
1024                    && !is_empty_Name(FNAME_GET_TOP)) 
1025                   tsym->fname = FNAME_GET_TOP;
1026
1027                /* remember the first in the range as the new current
1028                   (I've never seen a range with > 1) */
1029                if (k == ix_lo)
1030                   p3currsym = tsym;
1031                if (SHOW && SHOW_SYMS_P3) {
1032                    VG_(printf)("Phase3: %5d+%d  FCN(.bf)  0x%016llx  "
1033                                "lnno=%-4d  ", 
1034                                i-1-sym->n_numaux, (Int)sym->n_numaux, 
1035                                (ULong)sym->n_value,
1036                                fn_start_lnno );
1037                    print_Name(tsym->name);
1038                    VG_(printf)("\n");
1039                    if (!is_empty_Name(tsym->fname)) {
1040                       VG_(printf)("Phase3:                    ");
1041                       print_Name(tsym->fname);
1042                       VG_(printf)("\n");
1043                    }
1044                }
1045             }
1046          }
1047          continue;
1048       }
1049       /* --- END C_FCN(.bf) [function begin mark] --- */
1050
1051       /* --- BEGIN C_FCN(.ef) [function end mark] --- */
1052       if (sym->n_sclass == C_FCN 
1053           && sym->n_numaux == 1 
1054           && eq_string_Name(name, ".ef")) {
1055          /* aux is BLOCK */
1056          aux = SYM_IX(oi_symtab, i-1);
1057          /* In this case the n_value field appears to give the address
1058             of the first insn following the end of the function.
1059             Hence the - 1. */
1060          Addr fn_end_avma = ((Addr)sym->n_value) + text_bias - 1;
1061          Int  fn_end_lnno = ((AUXENT*)aux)->x_sym.x_misc.x_lnsz.x_lnno;
1062
1063          if (p3currsym
1064              && fn_end_avma >= p3currsym->first
1065              && fn_end_avma <= p3currsym->last) {
1066             if (p3currsym->elnno == 0 && fn_end_lnno > 0)
1067                p3currsym->elnno = fn_end_lnno;
1068             if (SHOW && SHOW_SYMS_P3) {
1069                 VG_(printf)("Phase3: %5d+%d  FCN(.ef)  0x%016llx  "
1070                             "lnno=%-4d  ", 
1071                             i-1-sym->n_numaux, (Int)sym->n_numaux, 
1072                             (ULong)sym->n_value,
1073                             fn_end_lnno );
1074                 print_Name(p3currsym->name);
1075                 VG_(printf)("\n");
1076             }
1077             if (fn_end_avma < p3currsym->last) {
1078                /* also take the opportunity to trim the symbol's
1079                   length to something less than established by the
1080                   initial estimation done by Phases 1 and 2. */
1081                if (0) VG_(printf)("trim end from %#lx to %#lx\n", 
1082                                   p3currsym->last, fn_end_avma);
1083                p3currsym->last = fn_end_avma;
1084             }
1085          }
1086          continue;
1087       }
1088       /* --- END C_FCN(.ef) [function end mark] --- */
1089
1090    }
1091
1092    /* ----------------------------------------------------------
1093       Phase 4: read and enumerate the line number entries, if 
1094       there are any.  This depends on knowing the function start/end
1095       line numbers established in Phase 3.
1096       ---------------------------------------------------------- */
1097
1098    if (SHOW && SHOW_SYMS_P4) {
1099       VG_(printf)("--- BEGIN Phase4 (read line number info) ---\n");
1100       VG_(printf)("--- note: shown addresses are ACTUAL VMAs ---\n");
1101    }
1102
1103    /* Re-sort 'syms' using the compare-start-addresses ordering, so we
1104       can use that in subsequent searches. */
1105    VG_(setCmpFnXA)(syms, cmp_XCoffSym_by_start);
1106    VG_(sortXA)(syms);
1107
1108    if (oi_lnos && oi_nent_lnos > 0) {
1109
1110 #     if defined(VGP_ppc32_aix5)
1111       vg_assert(LINESZ == 6); /* XCOFF32 */
1112 #     elif defined(VGP_ppc64_aix5)
1113       vg_assert(LINESZ == 12); /* XCOFF64 */
1114 #     else
1115 #     error "Unknown plat"
1116 #     endif
1117
1118 #     define LNO_IX(_tab,_n) \
1119          ((LINENO*)(((UChar*)(_tab)) + LINESZ * (_n)))
1120
1121       /* Current fn that we are processing line numbers for */
1122       XCoffSym* p4currsym = NULL;
1123
1124       /* SegInfo's string table pointer for p4currsym's file name.
1125          Allocated on demand, so as not to waste space in the
1126          SegInfo's string table. */
1127       UChar* si_fname_str = NULL;
1128
1129       /* Ditto the directory name, if we can manage it. */
1130       UChar* si_dname_str = NULL;
1131
1132       for (i = 0; i < oi_nent_lnos; i++) {
1133          LINENO* lno = LNO_IX(oi_lnos,i);
1134
1135          if (lno->l_lnno == 0) {
1136             /* New fn.  We get given the index in the symbol table of
1137                the relevant function.  It should be a C_EXT, C_WEAKEXT
1138                or C_HIDEXT flavour, according to the IBM docs. */
1139             Int sym_ix = (Int)lno->l_addr.l_symndx;
1140             sym = SYM_IX(oi_symtab, sym_ix);
1141             if (!(sym->n_sclass == C_EXT 
1142                   || sym->n_sclass == C_WEAKEXT 
1143                   || sym->n_sclass == C_HIDEXT))
1144                return "readxcoff.c: invalid symbol reference"
1145                       " in line number info";
1146             /* For these 3 symbol kinds, the n_value field is the
1147                symbol's stated VMA.  Convert this to an actual VMA and
1148                use that to find the associated XCoffSym. */
1149             Addr sym_avma = ((Addr)sym->n_value) + text_bias;
1150
1151             XCoffSym key;
1152             VG_(memset)(&key, 0, sizeof(key));
1153             key.first = sym_avma;
1154             Word ix_lo, ix_hi;
1155
1156             Bool found = VG_(lookupXA)(syms, &key, &ix_lo, &ix_hi);
1157             if (found) {
1158                /* All the 'syms' entries from ix_lo to ix_hi match.
1159                   Just use the lowest (sigh ..) */
1160                p4currsym = (XCoffSym*)VG_(indexXA)(syms, ix_lo);
1161             } else {
1162                /* We can't find the relevant sym, but we still have to
1163                   wade through the line number info for this function
1164                   until we get to the starting record for the next
1165                   one. */
1166                p4currsym = NULL;
1167             }
1168
1169             /* If we decide to add any line info for this fn to the
1170                SegInfo, we'll allocate this.  Otherwise don't
1171                bother. */
1172             si_fname_str = NULL;
1173             si_dname_str = NULL;
1174
1175             if (SHOW && SHOW_SYMS_P4) {
1176                VG_(printf)("Phase4: new fn (%d found), avma 0x%016llx  ", 
1177                            (Int)(ix_hi-ix_lo+1),
1178                            (ULong)sym_avma );
1179                if (p4currsym)
1180                   print_Name(p4currsym->name);
1181                else
1182                   VG_(printf)("UNKNOWN");
1183                VG_(printf)("\n");
1184             }
1185
1186          } else {
1187             /* Line number entry for the current fn. */
1188             if (!p4currsym)
1189                continue;
1190             Int line_no = (Int)(UInt)lno->l_lnno;
1191             line_no += (p4currsym->slnno - 1);
1192             Addr line_first_avma = ((Addr)lno->l_addr.l_paddr) + text_bias;
1193             if (line_first_avma < p4currsym->first
1194                 || line_first_avma > p4currsym->last)
1195                continue;
1196             Addr line_last_avma = p4currsym->last;
1197             /* Try to refine the last_avma by looking at the next
1198                line's entry. */
1199
1200             /* XXX: TODO.  What we have currently works only because
1201                the generic line number canonicaliser truncates
1202                overlapping address ranges in the way which we happen
1203                to need anyway. */
1204             if (SHOW && SHOW_SYMS_P4)
1205                VG_(printf)("Phase4:  line %d 0x%016llx - 0x%016llx\n", 
1206                            line_no, (ULong)line_first_avma, 
1207                                     (ULong)line_last_avma);
1208
1209             /* This now has to be allocated.  Try and figure out the
1210                dir name at the same time.  This is a bit ugly in that
1211                it involves messing with the string after it's been
1212                copied into the SegInfo's string table, but seems
1213                harmless enough. */
1214             if ((!si_fname_str) && !is_empty_Name(p4currsym->fname)) {
1215                si_dname_str = NULL;
1216                si_fname_str = ML_(addStr)(di, p4currsym->fname.vec,
1217                                               p4currsym->fname.len);
1218                UChar* lastslash = VG_(strrchr)(si_fname_str, '/');
1219                if (lastslash)
1220                   vg_assert(lastslash[0] == '/');
1221                if (lastslash[1] != 0) {
1222                   si_dname_str = si_fname_str;
1223                   lastslash[0] = 0; /* replace the / with a NUL
1224                                        terminator */
1225                   si_fname_str = lastslash+1;
1226                   if (0) VG_(printf)("XXX %s %s\n", si_dname_str, 
1227                                                     si_fname_str);
1228                }
1229             }
1230             /* finally .. */
1231             if (line_no >= 0)
1232                ML_(addLineInfo)(di, si_fname_str, si_dname_str,
1233                                 line_first_avma, line_last_avma+1,
1234                                 line_no, i/*debugging only*/);
1235          }
1236       }
1237
1238 #     undef LNO_IX
1239    }
1240
1241 #if defined(OFFICIAL_PHASE5)
1242    /* ----------------------------------------------------------
1243       Phase 5: Do another trawl of the XCOFF symbol table, looking
1244       for TOC entries for the entries we've already placed in 'syms'.
1245       ---------------------------------------------------------- */
1246
1247    if (SHOW && SHOW_SYMS_P5)
1248       VG_(printf)("--- BEGIN official Phase5 (find TOC pointers) ---\n");
1249
1250    Bool is_cfun;
1251
1252    i = 0;
1253    while (1) {
1254
1255       if (i >= oi_nent_symtab)
1256          break;
1257
1258       sym = SYM_IX(oi_symtab, i);
1259       is_text = sntext_1based_if_known != -1
1260                 && (Int)sym->n_scnum == sntext_1based_if_known;
1261       is_data = sndata_1based_if_known != -1
1262                 && (Int)sym->n_scnum == sndata_1based_if_known;
1263       is_cfun = sym->n_scnum == N_DEBUG 
1264                 && sym->n_sclass == C_FUN;
1265
1266       i++;
1267       i += sym->n_numaux;
1268
1269       if (!is_cfun && !is_data)
1270          continue;
1271
1272       if (SHOW && SHOW_SYMS_P5)
1273          VG_(printf)("Phase5o: %5d+%d  ", i-1-sym->n_numaux, 
1274                                           (Int)sym->n_numaux);
1275
1276       name = mk_const_Name("(unknown)");
1277       if (is_cfun)
1278          name = maybeDerefStrTab( sym, oi_debug, oi_n_debug );
1279       else 
1280       if (sym->n_sclass & DBXMASK)
1281          name = mk_const_Name("(dbxstr)");
1282       else
1283          name = maybeDerefStrTab( sym, oi_strtab, oi_n_strtab);
1284
1285       if (SHOW && SHOW_SYMS_P5) {
1286          VG_(printf)("%5s(%2d)  %6s  svma 0x%016llx ", 
1287                      is_text ? "text" : is_data ? "data" : "other",
1288                      (Int)sym->n_scnum, 
1289                      name_of_syment_n_sclass(sym->n_sclass), 
1290                      (ULong)sym->n_value);
1291          print_Name(name);
1292          VG_(printf)("\n");
1293       }
1294
1295       Addr avma = (Addr)sym->n_value + data_bias;
1296       if (0) VG_(printf)("data sym: avma %p, limits %p-%p\n", 
1297                          avma,  data_avma,data_avma + data_alen);
1298
1299       /* Does avma point to 3 valid words inside the actual data
1300          segment?  iow, can it possibly be a valid function
1301          descriptor?  If not, move on. */
1302       if (! (avma >= data_avma 
1303              && avma + 3 * sizeof(Word) <= data_avma + data_alen) )
1304          continue;
1305
1306       UWord* fndescr = (UWord*)avma;
1307
1308       if (SHOW && SHOW_SYMS_P5) 
1309           VG_(printf)("                  fndescr = {0x%lx,0x%lx}\n", 
1310                       fndescr[0], fndescr[1]);
1311
1312       /* Another check: fndescr[0], the entry point, must point inside
1313          the actual text segment.  Discard any that don't. */
1314
1315       Addr fndescr_0 = (Addr)fndescr[0];
1316       if (fndescr_0 < si->text_avma 
1317           || fndescr_0 >= si->text_avma+si->text_size)
1318          continue;
1319
1320       /* Let's suppose that fndescr is the descriptor for a
1321          function with name NAME.  If that's so, then 'syms'
1322          acquired by stage 2 should have an entry of name '.NAME'
1323          whose address is fndescr[0].  If so, then fndescr[1] must
1324          be the relevant r2 value for it. */
1325       /* Look in 'syms' to see if we have anything for address
1326          fndescr[0]. */
1327       XCoffSym key;
1328       VG_(memset)(&key, 0, sizeof(key));
1329       key.first = fndescr_0;
1330       Word ix_lo, ix_hi;
1331       Bool found = VG_(lookupXA)(syms, &key, &ix_lo, &ix_hi);
1332       if (found) {
1333          /* So all the 'syms' entries from ix_lo to ix_hi have an
1334             address which matches the entry point address stated in
1335             this descriptor.  For each one, as a final sanity
1336             check, see if the 'syms' entry has a name .NAME where
1337             NAME is that of the data symbol currently under
1338             consideration.  If so, it's a pretty good bet that this
1339             descriptor matches the text symbol we already have, and
1340             so we have a valid tocptr value from fndescr[1]. */
1341          for (k = ix_lo; k <= ix_hi; k++) {
1342             XCoffSym* tsym = (XCoffSym*)VG_(indexXA)(syms,k);
1343             vg_assert(!is_empty_Name(tsym->name));
1344             /* VG_(printf)("cmp %s %s\n", name, tsym->name); */
1345             /* VG_(printf)("found matching %d %s\n", k, tsym->name); */
1346             if (tsym->name.len == 1 + name.len
1347                 && tsym->name.vec[0] == '.'
1348                 && 0 == VG_(memcmp)(&tsym->name.vec[1],
1349                                     &name.vec[0], name.len)) {
1350                Addr r2val = fndescr[1];
1351                if (tsym->r2known) {
1352                   if (tsym->r2value != r2val)
1353                      /* COMPLAIN - conflicting r2 values*/ ;
1354                } else {
1355                   tsym->r2known = True;
1356                   tsym->r2value = r2val;
1357                }
1358             }
1359          }
1360       }
1361
1362    }
1363
1364 #else /* !defined(OFFICIAL_PHASE5) */
1365    /* ----------------------------------------------------------
1366       Alternative kludgey Phase 5: find TOC entries for 'syms' by the
1367       blunt-instrument approach of scanning the actual data section
1368       and noting anything that looks like a function descriptor.
1369       This is dangerous in the sense that if there are any 3 word
1370       structs which are not real function descriptors but just happen
1371       to look like them, then those will be included too.  
1372       Seems unlikely though.
1373       ---------------------------------------------------------- */
1374
1375    if (SHOW && SHOW_SYMS_P5)
1376       VG_(printf)("--- BEGIN kludged Phase5 (find TOC pointers) ---\n");
1377
1378    if (SHOW)
1379       VG_(printf)("Phase5: actual data segment: %#lx %#lx\n",
1380                   di->data_avma, di->data_avma + di->data_size);
1381
1382    /* Skip obviously-missing data sections. */
1383    if (di->data_avma != 0 && di->data_size >= sizeof(UWord)) {
1384
1385       /* set up for inspecting all the aligned words in the actual
1386          data section. */
1387
1388       Addr tmp = di->data_avma;
1389       while (tmp & (sizeof(UWord)-1))
1390          tmp++;
1391
1392       UWord* first_data_word = (UWord*)tmp;
1393       tmp = di->data_avma + di->data_size - sizeof(UWord);
1394       while (tmp & (sizeof(UWord)-1))
1395          tmp--;
1396       UWord* last_data_word = (UWord*)tmp;
1397
1398       if (SHOW) 
1399          VG_(printf)("Phase5: data segment conservatively aligned %p %p\n", 
1400                      first_data_word, last_data_word);
1401
1402       UWord* wP = first_data_word;
1403       UWord  w;
1404
1405       while (True) {
1406
1407          XCoffSym key;
1408          Word     ix_lo, ix_hi;
1409          Bool     found;
1410
1411          if (& wP[2] > last_data_word)
1412             break; /* no space left for a 3-word descriptor */
1413
1414          w = wP[0];
1415          if (!(w >= di->text_avma 
1416                && w < di->text_avma + di->text_size)) {
1417             wP++;
1418             continue; /* entry pointer is not to text segment */
1419          }
1420
1421          w = wP[1];
1422          if (!(w >= di->data_avma && w < di->data_avma + di->data_size)) {
1423             wP++;
1424             if (SHOW && SHOW_SYMS_P5) {
1425                VG_(memset)(&key, 0, sizeof(key));
1426                key.first = wP[0];
1427                found = VG_(lookupXA)(syms, &key, &ix_lo, &ix_hi);
1428                if (found) {
1429                   vg_assert(ix_lo <= ix_hi);
1430                   XCoffSym* tsym = (XCoffSym*)VG_(indexXA)(syms,ix_lo);
1431                   VG_(printf)("Phase5: bad tocptc at 0x%016llx={",
1432                               (ULong)(UWord)(wP-1));
1433                   print_Name(tsym->name);
1434                   VG_(printf)(",%p}\n", (void*)w);
1435                }
1436             }
1437             continue; /* r2 value does not point to data segment */
1438          }
1439
1440          /* ok, so wP might be a valid fn descr.  But does it point to
1441             a text symbol we know about?  Look in 'syms' to see if we
1442             have anything for wP[0]. */
1443          VG_(memset)(&key, 0, sizeof(key));
1444          key.first = wP[0];
1445          found = VG_(lookupXA)(syms, &key, &ix_lo, &ix_hi);
1446          if (found) {
1447             for (k = ix_lo; k <= ix_hi; k++) {
1448                XCoffSym* tsym = (XCoffSym*)VG_(indexXA)(syms,k);
1449                Addr r2val = wP[1];
1450                if (tsym->r2known) {
1451                   if (tsym->r2value != r2val)
1452                      /* COMPLAIN - conflicting r2 values*/ ;
1453                } else {
1454                   tsym->r2known = True;
1455                   tsym->r2value = r2val;
1456                   if (SHOW && SHOW_SYMS_P5) {
1457                      VG_(printf)("Phase5: found tocptr 0x%016llx for ", 
1458                                  (ULong)r2val);
1459                      print_Name(tsym->name);
1460                      VG_(printf)("\n");
1461                   }
1462                }
1463             }
1464          }
1465
1466          wP++;
1467       }
1468    }
1469
1470 #endif /* defined(OFFICIAL_PHASE5) */
1471
1472    /* ----------------------------------------------------------
1473       Phase 6: trivial: copy the syms out of 'syms' into the 
1474       generic debuginfo tables, and free up 'syms'.
1475       ---------------------------------------------------------- */
1476
1477    if (SHOW && SHOW_SYMS_P6) {
1478       VG_(printf)("--- BEGIN Phase6 (finalise symbol info) ---\n");
1479       VG_(printf)("--- note: shown addresses are ACTUAL VMAs ---\n");
1480    }
1481
1482    for (i = 0; i < nsyms; i++) {
1483       DiSym     dis;
1484       XCoffSym* s = (XCoffSym*)VG_(indexXA)(syms, i);
1485       Addr  addr = s->first;
1486       UWord size = s->last + 1 - s->first;
1487       Bool  guessed_toc = False;
1488
1489       /* If everything worked right, the symbol should fall within the
1490          mapped text segment.  Hence .. */
1491       Bool sane = addr >= di->text_avma 
1492                   && addr+size <= di->text_avma + di->text_size;
1493
1494       if (SHOW && SHOW_SYMS_P6) {
1495          VG_(printf)("Phase6: %s %3d  0x%08lx-0x%08lx  0x%08lx  ", 
1496                      sane ? "   " : "BAD",
1497                      i, 
1498                      addr,
1499                      addr + size - 1,
1500                      s->r2known ? s->r2value : 0 );
1501          print_Name(s->name);
1502          VG_(printf)("\n");
1503       }
1504
1505 #     if defined(VGP_ppc64_aix5)
1506       /* 64-bit kludge: if we can't find a plausible toc ptr just use
1507          the one specified in the XCOFF auxiliary header. */
1508       if ((!s->r2known)
1509           && toc_avma != 0
1510           && s->name.len > 8
1511           && 0==VG_(strncmp)(&s->name.vec[0], "._vgwZU_", 8)) {
1512          s->r2known = True;
1513          s->r2value = toc_avma;
1514          guessed_toc = True;
1515          if (SHOW && SHOW_SYMS_P6)
1516             VG_(printf)("Phase6: assuming toc 0x%08lx for above sym\n", 
1517                         s->r2value);
1518       }
1519 #     endif
1520
1521       /* Actually add the symbol (finallyatlast) */
1522       if (sane) {
1523          UInt nlen;
1524          dis.addr    = addr;
1525          dis.size    = size;
1526          dis.tocptr  = s->r2known ? s->r2value : 0;
1527          dis.isText  = True;
1528          dis.isIFunc = False;
1529          vg_assert(!is_empty_Name(s->name));
1530          nlen = s->name.len;
1531          vg_assert(nlen > 0);
1532          if (s->name.vec[0] == '.')
1533             dis.name = ML_(addStr)(di, &s->name.vec[1], nlen-1 );
1534          else
1535             dis.name = ML_(addStr)(di, &s->name.vec[0], nlen-0 );
1536          ML_(addSym)( di, &dis );
1537          if (0 && s->r2known)
1538             VG_(printf)("r2 known for %s\n",
1539                         "fixme-Name-printing(5)" /*s->name*/ );
1540
1541          if (guessed_toc)
1542             VG_(message)(Vg_DebugMsg, "WARNING: assuming toc 0x%lx for %s\n", 
1543                                       s->r2value, dis.name);
1544       }
1545    }
1546
1547    /* Free up the XA */
1548    VG_(deleteXA)(syms);
1549
1550 #  undef SYM_IX
1551
1552    return NULL; /*success*/
1553 }
1554
1555
1556 static void show_loader_section ( struct _DebugInfo* di,
1557                                   UChar* oi_start, UWord size )
1558 {
1559    Int i, j;
1560    LDHDR* hdr = (LDHDR*)oi_start;
1561    UChar* strtab_import = NULL;
1562    UChar* strtab_other  = NULL;
1563    if (SHOW) {
1564       VG_(printf)("   l_version           %llu\n", (ULong)hdr->l_version);
1565       VG_(printf)("   l_nsyms             %lld\n", (Long)hdr->l_nsyms);
1566       VG_(printf)("   l_nreloc            %lld\n", (Long)hdr->l_nreloc);
1567       VG_(printf)("   l_istlen (i st len) %lld\n", (Long)hdr->l_istlen);
1568       VG_(printf)("   l_impoff (i st off) %llu\n", (ULong)hdr->l_impoff);
1569       VG_(printf)("   l_nimpid (# imps)   %llu\n", (ULong)hdr->l_nimpid);
1570       VG_(printf)("   l_stlen  (st len)   %llu\n", (ULong)hdr->l_stlen);
1571       VG_(printf)("   l_stoff  (st off)   %llu\n", (ULong)hdr->l_stoff);
1572    }
1573
1574    if (hdr->l_istlen > 0)
1575       strtab_import = oi_start + hdr->l_impoff;
1576    if (hdr->l_stlen > 0)
1577       strtab_other = oi_start + hdr->l_stoff;
1578
1579    if (strtab_import) {
1580       if (SHOW)
1581          VG_(printf)("   Loader Import String Table: %llu bytes\n", 
1582                      (ULong)hdr->l_istlen);
1583       i = 0;
1584       j = 0;
1585       while (1) {
1586          if (i >= hdr->l_istlen)
1587             break;
1588          if (SHOW && SHOW_LD_STRTAB)
1589             VG_(printf)("     %3d%s ", i, (j%3)==0 ? "::" : "  ");
1590          j++;
1591          while (i < hdr->l_istlen && strtab_import[i]) {
1592             if (SHOW && SHOW_LD_STRTAB)
1593                VG_(printf)("%c", sanitiseChar(strtab_import[i]));
1594             i++;
1595          }
1596          i++;
1597          if (SHOW && SHOW_LD_STRTAB)
1598             VG_(printf)("\n");
1599       }
1600    }
1601
1602    if (strtab_other) {
1603       if (SHOW)
1604          VG_(printf)("   Loader Other String Table: %llu bytes\n", 
1605                      (ULong)hdr->l_stlen);
1606       i = 0;
1607       while (1) {
1608          int len = 0;
1609          if (i+1 >= hdr->l_stlen)
1610             break;
1611          len = (unsigned char)strtab_other[i];
1612          len <<= 8;
1613          len |= (unsigned char)strtab_other[i+1];
1614          i += 2;
1615          if (i >= hdr->l_stlen)
1616             break;
1617          if (SHOW && SHOW_LD_STRTAB)
1618             VG_(printf)("      %2d len %2d  ", i, len);
1619          while (len >= 0 && i < hdr->l_stlen && strtab_other[i]) {
1620             if (SHOW && SHOW_LD_STRTAB)
1621                VG_(printf)("%c", sanitiseChar(strtab_other[i]));
1622             i++;
1623             len--;
1624          }
1625          i++;
1626          if (SHOW && SHOW_LD_STRTAB)
1627             VG_(printf)("\n");
1628       }
1629    }
1630
1631    if (SHOW)
1632       VG_(printf)("   Loader Symbol Table: %lld entries\n", (Long)hdr->l_nsyms);
1633    LDSYM* sym = (LDSYM*)(oi_start + sizeof(LDHDR));
1634    for (i = 0; i < hdr->l_nsyms; i++) {
1635       Name name = maybeDerefStrTab( (SYMENT*)&sym[i],
1636                                     strtab_other, hdr->l_stlen );
1637       if (SHOW && SHOW_LD_SYMTAB) {
1638          VG_(printf)("      %2d:  %016llx  sec %d  ty 0x%02x  "
1639                      "scla 0x%02x  itab %d  ", 
1640                      i, (ULong)sym[i].l_value, (Int)sym[i].l_scnum, 
1641                      (Int)sym[i].l_smtype, (Int)sym[i].l_smclas,
1642                      (Int)sym[i].l_ifile);
1643          print_Name(name);
1644          VG_(printf)("\n");
1645       }
1646    }
1647
1648 #  if defined(VGP_ppc32_aix5)
1649    vg_assert(sizeof(LDREL) == 12);
1650 #  elif defined(VGP_ppc64_aix5)
1651    vg_assert(sizeof(LDREL) == 16);
1652 #  else
1653 #    error Unknown platform
1654 #  endif
1655
1656    LDREL* rel = (LDREL*)(&sym[hdr->l_nsyms]);
1657    if (SHOW)
1658       VG_(printf)("   Loader Relocation Table: %lld entries\n", 
1659                   (Long)hdr->l_nreloc);
1660    for (i = 0; i < hdr->l_nreloc; i++) {
1661       if (SHOW && SHOW_LD_RELTAB)
1662          VG_(printf)("      %3d:  va %016llx  sym %2lld  rty 0x%4x  sec %2d\n",
1663                      i, (ULong)rel[i].l_vaddr, (Long)rel[i].l_symndx, 
1664                         (Int)rel[i].l_rtype, (Int)rel[i].l_rsecnm);
1665    }
1666
1667    if (SHOW)
1668       VG_(printf)("\n");
1669 }
1670
1671
1672 /* Returns True on success, False on any kind of error. 
1673
1674    The object file from which to read symbols is mapped temporarily at
1675    [oimage .. oimage + n_oimage).
1676
1677    The VMA of where the relevant text section really got loaded (the
1678    "actual VMA", _avma) is [si->text_avma .. si->text_avma
1679    + si->text_size).
1680
1681    The VMA of the associated data section really got loaded
1682    (the "actual VMA", _avma) is [data_avma .. data_avma + data_alen).
1683
1684    We will need to peer at the loaded data section in order to make
1685    sense of TOC entries, hence we need to be assured it is mapped and
1686    readable.  m_aspacemgr should have given us that assurance, in the
1687    sense that data_avma/data_alen will be save to read in by the time
1688    we get here.
1689 */
1690 static 
1691 Bool read_xcoff_mapped_object ( struct _DebugInfo* di,
1692                                 UChar* oimage, UWord n_oimage )
1693 {
1694 #define BAD(_msg)  do { ML_(symerr)(di, True/*serious*/,_msg); \
1695                         return False; } while (0)
1696
1697    Int i, j;
1698
1699    /* The first byte after the oimage - we can't go here */
1700    UChar* oimage_after = oimage + n_oimage;
1701
1702    UChar* cursor = oimage;
1703
1704    /* ------------ File Header ------------ */
1705 #  if defined(VGP_ppc32_aix5)
1706    if (sizeof(FILHDR) != 20)
1707       BAD("readxcoff.c: invalid FILHDR size (32-bit)");
1708 #  elif defined(VGP_ppc64_aix5)
1709    if (sizeof(FILHDR) != 24)
1710       BAD("readxcoff.c: invalid FILHDR size (64-bit)");
1711 #  else
1712 #  error "Invalid platform"
1713 #  endif
1714
1715    if (n_oimage < sizeof(FILHDR))
1716       BAD("readxcoff.c: XCOFF object file header is implausibly small (2)");
1717
1718    FILHDR* t_filehdr = (FILHDR*)cursor;
1719    cursor += sizeof(FILHDR);
1720
1721    if (SHOW) {
1722       VG_(printf)("\nFile Header:\n");
1723       VG_(printf)("   magic             0x%04x (%s)\n", 
1724                   (UInt)t_filehdr->f_magic,
1725                   name_of_filhdr_f_magic(t_filehdr->f_magic));
1726    }
1727
1728 #  if defined(VGP_ppc32_aix5)
1729    if (t_filehdr->f_magic != 0x01DF /* XCOFF32 */)
1730       BAD("readxcoff.c: XCOFF32 object file header has invalid magic");
1731 #  elif defined(VGP_ppc64_aix5)
1732    if (t_filehdr->f_magic != 0x01F7 /* XCOFF64 */)
1733       BAD("readxcoff.c: XCOFF64 object file header has invalid magic");
1734 #  else
1735 #  error "Invalid platform"
1736 #  endif
1737
1738    if (SHOW) {
1739       VG_(printf)("   # of sections     %u\n",       (UInt)t_filehdr->f_nscns);
1740       VG_(printf)("   time/date         0x%08llx\n", (ULong)t_filehdr->f_timdat);
1741       VG_(printf)("   symtab foffset    %llu\n",     (ULong)t_filehdr->f_symptr);
1742       VG_(printf)("   # symtab entries  %llu\n",     (ULong)t_filehdr->f_nsyms);
1743       VG_(printf)("   size of aux hdr   %llu\n",     (ULong)t_filehdr->f_opthdr);
1744       VG_(printf)("   flags             0x%04x\n",   (UInt)t_filehdr->f_flags);
1745       if (t_filehdr->f_flags) {
1746          VG_(printf)("                     ");
1747          if (t_filehdr->f_flags & F_RELFLG)    VG_(printf)("NoRelocInfo ");
1748          if (t_filehdr->f_flags & F_EXEC)      VG_(printf)("IsExec ");
1749          if (t_filehdr->f_flags & F_LNNO)      VG_(printf)("NoLineInfo ");
1750          if (t_filehdr->f_flags & F_LSYMS)     VG_(printf)("LSYMS ");
1751          if (t_filehdr->f_flags & F_FDPR_PROF) VG_(printf)("FDPR_PROF ");
1752          if (t_filehdr->f_flags & F_FDPR_OPTI) VG_(printf)("FDPR_OPTI ");
1753          if (t_filehdr->f_flags & F_DSA)       VG_(printf)("LargeProc ");
1754 #        if defined(F_DEP_1)
1755          if (t_filehdr->f_flags & F_DEP_1)     VG_(printf)("DEP_1 ");
1756 #        endif
1757 #        if defined(F_VARPG)
1758          if (t_filehdr->f_flags & F_VARPG)     VG_(printf)("VARPG ");
1759 #        endif
1760          if (t_filehdr->f_flags & F_LPTEXT)    VG_(printf)("LPTEXT ");
1761          if (t_filehdr->f_flags & F_LPDATA)    VG_(printf)("LPDATA ");
1762          if (t_filehdr->f_flags & F_DYNLOAD)   VG_(printf)("Dynamic ");
1763          if (t_filehdr->f_flags & F_SHROBJ)    VG_(printf)("SharedObj ");
1764          if (t_filehdr->f_flags & F_LOADONLY)  VG_(printf)("LOADONLY ");
1765 #        if defined(F_DEP_2)
1766          if (t_filehdr->f_flags & F_DEP_2)     VG_(printf)("DEP_2 ");
1767 #        endif
1768          VG_(printf)("\n");
1769       }
1770    }
1771
1772    /* ------------ Auxiliary Header ------------ */
1773 #  if defined(VGP_ppc32_aix5)
1774    if (sizeof(AOUTHDR) != 72)
1775       BAD("readxcoff.c: invalid AOUTHDR size (32-bit)");
1776 #  elif defined(VGP_ppc64_aix5)
1777    if (sizeof(AOUTHDR) != 120)
1778       BAD("readxcoff.c: invalid AOUTHDR size (64-bit)");
1779 #  else
1780 #  error "Invalid platform"
1781 #  endif
1782
1783    Int sntext_1based_if_known = -1;
1784    Int sndata_1based_if_known = -1;
1785
1786    Addr  data_svma = 0; /* stated VMA of data section, if known */
1787    Bool  data_svma_known = False;
1788    Word  data_bias = 0;
1789    UWord data_alen_from_auxhdr = 0;
1790
1791    Addr  text_svma = 0; /* stated VMA of text section, if known */
1792    Bool  text_svma_known = False;
1793    Word  text_bias = 0;
1794
1795    Addr  toc_avma = 0; /* actual VMA of toc, if known */
1796    Addr  toc_svma = 0; /* stated VMA of toc, if known */
1797    Addr  toc_svma_known = False;
1798
1799    AOUTHDR* t_auxhdr = NULL;
1800    if (t_filehdr->f_opthdr > 0) {
1801       t_auxhdr = (AOUTHDR*)cursor;
1802       cursor += sizeof(AOUTHDR);
1803       sntext_1based_if_known = (Int)t_auxhdr->o_sntext;
1804       sndata_1based_if_known = (Int)t_auxhdr->o_sndata;
1805
1806       if (SHOW) {
1807          VG_(printf)("\nAuxiliary Header\n");
1808          VG_(printf)("   magic        0x%04x (should be 0x010b)\n", 
1809                      (UInt)t_auxhdr->magic);
1810          VG_(printf)("   vstamp       0x%04x\n", (UInt)t_auxhdr->vstamp);
1811          VG_(printf)("   tsize        %lld\n", (Long)t_auxhdr->tsize);
1812          VG_(printf)("   dsize        %lld\n", (Long)t_auxhdr->dsize);
1813          VG_(printf)("   bsize        %lld\n", (Long)t_auxhdr->bsize);
1814          VG_(printf)("   entry        0x%llx\n", (ULong)t_auxhdr->entry);
1815          VG_(printf)("   text_start   0x%llx (stated)\n",
1816                      (ULong)t_auxhdr->text_start);
1817          VG_(printf)("   data_start   0x%llx (stated)\n",
1818                      (ULong)t_auxhdr->data_start);
1819          VG_(printf)("   o_toc        0x%llx\n", (ULong)t_auxhdr->o_toc);
1820          VG_(printf)("   o_snentry    %d\n", (Int)t_auxhdr->o_snentry);
1821          VG_(printf)("   o_sntext     %d\n", (Int)t_auxhdr->o_sntext);
1822          VG_(printf)("   o_sndata     %d\n", (Int)t_auxhdr->o_sndata);
1823          VG_(printf)("   o_sntoc      %d\n", (Int)t_auxhdr->o_sntoc);
1824          VG_(printf)("   o_snloader   %d\n", (Int)t_auxhdr->o_snloader);
1825          VG_(printf)("   o_snbss      %d\n", (Int)t_auxhdr->o_snbss);
1826          VG_(printf)("   o_algntext   %d\n", (Int)t_auxhdr->o_algntext);
1827          VG_(printf)("   o_algndata   %d\n", (Int)t_auxhdr->o_algndata);
1828          VG_(printf)("   o_modtype    \"%c%c\"\n", 
1829                      (UChar)t_auxhdr->o_modtype[0],
1830                      (UChar)t_auxhdr->o_modtype[1] );
1831          VG_(printf)("   o_cpuflag    0x%02x\n", (UInt)t_auxhdr->o_cpuflag);
1832          VG_(printf)("   o_cputype    0x%02x\n", (UInt)t_auxhdr->o_cputype);
1833          VG_(printf)("   o_maxstack   %llu\n", (ULong)t_auxhdr->o_maxstack);
1834          VG_(printf)("   o_maxdata    %llu\n", (ULong)t_auxhdr->o_maxdata);
1835          VG_(printf)("   o_debugger   %u\n", t_auxhdr->o_debugger);
1836          /* printf("   o_textpsize  %u\n", (UInt)t_auxhdr->o_textpsize); */
1837          /* printf("   o_stackpsize %u\n", (UInt)t_auxhdr->o_stackpsize); */
1838       }
1839
1840       text_svma       = t_auxhdr->text_start;
1841       text_svma_known = True;
1842
1843       data_svma       = t_auxhdr->data_start;
1844       data_svma_known = True;
1845
1846       /* The auxhdr may claim the data section is longer than
1847          data_alen, so note the auxhdr-claimed size too. */
1848       data_alen_from_auxhdr = (UWord)t_auxhdr->dsize;
1849
1850       if (t_auxhdr->o_sntoc == t_auxhdr->o_sndata) {
1851          toc_svma       = (Addr)t_auxhdr->o_toc;
1852          toc_svma_known = True;
1853       }
1854    }
1855
1856    /* ------------ Section Headers ------------ */
1857 #  if defined(VGP_ppc32_aix5)
1858    if (sizeof(SCNHDR) != 40)
1859       BAD("readxcoff.c: invalid SCNHDR size (32-bit)");
1860 #  elif defined(VGP_ppc64_aix5)
1861    if (sizeof(SCNHDR) != 72)
1862       BAD("readxcoff.c: invalid SCNHDR size (64-bit)");
1863 #  else
1864 #  error "Invalid platform"
1865 #  endif
1866
1867    SCNHDR* t_scnhdr = (SCNHDR*)cursor;
1868
1869    if (SHOW)
1870       VG_(printf)("\nSection Headers: %d entries\n", t_filehdr->f_nscns);
1871
1872    /* Where the stabs strings are in the oimage */
1873    UChar* oi_debug   = NULL;
1874    UWord  oi_n_debug = 0;
1875
1876    /* Where the line number entries for the text section are
1877       in the oimage */
1878    UChar* oi_lnos      = NULL;
1879    UWord  oi_nent_lnos = 0; /* number of records */
1880
1881    for (i = 0; i < t_filehdr->f_nscns; i++) {
1882       UChar sname_safe[9];
1883       for (j = 0; j < 8; j++) 
1884          sname_safe[j] = t_scnhdr[i].s_name[j];
1885       sname_safe[8] = 0;
1886       if (SHOW) {
1887          VG_(printf)("   --- #%d ---\n", i);
1888          VG_(printf)("   s_name    %s\n", sname_safe);
1889          VG_(printf)("   s_paddr   0x%llx\n", (ULong)t_scnhdr[i].s_paddr);
1890          VG_(printf)("   s_vaddr   0x%llx\n", (ULong)t_scnhdr[i].s_vaddr);
1891          VG_(printf)("   s_size    %lld\n",   (Long)t_scnhdr[i].s_size);
1892          VG_(printf)("   s_scnptr  %lld\n",   (Long)t_scnhdr[i].s_scnptr);
1893          VG_(printf)("   s_relptr  %lld\n",   (Long)t_scnhdr[i].s_relptr);
1894          VG_(printf)("   s_lnnoptr %lld\n",   (Long)t_scnhdr[i].s_lnnoptr);
1895          VG_(printf)("   s_nreloc  %llu\n",   (ULong)t_scnhdr[i].s_nreloc);
1896          VG_(printf)("   s_nlnno   %llu\n",   (ULong)t_scnhdr[i].s_nlnno);
1897          VG_(printf)("   s_flags   0x%llx (%s)\n", 
1898                      (ULong)t_scnhdr[i].s_flags,
1899                      name_of_scnhdr_s_flags(t_scnhdr[i].s_flags));
1900       }
1901       /* find the stabs strings */
1902       if (t_scnhdr[i].s_flags == STYP_DEBUG) {
1903          oi_debug = oimage;
1904          oi_debug += (UWord)t_scnhdr[i].s_scnptr;
1905          oi_n_debug = (UWord)t_scnhdr[i].s_size;
1906       }
1907       /* find the line number entries for the text section */
1908       if (t_scnhdr[i].s_flags == STYP_TEXT && t_scnhdr[i].s_lnnoptr > 0) {
1909          oi_lnos = oimage;
1910          oi_lnos += (UWord)t_scnhdr[i].s_lnnoptr;
1911          oi_nent_lnos = (UWord)t_scnhdr[i].s_nlnno;
1912          /* XCOFF is clearly the result of years of kludgery, and
1913             here's one place it shows.  .s_nlnno is a 16-bit field, so
1914             if there are 65535 or more entries, they can't be
1915             represented here.  In that case, the real number is stored
1916             in a 32-bit field of a an "overflow section header" - a
1917             dummy section header which has no purpose other than to
1918             hold the correct count.  And then this kludge applies to
1919             XCOFF32, not XCOFF64. */
1920          if (t_scnhdr[i].s_nlnno == 0xFFFF 
1921              || t_scnhdr[i].s_nreloc == 0xFFFF) {
1922             /* have to test both fields, according to the docs */
1923             /* find the relevant overflow header */
1924             for (j = 0; j < t_filehdr->f_nscns; j++)
1925                if (t_scnhdr[j].s_flags == STYP_OVRFLO 
1926                    && t_scnhdr[j].s_nlnno == i+1 /* ref to correct scn? */
1927                    && t_scnhdr[j].s_nreloc == i+1 /* also must check this */)
1928                   break;
1929             vg_assert(j >= 0 && j <= t_filehdr->f_nscns);
1930             if (j == t_filehdr->f_nscns)
1931                /* Hmm.  We're hosed.  Give up. */
1932                BAD("readxcoff.c: can't find a required "
1933                    "overflow section header");
1934             /* finally, we have the real count. */
1935             oi_nent_lnos = (UWord)t_scnhdr[j].s_vaddr;
1936          }
1937       }
1938       cursor += sizeof(SCNHDR);
1939    }
1940    if (SHOW) {
1941       VG_(printf)("\n   debug image (stabs strings) at %p size %ld bytes\n", 
1942                   oi_debug, oi_n_debug);
1943       VG_(printf)("   line number info at %p with %ld entries\n",
1944                   oi_lnos, oi_nent_lnos);
1945    }
1946
1947    /* ------------ establish Text/data biases ------------ */
1948
1949    /* Calculate, into text_bias, the offset that has to be added to
1950       symbol table values (stated VMAs) so as to convert them to correct 
1951       addresses in the running image (actual VMAs).  I can't find any 
1952       documentation for this, so the following is determined empirically.
1953
1954       There appear to be two classes of loaded object:
1955
1956       .o files.  These have a stated text VMA of zero, and so their
1957          symbols start from zero and work upwards.  In that case the
1958          bias is precisely the offset where the text section is 
1959          loaded (si->text_avma), that is, the actual text VMA.
1960
1961          Except -- cryptically -- /usr/include/sys/ldr.h says that the
1962          ld_info.ldinfo_textorg field is "start of loaded program
1963          image (includes the XCOFF headers)".  And so to get the
1964          correct text bias it is necessary (determined empirically) to
1965          add on the file offset for the text section.  I guess this
1966          means that (1) it is assumed the text section is always the
1967          first in the file, and (2) in this case the stated text VMA
1968          is where the start of the file is mapped, not the start of
1969          the text section.
1970
1971          Last verified 24 May 06.
1972
1973       .so files, and executables.  These have a non-zero stated text 
1974          VMA, for example 0x10000150.  They appear to get loaded at some
1975          arbitrary address (actual VMA) which is always a whole number 
1976          of pages, eg 0x20002000, and in such a way that the offset is 
1977          a whole number of pages.  So in this example the offset (bias) 
1978          would be 0x20002000 - round_to_page_base(0x10000150).
1979    */
1980    if (text_svma_known) {
1981 #if 0
1982       if (text_svma == 0) {
1983          text_bias = di->text_avma;
1984          if (sntext_1based_if_known >= 1 
1985              && sntext_1based_if_known <= t_filehdr->f_nscns)
1986             text_bias += t_scnhdr[sntext_1based_if_known - 1].s_scnptr;
1987       } else {
1988          text_bias = di->text_avma - VG_PGROUNDDN(text_svma);
1989       }
1990 #else
1991       text_bias = di->text_avma - text_svma;
1992       if (sntext_1based_if_known >= 1 
1993           && sntext_1based_if_known <= t_filehdr->f_nscns)
1994          text_bias += t_scnhdr[sntext_1based_if_known - 1].s_scnptr;
1995
1996 #endif
1997       if (SHOW)
1998          VG_(printf)("   text section: stated vma 0x%lx, "
1999                      "actual vma 0x%lx, bias 0x%lx\n", 
2000                      text_svma, di->text_avma, text_bias);
2001    } else {
2002       text_bias = 0;
2003       if (SHOW)
2004          VG_(printf)("   text section: svma UNKNOWN, bias UNKNOWN\n");
2005    }
2006
2007    if (data_svma_known) {
2008       data_bias = di->data_avma - data_svma;
2009       if (SHOW)
2010          VG_(printf)("   data section: stated vma 0x%lx, "
2011                      "actual vma 0x%lx, bias 0x%lx\n", 
2012                      data_svma, di->data_avma, data_bias);
2013    } else {
2014       data_bias = 0;
2015       if (SHOW)
2016          VG_(printf)("   data section: svma UNKNOWN, bias UNKNOWN\n");
2017    }
2018
2019    if (toc_svma_known) {
2020       toc_avma = toc_svma + data_bias;
2021       if (SHOW)
2022          VG_(printf)("            toc: stated vma 0x%lx, actual vma 0x%lx\n",
2023                      toc_svma, toc_avma);
2024    } else {
2025       if (SHOW)
2026          VG_(printf)("            toc: svma UNKNOWN\n");
2027      toc_avma = 0;
2028    }
2029
2030    /* ------------ Section Data ------------ */
2031    for (i = 0; i < t_filehdr->f_nscns; i++) {
2032       if (SHOW)
2033          VG_(printf)("\nSection Data (sec %d, \"%s\")\n", 
2034                      i, name_of_scnhdr_s_flags(t_scnhdr[i].s_flags) );
2035       switch (t_scnhdr[i].s_flags & 0xFFFF) {
2036          case STYP_LOADER:
2037             show_loader_section( di, oimage + t_scnhdr[i].s_scnptr, 
2038                                  t_scnhdr[i].s_size );
2039             break;
2040          default:
2041             if (SHOW)
2042                VG_(printf)("   Not handled yet\n");
2043             break;
2044       }
2045    }
2046
2047    /* ------------ establish String Table ------------ */
2048    /* This is after the symbol table, if it exists at all. */
2049    /* This is a bit of a hack.  The easy way to find the string table
2050       is assume it immediately follows the symbol table.  That doesn't
2051       work if there is no symbol table; but on the other hand if there
2052       is no symbol table then there isn't much point in carrying on.
2053       Hence, if there is no symbol table we just give up here and
2054       claim to have successfully loaded zero symbols. */
2055    if (t_filehdr->f_nsyms == 0) {
2056       if (SHOW)
2057          VG_(printf)("Object contains no symbols.  Stopping here.\n");
2058       return True;
2059    }
2060
2061    cursor = oimage;
2062    cursor += t_filehdr->f_symptr; /* symtab start */
2063    cursor += SYMESZ * t_filehdr->f_nsyms; /* strtab start */
2064    /* Does this fall inside the file image?  The first 4 bytes is the
2065       string table size, so we need to be able to see at least
2066       them. */
2067    UChar* oi_strtab   = NULL;
2068    UWord  oi_n_strtab = 0;
2069    if (cursor + 4 <= oimage_after) {
2070       oi_strtab = cursor;
2071       oi_n_strtab = (UWord)( *(UInt*)oi_strtab );
2072       if (0) {
2073          VG_(printf)("oimage       %p\n", oimage);
2074          VG_(printf)("oimage_after %p\n", oimage_after);
2075          VG_(printf)("cursor       %p\n", cursor);
2076       }
2077       if (oi_strtab + oi_n_strtab > oimage_after)
2078          BAD("readxcoff.c: string table exceeds image end");
2079    }
2080
2081    /* ------------ Symbol Table ------------ */
2082    if (SHOW)
2083       VG_(printf)("\nSymbol Table: %llu entries\n", (ULong)t_filehdr->f_nsyms);
2084    cursor = oimage;
2085    cursor += t_filehdr->f_symptr;
2086    HChar* badness = read_symbol_table( 
2087                        di,
2088                        cursor, t_filehdr->f_nsyms, 
2089                        oi_strtab, oi_n_strtab,
2090                        oi_debug, oi_n_debug,
2091                        oi_lnos,  oi_nent_lnos,
2092                        sntext_1based_if_known, sndata_1based_if_known,
2093                        data_alen_from_auxhdr,
2094                        toc_avma,
2095                        text_bias, data_bias 
2096                     );
2097    if (badness)
2098       BAD(badness);
2099    /* cursor not used after this point */
2100
2101    /* ------------ String Table ------------ */
2102    if (oi_strtab) {
2103       if (SHOW)
2104          VG_(printf)("\nString Table: %lu bytes\n", oi_n_strtab);
2105       i = 4;
2106       while (1) {
2107          if (i >= oi_n_strtab)
2108             break;
2109          if (SHOW && SHOW_STRTAB)
2110             VG_(printf)("  %5d  ", i);
2111          while (i < oi_n_strtab && oi_strtab[i]) {
2112             if (SHOW && SHOW_STRTAB)
2113                VG_(printf)("%c", sanitiseChar(oi_strtab[i]));
2114             i++;
2115          }
2116          i++;
2117          if (SHOW && SHOW_STRTAB)
2118             VG_(printf)("\n");
2119       }
2120    }
2121
2122    if (SHOW)
2123       VG_(printf)("\n");
2124    return True;
2125
2126 #undef BAD
2127 }
2128
2129
2130 static ULong ascii_to_ULong ( void* vbuf, Int nbuf )
2131 {
2132    Int    i;
2133    UChar  c;
2134    UChar* buf = (UChar*)vbuf;
2135    ULong  n = 0;
2136    for (i = 0; i < nbuf; i++) {
2137       c = buf[i];
2138       if (c >= '0' && c <= '9')
2139          n = 10ULL * n + (ULong)(c - '0');
2140    }
2141    return n;
2142 }
2143
2144
2145 /* Returns True on success, False if any kind of problem. */
2146 static
2147 Bool read_xcoff_o_or_a ( /*MOD*/struct _DebugInfo* di,
2148                          HChar* a_name, HChar* o_name )
2149 {
2150    UChar* image   = NULL;
2151    Word   n_image = 0;
2152    Bool   ok;
2153    Int    i;
2154    SysRes sr, fd;
2155
2156    struct vg_stat stat_buf;
2157
2158    vg_assert(o_name);
2159
2160    if (a_name == NULL) {
2161       /* This is just a plain XCOFF object file. */
2162
2163       sr = VG_(stat)( o_name, &stat_buf );
2164       if (sr.isError) {
2165          ML_(symerr)(di, True, "can't stat XCOFF object file");
2166          return False;
2167       }
2168
2169       n_image = stat_buf.st_size;
2170       if (SHOW && SHOW_AR_DETAILS)
2171          VG_(printf)("XCOFF object file size %ld\n", n_image);
2172       if (n_image <= 0) {
2173          ML_(symerr)(di, True, "implausible XCOFF object file size");
2174          return False;
2175       }
2176
2177       fd = VG_(open)( o_name, VKI_O_RDONLY, 0 );
2178       if (fd.isError) {
2179          ML_(symerr)(di, True, "can't open XCOFF object file");
2180          return False;
2181       }
2182
2183       sr = VG_(am_mmap_file_float_valgrind)(n_image, VKI_PROT_READ, 
2184                                                      fd.res, 0);
2185       VG_(close)(fd.res);
2186
2187       if (sr.isError) {
2188          ML_(symerr)(di, True, "can't mmap XCOFF object file");
2189          return False;
2190       }
2191
2192       image = (UChar*)sr.res;
2193       ok = read_xcoff_mapped_object( di, image, n_image );
2194       VG_(am_munmap_valgrind)( (Addr)image, n_image);
2195
2196       /* assert OK */
2197       return ok;
2198
2199    } else {
2200
2201       /* It's an XCOFF .a file ("ar file format, large").  Map the
2202          whole thing in, find the member specified by O_NAME, and read
2203          symbols from that. */
2204
2205       sr = VG_(stat)( a_name, &stat_buf );
2206       if (sr.isError) {
2207          ML_(symerr)(di, True, "can't stat XCOFF archive file");
2208          return False;
2209       }
2210
2211       n_image = stat_buf.st_size;
2212       if (SHOW && SHOW_AR_DETAILS)
2213          VG_(printf)("XCOFF archive file size %ld\n", n_image);
2214       if (n_image <= 0) {
2215          ML_(symerr)(di, True, "implausible XCOFF archive file size");
2216          return False;
2217       }
2218
2219       fd = VG_(open)( a_name, VKI_O_RDONLY, 0 );
2220       if (fd.isError) {
2221          ML_(symerr)(di, True, "can't open XCOFF archive file");
2222          return False;
2223       }
2224
2225       sr = VG_(am_mmap_file_float_valgrind)(n_image, VKI_PROT_READ,
2226                                                      fd.res, 0);
2227       VG_(close)(fd.res);
2228
2229       if (sr.isError) {
2230          ML_(symerr)(di, True, "can't mmap XCOFF archive file");
2231          return False;
2232       }
2233
2234       image = (UChar*)sr.res;
2235       ok = False;
2236
2237       /* Right.  Let's go looking for the requested object.  First, 
2238          peer at the archive's fixed header. */
2239
2240       if (n_image < sizeof(FL_HDR)) {
2241          ML_(symerr)(di, True, "XCOFF archive too small for fixed header");
2242          goto done;
2243       }
2244
2245       FL_HDR* fl_hdr = (FL_HDR*)image;
2246       if (SHOW && SHOW_AR_DETAILS) {
2247          VG_(printf)("magic:  %s\n", fl_hdr->fl_magic);
2248          VG_(printf)("memoff: %s\n", fl_hdr->fl_memoff);
2249          VG_(printf)("gstoff: %s\n", fl_hdr->fl_gstoff);
2250          VG_(printf)("gst64off: %s\n", fl_hdr->fl_gst64off);
2251       }
2252
2253       { UChar* s = (UChar*)&fl_hdr->fl_magic;
2254         if (s[0] == '<' && s[1] == 'b' && s[2] == 'i' 
2255             && s[3] == 'g' && s[4] == 'a' && s[5] == 'f' 
2256             && s[6] == '>' && s[7] == '\n') {
2257            /* ok */
2258         } else {
2259            ML_(symerr)(di, True, 
2260                        "Is not XCOFF 'big'-variant .a format archive");
2261            goto done;
2262         }
2263       }
2264
2265       /* Get a pointer to the member table entry. */
2266       UChar* mtabC = image + ascii_to_ULong(&fl_hdr->fl_memoff, 
2267                                             sizeof(fl_hdr->fl_memoff));
2268       AR_HDR* mt_hdr = (AR_HDR*)mtabC;
2269
2270       if (mtabC < image || mtabC + sizeof(AR_HDR) > image + n_image) {
2271          ML_(symerr)(di, True, 
2272                      "XCOFF archive member table header exceeds image");
2273          goto done;
2274       }
2275
2276       /* should be: backquote newline */
2277       if (mt_hdr->_ar_name.ar_name[0] != 0x60 /* backquote */
2278           || mt_hdr->_ar_name.ar_name[1] != 0x0A /* \n */) {
2279          ML_(symerr)(di, True, 
2280                      "XCOFF archive member table header is invalid");
2281          goto done;
2282       }
2283
2284       if (SHOW) {
2285          VG_(printf)("member table ar_size = %lld\n", 
2286                      ascii_to_ULong(&mt_hdr->ar_size,20));
2287          VG_(printf)("member table ar_namlen = %lld\n", 
2288                      ascii_to_ULong(&mt_hdr->ar_namlen,4));
2289       }
2290
2291       if (mtabC < image 
2292           || mtabC + sizeof(AR_HDR) 
2293                    + ascii_to_ULong(&mt_hdr->ar_size, 20) 
2294              > image + n_image) {
2295          ML_(symerr)(di, True, "XCOFF archive member table exceeds image");
2296          goto done;
2297       }
2298
2299       UChar* data = mtabC + sizeof(AR_HDR) 
2300                           + ascii_to_ULong(&mt_hdr->ar_namlen,4);
2301       /* ALIGN */
2302       if ( ((UWord)data) & 1 ) data++;
2303       if (SHOW)
2304          VG_(printf)("member table data = %p\n", data);
2305
2306       UInt nmembers = ascii_to_ULong(data, 20);
2307       if (SHOW)
2308           VG_(printf)("member table contains %d entries\n", nmembers);
2309       for (i = 0; i < nmembers; i++) {
2310          if (SHOW && SHOW_AR_DETAILS)
2311             VG_(printf)("   %d has off %d\n", 
2312                         i, (Int)ascii_to_ULong(data + 20 + 20*i, 20));
2313       }
2314
2315       UChar* p = data + 20 + 20*nmembers;
2316
2317       for (i = 0; i < nmembers; i++) {
2318
2319          if (0 != VG_(strcmp)(p, o_name))
2320             goto move_on;
2321
2322          UInt objoff = ascii_to_ULong(data + 20 + 20*i, 20);
2323
2324          if (SHOW && SHOW_AR_DETAILS)
2325             VG_(printf)("got offset = %u\n", objoff);
2326
2327          vg_assert(ok == False);
2328
2329          /* Sanity check the selected member */
2330          UChar* o_hdrC = image + objoff;
2331          if (o_hdrC + sizeof(AR_HDR) >= image + n_image) {
2332             ML_(symerr)(di, True, 
2333                         "XCOFF archive member header exceeds image");
2334             goto done;
2335          }
2336          AR_HDR* o_hdr  = (AR_HDR*)o_hdrC;
2337          UWord   o_size = (UWord)ascii_to_ULong(&o_hdr->ar_size, 20);
2338          UChar*  o_data = o_hdrC + sizeof(AR_HDR)
2339                                  + (UWord)ascii_to_ULong(&o_hdr->ar_namlen,4);
2340
2341          /* ALIGN */
2342          if ( ((UWord)o_data) & 1 ) o_data++;
2343
2344          if (SHOW)
2345             VG_(printf)("member data = %p, size = %ld\n", o_data, o_size);
2346
2347          if (!(o_data >= image && o_data + o_size <= image + n_image)) {
2348             ML_(symerr)(di, True, 
2349                         "XCOFF archive member exceeds image");
2350             goto done;
2351          }
2352
2353          if (o_size < sizeof(FILHDR)) {
2354             ML_(symerr)(di, True, 
2355                         "XCOFF object file header is implausibly small (1)");
2356             goto done;
2357          }
2358
2359          /* It's the right name, but need to also check the magic
2360             number, since some archives contain both a 32-bit and
2361             64-bit version of the same object. */
2362          FILHDR* t_filhdr = (FILHDR*)o_data;
2363 #        if defined(VGP_ppc32_aix5)
2364          if (t_filhdr->f_magic == 0x01F7 /* XCOFF64 */) {
2365             if (0)
2366                VG_(printf)("Skipping 64-bit archive on 32-bit platform\n");
2367             goto move_on;
2368          }
2369 #        elif defined(VGP_ppc64_aix5)
2370          if (t_filhdr->f_magic == 0x01DF /* XCOFF32 */) {
2371             if (0)
2372                VG_(printf)("Skipping 32-bit archive on 64-bit platform\n");
2373             goto move_on;
2374          }
2375 #        endif
2376
2377          if (SHOW && SHOW_AR_DETAILS)
2378             VG_(printf)("\nimage: %p-%p   object: %p-%p\n\n", 
2379                         image, image+n_image-1, o_data, o_data+o_size-1);
2380          ok = read_xcoff_mapped_object( di, o_data, o_size );
2381          goto done;
2382
2383          vg_assert(0);
2384          /* NOTREACHED */
2385
2386         move_on:
2387          while (*p) {
2388             if (SHOW && SHOW_AR_DETAILS)
2389                VG_(printf)("%c", *p);
2390             p++;
2391          }
2392          if (SHOW && SHOW_AR_DETAILS)
2393             VG_(printf)("\n");
2394          p++;
2395       }
2396
2397       vg_assert(i == nmembers);
2398       ML_(symerr)(di, True, "can't find object in XCOFF archive file");
2399
2400      done:
2401       if (image) {
2402          VG_(am_munmap_valgrind)( (Addr)image, n_image );
2403          /* assert munmap succeeded */
2404       }
2405       return ok;
2406
2407    }
2408 }
2409
2410
2411 /* Main entry point for XCOFF reading.  The following di fields must
2412    be filled in by the caller:
2413
2414      filename
2415      memname (optional)
2416      text_avma, text_size
2417      data_avma, data_size
2418
2419    and all other fields should be zeroed.
2420 */
2421 Bool ML_(read_xcoff_debug_info) ( struct _DebugInfo* di,
2422                                   Bool is_mainexe )
2423 {
2424    Bool ok;
2425
2426    if (VG_(clo_verbosity) > 1 || VG_(clo_trace_redir)) {
2427       if (di->memname) {
2428          VG_(message)(Vg_DebugMsg, "Reading syms from %s(%s) (%#lx)\n",
2429                       di->filename, di->memname, di->text_avma);
2430       } else {
2431          VG_(message)(Vg_DebugMsg, "Reading syms from %s (%#lx)\n",
2432                       di->filename, di->text_avma);
2433       }
2434    }
2435
2436    if (SHOW) {
2437       VG_(printf)("------------------- BEGIN read xcoff ------------------\n");
2438       VG_(printf)("---         file: %s\n",  di->filename);
2439       VG_(printf)("---          mem: %s\n",  di->memname ? di->memname  
2440                                                          : (UChar*)"(none)" );
2441       VG_(printf)("--- t actual vma: %#lx\n", di->text_avma);
2442       VG_(printf)("--- t actual len: %ld\n",  di->text_size);
2443       VG_(printf)("--- d actual vma: %#lx\n", di->data_avma);
2444       VG_(printf)("--- d actual len: %ld\n",  di->data_size);
2445    }
2446
2447    if (di->memname) {
2448       /* XCOFF .a file.  di->filename is its name, di->memname is the
2449          name of the required .o within it. */
2450       ok = read_xcoff_o_or_a( di, di->filename, di->memname );
2451    } else {
2452       /* no archive member name, so di->filename is an XCOFF object */
2453       ok = read_xcoff_o_or_a( di, NULL, di->filename );
2454    }
2455
2456    di->soname = NULL;
2457    if (ok) {
2458       if (is_mainexe) {
2459          di->soname = "NONE";
2460       } else {
2461          UChar* p = VG_(strrchr)(di->filename, '/');
2462          p = p  ? p+1  : di->filename;
2463          /* p points at the main filename */
2464          if (di->memname) {
2465             /* set the soname to "archive.a(member.o)" */
2466             Int nbytes = VG_(strlen)(p) + 1 + VG_(strlen)(di->memname) + 1 + 1;
2467             UChar* so = ML_(dinfo_zalloc)("di.readxcoff.rxdi.1", nbytes);
2468             vg_assert(so);
2469             VG_(sprintf)(so, "%s(%s)", p, di->memname);
2470             vg_assert(VG_(strlen)(so) == nbytes-1);
2471             di->soname = so;
2472          } else {
2473             /* no member name, hence soname = "archive.a" */
2474             di->soname = ML_(dinfo_strdup)("di.readxcoff.rxdi.2", p);
2475          }
2476       }
2477       if (SHOW)
2478          VG_(printf)("Setting soname to %s\n", di->soname);
2479    }
2480
2481    if (SHOW)
2482       VG_(printf)("------------------- END read xcoff ------------------\n\n");
2483
2484    return ok;
2485 }
2486
2487 #endif // defined(VGO_aix5)
2488
2489 /*--------------------------------------------------------------------*/
2490 /*--- end                                                          ---*/
2491 /*--------------------------------------------------------------------*/