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