xref: /netbsd-src/external/gpl3/gcc/dist/libbacktrace/xcoff.c (revision 15a984a0d95c8f96abe9717ee6241762c55dc106)
1 /* xcoff.c -- Get debug data from an XCOFF file for backtraces.
2    Copyright (C) 2012-2022 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 #define SSUBTYP_DWRNGES	0x80000	/* DWARF ranges section.  */
137 
138 /* XCOFF symbol.  */
139 
140 #define SYMNMLEN	8
141 
142 #if BACKTRACE_XCOFF_SIZE == 32
143 
144 typedef 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 
165 typedef 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 
193 typedef 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 
238 typedef 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 
250 typedef 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 
272 typedef 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 
283 typedef 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 
298 struct 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 
310 struct 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 
322 struct 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 
334 struct 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 
344 struct 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 
365 struct 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 
375 struct 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 
393 struct 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 
405 static int
406 xcoff_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 
418 static void
419 xcoff_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 
429 static int
430 xcoff_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 
445 static int
446 xcoff_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 
464 static void
465 xcoff_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 
506 static void
507 xcoff_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 
564 static const char *
565 xcoff_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 
587 static int
588 xcoff_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 
652 static int
653 xcoff_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 
668 static int
669 xcoff_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 
687 static int
688 xcoff_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 
703 static int
704 xcoff_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 
724 static int
725 xcoff_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 
812 static int
813 xcoff_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 
861 static int
862 xcoff_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 
1064 fail:
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 
1071 static int
1072 xcoff_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 
1372 static int
1373 xcoff_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 
1392 static int
1393 xcoff_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 
1476 static void
1477 xcoff_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 
1556 int
1557 backtrace_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