1/* xcoff.c -- Get debug data from an XCOFF file for backtraces. 2 Copyright (C) 2012-2020 Free Software Foundation, Inc. 3 Adapted from elf.c. 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 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 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 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 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 341/* A growable vector of functions information. */ 342 343struct xcoff_func 344{ 345 /* PC. */ 346 uintptr_t pc; 347 /* The size of the function. */ 348 size_t size; 349 /* Function name. */ 350 const char *name; 351 /* File name. */ 352 const char *filename; 353 /* Pointer to first lnno entry. */ 354 uintptr_t lnnoptr; 355 /* Base address of containing section. */ 356 uintptr_t sect_base; 357 /* Starting source line number. */ 358 int lnno; 359}; 360 361/* A growable vector of function information. This is used while 362 reading the function symbols. */ 363 364struct xcoff_func_vector 365{ 366 /* Memory. This is an array of struct xcoff_func. */ 367 struct backtrace_vector vec; 368 /* Number of valid mappings. */ 369 size_t count; 370}; 371 372/* The information we need to map a PC to a file and line. */ 373 374struct xcoff_fileline_data 375{ 376 /* The data for the next file we know about. */ 377 struct xcoff_fileline_data *next; 378 /* Functions information. */ 379 struct xcoff_func_vector func_vec; 380 /* Include files information. */ 381 struct xcoff_incl_vector incl_vec; 382 /* Line numbers information. */ 383 const unsigned char *linenos; 384 size_t linenos_size; 385 uint64_t lnnoptr0; 386 /* Loader address. */ 387 uintptr_t base_address; 388}; 389 390/* Information we gather for the DWARF sections we care about. */ 391 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}; 401 402/* A dummy callback function used when we can't find any debug info. */ 403 404static int 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} 413 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) 422{ 423 error_callback (data, "no symbol table in XCOFF executable", -1); 424} 425 426/* Compare struct xcoff_symbol for qsort. */ 427 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 } 501} 502 503/* Return the symbol name and value for an ADDR. */ 504 505static void 506xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr, 507 backtrace_syminfo_callback callback, 508 backtrace_error_callback error_callback ATTRIBUTE_UNUSED, 509 void *data) 510{ 511 struct xcoff_syminfo_data *edata; 512 struct xcoff_symbol *sym = NULL; 513 const char *name; 514 515 if (!state->threaded) 516 { 517 for (edata = (struct xcoff_syminfo_data *) state->syminfo_data; 518 edata != NULL; 519 edata = edata->next) 520 { 521 sym = ((struct xcoff_symbol *) 522 bsearch (&addr, edata->symbols, edata->count, 523 sizeof (struct xcoff_symbol), xcoff_symbol_search)); 524 if (sym != NULL) 525 break; 526 } 527 } 528 else 529 { 530 struct xcoff_syminfo_data **pp; 531 532 pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data; 533 while (1) 534 { 535 edata = backtrace_atomic_load_pointer (pp); 536 if (edata == NULL) 537 break; 538 539 sym = ((struct xcoff_symbol *) 540 bsearch (&addr, edata->symbols, edata->count, 541 sizeof (struct xcoff_symbol), xcoff_symbol_search)); 542 if (sym != NULL) 543 break; 544 545 pp = &edata->next; 546 } 547 } 548 549 if (sym == NULL) 550 callback (data, addr, NULL, 0, 0); 551 else 552 { 553 name = sym->name; 554 /* AIX prepends a '.' to function entry points, remove it. */ 555 if (name && *name == '.') 556 ++name; 557 callback (data, addr, name, sym->address, sym->size); 558 } 559} 560 561/* Return the name of an XCOFF symbol. */ 562 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 651/* Compare struct xcoff_func for qsort. */ 652 653static int 654xcoff_func_compare (const void *v1, const void *v2) 655{ 656 const struct xcoff_func *fn1 = (const struct xcoff_func *) v1; 657 const struct xcoff_func *fn2 = (const struct xcoff_func *) v2; 658 659 if (fn1->pc < fn2->pc) 660 return -1; 661 else if (fn1->pc > fn2->pc) 662 return 1; 663 else 664 return 0; 665} 666 667/* Compare a PC against an xcoff_func for bsearch. */ 668 669static int 670xcoff_func_search (const void *vkey, const void *ventry) 671{ 672 const uintptr_t *key = (const uintptr_t *) vkey; 673 const struct xcoff_func *entry = (const struct xcoff_func *) ventry; 674 uintptr_t pc; 675 676 pc = *key; 677 if (pc < entry->pc) 678 return -1; 679 else if ((entry->size == 0 && pc > entry->pc) 680 || (entry->size > 0 && pc >= entry->pc + entry->size)) 681 return 1; 682 else 683 return 0; 684} 685 686/* Compare struct xcoff_incl for qsort. */ 687 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) 697 return 1; 698 else 699 return 0; 700} 701 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, 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{ 732 const struct xcoff_incl *incl, *bincl; 733 const struct xcoff_func *fn; 734 const b_xcoff_lineno *lineno; 735 const unsigned char *lineptr; 736 const char *function; 737 const char *filename; 738 uintptr_t lnnoptr, match; 739 uint32_t lnno = 0; 740 741 *found = 1; 742 743 if ((pc & 3) != 0) 744 ++pc; 745 746 /* Find the function first. */ 747 fn = ((struct xcoff_func *) 748 bsearch (&pc, fdata->func_vec.vec.base, fdata->func_vec.count, 749 sizeof (struct xcoff_func), xcoff_func_search)); 750 if (fn == NULL) 751 { 752 *found = 0; 753 return 0; 754 } 755 756 filename = fn->filename; 757 758 /* Find the line number next. */ 759 760 /* Skip first entry that points to symtab. */ 761 lnnoptr = fn->lnnoptr + LINESZ; 762 match = lnnoptr; 763 764 lineptr = fdata->linenos + (lnnoptr - fdata->lnnoptr0); 765 while (lineptr + LINESZ <= fdata->linenos + fdata->linenos_size) 766 { 767 lineno = (const b_xcoff_lineno *) lineptr; 768 if (lineno->l_lnno == 0) 769 break; 770 if (pc <= fdata->base_address + lineno->l_addr.l_paddr - fn->sect_base) 771 break; 772 match = lnnoptr; 773 lnno = lineno->l_lnno; 774 775 lnnoptr += LINESZ; 776 lineptr += LINESZ; 777 } 778 779 /* If part of a function other than the beginning comes from an 780 include file, the line numbers are absolute, rather than 781 relative to the beginning of the function. */ 782 incl = ((struct xcoff_incl *) 783 bsearch (&match, fdata->incl_vec.vec.base, 784 fdata->incl_vec.count, sizeof (struct xcoff_incl), 785 xcoff_incl_search)); 786 if (incl != NULL) 787 { 788 bincl = ((struct xcoff_incl *) 789 bsearch (&fn->lnnoptr, fdata->incl_vec.vec.base, 790 fdata->incl_vec.count, sizeof (struct xcoff_incl), 791 xcoff_incl_search)); 792 if (bincl != NULL && strcmp (incl->filename, bincl->filename) == 0) 793 { 794 lnno += fn->lnno - 1; 795 } 796 filename = incl->filename; 797 } 798 else 799 { 800 lnno += fn->lnno - 1; 801 } 802 803 function = fn->name; 804 /* AIX prepends a '.' to function entry points, remove it. */ 805 if (function != NULL && *function == '.') 806 ++function; 807 return callback (data, pc, filename, lnno, function); 808} 809 810/* Return the file/line information for a PC using the XCOFF lineno 811 mapping we built earlier. */ 812 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 860/* Initialize the function vector info for xcoff_fileline. */ 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; 873 struct xcoff_func *fn; 874 const b_xcoff_syment *fsym; 875 const b_xcoff_auxent *aux; 876 const char *filename; 877 const char *name; 878 struct xcoff_incl *incl; 879 uintptr_t begin, end; 880 uintptr_t lnno, lnnoptr; 881 uint32_t fsize; 882 size_t i; 883 884 fdata = ((struct xcoff_fileline_data *) 885 backtrace_alloc (state, sizeof (struct xcoff_fileline_data), 886 error_callback, data)); 887 if (fdata == NULL) 888 return 0; 889 memset (fdata, 0, sizeof *fdata); 890 fdata->base_address = base_address; 891 fdata->linenos = linenos; 892 fdata->linenos_size = linenos_size; 893 fdata->lnnoptr0 = lnnoptr0; 894 895 begin = 0; 896 filename = NULL; 897 fsym = NULL; 898 lnnoptr = 0; 899 fsize = 0; 900 for (i = 0; i < nsyms; ++i) 901 { 902 const b_xcoff_syment *asym = &syms[i]; 903 904 switch (asym->n_sclass) 905 { 906 case C_BINCL: 907 begin = asym->n_value; 908 break; 909 910 case C_EINCL: 911 if (begin == 0) 912 break; 913 end = asym->n_value; 914 incl = ((struct xcoff_incl *) 915 backtrace_vector_grow (state, sizeof (struct xcoff_incl), 916 error_callback, data, 917 &fdata->incl_vec.vec)); 918 if (incl != NULL) 919 { 920 incl->filename = xcoff_symname (asym, strtab, strtab_size); 921 incl->begin = begin; 922 incl->end = end; 923 ++fdata->incl_vec.count; 924 } 925 begin = 0; 926 break; 927 928 case C_FILE: 929 filename = xcoff_symname (asym, strtab, strtab_size); 930 if (filename == NULL) 931 break; 932 933 /* If the file auxiliary entry is not used, the symbol name is 934 the name of the source file. If the file auxiliary entry is 935 used, then the symbol name should be .file, and the first 936 file auxiliary entry (by convention) contains the source 937 file name. */ 938 939 if (asym->n_numaux > 0 && strcmp (filename, ".file") == 0) 940 { 941 aux = (const b_xcoff_auxent *) (asym + 1); 942 if (aux->x_file._x.x_zeroes != 0) 943 { 944 /* Make a copy as we will release the symtab view. */ 945 char name[FILNMLEN+1]; 946 strncpy (name, aux->x_file.x_fname, FILNMLEN); 947 name[FILNMLEN] = '\0'; 948 filename = strdup (name); 949 } 950 else if (aux->x_file._x.x_offset < strtab_size) 951 filename = (const char *) strtab + aux->x_file._x.x_offset; 952 else 953 filename = NULL; 954 } 955 break; 956 957 case C_EXT: 958 case C_HIDEXT: 959 case C_WEAKEXT: 960 fsym = NULL; 961 lnnoptr = 0; 962 fsize = 0; 963 if (!ISFCN (asym->n_type) || asym->n_numaux == 0 964 || asym->n_scnum <= 0) 965 break; 966 if (filename == NULL) 967 break; 968 aux = (const b_xcoff_auxent *) (asym + 1); 969 lnnoptr = aux->x_fcn.x_lnnoptr; 970 if (lnnoptr < lnnoptr0 971 || lnnoptr + LINESZ > lnnoptr0 + linenos_size) 972 break; 973 /* x_fsize will be 0 if there is no debug information. */ 974 fsize = aux->x_fcn.x_fsize; 975 fsym = asym; 976 break; 977 978 case C_FCN: 979 if (asym->n_numaux == 0) 980 break; 981 if (fsym == NULL) 982 break; 983 name = xcoff_symname (asym, strtab, strtab_size); 984 if (name == NULL || strcmp (name, ".bf") != 0) 985 { 986 fsym = NULL; 987 break; 988 } 989 aux = (const b_xcoff_auxent *) (asym + 1); 990#if BACKTRACE_XCOFF_SIZE == 32 991 lnno = (uint32_t) aux->x_block.x_lnnohi << 16 992 | aux->x_block.x_lnno; 993#else 994 lnno = aux->x_block.x_lnno; 995#endif 996 fn = ((struct xcoff_func *) 997 backtrace_vector_grow (state, sizeof (struct xcoff_func), 998 error_callback, data, 999 &fdata->func_vec.vec)); 1000 if (fn == NULL) 1001 break; 1002 fn->name = xcoff_symname (fsym, strtab, strtab_size); 1003 fn->filename = filename; 1004 fn->sect_base = sects[fsym->n_scnum - 1].s_paddr; 1005 fn->pc = base_address + fsym->n_value - fn->sect_base; 1006 fn->size = fsize; 1007 fn->lnno = lnno; 1008 fn->lnnoptr = lnnoptr; 1009 ++fdata->func_vec.count; 1010 break; 1011 } 1012 1013 i += asym->n_numaux; 1014 } 1015 1016 if (!backtrace_vector_release (state, &fdata->func_vec.vec, error_callback, 1017 data)) 1018 goto fail; 1019 backtrace_qsort (fdata->func_vec.vec.base, fdata->func_vec.count, 1020 sizeof (struct xcoff_func), xcoff_func_compare); 1021 1022 if (!backtrace_vector_release (state, &fdata->incl_vec.vec, error_callback, 1023 data)) 1024 goto fail; 1025 backtrace_qsort (fdata->incl_vec.vec.base, fdata->incl_vec.count, 1026 sizeof (struct xcoff_incl), xcoff_incl_compare); 1027 1028 if (!state->threaded) 1029 { 1030 struct xcoff_fileline_data **pp; 1031 1032 for (pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data; 1033 *pp != NULL; 1034 pp = &(*pp)->next) 1035 ; 1036 *pp = fdata; 1037 } 1038 else 1039 { 1040 while (1) 1041 { 1042 struct xcoff_fileline_data **pp; 1043 1044 pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data; 1045 1046 while (1) 1047 { 1048 struct xcoff_fileline_data *p; 1049 1050 p = backtrace_atomic_load_pointer (pp); 1051 1052 if (p == NULL) 1053 break; 1054 1055 pp = &p->next; 1056 } 1057 1058 if (__sync_bool_compare_and_swap (pp, NULL, fdata)) 1059 break; 1060 } 1061 } 1062 1063 return 1; 1064 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; 1082 struct backtrace_view dwarf_view; 1083 b_xcoff_filhdr fhdr; 1084 const b_xcoff_scnhdr *sects; 1085 const b_xcoff_scnhdr *stext; 1086 uint64_t lnnoptr; 1087 uint32_t nlnno; 1088 off_t str_off; 1089 off_t min_offset; 1090 off_t max_offset; 1091 struct dwsect_info dwsect[DEBUG_MAX]; 1092 size_t sects_size; 1093 size_t syms_size; 1094 int32_t str_size; 1095 int sects_view_valid; 1096 int linenos_view_valid; 1097 int syms_view_valid; 1098 int str_view_valid; 1099 int dwarf_view_valid; 1100 int magic_ok; 1101 int i; 1102 struct dwarf_sections dwarf_sections; 1103 1104 *found_sym = 0; 1105 1106 sects_view_valid = 0; 1107 linenos_view_valid = 0; 1108 syms_view_valid = 0; 1109 str_view_valid = 0; 1110 dwarf_view_valid = 0; 1111 1112 str_size = 0; 1113 1114 /* Map the XCOFF file header. */ 1115 if (!backtrace_get_view (state, descriptor, offset, sizeof (b_xcoff_filhdr), 1116 error_callback, data, &fhdr_view)) 1117 goto fail; 1118 1119 memcpy (&fhdr, fhdr_view.data, sizeof fhdr); 1120 magic_ok = (fhdr.f_magic == XCOFF_MAGIC); 1121 1122 backtrace_release_view (state, &fhdr_view, error_callback, data); 1123 1124 if (!magic_ok) 1125 { 1126 if (exe) 1127 error_callback (data, "executable file is not XCOFF", 0); 1128 goto fail; 1129 } 1130 1131 /* Verify object is of expected type. */ 1132 if ((exe && (fhdr.f_flags & F_SHROBJ)) 1133 || (!exe && !(fhdr.f_flags & F_SHROBJ))) 1134 goto fail; 1135 1136 /* Read the section headers. */ 1137 1138 sects_size = fhdr.f_nscns * sizeof (b_xcoff_scnhdr); 1139 1140 if (!backtrace_get_view (state, descriptor, 1141 offset + sizeof (fhdr) + fhdr.f_opthdr, 1142 sects_size, error_callback, data, §s_view)) 1143 goto fail; 1144 sects_view_valid = 1; 1145 sects = (const b_xcoff_scnhdr *) sects_view.data; 1146 1147 /* FIXME: assumes only one .text section. */ 1148 for (i = 0; i < fhdr.f_nscns; ++i) 1149 if ((sects[i].s_flags & 0xffff) == STYP_TEXT) 1150 break; 1151 if (i == fhdr.f_nscns) 1152 goto fail; 1153 1154 stext = §s[i]; 1155 1156 /* AIX ldinfo_textorg includes the XCOFF headers. */ 1157 base_address = (exe ? XCOFF_AIX_TEXTBASE : base_address) + stext->s_scnptr; 1158 1159 lnnoptr = stext->s_lnnoptr; 1160 nlnno = stext->s_nlnno; 1161 1162#if BACKTRACE_XCOFF_SIZE == 32 1163 if (nlnno == _OVERFLOW_MARKER) 1164 { 1165 int sntext = i + 1; 1166 /* Find the matching .ovrflo section. */ 1167 for (i = 0; i < fhdr.f_nscns; ++i) 1168 { 1169 if (((sects[i].s_flags & 0xffff) == STYP_OVRFLO) 1170 && sects[i].s_nlnno == sntext) 1171 { 1172 nlnno = sects[i].s_vaddr; 1173 break; 1174 } 1175 } 1176 } 1177#endif 1178 1179 /* Read the symbol table and the string table. */ 1180 1181 if (fhdr.f_symptr != 0) 1182 { 1183 struct xcoff_syminfo_data *sdata; 1184 1185 /* Symbol table is followed by the string table. The string table 1186 starts with its length (on 4 bytes). 1187 Map the symbol table and the length of the string table. */ 1188 syms_size = fhdr.f_nsyms * sizeof (b_xcoff_syment); 1189 1190 if (!backtrace_get_view (state, descriptor, offset + fhdr.f_symptr, 1191 syms_size + 4, error_callback, data, 1192 &syms_view)) 1193 goto fail; 1194 syms_view_valid = 1; 1195 1196 memcpy (&str_size, syms_view.data + syms_size, 4); 1197 1198 str_off = fhdr.f_symptr + syms_size; 1199 1200 if (str_size > 4) 1201 { 1202 /* Map string table (including the length word). */ 1203 1204 if (!backtrace_get_view (state, descriptor, offset + str_off, 1205 str_size, error_callback, data, &str_view)) 1206 goto fail; 1207 str_view_valid = 1; 1208 } 1209 1210 sdata = ((struct xcoff_syminfo_data *) 1211 backtrace_alloc (state, sizeof *sdata, error_callback, data)); 1212 if (sdata == NULL) 1213 goto fail; 1214 1215 if (!xcoff_initialize_syminfo (state, base_address, sects, 1216 syms_view.data, fhdr.f_nsyms, 1217 str_view.data, str_size, 1218 error_callback, data, sdata)) 1219 { 1220 backtrace_free (state, sdata, sizeof *sdata, error_callback, data); 1221 goto fail; 1222 } 1223 1224 *found_sym = 1; 1225 1226 xcoff_add_syminfo_data (state, sdata); 1227 } 1228 1229 /* Read all the DWARF sections in a single view, since they are 1230 probably adjacent in the file. We never release this view. */ 1231 1232 min_offset = 0; 1233 max_offset = 0; 1234 memset (dwsect, 0, sizeof dwsect); 1235 for (i = 0; i < fhdr.f_nscns; ++i) 1236 { 1237 off_t end; 1238 int idx; 1239 1240 if ((sects[i].s_flags & 0xffff) != STYP_DWARF 1241 || sects[i].s_size == 0) 1242 continue; 1243 /* Map DWARF section to array index. */ 1244 switch (sects[i].s_flags & 0xffff0000) 1245 { 1246 case SSUBTYP_DWINFO: 1247 idx = DEBUG_INFO; 1248 break; 1249 case SSUBTYP_DWLINE: 1250 idx = DEBUG_LINE; 1251 break; 1252 case SSUBTYP_DWABREV: 1253 idx = DEBUG_ABBREV; 1254 break; 1255 case SSUBTYP_DWARNGE: 1256 idx = DEBUG_RANGES; 1257 break; 1258 case SSUBTYP_DWSTR: 1259 idx = DEBUG_STR; 1260 break; 1261 default: 1262 continue; 1263 } 1264 if (min_offset == 0 || (off_t) sects[i].s_scnptr < min_offset) 1265 min_offset = sects[i].s_scnptr; 1266 end = sects[i].s_scnptr + sects[i].s_size; 1267 if (end > max_offset) 1268 max_offset = end; 1269 dwsect[idx].offset = sects[i].s_scnptr; 1270 dwsect[idx].size = sects[i].s_size; 1271 } 1272 if (min_offset != 0 && max_offset != 0) 1273 { 1274 if (!backtrace_get_view (state, descriptor, offset + min_offset, 1275 max_offset - min_offset, 1276 error_callback, data, &dwarf_view)) 1277 goto fail; 1278 dwarf_view_valid = 1; 1279 1280 for (i = 0; i < (int) DEBUG_MAX; ++i) 1281 { 1282 if (dwsect[i].offset == 0) 1283 dwsect[i].data = NULL; 1284 else 1285 dwsect[i].data = ((const unsigned char *) dwarf_view.data 1286 + (dwsect[i].offset - min_offset)); 1287 } 1288 1289 memset (&dwarf_sections, 0, sizeof dwarf_sections); 1290 1291 dwarf_sections.data[DEBUG_INFO] = dwsect[DEBUG_INFO].data; 1292 dwarf_sections.size[DEBUG_INFO] = dwsect[DEBUG_INFO].size; 1293#if BACKTRACE_XCOFF_SIZE == 32 1294 /* XXX workaround for broken lineoff */ 1295 dwarf_sections.data[DEBUG_LINE] = dwsect[DEBUG_LINE].data - 4; 1296#else 1297 /* XXX workaround for broken lineoff */ 1298 dwarf_sections.data[DEBUG_LINE] = dwsect[DEBUG_LINE].data - 12; 1299#endif 1300 dwarf_sections.size[DEBUG_LINE] = dwsect[DEBUG_LINE].size; 1301 dwarf_sections.data[DEBUG_ABBREV] = dwsect[DEBUG_ABBREV].data; 1302 dwarf_sections.size[DEBUG_ABBREV] = dwsect[DEBUG_ABBREV].size; 1303 dwarf_sections.data[DEBUG_RANGES] = dwsect[DEBUG_RANGES].data; 1304 dwarf_sections.size[DEBUG_RANGES] = dwsect[DEBUG_RANGES].size; 1305 dwarf_sections.data[DEBUG_STR] = dwsect[DEBUG_STR].data; 1306 dwarf_sections.size[DEBUG_STR] = dwsect[DEBUG_STR].size; 1307 1308 if (!backtrace_dwarf_add (state, 0, &dwarf_sections, 1309 1, /* big endian */ 1310 NULL, /* altlink */ 1311 error_callback, data, fileline_fn, 1312 NULL /* returned fileline_entry */)) 1313 goto fail; 1314 } 1315 1316 /* Read the XCOFF line number entries if DWARF sections not found. */ 1317 1318 if (!dwarf_view_valid && fhdr.f_symptr != 0 && lnnoptr != 0) 1319 { 1320 size_t linenos_size = (size_t) nlnno * LINESZ; 1321 1322 /* We never release this view. */ 1323 if (!backtrace_get_view (state, descriptor, offset + lnnoptr, 1324 linenos_size, 1325 error_callback, data, &linenos_view)) 1326 goto fail; 1327 linenos_view_valid = 1; 1328 1329 if (xcoff_initialize_fileline (state, base_address, sects, 1330 syms_view.data, fhdr.f_nsyms, 1331 str_view.data, str_size, 1332 linenos_view.data, linenos_size, 1333 lnnoptr, error_callback, data)) 1334 *fileline_fn = xcoff_fileline; 1335 } 1336 1337 backtrace_release_view (state, §s_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, §s_view, error_callback, data); 1353 if (str_view_valid) 1354 backtrace_release_view (state, &str_view, error_callback, data); 1355 if (syms_view_valid) 1356 backtrace_release_view (state, &syms_view, error_callback, data); 1357 if (linenos_view_valid) 1358 backtrace_release_view (state, &linenos_view, error_callback, data); 1359 if (dwarf_view_valid) 1360 backtrace_release_view (state, &dwarf_view, error_callback, data); 1361 if (descriptor != -1 && offset == 0) 1362 backtrace_close (descriptor, error_callback, data); 1363 return 0; 1364} 1365 1366#ifdef HAVE_LOADQUERY 1367 1368/* Read an integer value in human-readable format from an AIX 1369 big archive fixed-length or member header. */ 1370 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)) 1410 goto fail; 1411 1412 memcpy (&fl_hdr, view.data, sizeof (b_ar_fl_hdr)); 1413 1414 backtrace_release_view (state, &view, error_callback, data); 1415 1416 if (memcmp (fl_hdr.fl_magic, AIAMAGBIG, 8) != 0) 1417 goto fail; 1418 1419 memlen = strlen (member); 1420 1421 /* Read offset of first archive member. */ 1422 if (!xcoff_parse_decimal (fl_hdr.fl_fstmoff, sizeof fl_hdr.fl_fstmoff, &off)) 1423 goto fail; 1424 while (off != 0) 1425 { 1426 /* Map archive member header and member name. */ 1427 1428 if (!backtrace_get_view (state, descriptor, off, 1429 sizeof (b_ar_hdr) + memlen, 1430 error_callback, data, &view)) 1431 break; 1432 1433 ar_hdr = (const b_ar_hdr *) view.data; 1434 1435 /* Read archive member name length. */ 1436 if (!xcoff_parse_decimal (ar_hdr->ar_namlen, sizeof ar_hdr->ar_namlen, 1437 &len)) 1438 { 1439 backtrace_release_view (state, &view, error_callback, data); 1440 break; 1441 } 1442 if (len == memlen && !memcmp (ar_hdr->ar_name, member, memlen)) 1443 { 1444 off = (off + sizeof (b_ar_hdr) + memlen + 1) & ~1; 1445 1446 /* The archive can contain several members with the same name 1447 (e.g. 32-bit and 64-bit), so continue if not ok. */ 1448 1449 if (xcoff_add (state, descriptor, off, base_address, error_callback, 1450 data, fileline_fn, found_sym, 0)) 1451 { 1452 backtrace_release_view (state, &view, error_callback, data); 1453 return 1; 1454 } 1455 } 1456 1457 /* Read offset of next archive member. */ 1458 if (!xcoff_parse_decimal (ar_hdr->ar_nxtmem, sizeof ar_hdr->ar_nxtmem, 1459 &off)) 1460 { 1461 backtrace_release_view (state, &view, error_callback, data); 1462 break; 1463 } 1464 backtrace_release_view (state, &view, error_callback, data); 1465 } 1466 1467 fail: 1468 /* No matching member found. */ 1469 backtrace_close (descriptor, error_callback, data); 1470 return 0; 1471} 1472 1473/* Add the backtrace data for dynamically loaded libraries. */ 1474 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. */ 1554 1555int 1556backtrace_initialize (struct backtrace_state *state, 1557 const char *filename ATTRIBUTE_UNUSED, int descriptor, 1558 backtrace_error_callback error_callback, 1559 void *data, fileline *fileline_fn) 1560{ 1561 int ret; 1562 int found_sym; 1563 fileline xcoff_fileline_fn = xcoff_nodebug; 1564 1565 ret = xcoff_add (state, descriptor, 0, 0, error_callback, data, 1566 &xcoff_fileline_fn, &found_sym, 1); 1567 if (!ret) 1568 return 0; 1569 1570#ifdef HAVE_LOADQUERY 1571 xcoff_add_shared_libs (state, error_callback, data, &xcoff_fileline_fn, 1572 &found_sym); 1573#endif 1574 1575 if (!state->threaded) 1576 { 1577 if (found_sym) 1578 state->syminfo_fn = xcoff_syminfo; 1579 else if (state->syminfo_fn == NULL) 1580 state->syminfo_fn = xcoff_nosyms; 1581 } 1582 else 1583 { 1584 if (found_sym) 1585 backtrace_atomic_store_pointer (&state->syminfo_fn, xcoff_syminfo); 1586 else 1587 (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, 1588 xcoff_nosyms); 1589 } 1590 1591 if (!state->threaded) 1592 { 1593 if (state->fileline_fn == NULL || state->fileline_fn == xcoff_nodebug) 1594 *fileline_fn = xcoff_fileline_fn; 1595 } 1596 else 1597 { 1598 fileline current_fn; 1599 1600 current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); 1601 if (current_fn == NULL || current_fn == xcoff_nodebug) 1602 *fileline_fn = xcoff_fileline_fn; 1603 } 1604 1605 return 1; 1606} 1607