]> git.ipfire.org Git - thirdparty/gcc.git/blame - libbacktrace/xcoff.c
[Ada] Improve handling of SPARK_Mode in generic instances
[thirdparty/gcc.git] / libbacktrace / xcoff.c
CommitLineData
7e2a8417 1/* xcoff.c -- Get debug data from an XCOFF file for backtraces.
8d9254fc 2 Copyright (C) 2012-2020 Free Software Foundation, Inc.
7e2a8417 3 Adapted from elf.c.
b3530b94
TR
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
8
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 (2) Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 (3) The name of the author may not be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
20
21THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31POSSIBILITY OF SUCH DAMAGE. */
32
33#include "config.h"
34
7e2a8417
TR
35#include <errno.h>
36#include <stdlib.h>
37#include <string.h>
b3530b94
TR
38#include <sys/types.h>
39
7e2a8417
TR
40#ifdef HAVE_LOADQUERY
41#include <sys/ldr.h>
42#endif
43
b3530b94
TR
44#include "backtrace.h"
45#include "internal.h"
46
7e2a8417
TR
47/* The configure script must tell us whether we are 32-bit or 64-bit
48 XCOFF. We could make this code test and support either possibility,
49 but there is no point. This code only works for the currently
50 running executable, which means that we know the XCOFF mode at
51 configure time. */
52
53#if BACKTRACE_XCOFF_SIZE != 32 && BACKTRACE_XCOFF_SIZE != 64
54#error "Unknown BACKTRACE_XCOFF_SIZE"
55#endif
56
57/* XCOFF file header. */
58
59#if BACKTRACE_XCOFF_SIZE == 32
60
61typedef struct {
62 uint16_t f_magic;
63 uint16_t f_nscns;
64 uint32_t f_timdat;
65 uint32_t f_symptr;
66 uint32_t f_nsyms;
67 uint16_t f_opthdr;
68 uint16_t f_flags;
69} b_xcoff_filhdr;
70
71#define XCOFF_MAGIC 0737
72
73#else /* BACKTRACE_XCOFF_SIZE != 32 */
74
75typedef struct {
76 uint16_t f_magic;
77 uint16_t f_nscns;
78 uint32_t f_timdat;
79 uint64_t f_symptr;
80 uint16_t f_opthdr;
81 uint16_t f_flags;
82 uint32_t f_nsyms;
83} b_xcoff_filhdr;
84
85#define XCOFF_MAGIC 0767
86
87#endif /* BACKTRACE_XCOFF_SIZE != 32 */
88
89#define F_SHROBJ 0x2000 /* File is a shared object. */
90
91/* XCOFF section header. */
92
93#if BACKTRACE_XCOFF_SIZE == 32
94
95typedef struct {
96 char s_name[8];
97 uint32_t s_paddr;
98 uint32_t s_vaddr;
99 uint32_t s_size;
100 uint32_t s_scnptr;
101 uint32_t s_relptr;
102 uint32_t s_lnnoptr;
103 uint16_t s_nreloc;
104 uint16_t s_nlnno;
105 uint32_t s_flags;
106} b_xcoff_scnhdr;
107
108#define _OVERFLOW_MARKER 65535
109
110#else /* BACKTRACE_XCOFF_SIZE != 32 */
111
112typedef struct {
113 char name[8];
114 uint64_t s_paddr;
115 uint64_t s_vaddr;
116 uint64_t s_size;
117 uint64_t s_scnptr;
118 uint64_t s_relptr;
119 uint64_t s_lnnoptr;
120 uint32_t s_nreloc;
121 uint32_t s_nlnno;
122 uint32_t s_flags;
123} b_xcoff_scnhdr;
124
125#endif /* BACKTRACE_XCOFF_SIZE != 32 */
126
e90c74f5 127#define STYP_DWARF 0x10 /* DWARF debugging section. */
7e2a8417
TR
128#define STYP_TEXT 0x20 /* Executable text (code) section. */
129#define STYP_OVRFLO 0x8000 /* Line-number field overflow section. */
130
e90c74f5
TR
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
7e2a8417
TR
137/* XCOFF symbol. */
138
139#define SYMNMLEN 8
140
141#if BACKTRACE_XCOFF_SIZE == 32
142
143typedef 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
164typedef 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
192typedef 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
237typedef 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
249typedef 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
271typedef 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
282typedef 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
297struct 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
309struct 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
321struct 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
333struct 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
ca9a1314 341/* A growable vector of functions information. */
7e2a8417 342
ca9a1314 343struct xcoff_func
7e2a8417
TR
344{
345 /* PC. */
346 uintptr_t pc;
ca9a1314
TR
347 /* The size of the function. */
348 size_t size;
7e2a8417 349 /* Function name. */
ca9a1314
TR
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;
7e2a8417
TR
359};
360
ca9a1314
TR
361/* A growable vector of function information. This is used while
362 reading the function symbols. */
7e2a8417 363
ca9a1314 364struct xcoff_func_vector
7e2a8417 365{
ca9a1314 366 /* Memory. This is an array of struct xcoff_func. */
7e2a8417
TR
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
374struct xcoff_fileline_data
375{
376 /* The data for the next file we know about. */
377 struct xcoff_fileline_data *next;
ca9a1314
TR
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;
7e2a8417
TR
388};
389
e90c74f5
TR
390/* Information we gather for the DWARF sections we care about. */
391
392struct 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};
7e2a8417
TR
401
402/* A dummy callback function used when we can't find any debug info. */
b3530b94
TR
403
404static int
7e2a8417
TR
405xcoff_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}
b3530b94 413
7e2a8417
TR
414/* A dummy callback function used when we can't find a symbol
415 table. */
416
417static void
418xcoff_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)
b3530b94 422{
7e2a8417
TR
423 error_callback (data, "no symbol table in XCOFF executable", -1);
424}
425
426/* Compare struct xcoff_symbol for qsort. */
b3530b94 427
7e2a8417
TR
428static int
429xcoff_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
444static int
445xcoff_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
463static void
464xcoff_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 }
b3530b94
TR
501}
502
7e2a8417
TR
503/* Return the symbol name and value for an ADDR. */
504
b3530b94
TR
505static void
506xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr,
7e2a8417
TR
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;
ca9a1314 513 const char *name;
7e2a8417
TR
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
ca9a1314
TR
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 }
7e2a8417
TR
559}
560
561/* Return the name of an XCOFF symbol. */
562
563static const char *
564xcoff_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
586static int
587xcoff_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
ca9a1314 651/* Compare struct xcoff_func for qsort. */
7e2a8417
TR
652
653static int
ca9a1314 654xcoff_func_compare (const void *v1, const void *v2)
7e2a8417 655{
ca9a1314
TR
656 const struct xcoff_func *fn1 = (const struct xcoff_func *) v1;
657 const struct xcoff_func *fn2 = (const struct xcoff_func *) v2;
7e2a8417 658
ca9a1314 659 if (fn1->pc < fn2->pc)
7e2a8417 660 return -1;
ca9a1314 661 else if (fn1->pc > fn2->pc)
7e2a8417
TR
662 return 1;
663 else
664 return 0;
665}
666
ca9a1314 667/* Compare a PC against an xcoff_func for bsearch. */
7e2a8417
TR
668
669static int
ca9a1314 670xcoff_func_search (const void *vkey, const void *ventry)
7e2a8417
TR
671{
672 const uintptr_t *key = (const uintptr_t *) vkey;
ca9a1314 673 const struct xcoff_func *entry = (const struct xcoff_func *) ventry;
7e2a8417
TR
674 uintptr_t pc;
675
676 pc = *key;
677 if (pc < entry->pc)
678 return -1;
ca9a1314
TR
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
688static int
689xcoff_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)
7e2a8417
TR
697 return 1;
698 else
699 return 0;
700}
701
ca9a1314
TR
702/* Find a lnnoptr in an include file. */
703
704static int
705xcoff_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,
7e2a8417
TR
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
725static int
726xcoff_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{
ca9a1314
TR
732 const struct xcoff_incl *incl, *bincl;
733 const struct xcoff_func *fn;
734 const b_xcoff_lineno *lineno;
735 const unsigned char *lineptr;
7e2a8417 736 const char *function;
ca9a1314
TR
737 const char *filename;
738 uintptr_t lnnoptr, match;
739 uint32_t lnno = 0;
7e2a8417
TR
740
741 *found = 1;
742
ca9a1314
TR
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)
7e2a8417
TR
751 {
752 *found = 0;
753 return 0;
754 }
755
ca9a1314
TR
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;
7e2a8417 804 /* AIX prepends a '.' to function entry points, remove it. */
ca9a1314 805 if (function != NULL && *function == '.')
7e2a8417 806 ++function;
ca9a1314 807 return callback (data, pc, filename, lnno, function);
7e2a8417
TR
808}
809
810/* Return the file/line information for a PC using the XCOFF lineno
811 mapping we built earlier. */
812
813static int
814xcoff_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
ca9a1314 860/* Initialize the function vector info for xcoff_fileline. */
7e2a8417
TR
861
862static int
863xcoff_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;
ca9a1314 873 struct xcoff_func *fn;
7e2a8417
TR
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;
ca9a1314
TR
880 uintptr_t lnno, lnnoptr;
881 uint32_t fsize;
7e2a8417
TR
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;
7e2a8417 889 memset (fdata, 0, sizeof *fdata);
ca9a1314
TR
890 fdata->base_address = base_address;
891 fdata->linenos = linenos;
892 fdata->linenos_size = linenos_size;
893 fdata->lnnoptr0 = lnnoptr0;
7e2a8417
TR
894
895 begin = 0;
ca9a1314
TR
896 filename = NULL;
897 fsym = NULL;
898 lnnoptr = 0;
899 fsize = 0;
7e2a8417
TR
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),
ca9a1314
TR
916 error_callback, data,
917 &fdata->incl_vec.vec));
7e2a8417
TR
918 if (incl != NULL)
919 {
920 incl->filename = xcoff_symname (asym, strtab, strtab_size);
921 incl->begin = begin;
922 incl->end = end;
ca9a1314 923 ++fdata->incl_vec.count;
7e2a8417
TR
924 }
925 begin = 0;
926 break;
7e2a8417 927
7e2a8417
TR
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
ca9a1314 939 if (asym->n_numaux > 0 && strcmp (filename, ".file") == 0)
7e2a8417
TR
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;
ca9a1314
TR
961 lnnoptr = 0;
962 fsize = 0;
963 if (!ISFCN (asym->n_type) || asym->n_numaux == 0
964 || asym->n_scnum <= 0)
7e2a8417
TR
965 break;
966 if (filename == NULL)
967 break;
ca9a1314
TR
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;
7e2a8417
TR
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);
ca9a1314
TR
984 if (name == NULL || strcmp (name, ".bf") != 0)
985 {
986 fsym = NULL;
987 break;
988 }
7e2a8417
TR
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
ca9a1314
TR
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;
7e2a8417
TR
1010 break;
1011 }
1012
1013 i += asym->n_numaux;
1014 }
1015
ca9a1314
TR
1016 if (!backtrace_vector_release (state, &fdata->func_vec.vec, error_callback,
1017 data))
7e2a8417 1018 goto fail;
ca9a1314
TR
1019 backtrace_qsort (fdata->func_vec.vec.base, fdata->func_vec.count,
1020 sizeof (struct xcoff_func), xcoff_func_compare);
7e2a8417 1021
ca9a1314
TR
1022 if (!backtrace_vector_release (state, &fdata->incl_vec.vec, error_callback,
1023 data))
7e2a8417 1024 goto fail;
ca9a1314
TR
1025 backtrace_qsort (fdata->incl_vec.vec.base, fdata->incl_vec.count,
1026 sizeof (struct xcoff_incl), xcoff_incl_compare);
7e2a8417
TR
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
1065fail:
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
1072static int
1073xcoff_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;
e90c74f5 1082 struct backtrace_view dwarf_view;
7e2a8417
TR
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;
e90c74f5
TR
1089 off_t min_offset;
1090 off_t max_offset;
66ab5839 1091 struct dwsect_info dwsect[DEBUG_MAX];
7e2a8417
TR
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;
e90c74f5 1099 int dwarf_view_valid;
7e2a8417
TR
1100 int magic_ok;
1101 int i;
66ab5839 1102 struct dwarf_sections dwarf_sections;
7e2a8417
TR
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;
e90c74f5
TR
1110 dwarf_view_valid = 0;
1111
1112 str_size = 0;
7e2a8417
TR
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)
e90c74f5 1127 error_callback (data, "executable file is not XCOFF", 0);
7e2a8417
TR
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)
e90c74f5
TR
1149 if ((sects[i].s_flags & 0xffff) == STYP_TEXT)
1150 break;
7e2a8417
TR
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 {
e90c74f5
TR
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 }
7e2a8417
TR
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
e90c74f5
TR
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:
66ab5839 1247 idx = DEBUG_INFO;
e90c74f5
TR
1248 break;
1249 case SSUBTYP_DWLINE:
66ab5839 1250 idx = DEBUG_LINE;
e90c74f5
TR
1251 break;
1252 case SSUBTYP_DWABREV:
66ab5839 1253 idx = DEBUG_ABBREV;
e90c74f5
TR
1254 break;
1255 case SSUBTYP_DWARNGE:
66ab5839 1256 idx = DEBUG_RANGES;
e90c74f5
TR
1257 break;
1258 case SSUBTYP_DWSTR:
66ab5839 1259 idx = DEBUG_STR;
e90c74f5
TR
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
66ab5839 1280 for (i = 0; i < (int) DEBUG_MAX; ++i)
e90c74f5
TR
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
c926fd82
ILT
1289 memset (&dwarf_sections, 0, sizeof dwarf_sections);
1290
66ab5839
ILT
1291 dwarf_sections.data[DEBUG_INFO] = dwsect[DEBUG_INFO].data;
1292 dwarf_sections.size[DEBUG_INFO] = dwsect[DEBUG_INFO].size;
e90c74f5 1293#if BACKTRACE_XCOFF_SIZE == 32
66ab5839
ILT
1294 /* XXX workaround for broken lineoff */
1295 dwarf_sections.data[DEBUG_LINE] = dwsect[DEBUG_LINE].data - 4;
e90c74f5 1296#else
66ab5839
ILT
1297 /* XXX workaround for broken lineoff */
1298 dwarf_sections.data[DEBUG_LINE] = dwsect[DEBUG_LINE].data - 12;
e90c74f5 1299#endif
66ab5839
ILT
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,
e90c74f5 1309 1, /* big endian */
66ab5839 1310 NULL, /* altlink */
e6f00c83 1311 error_callback, data, fileline_fn,
66ab5839 1312 NULL /* returned fileline_entry */))
e90c74f5
TR
1313 goto fail;
1314 }
1315
1316 /* Read the XCOFF line number entries if DWARF sections not found. */
7e2a8417 1317
e90c74f5 1318 if (!dwarf_view_valid && fhdr.f_symptr != 0 && lnnoptr != 0)
7e2a8417
TR
1319 {
1320 size_t linenos_size = (size_t) nlnno * LINESZ;
1321
ca9a1314 1322 /* We never release this view. */
7e2a8417
TR
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;
7e2a8417
TR
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);
e90c74f5
TR
1359 if (dwarf_view_valid)
1360 backtrace_release_view (state, &dwarf_view, error_callback, data);
7e2a8417
TR
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
1371static int
1372xcoff_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
1391static int
1392xcoff_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))
afce7deb 1410 goto fail;
7e2a8417
TR
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)
afce7deb 1417 goto fail;
7e2a8417
TR
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))
afce7deb 1423 goto fail;
7e2a8417
TR
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))
afce7deb 1431 break;
7e2a8417
TR
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
afce7deb 1467 fail:
7e2a8417
TR
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
1475static void
1476xcoff_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. */
b3530b94
TR
1554
1555int
9283471b
ILT
1556backtrace_initialize (struct backtrace_state *state,
1557 const char *filename ATTRIBUTE_UNUSED, int descriptor,
7e2a8417
TR
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
5fe5f75f
ILT
1587 (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
1588 xcoff_nosyms);
7e2a8417
TR
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
b3530b94
TR
1605 return 1;
1606}