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