]> git.ipfire.org Git - thirdparty/gcc.git/blob - libbacktrace/xcoff.c
Update copyright years.
[thirdparty/gcc.git] / libbacktrace / xcoff.c
1 /* xcoff.c -- Get debug data from an XCOFF file for backtraces.
2 Copyright (C) 2012-2024 Free Software Foundation, Inc.
3 Adapted from elf.c.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 (2) Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 (3) The name of the author may not be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE. */
32
33 #include "config.h"
34
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39
40 #ifdef HAVE_LOADQUERY
41 #include <sys/ldr.h>
42 #endif
43
44 #include "backtrace.h"
45 #include "internal.h"
46
47 /* The configure script must tell us whether we are 32-bit or 64-bit
48 XCOFF. We could make this code test and support either possibility,
49 but there is no point. This code only works for the currently
50 running executable, which means that we know the XCOFF mode at
51 configure time. */
52
53 #if BACKTRACE_XCOFF_SIZE != 32 && BACKTRACE_XCOFF_SIZE != 64
54 #error "Unknown BACKTRACE_XCOFF_SIZE"
55 #endif
56
57 /* XCOFF file header. */
58
59 #if BACKTRACE_XCOFF_SIZE == 32
60
61 typedef struct {
62 uint16_t f_magic;
63 uint16_t f_nscns;
64 uint32_t f_timdat;
65 uint32_t f_symptr;
66 uint32_t f_nsyms;
67 uint16_t f_opthdr;
68 uint16_t f_flags;
69 } b_xcoff_filhdr;
70
71 #define XCOFF_MAGIC 0737
72
73 #else /* BACKTRACE_XCOFF_SIZE != 32 */
74
75 typedef struct {
76 uint16_t f_magic;
77 uint16_t f_nscns;
78 uint32_t f_timdat;
79 uint64_t f_symptr;
80 uint16_t f_opthdr;
81 uint16_t f_flags;
82 uint32_t f_nsyms;
83 } b_xcoff_filhdr;
84
85 #define XCOFF_MAGIC 0767
86
87 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
88
89 #define F_SHROBJ 0x2000 /* File is a shared object. */
90
91 /* XCOFF section header. */
92
93 #if BACKTRACE_XCOFF_SIZE == 32
94
95 typedef struct {
96 char s_name[8];
97 uint32_t s_paddr;
98 uint32_t s_vaddr;
99 uint32_t s_size;
100 uint32_t s_scnptr;
101 uint32_t s_relptr;
102 uint32_t s_lnnoptr;
103 uint16_t s_nreloc;
104 uint16_t s_nlnno;
105 uint32_t s_flags;
106 } b_xcoff_scnhdr;
107
108 #define _OVERFLOW_MARKER 65535
109
110 #else /* BACKTRACE_XCOFF_SIZE != 32 */
111
112 typedef struct {
113 char name[8];
114 uint64_t s_paddr;
115 uint64_t s_vaddr;
116 uint64_t s_size;
117 uint64_t s_scnptr;
118 uint64_t s_relptr;
119 uint64_t s_lnnoptr;
120 uint32_t s_nreloc;
121 uint32_t s_nlnno;
122 uint32_t s_flags;
123 } b_xcoff_scnhdr;
124
125 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
126
127 #define STYP_DWARF 0x10 /* DWARF debugging section. */
128 #define STYP_TEXT 0x20 /* Executable text (code) section. */
129 #define STYP_OVRFLO 0x8000 /* Line-number field overflow section. */
130
131 #define SSUBTYP_DWINFO 0x10000 /* DWARF info section. */
132 #define SSUBTYP_DWLINE 0x20000 /* DWARF line-number section. */
133 #define SSUBTYP_DWARNGE 0x50000 /* DWARF aranges section. */
134 #define SSUBTYP_DWABREV 0x60000 /* DWARF abbreviation section. */
135 #define SSUBTYP_DWSTR 0x70000 /* DWARF strings section. */
136 #define SSUBTYP_DWRNGES 0x80000 /* DWARF ranges section. */
137
138 /* XCOFF symbol. */
139
140 #define SYMNMLEN 8
141
142 #if BACKTRACE_XCOFF_SIZE == 32
143
144 typedef struct {
145 union {
146 char _name[SYMNMLEN];
147 struct {
148 uint32_t _zeroes;
149 uint32_t _offset;
150 } _s;
151 } _u;
152 #define n_name _u._name
153 #define n_zeroes _u._s._zeroes
154 #define n_offset_ _u._s._offset
155
156 uint32_t n_value;
157 int16_t n_scnum;
158 uint16_t n_type;
159 uint8_t n_sclass;
160 uint8_t n_numaux;
161 } __attribute__ ((packed)) b_xcoff_syment;
162
163 #else /* BACKTRACE_XCOFF_SIZE != 32 */
164
165 typedef struct {
166 uint64_t n_value;
167 uint32_t n_offset_;
168 int16_t n_scnum;
169 uint16_t n_type;
170 uint8_t n_sclass;
171 uint8_t n_numaux;
172 } __attribute__ ((packed)) b_xcoff_syment;
173
174 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
175
176 #define SYMESZ 18
177
178 #define C_EXT 2 /* External symbol. */
179 #define C_FCN 101 /* Beginning or end of function. */
180 #define C_FILE 103 /* Source file name. */
181 #define C_HIDEXT 107 /* Unnamed external symbol. */
182 #define C_BINCL 108 /* Beginning of include file. */
183 #define C_EINCL 109 /* End of include file. */
184 #define C_WEAKEXT 111 /* Weak external symbol. */
185
186 #define ISFCN(x) ((x) & 0x0020)
187
188 /* XCOFF AUX entry. */
189
190 #define AUXESZ 18
191 #define FILNMLEN 14
192
193 typedef union {
194 #if BACKTRACE_XCOFF_SIZE == 32
195 struct {
196 uint16_t pad;
197 uint16_t x_lnnohi;
198 uint16_t x_lnno;
199 } x_block;
200 #else
201 struct {
202 uint32_t x_lnno;
203 } x_block;
204 #endif
205 union {
206 char x_fname[FILNMLEN];
207 struct {
208 uint32_t x_zeroes;
209 uint32_t x_offset;
210 char pad[FILNMLEN-8];
211 uint8_t x_ftype;
212 } _x;
213 } x_file;
214 #if BACKTRACE_XCOFF_SIZE == 32
215 struct {
216 uint32_t x_exptr;
217 uint32_t x_fsize;
218 uint32_t x_lnnoptr;
219 uint32_t x_endndx;
220 } x_fcn;
221 #else
222 struct {
223 uint64_t x_lnnoptr;
224 uint32_t x_fsize;
225 uint32_t x_endndx;
226 } x_fcn;
227 #endif
228 struct {
229 uint8_t pad[AUXESZ-1];
230 uint8_t x_auxtype;
231 } x_auxtype;
232 } __attribute__ ((packed)) b_xcoff_auxent;
233
234 /* XCOFF line number entry. */
235
236 #if BACKTRACE_XCOFF_SIZE == 32
237
238 typedef struct {
239 union {
240 uint32_t l_symndx;
241 uint32_t l_paddr;
242 } l_addr;
243 uint16_t l_lnno;
244 } b_xcoff_lineno;
245
246 #define LINESZ 6
247
248 #else /* BACKTRACE_XCOFF_SIZE != 32 */
249
250 typedef struct {
251 union {
252 uint32_t l_symndx;
253 uint64_t l_paddr;
254 } l_addr;
255 uint32_t l_lnno;
256 } b_xcoff_lineno;
257
258 #define LINESZ 12
259
260 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
261
262 #if BACKTRACE_XCOFF_SIZE == 32
263 #define XCOFF_AIX_TEXTBASE 0x10000000u
264 #else
265 #define XCOFF_AIX_TEXTBASE 0x100000000ul
266 #endif
267
268 /* AIX big archive fixed-length header. */
269
270 #define AIAMAGBIG "<bigaf>\n"
271
272 typedef struct {
273 char fl_magic[8]; /* Archive magic string. */
274 char fl_memoff[20]; /* Offset to member table. */
275 char fl_gstoff[20]; /* Offset to global symbol table. */
276 char fl_gst64off[20]; /* Offset to global symbol table for 64-bit objects. */
277 char fl_fstmoff[20]; /* Offset to first archive member. */
278 char fl_freeoff[20]; /* Offset to first member on free list. */
279 } b_ar_fl_hdr;
280
281 /* AIX big archive file member header. */
282
283 typedef struct {
284 char ar_size[20]; /* File member size - decimal. */
285 char ar_nxtmem[20]; /* Next member offset - decimal. */
286 char ar_prvmem[20]; /* Previous member offset - decimal. */
287 char ar_date[12]; /* File member date - decimal. */
288 char ar_uid[12]; /* File member userid - decimal. */
289 char ar_gid[12]; /* File member group id - decimal. */
290 char ar_mode[12]; /* File member mode - octal. */
291 char ar_namlen[4]; /* File member name length - decimal. */
292 char ar_name[2]; /* Start of member name. */
293 } b_ar_hdr;
294
295
296 /* Information we keep for an XCOFF symbol. */
297
298 struct xcoff_symbol
299 {
300 /* The name of the symbol. */
301 const char *name;
302 /* The address of the symbol. */
303 uintptr_t address;
304 /* The size of the symbol. */
305 size_t size;
306 };
307
308 /* Information to pass to xcoff_syminfo. */
309
310 struct xcoff_syminfo_data
311 {
312 /* Symbols for the next module. */
313 struct xcoff_syminfo_data *next;
314 /* The XCOFF symbols, sorted by address. */
315 struct xcoff_symbol *symbols;
316 /* The number of symbols. */
317 size_t count;
318 };
319
320 /* Information about an include file. */
321
322 struct xcoff_incl
323 {
324 /* File name. */
325 const char *filename;
326 /* Offset to first line number from the include file. */
327 uintptr_t begin;
328 /* Offset to last line number from the include file. */
329 uintptr_t end;
330 };
331
332 /* A growable vector of include files information. */
333
334 struct xcoff_incl_vector
335 {
336 /* Memory. This is an array of struct xcoff_incl. */
337 struct backtrace_vector vec;
338 /* Number of include files. */
339 size_t count;
340 };
341
342 /* A growable vector of functions information. */
343
344 struct xcoff_func
345 {
346 /* PC. */
347 uintptr_t pc;
348 /* The size of the function. */
349 size_t size;
350 /* Function name. */
351 const char *name;
352 /* File name. */
353 const char *filename;
354 /* Pointer to first lnno entry. */
355 uintptr_t lnnoptr;
356 /* Base address of containing section. */
357 uintptr_t sect_base;
358 /* Starting source line number. */
359 int lnno;
360 };
361
362 /* A growable vector of function information. This is used while
363 reading the function symbols. */
364
365 struct xcoff_func_vector
366 {
367 /* Memory. This is an array of struct xcoff_func. */
368 struct backtrace_vector vec;
369 /* Number of valid mappings. */
370 size_t count;
371 };
372
373 /* The information we need to map a PC to a file and line. */
374
375 struct xcoff_fileline_data
376 {
377 /* The data for the next file we know about. */
378 struct xcoff_fileline_data *next;
379 /* Functions information. */
380 struct xcoff_func_vector func_vec;
381 /* Include files information. */
382 struct xcoff_incl_vector incl_vec;
383 /* Line numbers information. */
384 const unsigned char *linenos;
385 size_t linenos_size;
386 uint64_t lnnoptr0;
387 /* Loader address. */
388 uintptr_t base_address;
389 };
390
391 /* Information we gather for the DWARF sections we care about. */
392
393 struct dwsect_info
394 {
395 /* Section file offset. */
396 off_t offset;
397 /* Section size. */
398 size_t size;
399 /* Section contents, after read from file. */
400 const unsigned char *data;
401 };
402
403 /* A dummy callback function used when we can't find any debug info. */
404
405 static int
406 xcoff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
407 uintptr_t pc ATTRIBUTE_UNUSED,
408 backtrace_full_callback callback ATTRIBUTE_UNUSED,
409 backtrace_error_callback error_callback, void *data)
410 {
411 error_callback (data, "no debug info in XCOFF executable", -1);
412 return 0;
413 }
414
415 /* A dummy callback function used when we can't find a symbol
416 table. */
417
418 static void
419 xcoff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
420 uintptr_t addr ATTRIBUTE_UNUSED,
421 backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
422 backtrace_error_callback error_callback, void *data)
423 {
424 error_callback (data, "no symbol table in XCOFF executable", -1);
425 }
426
427 /* Compare struct xcoff_symbol for qsort. */
428
429 static int
430 xcoff_symbol_compare (const void *v1, const void *v2)
431 {
432 const struct xcoff_symbol *e1 = (const struct xcoff_symbol *) v1;
433 const struct xcoff_symbol *e2 = (const struct xcoff_symbol *) v2;
434
435 if (e1->address < e2->address)
436 return -1;
437 else if (e1->address > e2->address)
438 return 1;
439 else
440 return 0;
441 }
442
443 /* Compare an ADDR against an xcoff_symbol for bsearch. */
444
445 static int
446 xcoff_symbol_search (const void *vkey, const void *ventry)
447 {
448 const uintptr_t *key = (const uintptr_t *) vkey;
449 const struct xcoff_symbol *entry = (const struct xcoff_symbol *) ventry;
450 uintptr_t addr;
451
452 addr = *key;
453 if (addr < entry->address)
454 return -1;
455 else if ((entry->size == 0 && addr > entry->address)
456 || (entry->size > 0 && addr >= entry->address + entry->size))
457 return 1;
458 else
459 return 0;
460 }
461
462 /* Add XDATA to the list in STATE. */
463
464 static void
465 xcoff_add_syminfo_data (struct backtrace_state *state,
466 struct xcoff_syminfo_data *xdata)
467 {
468 if (!state->threaded)
469 {
470 struct xcoff_syminfo_data **pp;
471
472 for (pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
473 *pp != NULL;
474 pp = &(*pp)->next)
475 ;
476 *pp = xdata;
477 }
478 else
479 {
480 while (1)
481 {
482 struct xcoff_syminfo_data **pp;
483
484 pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
485
486 while (1)
487 {
488 struct xcoff_syminfo_data *p;
489
490 p = backtrace_atomic_load_pointer (pp);
491
492 if (p == NULL)
493 break;
494
495 pp = &p->next;
496 }
497
498 if (__sync_bool_compare_and_swap (pp, NULL, xdata))
499 break;
500 }
501 }
502 }
503
504 /* Return the symbol name and value for an ADDR. */
505
506 static void
507 xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr,
508 backtrace_syminfo_callback callback,
509 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
510 void *data)
511 {
512 struct xcoff_syminfo_data *edata;
513 struct xcoff_symbol *sym = NULL;
514 const char *name;
515
516 if (!state->threaded)
517 {
518 for (edata = (struct xcoff_syminfo_data *) state->syminfo_data;
519 edata != NULL;
520 edata = edata->next)
521 {
522 sym = ((struct xcoff_symbol *)
523 bsearch (&addr, edata->symbols, edata->count,
524 sizeof (struct xcoff_symbol), xcoff_symbol_search));
525 if (sym != NULL)
526 break;
527 }
528 }
529 else
530 {
531 struct xcoff_syminfo_data **pp;
532
533 pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
534 while (1)
535 {
536 edata = backtrace_atomic_load_pointer (pp);
537 if (edata == NULL)
538 break;
539
540 sym = ((struct xcoff_symbol *)
541 bsearch (&addr, edata->symbols, edata->count,
542 sizeof (struct xcoff_symbol), xcoff_symbol_search));
543 if (sym != NULL)
544 break;
545
546 pp = &edata->next;
547 }
548 }
549
550 if (sym == NULL)
551 callback (data, addr, NULL, 0, 0);
552 else
553 {
554 name = sym->name;
555 /* AIX prepends a '.' to function entry points, remove it. */
556 if (name && *name == '.')
557 ++name;
558 callback (data, addr, name, sym->address, sym->size);
559 }
560 }
561
562 /* Return the name of an XCOFF symbol. */
563
564 static const char *
565 xcoff_symname (const b_xcoff_syment *asym,
566 const unsigned char *strtab, size_t strtab_size)
567 {
568 #if BACKTRACE_XCOFF_SIZE == 32
569 if (asym->n_zeroes != 0)
570 {
571 /* Make a copy as we will release the symtab view. */
572 char name[SYMNMLEN+1];
573 strncpy (name, asym->n_name, SYMNMLEN);
574 name[SYMNMLEN] = '\0';
575 return strdup (name);
576 }
577 #endif
578 if (asym->n_sclass & 0x80)
579 return NULL; /* .debug */
580 if (asym->n_offset_ >= strtab_size)
581 return NULL;
582 return (const char *) strtab + asym->n_offset_;
583 }
584
585 /* Initialize the symbol table info for xcoff_syminfo. */
586
587 static int
588 xcoff_initialize_syminfo (struct backtrace_state *state,
589 uintptr_t base_address,
590 const b_xcoff_syment *syms, size_t nsyms,
591 const unsigned char *strtab, size_t strtab_size,
592 backtrace_error_callback error_callback, void *data,
593 struct xcoff_syminfo_data *sdata)
594 {
595 size_t xcoff_symbol_count;
596 size_t xcoff_symbol_size;
597 struct xcoff_symbol *xcoff_symbols;
598 size_t i;
599 unsigned int j;
600
601 /* We only care about function symbols. Count them. */
602 xcoff_symbol_count = 0;
603 for (i = 0; i < nsyms; ++i)
604 {
605 const b_xcoff_syment *asym = &syms[i];
606 if ((asym->n_sclass == C_EXT || asym->n_sclass == C_HIDEXT
607 || asym->n_sclass == C_WEAKEXT)
608 && ISFCN (asym->n_type) && asym->n_numaux > 0 && asym->n_scnum > 0)
609 ++xcoff_symbol_count;
610
611 i += asym->n_numaux;
612 }
613
614 xcoff_symbol_size = xcoff_symbol_count * sizeof (struct xcoff_symbol);
615 xcoff_symbols = ((struct xcoff_symbol *)
616 backtrace_alloc (state, xcoff_symbol_size, error_callback,
617 data));
618 if (xcoff_symbols == NULL)
619 return 0;
620
621 j = 0;
622 for (i = 0; i < nsyms; ++i)
623 {
624 const b_xcoff_syment *asym = &syms[i];
625 if ((asym->n_sclass == C_EXT || asym->n_sclass == C_HIDEXT
626 || asym->n_sclass == C_WEAKEXT)
627 && ISFCN (asym->n_type) && asym->n_numaux > 0 && asym->n_scnum > 0)
628 {
629 const b_xcoff_auxent *aux = (const b_xcoff_auxent *) (asym + 1);
630 xcoff_symbols[j].name = xcoff_symname (asym, strtab, strtab_size);
631 xcoff_symbols[j].address = base_address + asym->n_value;
632 /* x_fsize will be 0 if there is no debug information. */
633 xcoff_symbols[j].size = aux->x_fcn.x_fsize;
634 ++j;
635 }
636
637 i += asym->n_numaux;
638 }
639
640 backtrace_qsort (xcoff_symbols, xcoff_symbol_count,
641 sizeof (struct xcoff_symbol), xcoff_symbol_compare);
642
643 sdata->next = NULL;
644 sdata->symbols = xcoff_symbols;
645 sdata->count = xcoff_symbol_count;
646
647 return 1;
648 }
649
650 /* Compare struct xcoff_func for qsort. */
651
652 static int
653 xcoff_func_compare (const void *v1, const void *v2)
654 {
655 const struct xcoff_func *fn1 = (const struct xcoff_func *) v1;
656 const struct xcoff_func *fn2 = (const struct xcoff_func *) v2;
657
658 if (fn1->pc < fn2->pc)
659 return -1;
660 else if (fn1->pc > fn2->pc)
661 return 1;
662 else
663 return 0;
664 }
665
666 /* Compare a PC against an xcoff_func for bsearch. */
667
668 static int
669 xcoff_func_search (const void *vkey, const void *ventry)
670 {
671 const uintptr_t *key = (const uintptr_t *) vkey;
672 const struct xcoff_func *entry = (const struct xcoff_func *) ventry;
673 uintptr_t pc;
674
675 pc = *key;
676 if (pc < entry->pc)
677 return -1;
678 else if ((entry->size == 0 && pc > entry->pc)
679 || (entry->size > 0 && pc >= entry->pc + entry->size))
680 return 1;
681 else
682 return 0;
683 }
684
685 /* Compare struct xcoff_incl for qsort. */
686
687 static int
688 xcoff_incl_compare (const void *v1, const void *v2)
689 {
690 const struct xcoff_incl *in1 = (const struct xcoff_incl *) v1;
691 const struct xcoff_incl *in2 = (const struct xcoff_incl *) v2;
692
693 if (in1->begin < in2->begin)
694 return -1;
695 else if (in1->begin > in2->begin)
696 return 1;
697 else
698 return 0;
699 }
700
701 /* Find a lnnoptr in an include file. */
702
703 static int
704 xcoff_incl_search (const void *vkey, const void *ventry)
705 {
706 const uintptr_t *key = (const uintptr_t *) vkey;
707 const struct xcoff_incl *entry = (const struct xcoff_incl *) ventry;
708 uintptr_t lnno;
709
710 lnno = *key;
711 if (lnno < entry->begin)
712 return -1;
713 else if (lnno > entry->end)
714 return 1;
715 else
716 return 0;
717 }
718
719 /* Look for a PC in the function vector for one module. On success,
720 call CALLBACK and return whatever it returns. On error, call
721 ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found,
722 0 if not. */
723
724 static int
725 xcoff_lookup_pc (struct backtrace_state *state ATTRIBUTE_UNUSED,
726 struct xcoff_fileline_data *fdata, uintptr_t pc,
727 backtrace_full_callback callback,
728 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
729 void *data, int *found)
730 {
731 const struct xcoff_incl *incl, *bincl;
732 const struct xcoff_func *fn;
733 const b_xcoff_lineno *lineno;
734 const unsigned char *lineptr;
735 const char *function;
736 const char *filename;
737 uintptr_t lnnoptr, match;
738 uint32_t lnno = 0;
739
740 *found = 1;
741
742 if ((pc & 3) != 0)
743 ++pc;
744
745 /* Find the function first. */
746 fn = ((struct xcoff_func *)
747 bsearch (&pc, fdata->func_vec.vec.base, fdata->func_vec.count,
748 sizeof (struct xcoff_func), xcoff_func_search));
749 if (fn == NULL)
750 {
751 *found = 0;
752 return 0;
753 }
754
755 filename = fn->filename;
756
757 /* Find the line number next. */
758
759 /* Skip first entry that points to symtab. */
760 lnnoptr = fn->lnnoptr + LINESZ;
761 match = lnnoptr;
762
763 lineptr = fdata->linenos + (lnnoptr - fdata->lnnoptr0);
764 while (lineptr + LINESZ <= fdata->linenos + fdata->linenos_size)
765 {
766 lineno = (const b_xcoff_lineno *) lineptr;
767 if (lineno->l_lnno == 0)
768 break;
769 if (pc <= fdata->base_address + lineno->l_addr.l_paddr)
770 break;
771 match = lnnoptr;
772 lnno = lineno->l_lnno;
773
774 lnnoptr += LINESZ;
775 lineptr += LINESZ;
776 }
777
778 /* If part of a function other than the beginning comes from an
779 include file, the line numbers are absolute, rather than
780 relative to the beginning of the function. */
781 incl = ((struct xcoff_incl *)
782 bsearch (&match, fdata->incl_vec.vec.base,
783 fdata->incl_vec.count, sizeof (struct xcoff_incl),
784 xcoff_incl_search));
785 if (incl != NULL)
786 {
787 bincl = ((struct xcoff_incl *)
788 bsearch (&fn->lnnoptr, fdata->incl_vec.vec.base,
789 fdata->incl_vec.count, sizeof (struct xcoff_incl),
790 xcoff_incl_search));
791 if (bincl != NULL && strcmp (incl->filename, bincl->filename) == 0)
792 {
793 lnno += fn->lnno - 1;
794 }
795 filename = incl->filename;
796 }
797 else
798 {
799 lnno += fn->lnno - 1;
800 }
801
802 function = fn->name;
803 /* AIX prepends a '.' to function entry points, remove it. */
804 if (function != NULL && *function == '.')
805 ++function;
806 return callback (data, pc, filename, lnno, function);
807 }
808
809 /* Return the file/line information for a PC using the XCOFF lineno
810 mapping we built earlier. */
811
812 static int
813 xcoff_fileline (struct backtrace_state *state, uintptr_t pc,
814 backtrace_full_callback callback,
815 backtrace_error_callback error_callback, void *data)
816
817 {
818 struct xcoff_fileline_data *fdata;
819 int found;
820 int ret;
821
822 if (!state->threaded)
823 {
824 for (fdata = (struct xcoff_fileline_data *) state->fileline_data;
825 fdata != NULL;
826 fdata = fdata->next)
827 {
828 ret = xcoff_lookup_pc (state, fdata, pc, callback, error_callback,
829 data, &found);
830 if (ret != 0 || found)
831 return ret;
832 }
833 }
834 else
835 {
836 struct xcoff_fileline_data **pp;
837
838 pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
839 while (1)
840 {
841 fdata = backtrace_atomic_load_pointer (pp);
842 if (fdata == NULL)
843 break;
844
845 ret = xcoff_lookup_pc (state, fdata, pc, callback, error_callback,
846 data, &found);
847 if (ret != 0 || found)
848 return ret;
849
850 pp = &fdata->next;
851 }
852 }
853
854 /* FIXME: See if any libraries have been dlopen'ed. */
855
856 return callback (data, pc, NULL, 0, NULL);
857 }
858
859 /* Initialize the function vector info for xcoff_fileline. */
860
861 static int
862 xcoff_initialize_fileline (struct backtrace_state *state,
863 uintptr_t base_address,
864 const b_xcoff_scnhdr *sects,
865 const b_xcoff_syment *syms, size_t nsyms,
866 const unsigned char *strtab, size_t strtab_size,
867 const unsigned char *linenos, size_t linenos_size,
868 uint64_t lnnoptr0,
869 backtrace_error_callback error_callback, void *data)
870 {
871 struct xcoff_fileline_data *fdata;
872 struct xcoff_func *fn;
873 const b_xcoff_syment *fsym;
874 const b_xcoff_auxent *aux;
875 const char *filename;
876 const char *name;
877 struct xcoff_incl *incl;
878 uintptr_t begin, end;
879 uintptr_t lnno, lnnoptr;
880 uint32_t fsize;
881 size_t i;
882
883 fdata = ((struct xcoff_fileline_data *)
884 backtrace_alloc (state, sizeof (struct xcoff_fileline_data),
885 error_callback, data));
886 if (fdata == NULL)
887 return 0;
888 memset (fdata, 0, sizeof *fdata);
889 fdata->base_address = base_address;
890 fdata->linenos = linenos;
891 fdata->linenos_size = linenos_size;
892 fdata->lnnoptr0 = lnnoptr0;
893
894 begin = 0;
895 filename = NULL;
896 fsym = NULL;
897 lnnoptr = 0;
898 fsize = 0;
899 for (i = 0; i < nsyms; ++i)
900 {
901 const b_xcoff_syment *asym = &syms[i];
902
903 switch (asym->n_sclass)
904 {
905 case C_BINCL:
906 begin = asym->n_value;
907 break;
908
909 case C_EINCL:
910 if (begin == 0)
911 break;
912 end = asym->n_value;
913 incl = ((struct xcoff_incl *)
914 backtrace_vector_grow (state, sizeof (struct xcoff_incl),
915 error_callback, data,
916 &fdata->incl_vec.vec));
917 if (incl != NULL)
918 {
919 incl->filename = xcoff_symname (asym, strtab, strtab_size);
920 incl->begin = begin;
921 incl->end = end;
922 ++fdata->incl_vec.count;
923 }
924 begin = 0;
925 break;
926
927 case C_FILE:
928 filename = xcoff_symname (asym, strtab, strtab_size);
929 if (filename == NULL)
930 break;
931
932 /* If the file auxiliary entry is not used, the symbol name is
933 the name of the source file. If the file auxiliary entry is
934 used, then the symbol name should be .file, and the first
935 file auxiliary entry (by convention) contains the source
936 file name. */
937
938 if (asym->n_numaux > 0 && strcmp (filename, ".file") == 0)
939 {
940 aux = (const b_xcoff_auxent *) (asym + 1);
941 if (aux->x_file._x.x_zeroes != 0)
942 {
943 /* Make a copy as we will release the symtab view. */
944 char name[FILNMLEN+1];
945 strncpy (name, aux->x_file.x_fname, FILNMLEN);
946 name[FILNMLEN] = '\0';
947 filename = strdup (name);
948 }
949 else if (aux->x_file._x.x_offset < strtab_size)
950 filename = (const char *) strtab + aux->x_file._x.x_offset;
951 else
952 filename = NULL;
953 }
954 break;
955
956 case C_EXT:
957 case C_HIDEXT:
958 case C_WEAKEXT:
959 fsym = NULL;
960 lnnoptr = 0;
961 fsize = 0;
962 if (!ISFCN (asym->n_type) || asym->n_numaux == 0
963 || asym->n_scnum <= 0)
964 break;
965 if (filename == NULL)
966 break;
967 aux = (const b_xcoff_auxent *) (asym + 1);
968 lnnoptr = aux->x_fcn.x_lnnoptr;
969 if (lnnoptr < lnnoptr0
970 || lnnoptr + LINESZ > lnnoptr0 + linenos_size)
971 break;
972 /* x_fsize will be 0 if there is no debug information. */
973 fsize = aux->x_fcn.x_fsize;
974 fsym = asym;
975 break;
976
977 case C_FCN:
978 if (asym->n_numaux == 0)
979 break;
980 if (fsym == NULL)
981 break;
982 name = xcoff_symname (asym, strtab, strtab_size);
983 if (name == NULL || strcmp (name, ".bf") != 0)
984 {
985 fsym = NULL;
986 break;
987 }
988 aux = (const b_xcoff_auxent *) (asym + 1);
989 #if BACKTRACE_XCOFF_SIZE == 32
990 lnno = (uint32_t) aux->x_block.x_lnnohi << 16
991 | aux->x_block.x_lnno;
992 #else
993 lnno = aux->x_block.x_lnno;
994 #endif
995 fn = ((struct xcoff_func *)
996 backtrace_vector_grow (state, sizeof (struct xcoff_func),
997 error_callback, data,
998 &fdata->func_vec.vec));
999 if (fn == NULL)
1000 break;
1001 fn->name = xcoff_symname (fsym, strtab, strtab_size);
1002 fn->filename = filename;
1003 fn->sect_base = sects[fsym->n_scnum - 1].s_paddr;
1004 fn->pc = base_address + fsym->n_value;
1005 fn->size = fsize;
1006 fn->lnno = lnno;
1007 fn->lnnoptr = lnnoptr;
1008 ++fdata->func_vec.count;
1009 break;
1010 }
1011
1012 i += asym->n_numaux;
1013 }
1014
1015 if (!backtrace_vector_release (state, &fdata->func_vec.vec, error_callback,
1016 data))
1017 goto fail;
1018 backtrace_qsort (fdata->func_vec.vec.base, fdata->func_vec.count,
1019 sizeof (struct xcoff_func), xcoff_func_compare);
1020
1021 if (!backtrace_vector_release (state, &fdata->incl_vec.vec, error_callback,
1022 data))
1023 goto fail;
1024 backtrace_qsort (fdata->incl_vec.vec.base, fdata->incl_vec.count,
1025 sizeof (struct xcoff_incl), xcoff_incl_compare);
1026
1027 if (!state->threaded)
1028 {
1029 struct xcoff_fileline_data **pp;
1030
1031 for (pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
1032 *pp != NULL;
1033 pp = &(*pp)->next)
1034 ;
1035 *pp = fdata;
1036 }
1037 else
1038 {
1039 while (1)
1040 {
1041 struct xcoff_fileline_data **pp;
1042
1043 pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
1044
1045 while (1)
1046 {
1047 struct xcoff_fileline_data *p;
1048
1049 p = backtrace_atomic_load_pointer (pp);
1050
1051 if (p == NULL)
1052 break;
1053
1054 pp = &p->next;
1055 }
1056
1057 if (__sync_bool_compare_and_swap (pp, NULL, fdata))
1058 break;
1059 }
1060 }
1061
1062 return 1;
1063
1064 fail:
1065 return 0;
1066 }
1067
1068 /* Add the backtrace data for one XCOFF file. Returns 1 on success,
1069 0 on failure (in both cases descriptor is closed). */
1070
1071 static int
1072 xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
1073 uintptr_t base_address, backtrace_error_callback error_callback,
1074 void *data, fileline *fileline_fn, int *found_sym, int exe)
1075 {
1076 struct backtrace_view fhdr_view;
1077 struct backtrace_view sects_view;
1078 struct backtrace_view linenos_view;
1079 struct backtrace_view syms_view;
1080 struct backtrace_view str_view;
1081 struct backtrace_view dwarf_view;
1082 b_xcoff_filhdr fhdr;
1083 const b_xcoff_scnhdr *sects;
1084 const b_xcoff_scnhdr *stext;
1085 uint64_t lnnoptr;
1086 uint32_t nlnno;
1087 off_t str_off;
1088 off_t min_offset;
1089 off_t max_offset;
1090 struct dwsect_info dwsect[DEBUG_MAX];
1091 size_t sects_size;
1092 size_t syms_size;
1093 int32_t str_size;
1094 int sects_view_valid;
1095 int linenos_view_valid;
1096 int syms_view_valid;
1097 int str_view_valid;
1098 int dwarf_view_valid;
1099 int magic_ok;
1100 int i;
1101 struct dwarf_sections dwarf_sections;
1102
1103 *found_sym = 0;
1104
1105 sects_view_valid = 0;
1106 linenos_view_valid = 0;
1107 syms_view_valid = 0;
1108 str_view_valid = 0;
1109 dwarf_view_valid = 0;
1110
1111 str_size = 0;
1112
1113 /* Map the XCOFF file header. */
1114 if (!backtrace_get_view (state, descriptor, offset, sizeof (b_xcoff_filhdr),
1115 error_callback, data, &fhdr_view))
1116 goto fail;
1117
1118 memcpy (&fhdr, fhdr_view.data, sizeof fhdr);
1119 magic_ok = (fhdr.f_magic == XCOFF_MAGIC);
1120
1121 backtrace_release_view (state, &fhdr_view, error_callback, data);
1122
1123 if (!magic_ok)
1124 {
1125 if (exe)
1126 error_callback (data, "executable file is not XCOFF", 0);
1127 goto fail;
1128 }
1129
1130 /* Verify object is of expected type. */
1131 if ((exe && (fhdr.f_flags & F_SHROBJ))
1132 || (!exe && !(fhdr.f_flags & F_SHROBJ)))
1133 goto fail;
1134
1135 /* Read the section headers. */
1136
1137 sects_size = fhdr.f_nscns * sizeof (b_xcoff_scnhdr);
1138
1139 if (!backtrace_get_view (state, descriptor,
1140 offset + sizeof (fhdr) + fhdr.f_opthdr,
1141 sects_size, error_callback, data, &sects_view))
1142 goto fail;
1143 sects_view_valid = 1;
1144 sects = (const b_xcoff_scnhdr *) sects_view.data;
1145
1146 /* FIXME: assumes only one .text section. */
1147 for (i = 0; i < fhdr.f_nscns; ++i)
1148 if ((sects[i].s_flags & 0xffff) == STYP_TEXT)
1149 break;
1150 if (i == fhdr.f_nscns)
1151 goto fail;
1152
1153 stext = &sects[i];
1154
1155 /* base_address represents the difference between the
1156 virtual memory address of the shared object or a loaded
1157 executable and the offset of that object in the file
1158 from which it was loaded.
1159 On AIX, virtual address is either fixed for executable
1160 or given by ldinfo. This address will include the XCOFF
1161 headers. */
1162 base_address = ((exe ? XCOFF_AIX_TEXTBASE : base_address)
1163 + stext->s_scnptr
1164 - stext->s_paddr);
1165
1166 lnnoptr = stext->s_lnnoptr;
1167 nlnno = stext->s_nlnno;
1168
1169 #if BACKTRACE_XCOFF_SIZE == 32
1170 if (nlnno == _OVERFLOW_MARKER)
1171 {
1172 int sntext = i + 1;
1173 /* Find the matching .ovrflo section. */
1174 for (i = 0; i < fhdr.f_nscns; ++i)
1175 {
1176 if (((sects[i].s_flags & 0xffff) == STYP_OVRFLO)
1177 && sects[i].s_nlnno == sntext)
1178 {
1179 nlnno = sects[i].s_vaddr;
1180 break;
1181 }
1182 }
1183 }
1184 #endif
1185
1186 /* Read the symbol table and the string table. */
1187
1188 if (fhdr.f_symptr != 0)
1189 {
1190 struct xcoff_syminfo_data *sdata;
1191
1192 /* Symbol table is followed by the string table. The string table
1193 starts with its length (on 4 bytes).
1194 Map the symbol table and the length of the string table. */
1195 syms_size = fhdr.f_nsyms * sizeof (b_xcoff_syment);
1196
1197 if (!backtrace_get_view (state, descriptor, offset + fhdr.f_symptr,
1198 syms_size + 4, error_callback, data,
1199 &syms_view))
1200 goto fail;
1201 syms_view_valid = 1;
1202
1203 memcpy (&str_size, syms_view.data + syms_size, 4);
1204
1205 str_off = fhdr.f_symptr + syms_size;
1206
1207 if (str_size > 4)
1208 {
1209 /* Map string table (including the length word). */
1210
1211 if (!backtrace_get_view (state, descriptor, offset + str_off,
1212 str_size, error_callback, data, &str_view))
1213 goto fail;
1214 str_view_valid = 1;
1215 }
1216
1217 sdata = ((struct xcoff_syminfo_data *)
1218 backtrace_alloc (state, sizeof *sdata, error_callback, data));
1219 if (sdata == NULL)
1220 goto fail;
1221
1222 if (!xcoff_initialize_syminfo (state, base_address,
1223 syms_view.data, fhdr.f_nsyms,
1224 str_view.data, str_size,
1225 error_callback, data, sdata))
1226 {
1227 backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
1228 goto fail;
1229 }
1230
1231 *found_sym = 1;
1232
1233 xcoff_add_syminfo_data (state, sdata);
1234 }
1235
1236 /* Read all the DWARF sections in a single view, since they are
1237 probably adjacent in the file. We never release this view. */
1238
1239 min_offset = 0;
1240 max_offset = 0;
1241 memset (dwsect, 0, sizeof dwsect);
1242 for (i = 0; i < fhdr.f_nscns; ++i)
1243 {
1244 off_t end;
1245 int idx;
1246
1247 if ((sects[i].s_flags & 0xffff) != STYP_DWARF
1248 || sects[i].s_size == 0)
1249 continue;
1250 /* Map DWARF section to array index. */
1251 switch (sects[i].s_flags & 0xffff0000)
1252 {
1253 case SSUBTYP_DWINFO:
1254 idx = DEBUG_INFO;
1255 break;
1256 case SSUBTYP_DWLINE:
1257 idx = DEBUG_LINE;
1258 break;
1259 case SSUBTYP_DWABREV:
1260 idx = DEBUG_ABBREV;
1261 break;
1262 case SSUBTYP_DWRNGES:
1263 idx = DEBUG_RANGES;
1264 break;
1265 case SSUBTYP_DWSTR:
1266 idx = DEBUG_STR;
1267 break;
1268 default:
1269 continue;
1270 }
1271 if (min_offset == 0 || (off_t) sects[i].s_scnptr < min_offset)
1272 min_offset = sects[i].s_scnptr;
1273 end = sects[i].s_scnptr + sects[i].s_size;
1274 if (end > max_offset)
1275 max_offset = end;
1276 dwsect[idx].offset = sects[i].s_scnptr;
1277 dwsect[idx].size = sects[i].s_size;
1278 }
1279 if (min_offset != 0 && max_offset != 0)
1280 {
1281 if (!backtrace_get_view (state, descriptor, offset + min_offset,
1282 max_offset - min_offset,
1283 error_callback, data, &dwarf_view))
1284 goto fail;
1285 dwarf_view_valid = 1;
1286
1287 for (i = 0; i < (int) DEBUG_MAX; ++i)
1288 {
1289 if (dwsect[i].offset == 0)
1290 dwsect[i].data = NULL;
1291 else
1292 dwsect[i].data = ((const unsigned char *) dwarf_view.data
1293 + (dwsect[i].offset - min_offset));
1294 }
1295
1296 memset (&dwarf_sections, 0, sizeof dwarf_sections);
1297
1298 dwarf_sections.data[DEBUG_INFO] = dwsect[DEBUG_INFO].data;
1299 dwarf_sections.size[DEBUG_INFO] = dwsect[DEBUG_INFO].size;
1300 dwarf_sections.data[DEBUG_LINE] = dwsect[DEBUG_LINE].data;
1301 dwarf_sections.size[DEBUG_LINE] = dwsect[DEBUG_LINE].size;
1302 dwarf_sections.data[DEBUG_ABBREV] = dwsect[DEBUG_ABBREV].data;
1303 dwarf_sections.size[DEBUG_ABBREV] = dwsect[DEBUG_ABBREV].size;
1304 dwarf_sections.data[DEBUG_RANGES] = dwsect[DEBUG_RANGES].data;
1305 dwarf_sections.size[DEBUG_RANGES] = dwsect[DEBUG_RANGES].size;
1306 dwarf_sections.data[DEBUG_STR] = dwsect[DEBUG_STR].data;
1307 dwarf_sections.size[DEBUG_STR] = dwsect[DEBUG_STR].size;
1308
1309 if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,
1310 1, /* big endian */
1311 NULL, /* altlink */
1312 error_callback, data, fileline_fn,
1313 NULL /* returned fileline_entry */))
1314 goto fail;
1315 }
1316
1317 /* Read the XCOFF line number entries if DWARF sections not found. */
1318
1319 if (!dwarf_view_valid && fhdr.f_symptr != 0 && lnnoptr != 0)
1320 {
1321 size_t linenos_size = (size_t) nlnno * LINESZ;
1322
1323 /* We never release this view. */
1324 if (!backtrace_get_view (state, descriptor, offset + lnnoptr,
1325 linenos_size,
1326 error_callback, data, &linenos_view))
1327 goto fail;
1328 linenos_view_valid = 1;
1329
1330 if (xcoff_initialize_fileline (state, base_address, sects,
1331 syms_view.data, fhdr.f_nsyms,
1332 str_view.data, str_size,
1333 linenos_view.data, linenos_size,
1334 lnnoptr, error_callback, data))
1335 *fileline_fn = xcoff_fileline;
1336 }
1337
1338 backtrace_release_view (state, &sects_view, error_callback, data);
1339 sects_view_valid = 0;
1340 if (syms_view_valid)
1341 backtrace_release_view (state, &syms_view, error_callback, data);
1342 syms_view_valid = 0;
1343
1344 /* We've read all we need from the executable. */
1345 if (!backtrace_close (descriptor, error_callback, data))
1346 goto fail;
1347 descriptor = -1;
1348
1349 return 1;
1350
1351 fail:
1352 if (sects_view_valid)
1353 backtrace_release_view (state, &sects_view, error_callback, data);
1354 if (str_view_valid)
1355 backtrace_release_view (state, &str_view, error_callback, data);
1356 if (syms_view_valid)
1357 backtrace_release_view (state, &syms_view, error_callback, data);
1358 if (linenos_view_valid)
1359 backtrace_release_view (state, &linenos_view, error_callback, data);
1360 if (dwarf_view_valid)
1361 backtrace_release_view (state, &dwarf_view, error_callback, data);
1362 if (descriptor != -1 && offset == 0)
1363 backtrace_close (descriptor, error_callback, data);
1364 return 0;
1365 }
1366
1367 #ifdef HAVE_LOADQUERY
1368
1369 /* Read an integer value in human-readable format from an AIX
1370 big archive fixed-length or member header. */
1371
1372 static int
1373 xcoff_parse_decimal (const char *buf, size_t size, off_t *off)
1374 {
1375 char str[32];
1376 char *end;
1377
1378 if (size >= sizeof str)
1379 return 0;
1380 memcpy (str, buf, size);
1381 str[size] = '\0';
1382 *off = strtol (str, &end, 10);
1383 if (*end != '\0' && *end != ' ')
1384 return 0;
1385
1386 return 1;
1387 }
1388
1389 /* Add the backtrace data for a member of an AIX big archive.
1390 Returns 1 on success, 0 on failure. */
1391
1392 static int
1393 xcoff_armem_add (struct backtrace_state *state, int descriptor,
1394 uintptr_t base_address, const char *member,
1395 backtrace_error_callback error_callback, void *data,
1396 fileline *fileline_fn, int *found_sym)
1397 {
1398 struct backtrace_view view;
1399 b_ar_fl_hdr fl_hdr;
1400 const b_ar_hdr *ar_hdr;
1401 off_t off;
1402 off_t len;
1403 int memlen;
1404
1405 *found_sym = 0;
1406
1407 /* Map archive fixed-length header. */
1408
1409 if (!backtrace_get_view (state, descriptor, 0, sizeof (b_ar_fl_hdr),
1410 error_callback, data, &view))
1411 goto fail;
1412
1413 memcpy (&fl_hdr, view.data, sizeof (b_ar_fl_hdr));
1414
1415 backtrace_release_view (state, &view, error_callback, data);
1416
1417 if (memcmp (fl_hdr.fl_magic, AIAMAGBIG, 8) != 0)
1418 goto fail;
1419
1420 memlen = strlen (member);
1421
1422 /* Read offset of first archive member. */
1423 if (!xcoff_parse_decimal (fl_hdr.fl_fstmoff, sizeof fl_hdr.fl_fstmoff, &off))
1424 goto fail;
1425 while (off != 0)
1426 {
1427 /* Map archive member header and member name. */
1428
1429 if (!backtrace_get_view (state, descriptor, off,
1430 sizeof (b_ar_hdr) + memlen,
1431 error_callback, data, &view))
1432 break;
1433
1434 ar_hdr = (const b_ar_hdr *) view.data;
1435
1436 /* Read archive member name length. */
1437 if (!xcoff_parse_decimal (ar_hdr->ar_namlen, sizeof ar_hdr->ar_namlen,
1438 &len))
1439 {
1440 backtrace_release_view (state, &view, error_callback, data);
1441 break;
1442 }
1443 if (len == memlen && !memcmp (ar_hdr->ar_name, member, memlen))
1444 {
1445 off = (off + sizeof (b_ar_hdr) + memlen + 1) & ~1;
1446
1447 /* The archive can contain several members with the same name
1448 (e.g. 32-bit and 64-bit), so continue if not ok. */
1449
1450 if (xcoff_add (state, descriptor, off, base_address, error_callback,
1451 data, fileline_fn, found_sym, 0))
1452 {
1453 backtrace_release_view (state, &view, error_callback, data);
1454 return 1;
1455 }
1456 }
1457
1458 /* Read offset of next archive member. */
1459 if (!xcoff_parse_decimal (ar_hdr->ar_nxtmem, sizeof ar_hdr->ar_nxtmem,
1460 &off))
1461 {
1462 backtrace_release_view (state, &view, error_callback, data);
1463 break;
1464 }
1465 backtrace_release_view (state, &view, error_callback, data);
1466 }
1467
1468 fail:
1469 /* No matching member found. */
1470 backtrace_close (descriptor, error_callback, data);
1471 return 0;
1472 }
1473
1474 /* Add the backtrace data for dynamically loaded libraries. */
1475
1476 static void
1477 xcoff_add_shared_libs (struct backtrace_state *state,
1478 backtrace_error_callback error_callback,
1479 void *data, fileline *fileline_fn, int *found_sym)
1480 {
1481 const struct ld_info *ldinfo;
1482 void *buf;
1483 unsigned int buflen;
1484 const char *member;
1485 int descriptor;
1486 int does_not_exist;
1487 int lib_found_sym;
1488 int ret;
1489
1490 /* Retrieve the list of loaded libraries. */
1491
1492 buf = NULL;
1493 buflen = 512;
1494 do
1495 {
1496 buf = realloc (buf, buflen);
1497 if (buf == NULL)
1498 {
1499 ret = -1;
1500 break;
1501 }
1502 ret = loadquery (L_GETINFO, buf, buflen);
1503 if (ret == 0)
1504 break;
1505 buflen *= 2;
1506 }
1507 while (ret == -1 && errno == ENOMEM);
1508 if (ret != 0)
1509 {
1510 free (buf);
1511 return;
1512 }
1513
1514 ldinfo = (const struct ld_info *) buf;
1515 while ((const char *) ldinfo < (const char *) buf + buflen)
1516 {
1517 if (*ldinfo->ldinfo_filename != '/')
1518 goto next;
1519
1520 descriptor = backtrace_open (ldinfo->ldinfo_filename, error_callback,
1521 data, &does_not_exist);
1522 if (descriptor < 0)
1523 goto next;
1524
1525 /* Check if it is an archive (member name not empty). */
1526
1527 member = ldinfo->ldinfo_filename + strlen (ldinfo->ldinfo_filename) + 1;
1528 if (*member)
1529 {
1530 xcoff_armem_add (state, descriptor,
1531 (uintptr_t) ldinfo->ldinfo_textorg, member,
1532 error_callback, data, fileline_fn, &lib_found_sym);
1533 }
1534 else
1535 {
1536 xcoff_add (state, descriptor, 0, (uintptr_t) ldinfo->ldinfo_textorg,
1537 error_callback, data, fileline_fn, &lib_found_sym, 0);
1538 }
1539 if (lib_found_sym)
1540 *found_sym = 1;
1541
1542 next:
1543 if (ldinfo->ldinfo_next == 0)
1544 break;
1545 ldinfo = (const struct ld_info *) ((const char *) ldinfo
1546 + ldinfo->ldinfo_next);
1547 }
1548
1549 free (buf);
1550 }
1551 #endif /* HAVE_LOADQUERY */
1552
1553 /* Initialize the backtrace data we need from an XCOFF executable.
1554 Returns 1 on success, 0 on failure. */
1555
1556 int
1557 backtrace_initialize (struct backtrace_state *state,
1558 const char *filename ATTRIBUTE_UNUSED, int descriptor,
1559 backtrace_error_callback error_callback,
1560 void *data, fileline *fileline_fn)
1561 {
1562 int ret;
1563 int found_sym;
1564 fileline xcoff_fileline_fn = xcoff_nodebug;
1565
1566 ret = xcoff_add (state, descriptor, 0, 0, error_callback, data,
1567 &xcoff_fileline_fn, &found_sym, 1);
1568 if (!ret)
1569 return 0;
1570
1571 #ifdef HAVE_LOADQUERY
1572 xcoff_add_shared_libs (state, error_callback, data, &xcoff_fileline_fn,
1573 &found_sym);
1574 #endif
1575
1576 if (!state->threaded)
1577 {
1578 if (found_sym)
1579 state->syminfo_fn = xcoff_syminfo;
1580 else if (state->syminfo_fn == NULL)
1581 state->syminfo_fn = xcoff_nosyms;
1582 }
1583 else
1584 {
1585 if (found_sym)
1586 backtrace_atomic_store_pointer (&state->syminfo_fn, xcoff_syminfo);
1587 else
1588 (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
1589 xcoff_nosyms);
1590 }
1591
1592 if (!state->threaded)
1593 {
1594 if (state->fileline_fn == NULL || state->fileline_fn == xcoff_nodebug)
1595 *fileline_fn = xcoff_fileline_fn;
1596 }
1597 else
1598 {
1599 fileline current_fn;
1600
1601 current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
1602 if (current_fn == NULL || current_fn == xcoff_nodebug)
1603 *fileline_fn = xcoff_fileline_fn;
1604 }
1605
1606 return 1;
1607 }