1/* xcoff.c -- Get debug data from an XCOFF file for backtraces.
2   Copyright (C) 2012-2020 Free Software Foundation, Inc.
3   Adapted from elf.c.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
8
9    (1) Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11
12    (2) Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in
14    the documentation and/or other materials provided with the
15    distribution.
16
17    (3) The name of the author may not be used to
18    endorse or promote products derived from this software without
19    specific prior written permission.
20
21THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31POSSIBILITY OF SUCH DAMAGE.  */
32
33#include "config.h"
34
35#include <errno.h>
36#include <stdlib.h>
37#include <string.h>
38#include <sys/types.h>
39
40#ifdef HAVE_LOADQUERY
41#include <sys/ldr.h>
42#endif
43
44#include "backtrace.h"
45#include "internal.h"
46
47/* The configure script must tell us whether we are 32-bit or 64-bit
48   XCOFF.  We could make this code test and support either possibility,
49   but there is no point.  This code only works for the currently
50   running executable, which means that we know the XCOFF mode at
51   configure time.  */
52
53#if BACKTRACE_XCOFF_SIZE != 32 && BACKTRACE_XCOFF_SIZE != 64
54#error "Unknown BACKTRACE_XCOFF_SIZE"
55#endif
56
57/* XCOFF file header.  */
58
59#if BACKTRACE_XCOFF_SIZE == 32
60
61typedef struct {
62  uint16_t f_magic;
63  uint16_t f_nscns;
64  uint32_t f_timdat;
65  uint32_t f_symptr;
66  uint32_t f_nsyms;
67  uint16_t f_opthdr;
68  uint16_t f_flags;
69} b_xcoff_filhdr;
70
71#define XCOFF_MAGIC	0737
72
73#else /* BACKTRACE_XCOFF_SIZE != 32 */
74
75typedef struct {
76  uint16_t f_magic;
77  uint16_t f_nscns;
78  uint32_t f_timdat;
79  uint64_t f_symptr;
80  uint16_t f_opthdr;
81  uint16_t f_flags;
82  uint32_t f_nsyms;
83} b_xcoff_filhdr;
84
85#define XCOFF_MAGIC	0767
86
87#endif /* BACKTRACE_XCOFF_SIZE != 32 */
88
89#define F_SHROBJ	0x2000	/* File is a shared object.  */
90
91/* XCOFF section header.  */
92
93#if BACKTRACE_XCOFF_SIZE == 32
94
95typedef struct {
96  char s_name[8];
97  uint32_t s_paddr;
98  uint32_t s_vaddr;
99  uint32_t s_size;
100  uint32_t s_scnptr;
101  uint32_t s_relptr;
102  uint32_t s_lnnoptr;
103  uint16_t s_nreloc;
104  uint16_t s_nlnno;
105  uint32_t s_flags;
106} b_xcoff_scnhdr;
107
108#define _OVERFLOW_MARKER	65535
109
110#else /* BACKTRACE_XCOFF_SIZE != 32 */
111
112typedef struct {
113  char name[8];
114  uint64_t s_paddr;
115  uint64_t s_vaddr;
116  uint64_t s_size;
117  uint64_t s_scnptr;
118  uint64_t s_relptr;
119  uint64_t s_lnnoptr;
120  uint32_t s_nreloc;
121  uint32_t s_nlnno;
122  uint32_t s_flags;
123} b_xcoff_scnhdr;
124
125#endif /* BACKTRACE_XCOFF_SIZE != 32 */
126
127#define STYP_DWARF	0x10	/* DWARF debugging section.  */
128#define STYP_TEXT	0x20	/* Executable text (code) section.  */
129#define STYP_OVRFLO	0x8000	/* Line-number field overflow section.  */
130
131#define SSUBTYP_DWINFO	0x10000	/* DWARF info section.  */
132#define SSUBTYP_DWLINE	0x20000	/* DWARF line-number section.  */
133#define SSUBTYP_DWARNGE	0x50000	/* DWARF aranges section.  */
134#define SSUBTYP_DWABREV	0x60000	/* DWARF abbreviation section.  */
135#define SSUBTYP_DWSTR	0x70000	/* DWARF strings section.  */
136
137/* XCOFF symbol.  */
138
139#define SYMNMLEN	8
140
141#if BACKTRACE_XCOFF_SIZE == 32
142
143typedef struct {
144  union {
145    char _name[SYMNMLEN];
146    struct {
147      uint32_t _zeroes;
148      uint32_t _offset;
149    } _s;
150  } _u;
151#define n_name		_u._name
152#define n_zeroes	_u._s._zeroes
153#define n_offset_	_u._s._offset
154
155  uint32_t n_value;
156  int16_t  n_scnum;
157  uint16_t n_type;
158  uint8_t  n_sclass;
159  uint8_t  n_numaux;
160} __attribute__ ((packed)) b_xcoff_syment;
161
162#else /* BACKTRACE_XCOFF_SIZE != 32 */
163
164typedef struct {
165  uint64_t n_value;
166  uint32_t n_offset_;
167  int16_t  n_scnum;
168  uint16_t n_type;
169  uint8_t  n_sclass;
170  uint8_t  n_numaux;
171} __attribute__ ((packed)) b_xcoff_syment;
172
173#endif /* BACKTRACE_XCOFF_SIZE != 32 */
174
175#define SYMESZ	18
176
177#define C_EXT		2	/* External symbol.  */
178#define C_FCN		101	/* Beginning or end of function.  */
179#define C_FILE		103	/* Source file name.  */
180#define C_HIDEXT	107	/* Unnamed external symbol.  */
181#define C_BINCL		108	/* Beginning of include file.  */
182#define C_EINCL		109	/* End of include file.  */
183#define C_WEAKEXT	111	/* Weak external symbol.  */
184
185#define ISFCN(x)	((x) & 0x0020)
186
187/* XCOFF AUX entry.  */
188
189#define AUXESZ		18
190#define FILNMLEN	14
191
192typedef union {
193#if BACKTRACE_XCOFF_SIZE == 32
194  struct {
195    uint16_t pad;
196    uint16_t x_lnnohi;
197    uint16_t x_lnno;
198  } x_block;
199#else
200  struct {
201    uint32_t x_lnno;
202  } x_block;
203#endif
204  union {
205    char x_fname[FILNMLEN];
206    struct {
207      uint32_t x_zeroes;
208      uint32_t x_offset;
209      char     pad[FILNMLEN-8];
210      uint8_t  x_ftype;
211    } _x;
212  } x_file;
213#if BACKTRACE_XCOFF_SIZE == 32
214  struct {
215    uint32_t x_exptr;
216    uint32_t x_fsize;
217    uint32_t x_lnnoptr;
218    uint32_t x_endndx;
219  } x_fcn;
220#else
221  struct {
222    uint64_t x_lnnoptr;
223    uint32_t x_fsize;
224    uint32_t x_endndx;
225  } x_fcn;
226#endif
227  struct {
228    uint8_t pad[AUXESZ-1];
229    uint8_t x_auxtype;
230  } x_auxtype;
231} __attribute__ ((packed)) b_xcoff_auxent;
232
233/* XCOFF line number entry.  */
234
235#if BACKTRACE_XCOFF_SIZE == 32
236
237typedef struct {
238  union {
239    uint32_t l_symndx;
240    uint32_t l_paddr;
241  } l_addr;
242  uint16_t l_lnno;
243} b_xcoff_lineno;
244
245#define LINESZ	6
246
247#else /* BACKTRACE_XCOFF_SIZE != 32 */
248
249typedef struct {
250  union {
251    uint32_t l_symndx;
252    uint64_t l_paddr;
253  } l_addr;
254  uint32_t l_lnno;
255} b_xcoff_lineno;
256
257#define LINESZ	12
258
259#endif /* BACKTRACE_XCOFF_SIZE != 32 */
260
261#if BACKTRACE_XCOFF_SIZE == 32
262#define XCOFF_AIX_TEXTBASE	0x10000000u
263#else
264#define XCOFF_AIX_TEXTBASE	0x100000000ul
265#endif
266
267/* AIX big archive fixed-length header.  */
268
269#define AIAMAGBIG	"<bigaf>\n"
270
271typedef struct {
272  char fl_magic[8];	/* Archive magic string.  */
273  char fl_memoff[20];	/* Offset to member table.  */
274  char fl_gstoff[20];	/* Offset to global symbol table.  */
275  char fl_gst64off[20];	/* Offset to global symbol table for 64-bit objects.  */
276  char fl_fstmoff[20];	/* Offset to first archive member.  */
277  char fl_freeoff[20];	/* Offset to first member on free list.  */
278} b_ar_fl_hdr;
279
280/* AIX big archive file member header.  */
281
282typedef struct {
283  char ar_size[20];	/* File member size - decimal.  */
284  char ar_nxtmem[20];	/* Next member offset - decimal.  */
285  char ar_prvmem[20];	/* Previous member offset - decimal.  */
286  char ar_date[12];	/* File member date - decimal.  */
287  char ar_uid[12];	/* File member userid - decimal.  */
288  char ar_gid[12];	/* File member group id - decimal.  */
289  char ar_mode[12];	/* File member mode - octal.  */
290  char ar_namlen[4];	/* File member name length - decimal.  */
291  char ar_name[2];	/* Start of member name.  */
292} b_ar_hdr;
293
294
295/* Information we keep for an XCOFF symbol.  */
296
297struct xcoff_symbol
298{
299  /* The name of the symbol.  */
300  const char *name;
301  /* The address of the symbol.  */
302  uintptr_t address;
303  /* The size of the symbol.  */
304  size_t size;
305};
306
307/* Information to pass to xcoff_syminfo.  */
308
309struct xcoff_syminfo_data
310{
311  /* Symbols for the next module.  */
312  struct xcoff_syminfo_data *next;
313  /* The XCOFF symbols, sorted by address.  */
314  struct xcoff_symbol *symbols;
315  /* The number of symbols.  */
316  size_t count;
317};
318
319/* Information about an include file.  */
320
321struct xcoff_incl
322{
323  /* File name.  */
324  const char *filename;
325  /* Offset to first line number from the include file.  */
326  uintptr_t begin;
327  /* Offset to last line number from the include file.  */
328  uintptr_t end;
329};
330
331/* A growable vector of include files information.  */
332
333struct xcoff_incl_vector
334{
335  /* Memory.  This is an array of struct xcoff_incl.  */
336  struct backtrace_vector vec;
337  /* Number of include files.  */
338  size_t count;
339};
340
341/* A growable vector of functions information.  */
342
343struct xcoff_func
344{
345  /* PC.  */
346  uintptr_t pc;
347  /* The size of the function.  */
348  size_t size;
349  /* Function name.  */
350  const char *name;
351  /* File name.  */
352  const char *filename;
353  /* Pointer to first lnno entry.  */
354  uintptr_t lnnoptr;
355  /* Base address of containing section.  */
356  uintptr_t sect_base;
357  /* Starting source line number.  */
358  int lnno;
359};
360
361/* A growable vector of function information.  This is used while
362   reading the function symbols.  */
363
364struct xcoff_func_vector
365{
366  /* Memory.  This is an array of struct xcoff_func.  */
367  struct backtrace_vector vec;
368  /* Number of valid mappings.  */
369  size_t count;
370};
371
372/* The information we need to map a PC to a file and line.  */
373
374struct xcoff_fileline_data
375{
376  /* The data for the next file we know about.  */
377  struct xcoff_fileline_data *next;
378  /* Functions information.  */
379  struct xcoff_func_vector func_vec;
380  /* Include files information.  */
381  struct xcoff_incl_vector incl_vec;
382  /* Line numbers information.  */
383  const unsigned char *linenos;
384  size_t linenos_size;
385  uint64_t lnnoptr0;
386  /* Loader address.  */
387  uintptr_t base_address;
388};
389
390/* Information we gather for the DWARF sections we care about.  */
391
392struct dwsect_info
393{
394  /* Section file offset.  */
395  off_t offset;
396  /* Section size.  */
397  size_t size;
398  /* Section contents, after read from file.  */
399  const unsigned char *data;
400};
401
402/* A dummy callback function used when we can't find any debug info.  */
403
404static int
405xcoff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
406	       uintptr_t pc ATTRIBUTE_UNUSED,
407	       backtrace_full_callback callback ATTRIBUTE_UNUSED,
408	       backtrace_error_callback error_callback, void *data)
409{
410  error_callback (data, "no debug info in XCOFF executable", -1);
411  return 0;
412}
413
414/* A dummy callback function used when we can't find a symbol
415   table.  */
416
417static void
418xcoff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
419	      uintptr_t addr ATTRIBUTE_UNUSED,
420	      backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
421	      backtrace_error_callback error_callback, void *data)
422{
423  error_callback (data, "no symbol table in XCOFF executable", -1);
424}
425
426/* Compare struct xcoff_symbol for qsort.  */
427
428static int
429xcoff_symbol_compare (const void *v1, const void *v2)
430{
431  const struct xcoff_symbol *e1 = (const struct xcoff_symbol *) v1;
432  const struct xcoff_symbol *e2 = (const struct xcoff_symbol *) v2;
433
434  if (e1->address < e2->address)
435    return -1;
436  else if (e1->address > e2->address)
437    return 1;
438  else
439    return 0;
440}
441
442/* Compare an ADDR against an xcoff_symbol for bsearch.  */
443
444static int
445xcoff_symbol_search (const void *vkey, const void *ventry)
446{
447  const uintptr_t *key = (const uintptr_t *) vkey;
448  const struct xcoff_symbol *entry = (const struct xcoff_symbol *) ventry;
449  uintptr_t addr;
450
451  addr = *key;
452  if (addr < entry->address)
453    return -1;
454  else if ((entry->size == 0 && addr > entry->address)
455	   || (entry->size > 0 && addr >= entry->address + entry->size))
456    return 1;
457  else
458    return 0;
459}
460
461/* Add XDATA to the list in STATE.  */
462
463static void
464xcoff_add_syminfo_data (struct backtrace_state *state,
465			struct xcoff_syminfo_data *xdata)
466{
467  if (!state->threaded)
468    {
469      struct xcoff_syminfo_data **pp;
470
471      for (pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
472	   *pp != NULL;
473	   pp = &(*pp)->next)
474	;
475      *pp = xdata;
476    }
477  else
478    {
479      while (1)
480	{
481	  struct xcoff_syminfo_data **pp;
482
483	  pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
484
485	  while (1)
486	    {
487	      struct xcoff_syminfo_data *p;
488
489	      p = backtrace_atomic_load_pointer (pp);
490
491	      if (p == NULL)
492		break;
493
494	      pp = &p->next;
495	    }
496
497	  if (__sync_bool_compare_and_swap (pp, NULL, xdata))
498	    break;
499	}
500    }
501}
502
503/* Return the symbol name and value for an ADDR.  */
504
505static void
506xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr,
507	       backtrace_syminfo_callback callback,
508	       backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
509	       void *data)
510{
511  struct xcoff_syminfo_data *edata;
512  struct xcoff_symbol *sym = NULL;
513  const char *name;
514
515  if (!state->threaded)
516    {
517      for (edata = (struct xcoff_syminfo_data *) state->syminfo_data;
518	   edata != NULL;
519	   edata = edata->next)
520	{
521	  sym = ((struct xcoff_symbol *)
522		 bsearch (&addr, edata->symbols, edata->count,
523			  sizeof (struct xcoff_symbol), xcoff_symbol_search));
524	  if (sym != NULL)
525	    break;
526	}
527    }
528  else
529    {
530      struct xcoff_syminfo_data **pp;
531
532      pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
533      while (1)
534	{
535	  edata = backtrace_atomic_load_pointer (pp);
536	  if (edata == NULL)
537	    break;
538
539	  sym = ((struct xcoff_symbol *)
540		 bsearch (&addr, edata->symbols, edata->count,
541			  sizeof (struct xcoff_symbol), xcoff_symbol_search));
542	  if (sym != NULL)
543	    break;
544
545	  pp = &edata->next;
546	}
547    }
548
549  if (sym == NULL)
550    callback (data, addr, NULL, 0, 0);
551  else
552    {
553      name = sym->name;
554      /* AIX prepends a '.' to function entry points, remove it.  */
555      if (name && *name == '.')
556	++name;
557      callback (data, addr, name, sym->address, sym->size);
558    }
559}
560
561/* Return the name of an XCOFF symbol.  */
562
563static const char *
564xcoff_symname (const b_xcoff_syment *asym,
565	       const unsigned char *strtab, size_t strtab_size)
566{
567#if BACKTRACE_XCOFF_SIZE == 32
568  if (asym->n_zeroes != 0)
569    {
570      /* Make a copy as we will release the symtab view.  */
571      char name[SYMNMLEN+1];
572      strncpy (name, asym->n_name, SYMNMLEN);
573      name[SYMNMLEN] = '\0';
574      return strdup (name);
575    }
576#endif
577  if (asym->n_sclass & 0x80)
578    return NULL; /* .debug */
579  if (asym->n_offset_ >= strtab_size)
580    return NULL;
581  return (const char *) strtab + asym->n_offset_;
582}
583
584/* Initialize the symbol table info for xcoff_syminfo.  */
585
586static int
587xcoff_initialize_syminfo (struct backtrace_state *state,
588			  uintptr_t base_address,
589			  const b_xcoff_scnhdr *sects,
590			  const b_xcoff_syment *syms, size_t nsyms,
591			  const unsigned char *strtab, size_t strtab_size,
592			  backtrace_error_callback error_callback, void *data,
593			  struct xcoff_syminfo_data *sdata)
594{
595  size_t xcoff_symbol_count;
596  size_t xcoff_symbol_size;
597  struct xcoff_symbol *xcoff_symbols;
598  size_t i;
599  unsigned int j;
600
601  /* We only care about function symbols.  Count them.  */
602  xcoff_symbol_count = 0;
603  for (i = 0; i < nsyms; ++i)
604    {
605      const b_xcoff_syment *asym = &syms[i];
606      if ((asym->n_sclass == C_EXT || asym->n_sclass == C_HIDEXT
607	    || asym->n_sclass == C_WEAKEXT)
608	  && ISFCN (asym->n_type) && asym->n_numaux > 0 && asym->n_scnum > 0)
609	++xcoff_symbol_count;
610
611      i += asym->n_numaux;
612    }
613
614  xcoff_symbol_size = xcoff_symbol_count * sizeof (struct xcoff_symbol);
615  xcoff_symbols = ((struct xcoff_symbol *)
616		   backtrace_alloc (state, xcoff_symbol_size, error_callback,
617				    data));
618  if (xcoff_symbols == NULL)
619    return 0;
620
621  j = 0;
622  for (i = 0; i < nsyms; ++i)
623    {
624      const b_xcoff_syment *asym = &syms[i];
625      if ((asym->n_sclass == C_EXT || asym->n_sclass == C_HIDEXT
626	    || asym->n_sclass == C_WEAKEXT)
627	  && ISFCN (asym->n_type) && asym->n_numaux > 0 && asym->n_scnum > 0)
628	{
629	  const b_xcoff_auxent *aux = (const b_xcoff_auxent *) (asym + 1);
630	  xcoff_symbols[j].name = xcoff_symname (asym, strtab, strtab_size);
631	  xcoff_symbols[j].address = base_address + asym->n_value
632				   - sects[asym->n_scnum - 1].s_paddr;
633	  /* x_fsize will be 0 if there is no debug information.  */
634	  xcoff_symbols[j].size = aux->x_fcn.x_fsize;
635	  ++j;
636	}
637
638      i += asym->n_numaux;
639    }
640
641  backtrace_qsort (xcoff_symbols, xcoff_symbol_count,
642		   sizeof (struct xcoff_symbol), xcoff_symbol_compare);
643
644  sdata->next = NULL;
645  sdata->symbols = xcoff_symbols;
646  sdata->count = xcoff_symbol_count;
647
648  return 1;
649}
650
651/* Compare struct xcoff_func for qsort.  */
652
653static int
654xcoff_func_compare (const void *v1, const void *v2)
655{
656  const struct xcoff_func *fn1 = (const struct xcoff_func *) v1;
657  const struct xcoff_func *fn2 = (const struct xcoff_func *) v2;
658
659  if (fn1->pc < fn2->pc)
660    return -1;
661  else if (fn1->pc > fn2->pc)
662    return 1;
663  else
664    return 0;
665}
666
667/* Compare a PC against an xcoff_func for bsearch.  */
668
669static int
670xcoff_func_search (const void *vkey, const void *ventry)
671{
672  const uintptr_t *key = (const uintptr_t *) vkey;
673  const struct xcoff_func *entry = (const struct xcoff_func *) ventry;
674  uintptr_t pc;
675
676  pc = *key;
677  if (pc < entry->pc)
678    return -1;
679  else if ((entry->size == 0 && pc > entry->pc)
680	   || (entry->size > 0 && pc >= entry->pc + entry->size))
681    return 1;
682  else
683    return 0;
684}
685
686/* Compare struct xcoff_incl for qsort.  */
687
688static int
689xcoff_incl_compare (const void *v1, const void *v2)
690{
691  const struct xcoff_incl *in1 = (const struct xcoff_incl *) v1;
692  const struct xcoff_incl *in2 = (const struct xcoff_incl *) v2;
693
694  if (in1->begin < in2->begin)
695    return -1;
696  else if (in1->begin > in2->begin)
697    return 1;
698  else
699    return 0;
700}
701
702/* Find a lnnoptr in an include file.  */
703
704static int
705xcoff_incl_search (const void *vkey, const void *ventry)
706{
707  const uintptr_t *key = (const uintptr_t *) vkey;
708  const struct xcoff_incl *entry = (const struct xcoff_incl *) ventry;
709  uintptr_t lnno;
710
711  lnno = *key;
712  if (lnno < entry->begin)
713    return -1;
714  else if (lnno > entry->end)
715    return 1;
716  else
717    return 0;
718}
719
720/* Look for a PC in the function vector for one module.  On success,
721   call CALLBACK and return whatever it returns.  On error, call
722   ERROR_CALLBACK and return 0.  Sets *FOUND to 1 if the PC is found,
723   0 if not.  */
724
725static int
726xcoff_lookup_pc (struct backtrace_state *state ATTRIBUTE_UNUSED,
727		 struct xcoff_fileline_data *fdata, uintptr_t pc,
728		 backtrace_full_callback callback,
729		 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
730		 void *data, int *found)
731{
732  const struct xcoff_incl *incl, *bincl;
733  const struct xcoff_func *fn;
734  const b_xcoff_lineno *lineno;
735  const unsigned char *lineptr;
736  const char *function;
737  const char *filename;
738  uintptr_t lnnoptr, match;
739  uint32_t lnno = 0;
740
741  *found = 1;
742
743  if ((pc & 3) != 0)
744    ++pc;
745
746  /* Find the function first.  */
747  fn = ((struct xcoff_func *)
748	bsearch (&pc, fdata->func_vec.vec.base, fdata->func_vec.count,
749		 sizeof (struct xcoff_func), xcoff_func_search));
750  if (fn == NULL)
751    {
752      *found = 0;
753      return 0;
754    }
755
756  filename = fn->filename;
757
758  /* Find the line number next.  */
759
760  /* Skip first entry that points to symtab.  */
761  lnnoptr = fn->lnnoptr + LINESZ;
762  match = lnnoptr;
763
764  lineptr = fdata->linenos + (lnnoptr - fdata->lnnoptr0);
765  while (lineptr + LINESZ <= fdata->linenos + fdata->linenos_size)
766    {
767      lineno = (const b_xcoff_lineno *) lineptr;
768      if (lineno->l_lnno == 0)
769	break;
770      if (pc <= fdata->base_address + lineno->l_addr.l_paddr - fn->sect_base)
771	break;
772      match = lnnoptr;
773      lnno = lineno->l_lnno;
774
775      lnnoptr += LINESZ;
776      lineptr += LINESZ;
777    }
778
779  /* If part of a function other than the beginning comes from an
780     include file, the line numbers are absolute, rather than
781     relative to the beginning of the function.  */
782  incl = ((struct xcoff_incl *)
783	  bsearch (&match, fdata->incl_vec.vec.base,
784		   fdata->incl_vec.count, sizeof (struct xcoff_incl),
785		   xcoff_incl_search));
786  if (incl != NULL)
787    {
788      bincl = ((struct xcoff_incl *)
789	       bsearch (&fn->lnnoptr, fdata->incl_vec.vec.base,
790			fdata->incl_vec.count, sizeof (struct xcoff_incl),
791			xcoff_incl_search));
792      if (bincl != NULL && strcmp (incl->filename, bincl->filename) == 0)
793	{
794	  lnno += fn->lnno - 1;
795	}
796      filename = incl->filename;
797    }
798  else
799    {
800      lnno += fn->lnno - 1;
801    }
802
803  function = fn->name;
804  /* AIX prepends a '.' to function entry points, remove it.  */
805  if (function != NULL && *function == '.')
806    ++function;
807  return callback (data, pc, filename, lnno, function);
808}
809
810/* Return the file/line information for a PC using the XCOFF lineno
811   mapping we built earlier.  */
812
813static int
814xcoff_fileline (struct backtrace_state *state, uintptr_t pc,
815		backtrace_full_callback callback,
816		backtrace_error_callback error_callback, void *data)
817
818{
819  struct xcoff_fileline_data *fdata;
820  int found;
821  int ret;
822
823  if (!state->threaded)
824    {
825      for (fdata = (struct xcoff_fileline_data *) state->fileline_data;
826	   fdata != NULL;
827	   fdata = fdata->next)
828	{
829	  ret = xcoff_lookup_pc (state, fdata, pc, callback, error_callback,
830				 data, &found);
831	  if (ret != 0 || found)
832	    return ret;
833	}
834    }
835  else
836    {
837      struct xcoff_fileline_data **pp;
838
839      pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
840      while (1)
841	{
842	  fdata = backtrace_atomic_load_pointer (pp);
843	  if (fdata == NULL)
844	    break;
845
846	  ret = xcoff_lookup_pc (state, fdata, pc, callback, error_callback,
847				 data, &found);
848	  if (ret != 0 || found)
849	    return ret;
850
851	  pp = &fdata->next;
852	}
853    }
854
855  /* FIXME: See if any libraries have been dlopen'ed.  */
856
857  return callback (data, pc, NULL, 0, NULL);
858}
859
860/* Initialize the function vector info for xcoff_fileline.  */
861
862static int
863xcoff_initialize_fileline (struct backtrace_state *state,
864			   uintptr_t base_address,
865			   const b_xcoff_scnhdr *sects,
866			   const b_xcoff_syment *syms, size_t nsyms,
867			   const unsigned char *strtab, size_t strtab_size,
868			   const unsigned char *linenos, size_t linenos_size,
869			   uint64_t lnnoptr0,
870			   backtrace_error_callback error_callback, void *data)
871{
872  struct xcoff_fileline_data *fdata;
873  struct xcoff_func *fn;
874  const b_xcoff_syment *fsym;
875  const b_xcoff_auxent *aux;
876  const char *filename;
877  const char *name;
878  struct xcoff_incl *incl;
879  uintptr_t begin, end;
880  uintptr_t lnno, lnnoptr;
881  uint32_t fsize;
882  size_t i;
883
884  fdata = ((struct xcoff_fileline_data *)
885	   backtrace_alloc (state, sizeof (struct xcoff_fileline_data),
886			    error_callback, data));
887  if (fdata == NULL)
888    return 0;
889  memset (fdata, 0, sizeof *fdata);
890  fdata->base_address = base_address;
891  fdata->linenos = linenos;
892  fdata->linenos_size = linenos_size;
893  fdata->lnnoptr0 = lnnoptr0;
894
895  begin = 0;
896  filename = NULL;
897  fsym = NULL;
898  lnnoptr = 0;
899  fsize = 0;
900  for (i = 0; i < nsyms; ++i)
901    {
902      const b_xcoff_syment *asym = &syms[i];
903
904      switch (asym->n_sclass)
905	{
906	  case C_BINCL:
907	    begin = asym->n_value;
908	    break;
909
910	  case C_EINCL:
911	    if (begin == 0)
912	      break;
913	    end = asym->n_value;
914	    incl = ((struct xcoff_incl *)
915		    backtrace_vector_grow (state, sizeof (struct xcoff_incl),
916					   error_callback, data,
917					   &fdata->incl_vec.vec));
918	    if (incl != NULL)
919	      {
920		incl->filename = xcoff_symname (asym, strtab, strtab_size);
921		incl->begin = begin;
922		incl->end = end;
923		++fdata->incl_vec.count;
924	      }
925	    begin = 0;
926	    break;
927
928	  case C_FILE:
929	    filename = xcoff_symname (asym, strtab, strtab_size);
930	    if (filename == NULL)
931	      break;
932
933	    /* If the file auxiliary entry is not used, the symbol name is
934	       the name of the source file. If the file auxiliary entry is
935	       used, then the symbol name should be .file, and the first
936	       file auxiliary entry (by convention) contains the source
937	       file name.  */
938
939	    if (asym->n_numaux > 0 && strcmp (filename, ".file") == 0)
940	      {
941		aux = (const b_xcoff_auxent *) (asym + 1);
942		if (aux->x_file._x.x_zeroes != 0)
943		  {
944		    /* Make a copy as we will release the symtab view.  */
945		    char name[FILNMLEN+1];
946		    strncpy (name, aux->x_file.x_fname, FILNMLEN);
947		    name[FILNMLEN] = '\0';
948		    filename = strdup (name);
949		  }
950		else if (aux->x_file._x.x_offset < strtab_size)
951		  filename = (const char *) strtab + aux->x_file._x.x_offset;
952		else
953		  filename = NULL;
954	      }
955	    break;
956
957	  case C_EXT:
958	  case C_HIDEXT:
959	  case C_WEAKEXT:
960	    fsym = NULL;
961	    lnnoptr = 0;
962	    fsize = 0;
963	    if (!ISFCN (asym->n_type) || asym->n_numaux == 0
964		|| asym->n_scnum <= 0)
965	      break;
966	    if (filename == NULL)
967	      break;
968	    aux = (const b_xcoff_auxent *) (asym + 1);
969	    lnnoptr = aux->x_fcn.x_lnnoptr;
970	    if (lnnoptr < lnnoptr0
971		|| lnnoptr + LINESZ > lnnoptr0 + linenos_size)
972	      break;
973	    /* x_fsize will be 0 if there is no debug information.  */
974	    fsize = aux->x_fcn.x_fsize;
975	    fsym = asym;
976	    break;
977
978	  case C_FCN:
979	    if (asym->n_numaux == 0)
980	      break;
981	    if (fsym == NULL)
982	      break;
983	    name = xcoff_symname (asym, strtab, strtab_size);
984	    if (name == NULL || strcmp (name, ".bf") != 0)
985	      {
986		fsym = NULL;
987		break;
988	      }
989	    aux = (const b_xcoff_auxent *) (asym + 1);
990#if BACKTRACE_XCOFF_SIZE == 32
991	    lnno = (uint32_t) aux->x_block.x_lnnohi << 16
992		 | aux->x_block.x_lnno;
993#else
994	    lnno = aux->x_block.x_lnno;
995#endif
996	    fn = ((struct xcoff_func *)
997		  backtrace_vector_grow (state, sizeof (struct xcoff_func),
998					 error_callback, data,
999					 &fdata->func_vec.vec));
1000	    if (fn == NULL)
1001	      break;
1002	    fn->name = xcoff_symname (fsym, strtab, strtab_size);
1003	    fn->filename = filename;
1004	    fn->sect_base = sects[fsym->n_scnum - 1].s_paddr;
1005	    fn->pc = base_address + fsym->n_value - fn->sect_base;
1006	    fn->size = fsize;
1007	    fn->lnno = lnno;
1008	    fn->lnnoptr = lnnoptr;
1009	    ++fdata->func_vec.count;
1010	    break;
1011	}
1012
1013      i += asym->n_numaux;
1014    }
1015
1016  if (!backtrace_vector_release (state, &fdata->func_vec.vec, error_callback,
1017				 data))
1018    goto fail;
1019  backtrace_qsort (fdata->func_vec.vec.base, fdata->func_vec.count,
1020		   sizeof (struct xcoff_func), xcoff_func_compare);
1021
1022  if (!backtrace_vector_release (state, &fdata->incl_vec.vec, error_callback,
1023				 data))
1024    goto fail;
1025  backtrace_qsort (fdata->incl_vec.vec.base, fdata->incl_vec.count,
1026		   sizeof (struct xcoff_incl), xcoff_incl_compare);
1027
1028  if (!state->threaded)
1029    {
1030      struct xcoff_fileline_data **pp;
1031
1032      for (pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
1033	   *pp != NULL;
1034	   pp = &(*pp)->next)
1035	;
1036      *pp = fdata;
1037    }
1038  else
1039    {
1040      while (1)
1041	{
1042	  struct xcoff_fileline_data **pp;
1043
1044	  pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
1045
1046	  while (1)
1047	    {
1048	      struct xcoff_fileline_data *p;
1049
1050	      p = backtrace_atomic_load_pointer (pp);
1051
1052	      if (p == NULL)
1053		break;
1054
1055	      pp = &p->next;
1056	    }
1057
1058	  if (__sync_bool_compare_and_swap (pp, NULL, fdata))
1059	    break;
1060	}
1061    }
1062
1063  return 1;
1064
1065fail:
1066  return 0;
1067}
1068
1069/* Add the backtrace data for one XCOFF file.  Returns 1 on success,
1070   0 on failure (in both cases descriptor is closed).  */
1071
1072static int
1073xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
1074	   uintptr_t base_address, backtrace_error_callback error_callback,
1075	   void *data, fileline *fileline_fn, int *found_sym, int exe)
1076{
1077  struct backtrace_view fhdr_view;
1078  struct backtrace_view sects_view;
1079  struct backtrace_view linenos_view;
1080  struct backtrace_view syms_view;
1081  struct backtrace_view str_view;
1082  struct backtrace_view dwarf_view;
1083  b_xcoff_filhdr fhdr;
1084  const b_xcoff_scnhdr *sects;
1085  const b_xcoff_scnhdr *stext;
1086  uint64_t lnnoptr;
1087  uint32_t nlnno;
1088  off_t str_off;
1089  off_t min_offset;
1090  off_t max_offset;
1091  struct dwsect_info dwsect[DEBUG_MAX];
1092  size_t sects_size;
1093  size_t syms_size;
1094  int32_t str_size;
1095  int sects_view_valid;
1096  int linenos_view_valid;
1097  int syms_view_valid;
1098  int str_view_valid;
1099  int dwarf_view_valid;
1100  int magic_ok;
1101  int i;
1102  struct dwarf_sections dwarf_sections;
1103
1104  *found_sym = 0;
1105
1106  sects_view_valid = 0;
1107  linenos_view_valid = 0;
1108  syms_view_valid = 0;
1109  str_view_valid = 0;
1110  dwarf_view_valid = 0;
1111
1112  str_size = 0;
1113
1114  /* Map the XCOFF file header.  */
1115  if (!backtrace_get_view (state, descriptor, offset, sizeof (b_xcoff_filhdr),
1116			   error_callback, data, &fhdr_view))
1117    goto fail;
1118
1119  memcpy (&fhdr, fhdr_view.data, sizeof fhdr);
1120  magic_ok = (fhdr.f_magic == XCOFF_MAGIC);
1121
1122  backtrace_release_view (state, &fhdr_view, error_callback, data);
1123
1124  if (!magic_ok)
1125    {
1126      if (exe)
1127	error_callback (data, "executable file is not XCOFF", 0);
1128      goto fail;
1129    }
1130
1131  /* Verify object is of expected type.  */
1132  if ((exe && (fhdr.f_flags & F_SHROBJ))
1133      || (!exe && !(fhdr.f_flags & F_SHROBJ)))
1134    goto fail;
1135
1136  /* Read the section headers.  */
1137
1138  sects_size = fhdr.f_nscns * sizeof (b_xcoff_scnhdr);
1139
1140  if (!backtrace_get_view (state, descriptor,
1141			   offset + sizeof (fhdr) + fhdr.f_opthdr,
1142			   sects_size, error_callback, data, &sects_view))
1143    goto fail;
1144  sects_view_valid = 1;
1145  sects = (const b_xcoff_scnhdr *) sects_view.data;
1146
1147  /* FIXME: assumes only one .text section.  */
1148  for (i = 0; i < fhdr.f_nscns; ++i)
1149    if ((sects[i].s_flags & 0xffff) == STYP_TEXT)
1150      break;
1151  if (i == fhdr.f_nscns)
1152    goto fail;
1153
1154  stext = &sects[i];
1155
1156  /* AIX ldinfo_textorg includes the XCOFF headers.  */
1157  base_address = (exe ? XCOFF_AIX_TEXTBASE : base_address) + stext->s_scnptr;
1158
1159  lnnoptr = stext->s_lnnoptr;
1160  nlnno = stext->s_nlnno;
1161
1162#if BACKTRACE_XCOFF_SIZE == 32
1163  if (nlnno == _OVERFLOW_MARKER)
1164    {
1165      int sntext = i + 1;
1166      /* Find the matching .ovrflo section.  */
1167      for (i = 0; i < fhdr.f_nscns; ++i)
1168	{
1169	  if (((sects[i].s_flags & 0xffff) == STYP_OVRFLO)
1170	      && sects[i].s_nlnno == sntext)
1171	    {
1172	      nlnno = sects[i].s_vaddr;
1173	      break;
1174	    }
1175	}
1176    }
1177#endif
1178
1179  /* Read the symbol table and the string table.  */
1180
1181  if (fhdr.f_symptr != 0)
1182    {
1183      struct xcoff_syminfo_data *sdata;
1184
1185      /* Symbol table is followed by the string table.  The string table
1186	 starts with its length (on 4 bytes).
1187	 Map the symbol table and the length of the string table.  */
1188      syms_size = fhdr.f_nsyms * sizeof (b_xcoff_syment);
1189
1190      if (!backtrace_get_view (state, descriptor, offset + fhdr.f_symptr,
1191			       syms_size + 4, error_callback, data,
1192			       &syms_view))
1193	goto fail;
1194      syms_view_valid = 1;
1195
1196      memcpy (&str_size, syms_view.data + syms_size, 4);
1197
1198      str_off = fhdr.f_symptr + syms_size;
1199
1200      if (str_size > 4)
1201	{
1202	  /* Map string table (including the length word).  */
1203
1204	  if (!backtrace_get_view (state, descriptor, offset + str_off,
1205				   str_size, error_callback, data, &str_view))
1206	    goto fail;
1207	  str_view_valid = 1;
1208	}
1209
1210      sdata = ((struct xcoff_syminfo_data *)
1211	       backtrace_alloc (state, sizeof *sdata, error_callback, data));
1212      if (sdata == NULL)
1213	goto fail;
1214
1215      if (!xcoff_initialize_syminfo (state, base_address, sects,
1216				     syms_view.data, fhdr.f_nsyms,
1217				     str_view.data, str_size,
1218				     error_callback, data, sdata))
1219	{
1220	  backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
1221	  goto fail;
1222	}
1223
1224      *found_sym = 1;
1225
1226      xcoff_add_syminfo_data (state, sdata);
1227    }
1228
1229  /* Read all the DWARF sections in a single view, since they are
1230     probably adjacent in the file.  We never release this view.  */
1231
1232  min_offset = 0;
1233  max_offset = 0;
1234  memset (dwsect, 0, sizeof dwsect);
1235  for (i = 0; i < fhdr.f_nscns; ++i)
1236    {
1237      off_t end;
1238      int idx;
1239
1240      if ((sects[i].s_flags & 0xffff) != STYP_DWARF
1241	  || sects[i].s_size == 0)
1242	continue;
1243      /* Map DWARF section to array index.  */
1244      switch (sects[i].s_flags & 0xffff0000)
1245	{
1246	  case SSUBTYP_DWINFO:
1247	    idx = DEBUG_INFO;
1248	    break;
1249	  case SSUBTYP_DWLINE:
1250	    idx = DEBUG_LINE;
1251	    break;
1252	  case SSUBTYP_DWABREV:
1253	    idx = DEBUG_ABBREV;
1254	    break;
1255	  case SSUBTYP_DWARNGE:
1256	    idx = DEBUG_RANGES;
1257	    break;
1258	  case SSUBTYP_DWSTR:
1259	    idx = DEBUG_STR;
1260	    break;
1261	  default:
1262	    continue;
1263	}
1264      if (min_offset == 0 || (off_t) sects[i].s_scnptr < min_offset)
1265	min_offset = sects[i].s_scnptr;
1266      end = sects[i].s_scnptr + sects[i].s_size;
1267      if (end > max_offset)
1268	max_offset = end;
1269      dwsect[idx].offset = sects[i].s_scnptr;
1270      dwsect[idx].size = sects[i].s_size;
1271    }
1272  if (min_offset != 0 && max_offset != 0)
1273    {
1274      if (!backtrace_get_view (state, descriptor, offset + min_offset,
1275			       max_offset - min_offset,
1276			       error_callback, data, &dwarf_view))
1277	goto fail;
1278      dwarf_view_valid = 1;
1279
1280      for (i = 0; i < (int) DEBUG_MAX; ++i)
1281	{
1282	  if (dwsect[i].offset == 0)
1283	    dwsect[i].data = NULL;
1284	  else
1285	    dwsect[i].data = ((const unsigned char *) dwarf_view.data
1286			      + (dwsect[i].offset - min_offset));
1287	}
1288
1289      memset (&dwarf_sections, 0, sizeof dwarf_sections);
1290
1291      dwarf_sections.data[DEBUG_INFO] = dwsect[DEBUG_INFO].data;
1292      dwarf_sections.size[DEBUG_INFO] = dwsect[DEBUG_INFO].size;
1293#if BACKTRACE_XCOFF_SIZE == 32
1294      /* XXX workaround for broken lineoff */
1295      dwarf_sections.data[DEBUG_LINE] = dwsect[DEBUG_LINE].data - 4;
1296#else
1297      /* XXX workaround for broken lineoff */
1298      dwarf_sections.data[DEBUG_LINE] = dwsect[DEBUG_LINE].data - 12;
1299#endif
1300      dwarf_sections.size[DEBUG_LINE] = dwsect[DEBUG_LINE].size;
1301      dwarf_sections.data[DEBUG_ABBREV] = dwsect[DEBUG_ABBREV].data;
1302      dwarf_sections.size[DEBUG_ABBREV] = dwsect[DEBUG_ABBREV].size;
1303      dwarf_sections.data[DEBUG_RANGES] = dwsect[DEBUG_RANGES].data;
1304      dwarf_sections.size[DEBUG_RANGES] = dwsect[DEBUG_RANGES].size;
1305      dwarf_sections.data[DEBUG_STR] = dwsect[DEBUG_STR].data;
1306      dwarf_sections.size[DEBUG_STR] = dwsect[DEBUG_STR].size;
1307
1308      if (!backtrace_dwarf_add (state, 0, &dwarf_sections,
1309				1, /* big endian */
1310				NULL, /* altlink */
1311				error_callback, data, fileline_fn,
1312				NULL /* returned fileline_entry */))
1313	goto fail;
1314    }
1315
1316  /* Read the XCOFF line number entries if DWARF sections not found.  */
1317
1318  if (!dwarf_view_valid && fhdr.f_symptr != 0 && lnnoptr != 0)
1319    {
1320      size_t linenos_size = (size_t) nlnno * LINESZ;
1321
1322      /* We never release this view.  */
1323      if (!backtrace_get_view (state, descriptor, offset + lnnoptr,
1324			       linenos_size,
1325			       error_callback, data, &linenos_view))
1326	goto fail;
1327      linenos_view_valid = 1;
1328
1329      if (xcoff_initialize_fileline (state, base_address, sects,
1330				     syms_view.data, fhdr.f_nsyms,
1331				     str_view.data, str_size,
1332				     linenos_view.data, linenos_size,
1333				     lnnoptr, error_callback, data))
1334	*fileline_fn = xcoff_fileline;
1335    }
1336
1337  backtrace_release_view (state, &sects_view, error_callback, data);
1338  sects_view_valid = 0;
1339  if (syms_view_valid)
1340    backtrace_release_view (state, &syms_view, error_callback, data);
1341  syms_view_valid = 0;
1342
1343  /* We've read all we need from the executable.  */
1344  if (!backtrace_close (descriptor, error_callback, data))
1345    goto fail;
1346  descriptor = -1;
1347
1348  return 1;
1349
1350 fail:
1351  if (sects_view_valid)
1352    backtrace_release_view (state, &sects_view, error_callback, data);
1353  if (str_view_valid)
1354    backtrace_release_view (state, &str_view, error_callback, data);
1355  if (syms_view_valid)
1356    backtrace_release_view (state, &syms_view, error_callback, data);
1357  if (linenos_view_valid)
1358    backtrace_release_view (state, &linenos_view, error_callback, data);
1359  if (dwarf_view_valid)
1360    backtrace_release_view (state, &dwarf_view, error_callback, data);
1361  if (descriptor != -1 && offset == 0)
1362    backtrace_close (descriptor, error_callback, data);
1363  return 0;
1364}
1365
1366#ifdef HAVE_LOADQUERY
1367
1368/* Read an integer value in human-readable format from an AIX
1369   big archive fixed-length or member header.  */
1370
1371static int
1372xcoff_parse_decimal (const char *buf, size_t size, off_t *off)
1373{
1374  char str[32];
1375  char *end;
1376
1377  if (size >= sizeof str)
1378    return 0;
1379  memcpy (str, buf, size);
1380  str[size] = '\0';
1381  *off = strtol (str, &end, 10);
1382  if (*end != '\0' && *end != ' ')
1383    return 0;
1384
1385  return 1;
1386}
1387
1388/* Add the backtrace data for a member of an AIX big archive.
1389   Returns 1 on success, 0 on failure.  */
1390
1391static int
1392xcoff_armem_add (struct backtrace_state *state, int descriptor,
1393		 uintptr_t base_address, const char *member,
1394		 backtrace_error_callback error_callback, void *data,
1395		 fileline *fileline_fn, int *found_sym)
1396{
1397  struct backtrace_view view;
1398  b_ar_fl_hdr fl_hdr;
1399  const b_ar_hdr *ar_hdr;
1400  off_t off;
1401  off_t len;
1402  int memlen;
1403
1404  *found_sym = 0;
1405
1406  /* Map archive fixed-length header.  */
1407
1408  if (!backtrace_get_view (state, descriptor, 0, sizeof (b_ar_fl_hdr),
1409			   error_callback, data, &view))
1410    goto fail;
1411
1412  memcpy (&fl_hdr, view.data, sizeof (b_ar_fl_hdr));
1413
1414  backtrace_release_view (state, &view, error_callback, data);
1415
1416  if (memcmp (fl_hdr.fl_magic, AIAMAGBIG, 8) != 0)
1417    goto fail;
1418
1419  memlen = strlen (member);
1420
1421  /* Read offset of first archive member.  */
1422  if (!xcoff_parse_decimal (fl_hdr.fl_fstmoff, sizeof fl_hdr.fl_fstmoff, &off))
1423    goto fail;
1424  while (off != 0)
1425    {
1426      /* Map archive member header and member name.  */
1427
1428      if (!backtrace_get_view (state, descriptor, off,
1429			       sizeof (b_ar_hdr) + memlen,
1430			       error_callback, data, &view))
1431	break;
1432
1433      ar_hdr = (const b_ar_hdr *) view.data;
1434
1435      /* Read archive member name length.  */
1436      if (!xcoff_parse_decimal (ar_hdr->ar_namlen, sizeof ar_hdr->ar_namlen,
1437				&len))
1438	{
1439	  backtrace_release_view (state, &view, error_callback, data);
1440	  break;
1441	}
1442      if (len == memlen && !memcmp (ar_hdr->ar_name, member, memlen))
1443	{
1444	  off = (off + sizeof (b_ar_hdr) + memlen + 1) & ~1;
1445
1446	  /* The archive can contain several members with the same name
1447	     (e.g. 32-bit and 64-bit), so continue if not ok.  */
1448
1449	  if (xcoff_add (state, descriptor, off, base_address, error_callback,
1450			 data, fileline_fn, found_sym, 0))
1451	    {
1452	      backtrace_release_view (state, &view, error_callback, data);
1453	      return 1;
1454	    }
1455	}
1456
1457      /* Read offset of next archive member.  */
1458      if (!xcoff_parse_decimal (ar_hdr->ar_nxtmem, sizeof ar_hdr->ar_nxtmem,
1459				&off))
1460	{
1461	  backtrace_release_view (state, &view, error_callback, data);
1462	  break;
1463	}
1464      backtrace_release_view (state, &view, error_callback, data);
1465    }
1466
1467 fail:
1468  /* No matching member found.  */
1469  backtrace_close (descriptor, error_callback, data);
1470  return 0;
1471}
1472
1473/* Add the backtrace data for dynamically loaded libraries.  */
1474
1475static void
1476xcoff_add_shared_libs (struct backtrace_state *state,
1477		       backtrace_error_callback error_callback,
1478		       void *data, fileline *fileline_fn, int *found_sym)
1479{
1480  const struct ld_info *ldinfo;
1481  void *buf;
1482  unsigned int buflen;
1483  const char *member;
1484  int descriptor;
1485  int does_not_exist;
1486  int lib_found_sym;
1487  int ret;
1488
1489  /* Retrieve the list of loaded libraries.  */
1490
1491  buf = NULL;
1492  buflen = 512;
1493  do
1494    {
1495      buf = realloc (buf, buflen);
1496      if (buf == NULL)
1497	{
1498	  ret = -1;
1499	  break;
1500	}
1501      ret = loadquery (L_GETINFO, buf, buflen);
1502      if (ret == 0)
1503	break;
1504      buflen *= 2;
1505    }
1506  while (ret == -1 && errno == ENOMEM);
1507  if (ret != 0)
1508    {
1509      free (buf);
1510      return;
1511    }
1512
1513  ldinfo = (const struct ld_info *) buf;
1514  while ((const char *) ldinfo < (const char *) buf + buflen)
1515    {
1516      if (*ldinfo->ldinfo_filename != '/')
1517	goto next;
1518
1519      descriptor = backtrace_open (ldinfo->ldinfo_filename, error_callback,
1520				   data, &does_not_exist);
1521      if (descriptor < 0)
1522	goto next;
1523
1524      /* Check if it is an archive (member name not empty).  */
1525
1526      member = ldinfo->ldinfo_filename + strlen (ldinfo->ldinfo_filename) + 1;
1527      if (*member)
1528	{
1529	  xcoff_armem_add (state, descriptor,
1530			   (uintptr_t) ldinfo->ldinfo_textorg, member,
1531			   error_callback, data, fileline_fn, &lib_found_sym);
1532	}
1533      else
1534	{
1535	  xcoff_add (state, descriptor, 0, (uintptr_t) ldinfo->ldinfo_textorg,
1536		     error_callback, data, fileline_fn, &lib_found_sym, 0);
1537	}
1538      if (lib_found_sym)
1539	*found_sym = 1;
1540
1541 next:
1542      if (ldinfo->ldinfo_next == 0)
1543	break;
1544      ldinfo = (const struct ld_info *) ((const char *) ldinfo
1545					 + ldinfo->ldinfo_next);
1546    }
1547
1548    free (buf);
1549}
1550#endif /* HAVE_LOADQUERY */
1551
1552/* Initialize the backtrace data we need from an XCOFF executable.
1553   Returns 1 on success, 0 on failure.  */
1554
1555int
1556backtrace_initialize (struct backtrace_state *state,
1557		      const char *filename ATTRIBUTE_UNUSED, int descriptor,
1558		      backtrace_error_callback error_callback,
1559		      void *data, fileline *fileline_fn)
1560{
1561  int ret;
1562  int found_sym;
1563  fileline xcoff_fileline_fn = xcoff_nodebug;
1564
1565  ret = xcoff_add (state, descriptor, 0, 0, error_callback, data,
1566		   &xcoff_fileline_fn, &found_sym, 1);
1567  if (!ret)
1568    return 0;
1569
1570#ifdef HAVE_LOADQUERY
1571  xcoff_add_shared_libs (state, error_callback, data, &xcoff_fileline_fn,
1572			 &found_sym);
1573#endif
1574
1575  if (!state->threaded)
1576    {
1577      if (found_sym)
1578	state->syminfo_fn = xcoff_syminfo;
1579      else if (state->syminfo_fn == NULL)
1580	state->syminfo_fn = xcoff_nosyms;
1581    }
1582  else
1583    {
1584      if (found_sym)
1585	backtrace_atomic_store_pointer (&state->syminfo_fn, xcoff_syminfo);
1586      else
1587	(void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
1588					     xcoff_nosyms);
1589    }
1590
1591  if (!state->threaded)
1592    {
1593      if (state->fileline_fn == NULL || state->fileline_fn == xcoff_nodebug)
1594	*fileline_fn = xcoff_fileline_fn;
1595    }
1596  else
1597    {
1598      fileline current_fn;
1599
1600      current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
1601      if (current_fn == NULL || current_fn == xcoff_nodebug)
1602	*fileline_fn = xcoff_fileline_fn;
1603    }
1604
1605  return 1;
1606}
1607