xref: /netbsd-src/external/gpl3/gcc.old/dist/libbacktrace/xcoff.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
1 /* xcoff.c -- Get debug data from an XCOFF file for backtraces.
2    Copyright (C) 2012-2019 Free Software Foundation, Inc.
3    Adapted from elf.c.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
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 
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY 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 
61 typedef 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 
75 typedef 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 
95 typedef 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 
112 typedef 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 
143 typedef 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 
164 typedef 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 
192 typedef 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 
237 typedef 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 
249 typedef 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 
271 typedef 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 
282 typedef 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 
297 struct 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 
309 struct 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 
321 struct 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 
333 struct 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 
343 struct 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 
364 struct 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 
374 struct 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 /* An index of DWARF sections we care about.  */
391 
392 enum dwarf_section
393 {
394   DWSECT_INFO,
395   DWSECT_LINE,
396   DWSECT_ABBREV,
397   DWSECT_RANGES,
398   DWSECT_STR,
399   DWSECT_MAX
400 };
401 
402 /* Information we gather for the DWARF sections we care about.  */
403 
404 struct dwsect_info
405 {
406   /* Section file offset.  */
407   off_t offset;
408   /* Section size.  */
409   size_t size;
410   /* Section contents, after read from file.  */
411   const unsigned char *data;
412 };
413 
414 /* A dummy callback function used when we can't find any debug info.  */
415 
416 static int
417 xcoff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
418 	       uintptr_t pc ATTRIBUTE_UNUSED,
419 	       backtrace_full_callback callback ATTRIBUTE_UNUSED,
420 	       backtrace_error_callback error_callback, void *data)
421 {
422   error_callback (data, "no debug info in XCOFF executable", -1);
423   return 0;
424 }
425 
426 /* A dummy callback function used when we can't find a symbol
427    table.  */
428 
429 static void
430 xcoff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
431 	      uintptr_t addr ATTRIBUTE_UNUSED,
432 	      backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
433 	      backtrace_error_callback error_callback, void *data)
434 {
435   error_callback (data, "no symbol table in XCOFF executable", -1);
436 }
437 
438 /* Compare struct xcoff_symbol for qsort.  */
439 
440 static int
441 xcoff_symbol_compare (const void *v1, const void *v2)
442 {
443   const struct xcoff_symbol *e1 = (const struct xcoff_symbol *) v1;
444   const struct xcoff_symbol *e2 = (const struct xcoff_symbol *) v2;
445 
446   if (e1->address < e2->address)
447     return -1;
448   else if (e1->address > e2->address)
449     return 1;
450   else
451     return 0;
452 }
453 
454 /* Compare an ADDR against an xcoff_symbol for bsearch.  */
455 
456 static int
457 xcoff_symbol_search (const void *vkey, const void *ventry)
458 {
459   const uintptr_t *key = (const uintptr_t *) vkey;
460   const struct xcoff_symbol *entry = (const struct xcoff_symbol *) ventry;
461   uintptr_t addr;
462 
463   addr = *key;
464   if (addr < entry->address)
465     return -1;
466   else if ((entry->size == 0 && addr > entry->address)
467 	   || (entry->size > 0 && addr >= entry->address + entry->size))
468     return 1;
469   else
470     return 0;
471 }
472 
473 /* Add XDATA to the list in STATE.  */
474 
475 static void
476 xcoff_add_syminfo_data (struct backtrace_state *state,
477 			struct xcoff_syminfo_data *xdata)
478 {
479   if (!state->threaded)
480     {
481       struct xcoff_syminfo_data **pp;
482 
483       for (pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
484 	   *pp != NULL;
485 	   pp = &(*pp)->next)
486 	;
487       *pp = xdata;
488     }
489   else
490     {
491       while (1)
492 	{
493 	  struct xcoff_syminfo_data **pp;
494 
495 	  pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
496 
497 	  while (1)
498 	    {
499 	      struct xcoff_syminfo_data *p;
500 
501 	      p = backtrace_atomic_load_pointer (pp);
502 
503 	      if (p == NULL)
504 		break;
505 
506 	      pp = &p->next;
507 	    }
508 
509 	  if (__sync_bool_compare_and_swap (pp, NULL, xdata))
510 	    break;
511 	}
512     }
513 }
514 
515 /* Return the symbol name and value for an ADDR.  */
516 
517 static void
518 xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr,
519 	       backtrace_syminfo_callback callback,
520 	       backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
521 	       void *data)
522 {
523   struct xcoff_syminfo_data *edata;
524   struct xcoff_symbol *sym = NULL;
525   const char *name;
526 
527   if (!state->threaded)
528     {
529       for (edata = (struct xcoff_syminfo_data *) state->syminfo_data;
530 	   edata != NULL;
531 	   edata = edata->next)
532 	{
533 	  sym = ((struct xcoff_symbol *)
534 		 bsearch (&addr, edata->symbols, edata->count,
535 			  sizeof (struct xcoff_symbol), xcoff_symbol_search));
536 	  if (sym != NULL)
537 	    break;
538 	}
539     }
540   else
541     {
542       struct xcoff_syminfo_data **pp;
543 
544       pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
545       while (1)
546 	{
547 	  edata = backtrace_atomic_load_pointer (pp);
548 	  if (edata == NULL)
549 	    break;
550 
551 	  sym = ((struct xcoff_symbol *)
552 		 bsearch (&addr, edata->symbols, edata->count,
553 			  sizeof (struct xcoff_symbol), xcoff_symbol_search));
554 	  if (sym != NULL)
555 	    break;
556 
557 	  pp = &edata->next;
558 	}
559     }
560 
561   if (sym == NULL)
562     callback (data, addr, NULL, 0, 0);
563   else
564     {
565       name = sym->name;
566       /* AIX prepends a '.' to function entry points, remove it.  */
567       if (name && *name == '.')
568 	++name;
569       callback (data, addr, name, sym->address, sym->size);
570     }
571 }
572 
573 /* Return the name of an XCOFF symbol.  */
574 
575 static const char *
576 xcoff_symname (const b_xcoff_syment *asym,
577 	       const unsigned char *strtab, size_t strtab_size)
578 {
579 #if BACKTRACE_XCOFF_SIZE == 32
580   if (asym->n_zeroes != 0)
581     {
582       /* Make a copy as we will release the symtab view.  */
583       char name[SYMNMLEN+1];
584       strncpy (name, asym->n_name, SYMNMLEN);
585       name[SYMNMLEN] = '\0';
586       return strdup (name);
587     }
588 #endif
589   if (asym->n_sclass & 0x80)
590     return NULL; /* .debug */
591   if (asym->n_offset_ >= strtab_size)
592     return NULL;
593   return (const char *) strtab + asym->n_offset_;
594 }
595 
596 /* Initialize the symbol table info for xcoff_syminfo.  */
597 
598 static int
599 xcoff_initialize_syminfo (struct backtrace_state *state,
600 			  uintptr_t base_address,
601 			  const b_xcoff_scnhdr *sects,
602 			  const b_xcoff_syment *syms, size_t nsyms,
603 			  const unsigned char *strtab, size_t strtab_size,
604 			  backtrace_error_callback error_callback, void *data,
605 			  struct xcoff_syminfo_data *sdata)
606 {
607   size_t xcoff_symbol_count;
608   size_t xcoff_symbol_size;
609   struct xcoff_symbol *xcoff_symbols;
610   size_t i;
611   unsigned int j;
612 
613   /* We only care about function symbols.  Count them.  */
614   xcoff_symbol_count = 0;
615   for (i = 0; i < nsyms; ++i)
616     {
617       const b_xcoff_syment *asym = &syms[i];
618       if ((asym->n_sclass == C_EXT || asym->n_sclass == C_HIDEXT
619 	    || asym->n_sclass == C_WEAKEXT)
620 	  && ISFCN (asym->n_type) && asym->n_numaux > 0 && asym->n_scnum > 0)
621 	++xcoff_symbol_count;
622 
623       i += asym->n_numaux;
624     }
625 
626   xcoff_symbol_size = xcoff_symbol_count * sizeof (struct xcoff_symbol);
627   xcoff_symbols = ((struct xcoff_symbol *)
628 		   backtrace_alloc (state, xcoff_symbol_size, error_callback,
629 				    data));
630   if (xcoff_symbols == NULL)
631     return 0;
632 
633   j = 0;
634   for (i = 0; i < nsyms; ++i)
635     {
636       const b_xcoff_syment *asym = &syms[i];
637       if ((asym->n_sclass == C_EXT || asym->n_sclass == C_HIDEXT
638 	    || asym->n_sclass == C_WEAKEXT)
639 	  && ISFCN (asym->n_type) && asym->n_numaux > 0 && asym->n_scnum > 0)
640 	{
641 	  const b_xcoff_auxent *aux = (const b_xcoff_auxent *) (asym + 1);
642 	  xcoff_symbols[j].name = xcoff_symname (asym, strtab, strtab_size);
643 	  xcoff_symbols[j].address = base_address + asym->n_value
644 				   - sects[asym->n_scnum - 1].s_paddr;
645 	  /* x_fsize will be 0 if there is no debug information.  */
646 	  xcoff_symbols[j].size = aux->x_fcn.x_fsize;
647 	  ++j;
648 	}
649 
650       i += asym->n_numaux;
651     }
652 
653   backtrace_qsort (xcoff_symbols, xcoff_symbol_count,
654 		   sizeof (struct xcoff_symbol), xcoff_symbol_compare);
655 
656   sdata->next = NULL;
657   sdata->symbols = xcoff_symbols;
658   sdata->count = xcoff_symbol_count;
659 
660   return 1;
661 }
662 
663 /* Compare struct xcoff_func for qsort.  */
664 
665 static int
666 xcoff_func_compare (const void *v1, const void *v2)
667 {
668   const struct xcoff_func *fn1 = (const struct xcoff_func *) v1;
669   const struct xcoff_func *fn2 = (const struct xcoff_func *) v2;
670 
671   if (fn1->pc < fn2->pc)
672     return -1;
673   else if (fn1->pc > fn2->pc)
674     return 1;
675   else
676     return 0;
677 }
678 
679 /* Compare a PC against an xcoff_func for bsearch.  */
680 
681 static int
682 xcoff_func_search (const void *vkey, const void *ventry)
683 {
684   const uintptr_t *key = (const uintptr_t *) vkey;
685   const struct xcoff_func *entry = (const struct xcoff_func *) ventry;
686   uintptr_t pc;
687 
688   pc = *key;
689   if (pc < entry->pc)
690     return -1;
691   else if ((entry->size == 0 && pc > entry->pc)
692 	   || (entry->size > 0 && pc >= entry->pc + entry->size))
693     return 1;
694   else
695     return 0;
696 }
697 
698 /* Compare struct xcoff_incl for qsort.  */
699 
700 static int
701 xcoff_incl_compare (const void *v1, const void *v2)
702 {
703   const struct xcoff_incl *in1 = (const struct xcoff_incl *) v1;
704   const struct xcoff_incl *in2 = (const struct xcoff_incl *) v2;
705 
706   if (in1->begin < in2->begin)
707     return -1;
708   else if (in1->begin > in2->begin)
709     return 1;
710   else
711     return 0;
712 }
713 
714 /* Find a lnnoptr in an include file.  */
715 
716 static int
717 xcoff_incl_search (const void *vkey, const void *ventry)
718 {
719   const uintptr_t *key = (const uintptr_t *) vkey;
720   const struct xcoff_incl *entry = (const struct xcoff_incl *) ventry;
721   uintptr_t lnno;
722 
723   lnno = *key;
724   if (lnno < entry->begin)
725     return -1;
726   else if (lnno > entry->end)
727     return 1;
728   else
729     return 0;
730 }
731 
732 /* Look for a PC in the function vector for one module.  On success,
733    call CALLBACK and return whatever it returns.  On error, call
734    ERROR_CALLBACK and return 0.  Sets *FOUND to 1 if the PC is found,
735    0 if not.  */
736 
737 static int
738 xcoff_lookup_pc (struct backtrace_state *state ATTRIBUTE_UNUSED,
739 		 struct xcoff_fileline_data *fdata, uintptr_t pc,
740 		 backtrace_full_callback callback,
741 		 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
742 		 void *data, int *found)
743 {
744   const struct xcoff_incl *incl, *bincl;
745   const struct xcoff_func *fn;
746   const b_xcoff_lineno *lineno;
747   const unsigned char *lineptr;
748   const char *function;
749   const char *filename;
750   uintptr_t lnnoptr, match;
751   uint32_t lnno = 0;
752 
753   *found = 1;
754 
755   if ((pc & 3) != 0)
756     ++pc;
757 
758   /* Find the function first.  */
759   fn = ((struct xcoff_func *)
760 	bsearch (&pc, fdata->func_vec.vec.base, fdata->func_vec.count,
761 		 sizeof (struct xcoff_func), xcoff_func_search));
762   if (fn == NULL)
763     {
764       *found = 0;
765       return 0;
766     }
767 
768   filename = fn->filename;
769 
770   /* Find the line number next.  */
771 
772   /* Skip first entry that points to symtab.  */
773   lnnoptr = fn->lnnoptr + LINESZ;
774   match = lnnoptr;
775 
776   lineptr = fdata->linenos + (lnnoptr - fdata->lnnoptr0);
777   while (lineptr + LINESZ <= fdata->linenos + fdata->linenos_size)
778     {
779       lineno = (const b_xcoff_lineno *) lineptr;
780       if (lineno->l_lnno == 0)
781 	break;
782       if (pc <= fdata->base_address + lineno->l_addr.l_paddr - fn->sect_base)
783 	break;
784       match = lnnoptr;
785       lnno = lineno->l_lnno;
786 
787       lnnoptr += LINESZ;
788       lineptr += LINESZ;
789     }
790 
791   /* If part of a function other than the beginning comes from an
792      include file, the line numbers are absolute, rather than
793      relative to the beginning of the function.  */
794   incl = ((struct xcoff_incl *)
795 	  bsearch (&match, fdata->incl_vec.vec.base,
796 		   fdata->incl_vec.count, sizeof (struct xcoff_incl),
797 		   xcoff_incl_search));
798   if (incl != NULL)
799     {
800       bincl = ((struct xcoff_incl *)
801 	       bsearch (&fn->lnnoptr, fdata->incl_vec.vec.base,
802 			fdata->incl_vec.count, sizeof (struct xcoff_incl),
803 			xcoff_incl_search));
804       if (bincl != NULL && strcmp (incl->filename, bincl->filename) == 0)
805 	{
806 	  lnno += fn->lnno - 1;
807 	}
808       filename = incl->filename;
809     }
810   else
811     {
812       lnno += fn->lnno - 1;
813     }
814 
815   function = fn->name;
816   /* AIX prepends a '.' to function entry points, remove it.  */
817   if (function != NULL && *function == '.')
818     ++function;
819   return callback (data, pc, filename, lnno, function);
820 }
821 
822 /* Return the file/line information for a PC using the XCOFF lineno
823    mapping we built earlier.  */
824 
825 static int
826 xcoff_fileline (struct backtrace_state *state, uintptr_t pc,
827 		backtrace_full_callback callback,
828 		backtrace_error_callback error_callback, void *data)
829 
830 {
831   struct xcoff_fileline_data *fdata;
832   int found;
833   int ret;
834 
835   if (!state->threaded)
836     {
837       for (fdata = (struct xcoff_fileline_data *) state->fileline_data;
838 	   fdata != NULL;
839 	   fdata = fdata->next)
840 	{
841 	  ret = xcoff_lookup_pc (state, fdata, pc, callback, error_callback,
842 				 data, &found);
843 	  if (ret != 0 || found)
844 	    return ret;
845 	}
846     }
847   else
848     {
849       struct xcoff_fileline_data **pp;
850 
851       pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
852       while (1)
853 	{
854 	  fdata = backtrace_atomic_load_pointer (pp);
855 	  if (fdata == NULL)
856 	    break;
857 
858 	  ret = xcoff_lookup_pc (state, fdata, pc, callback, error_callback,
859 				 data, &found);
860 	  if (ret != 0 || found)
861 	    return ret;
862 
863 	  pp = &fdata->next;
864 	}
865     }
866 
867   /* FIXME: See if any libraries have been dlopen'ed.  */
868 
869   return callback (data, pc, NULL, 0, NULL);
870 }
871 
872 /* Initialize the function vector info for xcoff_fileline.  */
873 
874 static int
875 xcoff_initialize_fileline (struct backtrace_state *state,
876 			   uintptr_t base_address,
877 			   const b_xcoff_scnhdr *sects,
878 			   const b_xcoff_syment *syms, size_t nsyms,
879 			   const unsigned char *strtab, size_t strtab_size,
880 			   const unsigned char *linenos, size_t linenos_size,
881 			   uint64_t lnnoptr0,
882 			   backtrace_error_callback error_callback, void *data)
883 {
884   struct xcoff_fileline_data *fdata;
885   struct xcoff_func *fn;
886   const b_xcoff_syment *fsym;
887   const b_xcoff_auxent *aux;
888   const char *filename;
889   const char *name;
890   struct xcoff_incl *incl;
891   uintptr_t begin, end;
892   uintptr_t lnno, lnnoptr;
893   uint32_t fsize;
894   size_t i;
895 
896   fdata = ((struct xcoff_fileline_data *)
897 	   backtrace_alloc (state, sizeof (struct xcoff_fileline_data),
898 			    error_callback, data));
899   if (fdata == NULL)
900     return 0;
901   memset (fdata, 0, sizeof *fdata);
902   fdata->base_address = base_address;
903   fdata->linenos = linenos;
904   fdata->linenos_size = linenos_size;
905   fdata->lnnoptr0 = lnnoptr0;
906 
907   begin = 0;
908   filename = NULL;
909   fsym = NULL;
910   lnnoptr = 0;
911   fsize = 0;
912   for (i = 0; i < nsyms; ++i)
913     {
914       const b_xcoff_syment *asym = &syms[i];
915 
916       switch (asym->n_sclass)
917 	{
918 	  case C_BINCL:
919 	    begin = asym->n_value;
920 	    break;
921 
922 	  case C_EINCL:
923 	    if (begin == 0)
924 	      break;
925 	    end = asym->n_value;
926 	    incl = ((struct xcoff_incl *)
927 		    backtrace_vector_grow (state, sizeof (struct xcoff_incl),
928 					   error_callback, data,
929 					   &fdata->incl_vec.vec));
930 	    if (incl != NULL)
931 	      {
932 		incl->filename = xcoff_symname (asym, strtab, strtab_size);
933 		incl->begin = begin;
934 		incl->end = end;
935 		++fdata->incl_vec.count;
936 	      }
937 	    begin = 0;
938 	    break;
939 
940 	  case C_FILE:
941 	    filename = xcoff_symname (asym, strtab, strtab_size);
942 	    if (filename == NULL)
943 	      break;
944 
945 	    /* If the file auxiliary entry is not used, the symbol name is
946 	       the name of the source file. If the file auxiliary entry is
947 	       used, then the symbol name should be .file, and the first
948 	       file auxiliary entry (by convention) contains the source
949 	       file name.  */
950 
951 	    if (asym->n_numaux > 0 && strcmp (filename, ".file") == 0)
952 	      {
953 		aux = (const b_xcoff_auxent *) (asym + 1);
954 		if (aux->x_file._x.x_zeroes != 0)
955 		  {
956 		    /* Make a copy as we will release the symtab view.  */
957 		    char name[FILNMLEN+1];
958 		    strncpy (name, aux->x_file.x_fname, FILNMLEN);
959 		    name[FILNMLEN] = '\0';
960 		    filename = strdup (name);
961 		  }
962 		else if (aux->x_file._x.x_offset < strtab_size)
963 		  filename = (const char *) strtab + aux->x_file._x.x_offset;
964 		else
965 		  filename = NULL;
966 	      }
967 	    break;
968 
969 	  case C_EXT:
970 	  case C_HIDEXT:
971 	  case C_WEAKEXT:
972 	    fsym = NULL;
973 	    lnnoptr = 0;
974 	    fsize = 0;
975 	    if (!ISFCN (asym->n_type) || asym->n_numaux == 0
976 		|| asym->n_scnum <= 0)
977 	      break;
978 	    if (filename == NULL)
979 	      break;
980 	    aux = (const b_xcoff_auxent *) (asym + 1);
981 	    lnnoptr = aux->x_fcn.x_lnnoptr;
982 	    if (lnnoptr < lnnoptr0
983 		|| lnnoptr + LINESZ > lnnoptr0 + linenos_size)
984 	      break;
985 	    /* x_fsize will be 0 if there is no debug information.  */
986 	    fsize = aux->x_fcn.x_fsize;
987 	    fsym = asym;
988 	    break;
989 
990 	  case C_FCN:
991 	    if (asym->n_numaux == 0)
992 	      break;
993 	    if (fsym == NULL)
994 	      break;
995 	    name = xcoff_symname (asym, strtab, strtab_size);
996 	    if (name == NULL || strcmp (name, ".bf") != 0)
997 	      {
998 		fsym = NULL;
999 		break;
1000 	      }
1001 	    aux = (const b_xcoff_auxent *) (asym + 1);
1002 #if BACKTRACE_XCOFF_SIZE == 32
1003 	    lnno = (uint32_t) aux->x_block.x_lnnohi << 16
1004 		 | aux->x_block.x_lnno;
1005 #else
1006 	    lnno = aux->x_block.x_lnno;
1007 #endif
1008 	    fn = ((struct xcoff_func *)
1009 		  backtrace_vector_grow (state, sizeof (struct xcoff_func),
1010 					 error_callback, data,
1011 					 &fdata->func_vec.vec));
1012 	    if (fn == NULL)
1013 	      break;
1014 	    fn->name = xcoff_symname (fsym, strtab, strtab_size);
1015 	    fn->filename = filename;
1016 	    fn->sect_base = sects[fsym->n_scnum - 1].s_paddr;
1017 	    fn->pc = base_address + fsym->n_value - fn->sect_base;
1018 	    fn->size = fsize;
1019 	    fn->lnno = lnno;
1020 	    fn->lnnoptr = lnnoptr;
1021 	    ++fdata->func_vec.count;
1022 	    break;
1023 	}
1024 
1025       i += asym->n_numaux;
1026     }
1027 
1028   if (!backtrace_vector_release (state, &fdata->func_vec.vec, error_callback,
1029 				 data))
1030     goto fail;
1031   backtrace_qsort (fdata->func_vec.vec.base, fdata->func_vec.count,
1032 		   sizeof (struct xcoff_func), xcoff_func_compare);
1033 
1034   if (!backtrace_vector_release (state, &fdata->incl_vec.vec, error_callback,
1035 				 data))
1036     goto fail;
1037   backtrace_qsort (fdata->incl_vec.vec.base, fdata->incl_vec.count,
1038 		   sizeof (struct xcoff_incl), xcoff_incl_compare);
1039 
1040   if (!state->threaded)
1041     {
1042       struct xcoff_fileline_data **pp;
1043 
1044       for (pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
1045 	   *pp != NULL;
1046 	   pp = &(*pp)->next)
1047 	;
1048       *pp = fdata;
1049     }
1050   else
1051     {
1052       while (1)
1053 	{
1054 	  struct xcoff_fileline_data **pp;
1055 
1056 	  pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
1057 
1058 	  while (1)
1059 	    {
1060 	      struct xcoff_fileline_data *p;
1061 
1062 	      p = backtrace_atomic_load_pointer (pp);
1063 
1064 	      if (p == NULL)
1065 		break;
1066 
1067 	      pp = &p->next;
1068 	    }
1069 
1070 	  if (__sync_bool_compare_and_swap (pp, NULL, fdata))
1071 	    break;
1072 	}
1073     }
1074 
1075   return 1;
1076 
1077 fail:
1078   return 0;
1079 }
1080 
1081 /* Add the backtrace data for one XCOFF file.  Returns 1 on success,
1082    0 on failure (in both cases descriptor is closed).  */
1083 
1084 static int
1085 xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
1086 	   uintptr_t base_address, backtrace_error_callback error_callback,
1087 	   void *data, fileline *fileline_fn, int *found_sym, int exe)
1088 {
1089   struct backtrace_view fhdr_view;
1090   struct backtrace_view sects_view;
1091   struct backtrace_view linenos_view;
1092   struct backtrace_view syms_view;
1093   struct backtrace_view str_view;
1094   struct backtrace_view dwarf_view;
1095   b_xcoff_filhdr fhdr;
1096   const b_xcoff_scnhdr *sects;
1097   const b_xcoff_scnhdr *stext;
1098   uint64_t lnnoptr;
1099   uint32_t nlnno;
1100   off_t str_off;
1101   off_t min_offset;
1102   off_t max_offset;
1103   struct dwsect_info dwsect[DWSECT_MAX];
1104   size_t sects_size;
1105   size_t syms_size;
1106   int32_t str_size;
1107   int sects_view_valid;
1108   int linenos_view_valid;
1109   int syms_view_valid;
1110   int str_view_valid;
1111   int dwarf_view_valid;
1112   int magic_ok;
1113   int i;
1114 
1115   *found_sym = 0;
1116 
1117   sects_view_valid = 0;
1118   linenos_view_valid = 0;
1119   syms_view_valid = 0;
1120   str_view_valid = 0;
1121   dwarf_view_valid = 0;
1122 
1123   str_size = 0;
1124 
1125   /* Map the XCOFF file header.  */
1126   if (!backtrace_get_view (state, descriptor, offset, sizeof (b_xcoff_filhdr),
1127 			   error_callback, data, &fhdr_view))
1128     goto fail;
1129 
1130   memcpy (&fhdr, fhdr_view.data, sizeof fhdr);
1131   magic_ok = (fhdr.f_magic == XCOFF_MAGIC);
1132 
1133   backtrace_release_view (state, &fhdr_view, error_callback, data);
1134 
1135   if (!magic_ok)
1136     {
1137       if (exe)
1138 	error_callback (data, "executable file is not XCOFF", 0);
1139       goto fail;
1140     }
1141 
1142   /* Verify object is of expected type.  */
1143   if ((exe && (fhdr.f_flags & F_SHROBJ))
1144       || (!exe && !(fhdr.f_flags & F_SHROBJ)))
1145     goto fail;
1146 
1147   /* Read the section headers.  */
1148 
1149   sects_size = fhdr.f_nscns * sizeof (b_xcoff_scnhdr);
1150 
1151   if (!backtrace_get_view (state, descriptor,
1152 			   offset + sizeof (fhdr) + fhdr.f_opthdr,
1153 			   sects_size, error_callback, data, &sects_view))
1154     goto fail;
1155   sects_view_valid = 1;
1156   sects = (const b_xcoff_scnhdr *) sects_view.data;
1157 
1158   /* FIXME: assumes only one .text section.  */
1159   for (i = 0; i < fhdr.f_nscns; ++i)
1160     if ((sects[i].s_flags & 0xffff) == STYP_TEXT)
1161       break;
1162   if (i == fhdr.f_nscns)
1163     goto fail;
1164 
1165   stext = &sects[i];
1166 
1167   /* AIX ldinfo_textorg includes the XCOFF headers.  */
1168   base_address = (exe ? XCOFF_AIX_TEXTBASE : base_address) + stext->s_scnptr;
1169 
1170   lnnoptr = stext->s_lnnoptr;
1171   nlnno = stext->s_nlnno;
1172 
1173 #if BACKTRACE_XCOFF_SIZE == 32
1174   if (nlnno == _OVERFLOW_MARKER)
1175     {
1176       int sntext = i + 1;
1177       /* Find the matching .ovrflo section.  */
1178       for (i = 0; i < fhdr.f_nscns; ++i)
1179 	{
1180 	  if (((sects[i].s_flags & 0xffff) == STYP_OVRFLO)
1181 	      && sects[i].s_nlnno == sntext)
1182 	    {
1183 	      nlnno = sects[i].s_vaddr;
1184 	      break;
1185 	    }
1186 	}
1187     }
1188 #endif
1189 
1190   /* Read the symbol table and the string table.  */
1191 
1192   if (fhdr.f_symptr != 0)
1193     {
1194       struct xcoff_syminfo_data *sdata;
1195 
1196       /* Symbol table is followed by the string table.  The string table
1197 	 starts with its length (on 4 bytes).
1198 	 Map the symbol table and the length of the string table.  */
1199       syms_size = fhdr.f_nsyms * sizeof (b_xcoff_syment);
1200 
1201       if (!backtrace_get_view (state, descriptor, offset + fhdr.f_symptr,
1202 			       syms_size + 4, error_callback, data,
1203 			       &syms_view))
1204 	goto fail;
1205       syms_view_valid = 1;
1206 
1207       memcpy (&str_size, syms_view.data + syms_size, 4);
1208 
1209       str_off = fhdr.f_symptr + syms_size;
1210 
1211       if (str_size > 4)
1212 	{
1213 	  /* Map string table (including the length word).  */
1214 
1215 	  if (!backtrace_get_view (state, descriptor, offset + str_off,
1216 				   str_size, error_callback, data, &str_view))
1217 	    goto fail;
1218 	  str_view_valid = 1;
1219 	}
1220 
1221       sdata = ((struct xcoff_syminfo_data *)
1222 	       backtrace_alloc (state, sizeof *sdata, error_callback, data));
1223       if (sdata == NULL)
1224 	goto fail;
1225 
1226       if (!xcoff_initialize_syminfo (state, base_address, sects,
1227 				     syms_view.data, fhdr.f_nsyms,
1228 				     str_view.data, str_size,
1229 				     error_callback, data, sdata))
1230 	{
1231 	  backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
1232 	  goto fail;
1233 	}
1234 
1235       *found_sym = 1;
1236 
1237       xcoff_add_syminfo_data (state, sdata);
1238     }
1239 
1240   /* Read all the DWARF sections in a single view, since they are
1241      probably adjacent in the file.  We never release this view.  */
1242 
1243   min_offset = 0;
1244   max_offset = 0;
1245   memset (dwsect, 0, sizeof dwsect);
1246   for (i = 0; i < fhdr.f_nscns; ++i)
1247     {
1248       off_t end;
1249       int idx;
1250 
1251       if ((sects[i].s_flags & 0xffff) != STYP_DWARF
1252 	  || sects[i].s_size == 0)
1253 	continue;
1254       /* Map DWARF section to array index.  */
1255       switch (sects[i].s_flags & 0xffff0000)
1256 	{
1257 	  case SSUBTYP_DWINFO:
1258 	    idx = DWSECT_INFO;
1259 	    break;
1260 	  case SSUBTYP_DWLINE:
1261 	    idx = DWSECT_LINE;
1262 	    break;
1263 	  case SSUBTYP_DWABREV:
1264 	    idx = DWSECT_ABBREV;
1265 	    break;
1266 	  case SSUBTYP_DWARNGE:
1267 	    idx = DWSECT_RANGES;
1268 	    break;
1269 	  case SSUBTYP_DWSTR:
1270 	    idx = DWSECT_STR;
1271 	    break;
1272 	  default:
1273 	    continue;
1274 	}
1275       if (min_offset == 0 || (off_t) sects[i].s_scnptr < min_offset)
1276 	min_offset = sects[i].s_scnptr;
1277       end = sects[i].s_scnptr + sects[i].s_size;
1278       if (end > max_offset)
1279 	max_offset = end;
1280       dwsect[idx].offset = sects[i].s_scnptr;
1281       dwsect[idx].size = sects[i].s_size;
1282     }
1283   if (min_offset != 0 && max_offset != 0)
1284     {
1285       if (!backtrace_get_view (state, descriptor, offset + min_offset,
1286 			       max_offset - min_offset,
1287 			       error_callback, data, &dwarf_view))
1288 	goto fail;
1289       dwarf_view_valid = 1;
1290 
1291       for (i = 0; i < (int) DWSECT_MAX; ++i)
1292 	{
1293 	  if (dwsect[i].offset == 0)
1294 	    dwsect[i].data = NULL;
1295 	  else
1296 	    dwsect[i].data = ((const unsigned char *) dwarf_view.data
1297 			      + (dwsect[i].offset - min_offset));
1298 	}
1299 
1300       if (!backtrace_dwarf_add (state, 0,
1301 				dwsect[DWSECT_INFO].data,
1302 				dwsect[DWSECT_INFO].size,
1303 #if BACKTRACE_XCOFF_SIZE == 32
1304 				/* XXX workaround for broken lineoff */
1305 				dwsect[DWSECT_LINE].data - 4,
1306 #else
1307 				/* XXX workaround for broken lineoff */
1308 				dwsect[DWSECT_LINE].data - 12,
1309 #endif
1310 				dwsect[DWSECT_LINE].size,
1311 				dwsect[DWSECT_ABBREV].data,
1312 				dwsect[DWSECT_ABBREV].size,
1313 				dwsect[DWSECT_RANGES].data,
1314 				dwsect[DWSECT_RANGES].size,
1315 				dwsect[DWSECT_STR].data,
1316 				dwsect[DWSECT_STR].size,
1317 				1, /* big endian */
1318 				NULL,
1319 				error_callback, data, fileline_fn,
1320 				NULL))
1321 	goto fail;
1322     }
1323 
1324   /* Read the XCOFF line number entries if DWARF sections not found.  */
1325 
1326   if (!dwarf_view_valid && fhdr.f_symptr != 0 && lnnoptr != 0)
1327     {
1328       size_t linenos_size = (size_t) nlnno * LINESZ;
1329 
1330       /* We never release this view.  */
1331       if (!backtrace_get_view (state, descriptor, offset + lnnoptr,
1332 			       linenos_size,
1333 			       error_callback, data, &linenos_view))
1334 	goto fail;
1335       linenos_view_valid = 1;
1336 
1337       if (xcoff_initialize_fileline (state, base_address, sects,
1338 				     syms_view.data, fhdr.f_nsyms,
1339 				     str_view.data, str_size,
1340 				     linenos_view.data, linenos_size,
1341 				     lnnoptr, error_callback, data))
1342 	*fileline_fn = xcoff_fileline;
1343     }
1344 
1345   backtrace_release_view (state, &sects_view, error_callback, data);
1346   sects_view_valid = 0;
1347   if (syms_view_valid)
1348     backtrace_release_view (state, &syms_view, error_callback, data);
1349   syms_view_valid = 0;
1350 
1351   /* We've read all we need from the executable.  */
1352   if (!backtrace_close (descriptor, error_callback, data))
1353     goto fail;
1354   descriptor = -1;
1355 
1356   return 1;
1357 
1358  fail:
1359   if (sects_view_valid)
1360     backtrace_release_view (state, &sects_view, error_callback, data);
1361   if (str_view_valid)
1362     backtrace_release_view (state, &str_view, error_callback, data);
1363   if (syms_view_valid)
1364     backtrace_release_view (state, &syms_view, error_callback, data);
1365   if (linenos_view_valid)
1366     backtrace_release_view (state, &linenos_view, error_callback, data);
1367   if (dwarf_view_valid)
1368     backtrace_release_view (state, &dwarf_view, error_callback, data);
1369   if (descriptor != -1 && offset == 0)
1370     backtrace_close (descriptor, error_callback, data);
1371   return 0;
1372 }
1373 
1374 #ifdef HAVE_LOADQUERY
1375 
1376 /* Read an integer value in human-readable format from an AIX
1377    big archive fixed-length or member header.  */
1378 
1379 static int
1380 xcoff_parse_decimal (const char *buf, size_t size, off_t *off)
1381 {
1382   char str[32];
1383   char *end;
1384 
1385   if (size >= sizeof str)
1386     return 0;
1387   memcpy (str, buf, size);
1388   str[size] = '\0';
1389   *off = strtol (str, &end, 10);
1390   if (*end != '\0' && *end != ' ')
1391     return 0;
1392 
1393   return 1;
1394 }
1395 
1396 /* Add the backtrace data for a member of an AIX big archive.
1397    Returns 1 on success, 0 on failure.  */
1398 
1399 static int
1400 xcoff_armem_add (struct backtrace_state *state, int descriptor,
1401 		 uintptr_t base_address, const char *member,
1402 		 backtrace_error_callback error_callback, void *data,
1403 		 fileline *fileline_fn, int *found_sym)
1404 {
1405   struct backtrace_view view;
1406   b_ar_fl_hdr fl_hdr;
1407   const b_ar_hdr *ar_hdr;
1408   off_t off;
1409   off_t len;
1410   int memlen;
1411 
1412   *found_sym = 0;
1413 
1414   /* Map archive fixed-length header.  */
1415 
1416   if (!backtrace_get_view (state, descriptor, 0, sizeof (b_ar_fl_hdr),
1417 			   error_callback, data, &view))
1418     goto fail;
1419 
1420   memcpy (&fl_hdr, view.data, sizeof (b_ar_fl_hdr));
1421 
1422   backtrace_release_view (state, &view, error_callback, data);
1423 
1424   if (memcmp (fl_hdr.fl_magic, AIAMAGBIG, 8) != 0)
1425     goto fail;
1426 
1427   memlen = strlen (member);
1428 
1429   /* Read offset of first archive member.  */
1430   if (!xcoff_parse_decimal (fl_hdr.fl_fstmoff, sizeof fl_hdr.fl_fstmoff, &off))
1431     goto fail;
1432   while (off != 0)
1433     {
1434       /* Map archive member header and member name.  */
1435 
1436       if (!backtrace_get_view (state, descriptor, off,
1437 			       sizeof (b_ar_hdr) + memlen,
1438 			       error_callback, data, &view))
1439 	break;
1440 
1441       ar_hdr = (const b_ar_hdr *) view.data;
1442 
1443       /* Read archive member name length.  */
1444       if (!xcoff_parse_decimal (ar_hdr->ar_namlen, sizeof ar_hdr->ar_namlen,
1445 				&len))
1446 	{
1447 	  backtrace_release_view (state, &view, error_callback, data);
1448 	  break;
1449 	}
1450       if (len == memlen && !memcmp (ar_hdr->ar_name, member, memlen))
1451 	{
1452 	  off = (off + sizeof (b_ar_hdr) + memlen + 1) & ~1;
1453 
1454 	  /* The archive can contain several members with the same name
1455 	     (e.g. 32-bit and 64-bit), so continue if not ok.  */
1456 
1457 	  if (xcoff_add (state, descriptor, off, base_address, error_callback,
1458 			 data, fileline_fn, found_sym, 0))
1459 	    {
1460 	      backtrace_release_view (state, &view, error_callback, data);
1461 	      return 1;
1462 	    }
1463 	}
1464 
1465       /* Read offset of next archive member.  */
1466       if (!xcoff_parse_decimal (ar_hdr->ar_nxtmem, sizeof ar_hdr->ar_nxtmem,
1467 				&off))
1468 	{
1469 	  backtrace_release_view (state, &view, error_callback, data);
1470 	  break;
1471 	}
1472       backtrace_release_view (state, &view, error_callback, data);
1473     }
1474 
1475  fail:
1476   /* No matching member found.  */
1477   backtrace_close (descriptor, error_callback, data);
1478   return 0;
1479 }
1480 
1481 /* Add the backtrace data for dynamically loaded libraries.  */
1482 
1483 static void
1484 xcoff_add_shared_libs (struct backtrace_state *state,
1485 		       backtrace_error_callback error_callback,
1486 		       void *data, fileline *fileline_fn, int *found_sym)
1487 {
1488   const struct ld_info *ldinfo;
1489   void *buf;
1490   unsigned int buflen;
1491   const char *member;
1492   int descriptor;
1493   int does_not_exist;
1494   int lib_found_sym;
1495   int ret;
1496 
1497   /* Retrieve the list of loaded libraries.  */
1498 
1499   buf = NULL;
1500   buflen = 512;
1501   do
1502     {
1503       buf = realloc (buf, buflen);
1504       if (buf == NULL)
1505 	{
1506 	  ret = -1;
1507 	  break;
1508 	}
1509       ret = loadquery (L_GETINFO, buf, buflen);
1510       if (ret == 0)
1511 	break;
1512       buflen *= 2;
1513     }
1514   while (ret == -1 && errno == ENOMEM);
1515   if (ret != 0)
1516     {
1517       free (buf);
1518       return;
1519     }
1520 
1521   ldinfo = (const struct ld_info *) buf;
1522   while ((const char *) ldinfo < (const char *) buf + buflen)
1523     {
1524       if (*ldinfo->ldinfo_filename != '/')
1525 	goto next;
1526 
1527       descriptor = backtrace_open (ldinfo->ldinfo_filename, error_callback,
1528 				   data, &does_not_exist);
1529       if (descriptor < 0)
1530 	goto next;
1531 
1532       /* Check if it is an archive (member name not empty).  */
1533 
1534       member = ldinfo->ldinfo_filename + strlen (ldinfo->ldinfo_filename) + 1;
1535       if (*member)
1536 	{
1537 	  xcoff_armem_add (state, descriptor,
1538 			   (uintptr_t) ldinfo->ldinfo_textorg, member,
1539 			   error_callback, data, fileline_fn, &lib_found_sym);
1540 	}
1541       else
1542 	{
1543 	  xcoff_add (state, descriptor, 0, (uintptr_t) ldinfo->ldinfo_textorg,
1544 		     error_callback, data, fileline_fn, &lib_found_sym, 0);
1545 	}
1546       if (lib_found_sym)
1547 	*found_sym = 1;
1548 
1549  next:
1550       if (ldinfo->ldinfo_next == 0)
1551 	break;
1552       ldinfo = (const struct ld_info *) ((const char *) ldinfo
1553 					 + ldinfo->ldinfo_next);
1554     }
1555 
1556     free (buf);
1557 }
1558 #endif /* HAVE_LOADQUERY */
1559 
1560 /* Initialize the backtrace data we need from an XCOFF executable.
1561    Returns 1 on success, 0 on failure.  */
1562 
1563 int
1564 backtrace_initialize (struct backtrace_state *state,
1565 		      const char *filename ATTRIBUTE_UNUSED, int descriptor,
1566 		      backtrace_error_callback error_callback,
1567 		      void *data, fileline *fileline_fn)
1568 {
1569   int ret;
1570   int found_sym;
1571   fileline xcoff_fileline_fn = xcoff_nodebug;
1572 
1573   ret = xcoff_add (state, descriptor, 0, 0, error_callback, data,
1574 		   &xcoff_fileline_fn, &found_sym, 1);
1575   if (!ret)
1576     return 0;
1577 
1578 #ifdef HAVE_LOADQUERY
1579   xcoff_add_shared_libs (state, error_callback, data, &xcoff_fileline_fn,
1580 			 &found_sym);
1581 #endif
1582 
1583   if (!state->threaded)
1584     {
1585       if (found_sym)
1586 	state->syminfo_fn = xcoff_syminfo;
1587       else if (state->syminfo_fn == NULL)
1588 	state->syminfo_fn = xcoff_nosyms;
1589     }
1590   else
1591     {
1592       if (found_sym)
1593 	backtrace_atomic_store_pointer (&state->syminfo_fn, xcoff_syminfo);
1594       else
1595 	(void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
1596 					     xcoff_nosyms);
1597     }
1598 
1599   if (!state->threaded)
1600     {
1601       if (state->fileline_fn == NULL || state->fileline_fn == xcoff_nodebug)
1602 	*fileline_fn = xcoff_fileline_fn;
1603     }
1604   else
1605     {
1606       fileline current_fn;
1607 
1608       current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
1609       if (current_fn == NULL || current_fn == xcoff_nodebug)
1610 	*fileline_fn = xcoff_fileline_fn;
1611     }
1612 
1613   return 1;
1614 }
1615