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