The open source OpenXR runtime
at prediction-2 1360 lines 36 kB view raw
1/* elf.c -- Get debug data from a Mach-O file for backtraces. 2 Copyright (C) 2020-2021 Free Software Foundation, Inc. 3 Written by Ian Lance Taylor, Google. 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 <sys/types.h> 36#include <dirent.h> 37#include <stdlib.h> 38#include <string.h> 39 40#ifdef HAVE_MACH_O_DYLD_H 41#include <mach-o/dyld.h> 42#endif 43 44#include "backtrace.hpp" 45#include "internal.hpp" 46 47namespace tracy 48{ 49 50/* Mach-O file header for a 32-bit executable. */ 51 52struct macho_header_32 53{ 54 uint32_t magic; /* Magic number (MACH_O_MAGIC_32) */ 55 uint32_t cputype; /* CPU type */ 56 uint32_t cpusubtype; /* CPU subtype */ 57 uint32_t filetype; /* Type of file (object, executable) */ 58 uint32_t ncmds; /* Number of load commands */ 59 uint32_t sizeofcmds; /* Total size of load commands */ 60 uint32_t flags; /* Flags for special features */ 61}; 62 63/* Mach-O file header for a 64-bit executable. */ 64 65struct macho_header_64 66{ 67 uint32_t magic; /* Magic number (MACH_O_MAGIC_64) */ 68 uint32_t cputype; /* CPU type */ 69 uint32_t cpusubtype; /* CPU subtype */ 70 uint32_t filetype; /* Type of file (object, executable) */ 71 uint32_t ncmds; /* Number of load commands */ 72 uint32_t sizeofcmds; /* Total size of load commands */ 73 uint32_t flags; /* Flags for special features */ 74 uint32_t reserved; /* Reserved */ 75}; 76 77/* Mach-O file header for a fat executable. */ 78 79struct macho_header_fat 80{ 81 uint32_t magic; /* Magic number (MACH_O_MH_(MAGIC|CIGAM)_FAT(_64)?) */ 82 uint32_t nfat_arch; /* Number of components */ 83}; 84 85/* Values for the header magic field. */ 86 87#define MACH_O_MH_MAGIC_32 0xfeedface 88#define MACH_O_MH_MAGIC_64 0xfeedfacf 89#define MACH_O_MH_MAGIC_FAT 0xcafebabe 90#define MACH_O_MH_CIGAM_FAT 0xbebafeca 91#define MACH_O_MH_MAGIC_FAT_64 0xcafebabf 92#define MACH_O_MH_CIGAM_FAT_64 0xbfbafeca 93 94/* Value for the header filetype field. */ 95 96#define MACH_O_MH_EXECUTE 0x02 97#define MACH_O_MH_DYLIB 0x06 98#define MACH_O_MH_DSYM 0x0a 99 100/* A component of a fat file. A fat file starts with a 101 macho_header_fat followed by nfat_arch instances of this 102 struct. */ 103 104struct macho_fat_arch 105{ 106 uint32_t cputype; /* CPU type */ 107 uint32_t cpusubtype; /* CPU subtype */ 108 uint32_t offset; /* File offset of this entry */ 109 uint32_t size; /* Size of this entry */ 110 uint32_t align; /* Alignment of this entry */ 111}; 112 113/* A component of a 64-bit fat file. This is used if the magic field 114 is MAGIC_FAT_64. This is only used when some file size or file 115 offset is too large to represent in the 32-bit format. */ 116 117struct macho_fat_arch_64 118{ 119 uint32_t cputype; /* CPU type */ 120 uint32_t cpusubtype; /* CPU subtype */ 121 uint64_t offset; /* File offset of this entry */ 122 uint64_t size; /* Size of this entry */ 123 uint32_t align; /* Alignment of this entry */ 124 uint32_t reserved; /* Reserved */ 125}; 126 127/* Values for the fat_arch cputype field (and the header cputype 128 field). */ 129 130#define MACH_O_CPU_ARCH_ABI64 0x01000000 131 132#define MACH_O_CPU_TYPE_X86 7 133#define MACH_O_CPU_TYPE_ARM 12 134#define MACH_O_CPU_TYPE_PPC 18 135 136#define MACH_O_CPU_TYPE_X86_64 (MACH_O_CPU_TYPE_X86 | MACH_O_CPU_ARCH_ABI64) 137#define MACH_O_CPU_TYPE_ARM64 (MACH_O_CPU_TYPE_ARM | MACH_O_CPU_ARCH_ABI64) 138#define MACH_O_CPU_TYPE_PPC64 (MACH_O_CPU_TYPE_PPC | MACH_O_CPU_ARCH_ABI64) 139 140/* The header of a load command. */ 141 142struct macho_load_command 143{ 144 uint32_t cmd; /* The type of load command */ 145 uint32_t cmdsize; /* Size in bytes of the entire command */ 146}; 147 148/* Values for the load_command cmd field. */ 149 150#define MACH_O_LC_SEGMENT 0x01 151#define MACH_O_LC_SYMTAB 0x02 152#define MACH_O_LC_SEGMENT_64 0x19 153#define MACH_O_LC_UUID 0x1b 154 155/* The length of a section of segment name. */ 156 157#define MACH_O_NAMELEN (16) 158 159/* LC_SEGMENT load command. */ 160 161struct macho_segment_command 162{ 163 uint32_t cmd; /* The type of load command (LC_SEGMENT) */ 164 uint32_t cmdsize; /* Size in bytes of the entire command */ 165 char segname[MACH_O_NAMELEN]; /* Segment name */ 166 uint32_t vmaddr; /* Virtual memory address */ 167 uint32_t vmsize; /* Virtual memory size */ 168 uint32_t fileoff; /* Offset of data to be mapped */ 169 uint32_t filesize; /* Size of data in file */ 170 uint32_t maxprot; /* Maximum permitted virtual protection */ 171 uint32_t initprot; /* Initial virtual memory protection */ 172 uint32_t nsects; /* Number of sections in this segment */ 173 uint32_t flags; /* Flags */ 174}; 175 176/* LC_SEGMENT_64 load command. */ 177 178struct macho_segment_64_command 179{ 180 uint32_t cmd; /* The type of load command (LC_SEGMENT) */ 181 uint32_t cmdsize; /* Size in bytes of the entire command */ 182 char segname[MACH_O_NAMELEN]; /* Segment name */ 183 uint64_t vmaddr; /* Virtual memory address */ 184 uint64_t vmsize; /* Virtual memory size */ 185 uint64_t fileoff; /* Offset of data to be mapped */ 186 uint64_t filesize; /* Size of data in file */ 187 uint32_t maxprot; /* Maximum permitted virtual protection */ 188 uint32_t initprot; /* Initial virtual memory protection */ 189 uint32_t nsects; /* Number of sections in this segment */ 190 uint32_t flags; /* Flags */ 191}; 192 193/* LC_SYMTAB load command. */ 194 195struct macho_symtab_command 196{ 197 uint32_t cmd; /* The type of load command (LC_SEGMENT) */ 198 uint32_t cmdsize; /* Size in bytes of the entire command */ 199 uint32_t symoff; /* File offset of symbol table */ 200 uint32_t nsyms; /* Number of symbols */ 201 uint32_t stroff; /* File offset of string table */ 202 uint32_t strsize; /* String table size */ 203}; 204 205/* The length of a Mach-O uuid. */ 206 207#define MACH_O_UUID_LEN (16) 208 209/* LC_UUID load command. */ 210 211struct macho_uuid_command 212{ 213 uint32_t cmd; /* Type of load command (LC_UUID) */ 214 uint32_t cmdsize; /* Size in bytes of command */ 215 unsigned char uuid[MACH_O_UUID_LEN]; /* UUID */ 216}; 217 218/* 32-bit section header within a LC_SEGMENT segment. */ 219 220struct macho_section 221{ 222 char sectname[MACH_O_NAMELEN]; /* Section name */ 223 char segment[MACH_O_NAMELEN]; /* Segment of this section */ 224 uint32_t addr; /* Address in memory */ 225 uint32_t size; /* Section size */ 226 uint32_t offset; /* File offset */ 227 uint32_t align; /* Log2 of section alignment */ 228 uint32_t reloff; /* File offset of relocations */ 229 uint32_t nreloc; /* Number of relocs for this section */ 230 uint32_t flags; /* Flags */ 231 uint32_t reserved1; 232 uint32_t reserved2; 233}; 234 235/* 64-bit section header within a LC_SEGMENT_64 segment. */ 236 237struct macho_section_64 238{ 239 char sectname[MACH_O_NAMELEN]; /* Section name */ 240 char segment[MACH_O_NAMELEN]; /* Segment of this section */ 241 uint64_t addr; /* Address in memory */ 242 uint64_t size; /* Section size */ 243 uint32_t offset; /* File offset */ 244 uint32_t align; /* Log2 of section alignment */ 245 uint32_t reloff; /* File offset of section relocations */ 246 uint32_t nreloc; /* Number of relocs for this section */ 247 uint32_t flags; /* Flags */ 248 uint32_t reserved1; 249 uint32_t reserved2; 250 uint32_t reserved3; 251}; 252 253/* 32-bit symbol data. */ 254 255struct macho_nlist 256{ 257 uint32_t n_strx; /* Index of name in string table */ 258 uint8_t n_type; /* Type flag */ 259 uint8_t n_sect; /* Section number */ 260 uint16_t n_desc; /* Stabs description field */ 261 uint32_t n_value; /* Value */ 262}; 263 264/* 64-bit symbol data. */ 265 266struct macho_nlist_64 267{ 268 uint32_t n_strx; /* Index of name in string table */ 269 uint8_t n_type; /* Type flag */ 270 uint8_t n_sect; /* Section number */ 271 uint16_t n_desc; /* Stabs description field */ 272 uint64_t n_value; /* Value */ 273}; 274 275/* Value found in nlist n_type field. */ 276 277#define MACH_O_N_EXT 0x01 /* Extern symbol */ 278#define MACH_O_N_ABS 0x02 /* Absolute symbol */ 279#define MACH_O_N_SECT 0x0e /* Defined in section */ 280 281#define MACH_O_N_TYPE 0x0e /* Mask for type bits */ 282#define MACH_O_N_STAB 0xe0 /* Stabs debugging symbol */ 283 284/* Information we keep for a Mach-O symbol. */ 285 286struct macho_symbol 287{ 288 const char *name; /* Symbol name */ 289 uintptr_t address; /* Symbol address */ 290}; 291 292/* Information to pass to macho_syminfo. */ 293 294struct macho_syminfo_data 295{ 296 struct macho_syminfo_data *next; /* Next module */ 297 struct macho_symbol *symbols; /* Symbols sorted by address */ 298 size_t count; /* Number of symbols */ 299}; 300 301/* Names of sections, indexed by enum dwarf_section in internal.h. */ 302 303static const char * const dwarf_section_names[DEBUG_MAX] = 304{ 305 "__debug_info", 306 "__debug_line", 307 "__debug_abbrev", 308 "__debug_ranges", 309 "__debug_str", 310 "", /* DEBUG_ADDR */ 311 "__debug_str_offs", 312 "", /* DEBUG_LINE_STR */ 313 "__debug_rnglists" 314}; 315 316/* Forward declaration. */ 317 318static int macho_add (struct backtrace_state *, const char *, int, off_t, 319 const unsigned char *, uintptr_t, int, 320 backtrace_error_callback, void *, fileline *, int *); 321 322/* A dummy callback function used when we can't find any debug info. */ 323 324static int 325macho_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, 326 uintptr_t pc ATTRIBUTE_UNUSED, 327 backtrace_full_callback callback ATTRIBUTE_UNUSED, 328 backtrace_error_callback error_callback, void *data) 329{ 330 error_callback (data, "no debug info in Mach-O executable", -1); 331 return 0; 332} 333 334/* A dummy callback function used when we can't find a symbol 335 table. */ 336 337static void 338macho_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, 339 uintptr_t addr ATTRIBUTE_UNUSED, 340 backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, 341 backtrace_error_callback error_callback, void *data) 342{ 343 error_callback (data, "no symbol table in Mach-O executable", -1); 344} 345 346/* Add a single DWARF section to DWARF_SECTIONS, if we need the 347 section. Returns 1 on success, 0 on failure. */ 348 349static int 350macho_add_dwarf_section (struct backtrace_state *state, int descriptor, 351 const char *sectname, uint32_t offset, uint64_t size, 352 backtrace_error_callback error_callback, void *data, 353 struct dwarf_sections *dwarf_sections) 354{ 355 int i; 356 357 for (i = 0; i < (int) DEBUG_MAX; ++i) 358 { 359 if (dwarf_section_names[i][0] != '\0' 360 && strncmp (sectname, dwarf_section_names[i], MACH_O_NAMELEN) == 0) 361 { 362 struct backtrace_view section_view; 363 364 /* FIXME: Perhaps it would be better to try to use a single 365 view to read all the DWARF data, as we try to do for 366 ELF. */ 367 368 if (!backtrace_get_view (state, descriptor, offset, size, 369 error_callback, data, &section_view)) 370 return 0; 371 dwarf_sections->data[i] = (const unsigned char *) section_view.data; 372 dwarf_sections->size[i] = size; 373 break; 374 } 375 } 376 return 1; 377} 378 379/* Collect DWARF sections from a DWARF segment. Returns 1 on success, 380 0 on failure. */ 381 382static int 383macho_add_dwarf_segment (struct backtrace_state *state, int descriptor, 384 off_t offset, unsigned int cmd, const char *psecs, 385 size_t sizesecs, unsigned int nsects, 386 backtrace_error_callback error_callback, void *data, 387 struct dwarf_sections *dwarf_sections) 388{ 389 size_t sec_header_size; 390 size_t secoffset; 391 unsigned int i; 392 393 switch (cmd) 394 { 395 case MACH_O_LC_SEGMENT: 396 sec_header_size = sizeof (struct macho_section); 397 break; 398 case MACH_O_LC_SEGMENT_64: 399 sec_header_size = sizeof (struct macho_section_64); 400 break; 401 default: 402 abort (); 403 } 404 405 secoffset = 0; 406 for (i = 0; i < nsects; ++i) 407 { 408 if (secoffset + sec_header_size > sizesecs) 409 { 410 error_callback (data, "section overflow withing segment", 0); 411 return 0; 412 } 413 414 switch (cmd) 415 { 416 case MACH_O_LC_SEGMENT: 417 { 418 struct macho_section section; 419 420 memcpy (&section, psecs + secoffset, sizeof section); 421 macho_add_dwarf_section (state, descriptor, section.sectname, 422 offset + section.offset, section.size, 423 error_callback, data, dwarf_sections); 424 } 425 break; 426 427 case MACH_O_LC_SEGMENT_64: 428 { 429 struct macho_section_64 section; 430 431 memcpy (&section, psecs + secoffset, sizeof section); 432 macho_add_dwarf_section (state, descriptor, section.sectname, 433 offset + section.offset, section.size, 434 error_callback, data, dwarf_sections); 435 } 436 break; 437 438 default: 439 abort (); 440 } 441 442 secoffset += sec_header_size; 443 } 444 445 return 1; 446} 447 448/* Compare struct macho_symbol for qsort. */ 449 450static int 451macho_symbol_compare (const void *v1, const void *v2) 452{ 453 const struct macho_symbol *m1 = (const struct macho_symbol *) v1; 454 const struct macho_symbol *m2 = (const struct macho_symbol *) v2; 455 456 if (m1->address < m2->address) 457 return -1; 458 else if (m1->address > m2->address) 459 return 1; 460 else 461 return 0; 462} 463 464/* Compare an address against a macho_symbol for bsearch. We allocate 465 one extra entry in the array so that this can safely look at the 466 next entry. */ 467 468static int 469macho_symbol_search (const void *vkey, const void *ventry) 470{ 471 const uintptr_t *key = (const uintptr_t *) vkey; 472 const struct macho_symbol *entry = (const struct macho_symbol *) ventry; 473 uintptr_t addr; 474 475 addr = *key; 476 if (addr < entry->address) 477 return -1; 478 else if (entry->name[0] == '\0' 479 && entry->address == ~(uintptr_t) 0) 480 return -1; 481 else if ((entry + 1)->name[0] == '\0' 482 && (entry + 1)->address == ~(uintptr_t) 0) 483 return -1; 484 else if (addr >= (entry + 1)->address) 485 return 1; 486 else 487 return 0; 488} 489 490/* Return whether the symbol type field indicates a symbol table entry 491 that we care about: a function or data symbol. */ 492 493static int 494macho_defined_symbol (uint8_t type) 495{ 496 if ((type & MACH_O_N_STAB) != 0) 497 return 0; 498 if ((type & MACH_O_N_EXT) != 0) 499 return 0; 500 switch (type & MACH_O_N_TYPE) 501 { 502 case MACH_O_N_ABS: 503 return 1; 504 case MACH_O_N_SECT: 505 return 1; 506 default: 507 return 0; 508 } 509} 510 511/* Add symbol table information for a Mach-O file. */ 512 513static int 514macho_add_symtab (struct backtrace_state *state, int descriptor, 515 uintptr_t base_address, int is_64, 516 off_t symoff, unsigned int nsyms, off_t stroff, 517 unsigned int strsize, 518 backtrace_error_callback error_callback, void *data) 519{ 520 size_t symsize; 521 struct backtrace_view sym_view; 522 int sym_view_valid; 523 struct backtrace_view str_view; 524 int str_view_valid; 525 size_t ndefs; 526 size_t symtaboff; 527 unsigned int i; 528 size_t macho_symbol_size; 529 struct macho_symbol *macho_symbols; 530 unsigned int j; 531 struct macho_syminfo_data *sdata; 532 533 sym_view_valid = 0; 534 str_view_valid = 0; 535 macho_symbol_size = 0; 536 macho_symbols = NULL; 537 538 if (is_64) 539 symsize = sizeof (struct macho_nlist_64); 540 else 541 symsize = sizeof (struct macho_nlist); 542 543 if (!backtrace_get_view (state, descriptor, symoff, nsyms * symsize, 544 error_callback, data, &sym_view)) 545 goto fail; 546 sym_view_valid = 1; 547 548 if (!backtrace_get_view (state, descriptor, stroff, strsize, 549 error_callback, data, &str_view)) 550 return 0; 551 str_view_valid = 1; 552 553 ndefs = 0; 554 symtaboff = 0; 555 for (i = 0; i < nsyms; ++i, symtaboff += symsize) 556 { 557 if (is_64) 558 { 559 struct macho_nlist_64 nlist; 560 561 memcpy (&nlist, (const char *) sym_view.data + symtaboff, 562 sizeof nlist); 563 if (macho_defined_symbol (nlist.n_type)) 564 ++ndefs; 565 } 566 else 567 { 568 struct macho_nlist nlist; 569 570 memcpy (&nlist, (const char *) sym_view.data + symtaboff, 571 sizeof nlist); 572 if (macho_defined_symbol (nlist.n_type)) 573 ++ndefs; 574 } 575 } 576 577 /* Add 1 to ndefs to make room for a sentinel. */ 578 macho_symbol_size = (ndefs + 1) * sizeof (struct macho_symbol); 579 macho_symbols = ((struct macho_symbol *) 580 backtrace_alloc (state, macho_symbol_size, error_callback, 581 data)); 582 if (macho_symbols == NULL) 583 goto fail; 584 585 j = 0; 586 symtaboff = 0; 587 for (i = 0; i < nsyms; ++i, symtaboff += symsize) 588 { 589 uint32_t strx; 590 uint64_t value; 591 const char *name; 592 593 strx = 0; 594 value = 0; 595 if (is_64) 596 { 597 struct macho_nlist_64 nlist; 598 599 memcpy (&nlist, (const char *) sym_view.data + symtaboff, 600 sizeof nlist); 601 if (!macho_defined_symbol (nlist.n_type)) 602 continue; 603 604 strx = nlist.n_strx; 605 value = nlist.n_value; 606 } 607 else 608 { 609 struct macho_nlist nlist; 610 611 memcpy (&nlist, (const char *) sym_view.data + symtaboff, 612 sizeof nlist); 613 if (!macho_defined_symbol (nlist.n_type)) 614 continue; 615 616 strx = nlist.n_strx; 617 value = nlist.n_value; 618 } 619 620 if (strx >= strsize) 621 { 622 error_callback (data, "symbol string index out of range", 0); 623 goto fail; 624 } 625 626 name = (const char *) str_view.data + strx; 627 if (name[0] == '_') 628 ++name; 629 macho_symbols[j].name = name; 630 macho_symbols[j].address = value + base_address; 631 ++j; 632 } 633 634 sdata = ((struct macho_syminfo_data *) 635 backtrace_alloc (state, sizeof *sdata, error_callback, data)); 636 if (sdata == NULL) 637 goto fail; 638 639 /* We need to keep the string table since it holds the names, but we 640 can release the symbol table. */ 641 642 backtrace_release_view (state, &sym_view, error_callback, data); 643 sym_view_valid = 0; 644 str_view_valid = 0; 645 646 /* Add a trailing sentinel symbol. */ 647 macho_symbols[j].name = ""; 648 macho_symbols[j].address = ~(uintptr_t) 0; 649 650 backtrace_qsort (macho_symbols, ndefs + 1, sizeof (struct macho_symbol), 651 macho_symbol_compare); 652 653 sdata->next = NULL; 654 sdata->symbols = macho_symbols; 655 sdata->count = ndefs; 656 657 if (!state->threaded) 658 { 659 struct macho_syminfo_data **pp; 660 661 for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; 662 *pp != NULL; 663 pp = &(*pp)->next) 664 ; 665 *pp = sdata; 666 } 667 else 668 { 669 while (1) 670 { 671 struct macho_syminfo_data **pp; 672 673 pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; 674 675 while (1) 676 { 677 struct macho_syminfo_data *p; 678 679 p = backtrace_atomic_load_pointer (pp); 680 681 if (p == NULL) 682 break; 683 684 pp = &p->next; 685 } 686 687 if (__sync_bool_compare_and_swap (pp, NULL, sdata)) 688 break; 689 } 690 } 691 692 return 1; 693 694 fail: 695 if (macho_symbols != NULL) 696 backtrace_free (state, macho_symbols, macho_symbol_size, 697 error_callback, data); 698 if (sym_view_valid) 699 backtrace_release_view (state, &sym_view, error_callback, data); 700 if (str_view_valid) 701 backtrace_release_view (state, &str_view, error_callback, data); 702 return 0; 703} 704 705/* Return the symbol name and value for an ADDR. */ 706 707static void 708macho_syminfo (struct backtrace_state *state, uintptr_t addr, 709 backtrace_syminfo_callback callback, 710 backtrace_error_callback error_callback ATTRIBUTE_UNUSED, 711 void *data) 712{ 713 struct macho_syminfo_data *sdata; 714 struct macho_symbol *sym; 715 716 sym = NULL; 717 if (!state->threaded) 718 { 719 for (sdata = (struct macho_syminfo_data *) state->syminfo_data; 720 sdata != NULL; 721 sdata = sdata->next) 722 { 723 sym = ((struct macho_symbol *) 724 bsearch (&addr, sdata->symbols, sdata->count, 725 sizeof (struct macho_symbol), macho_symbol_search)); 726 if (sym != NULL) 727 break; 728 } 729 } 730 else 731 { 732 struct macho_syminfo_data **pp; 733 734 pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; 735 while (1) 736 { 737 sdata = backtrace_atomic_load_pointer (pp); 738 if (sdata == NULL) 739 break; 740 741 sym = ((struct macho_symbol *) 742 bsearch (&addr, sdata->symbols, sdata->count, 743 sizeof (struct macho_symbol), macho_symbol_search)); 744 if (sym != NULL) 745 break; 746 747 pp = &sdata->next; 748 } 749 } 750 751 if (sym == NULL) 752 callback (data, addr, NULL, 0, 0); 753 else 754 callback (data, addr, sym->name, sym->address, 0); 755} 756 757/* Look through a fat file to find the relevant executable. Returns 1 758 on success, 0 on failure (in both cases descriptor is closed). */ 759 760static int 761macho_add_fat (struct backtrace_state *state, const char *filename, 762 int descriptor, int swapped, off_t offset, 763 const unsigned char *match_uuid, uintptr_t base_address, 764 int skip_symtab, uint32_t nfat_arch, int is_64, 765 backtrace_error_callback error_callback, void *data, 766 fileline *fileline_fn, int *found_sym) 767{ 768 int arch_view_valid; 769 unsigned int cputype; 770 size_t arch_size; 771 struct backtrace_view arch_view; 772 unsigned int i; 773 774 arch_view_valid = 0; 775 776#if defined (__x86_64__) 777 cputype = MACH_O_CPU_TYPE_X86_64; 778#elif defined (__i386__) 779 cputype = MACH_O_CPU_TYPE_X86; 780#elif defined (__aarch64__) 781 cputype = MACH_O_CPU_TYPE_ARM64; 782#elif defined (__arm__) 783 cputype = MACH_O_CPU_TYPE_ARM; 784#elif defined (__ppc__) 785 cputype = MACH_O_CPU_TYPE_PPC; 786#elif defined (__ppc64__) 787 cputype = MACH_O_CPU_TYPE_PPC64; 788#else 789 error_callback (data, "unknown Mach-O architecture", 0); 790 goto fail; 791#endif 792 793 if (is_64) 794 arch_size = sizeof (struct macho_fat_arch_64); 795 else 796 arch_size = sizeof (struct macho_fat_arch); 797 798 if (!backtrace_get_view (state, descriptor, offset, 799 nfat_arch * arch_size, 800 error_callback, data, &arch_view)) 801 goto fail; 802 803 for (i = 0; i < nfat_arch; ++i) 804 { 805 uint32_t fcputype; 806 uint64_t foffset; 807 808 if (is_64) 809 { 810 struct macho_fat_arch_64 fat_arch_64; 811 812 memcpy (&fat_arch_64, 813 (const char *) arch_view.data + i * arch_size, 814 arch_size); 815 fcputype = fat_arch_64.cputype; 816 foffset = fat_arch_64.offset; 817 if (swapped) 818 { 819 fcputype = __builtin_bswap32 (fcputype); 820 foffset = __builtin_bswap64 (foffset); 821 } 822 } 823 else 824 { 825 struct macho_fat_arch fat_arch_32; 826 827 memcpy (&fat_arch_32, 828 (const char *) arch_view.data + i * arch_size, 829 arch_size); 830 fcputype = fat_arch_32.cputype; 831 foffset = (uint64_t) fat_arch_32.offset; 832 if (swapped) 833 { 834 fcputype = __builtin_bswap32 (fcputype); 835 foffset = (uint64_t) __builtin_bswap32 ((uint32_t) foffset); 836 } 837 } 838 839 if (fcputype == cputype) 840 { 841 /* FIXME: What about cpusubtype? */ 842 backtrace_release_view (state, &arch_view, error_callback, data); 843 return macho_add (state, filename, descriptor, foffset, match_uuid, 844 base_address, skip_symtab, error_callback, data, 845 fileline_fn, found_sym); 846 } 847 } 848 849 error_callback (data, "could not find executable in fat file", 0); 850 851 fail: 852 if (arch_view_valid) 853 backtrace_release_view (state, &arch_view, error_callback, data); 854 if (descriptor != -1) 855 backtrace_close (descriptor, error_callback, data); 856 return 0; 857} 858 859/* Look for the dsym file for FILENAME. This is called if FILENAME 860 does not have debug info or a symbol table. Returns 1 on success, 861 0 on failure. */ 862 863static int 864macho_add_dsym (struct backtrace_state *state, const char *filename, 865 uintptr_t base_address, const unsigned char *uuid, 866 backtrace_error_callback error_callback, void *data, 867 fileline* fileline_fn) 868{ 869 const char *p; 870 const char *dirname; 871 char *diralc; 872 size_t dirnamelen; 873 const char *basename; 874 size_t basenamelen; 875 const char *dsymsuffixdir; 876 size_t dsymsuffixdirlen; 877 size_t dsymlen; 878 char *dsym; 879 char *ps; 880 int d; 881 int does_not_exist; 882 int dummy_found_sym; 883 884 diralc = NULL; 885 dirnamelen = 0; 886 dsym = NULL; 887 dsymlen = 0; 888 889 p = strrchr (filename, '/'); 890 if (p == NULL) 891 { 892 dirname = "."; 893 dirnamelen = 1; 894 basename = filename; 895 basenamelen = strlen (basename); 896 diralc = NULL; 897 } 898 else 899 { 900 dirnamelen = p - filename; 901 diralc = (char*)backtrace_alloc (state, dirnamelen + 1, error_callback, data); 902 if (diralc == NULL) 903 goto fail; 904 memcpy (diralc, filename, dirnamelen); 905 diralc[dirnamelen] = '\0'; 906 dirname = diralc; 907 basename = p + 1; 908 basenamelen = strlen (basename); 909 } 910 911 dsymsuffixdir = ".dSYM/Contents/Resources/DWARF/"; 912 dsymsuffixdirlen = strlen (dsymsuffixdir); 913 914 dsymlen = (dirnamelen 915 + 1 916 + basenamelen 917 + dsymsuffixdirlen 918 + basenamelen 919 + 1); 920 dsym = (char*)backtrace_alloc (state, dsymlen, error_callback, data); 921 if (dsym == NULL) 922 goto fail; 923 924 ps = dsym; 925 memcpy (ps, dirname, dirnamelen); 926 ps += dirnamelen; 927 *ps++ = '/'; 928 memcpy (ps, basename, basenamelen); 929 ps += basenamelen; 930 memcpy (ps, dsymsuffixdir, dsymsuffixdirlen); 931 ps += dsymsuffixdirlen; 932 memcpy (ps, basename, basenamelen); 933 ps += basenamelen; 934 *ps = '\0'; 935 936 if (diralc != NULL) 937 { 938 backtrace_free (state, diralc, dirnamelen + 1, error_callback, data); 939 diralc = NULL; 940 } 941 942 d = backtrace_open (dsym, error_callback, data, &does_not_exist); 943 if (d < 0) 944 { 945 /* The file does not exist, so we can't read the debug info. 946 Just return success. */ 947 backtrace_free (state, dsym, dsymlen, error_callback, data); 948 return 1; 949 } 950 951 if (!macho_add (state, dsym, d, 0, uuid, base_address, 1, 952 error_callback, data, fileline_fn, &dummy_found_sym)) 953 goto fail; 954 955 backtrace_free (state, dsym, dsymlen, error_callback, data); 956 957 return 1; 958 959 fail: 960 if (dsym != NULL) 961 backtrace_free (state, dsym, dsymlen, error_callback, data); 962 if (diralc != NULL) 963 backtrace_free (state, diralc, dirnamelen, error_callback, data); 964 return 0; 965} 966 967/* Add the backtrace data for a Macho-O file. Returns 1 on success, 0 968 on failure (in both cases descriptor is closed). 969 970 FILENAME: the name of the executable. 971 DESCRIPTOR: an open descriptor for the executable, closed here. 972 OFFSET: the offset within the file of this executable, for fat files. 973 MATCH_UUID: if not NULL, UUID that must match. 974 BASE_ADDRESS: the load address of the executable. 975 SKIP_SYMTAB: if non-zero, ignore the symbol table; used for dSYM files. 976 FILELINE_FN: set to the fileline function, by backtrace_dwarf_add. 977 FOUND_SYM: set to non-zero if we found the symbol table. 978*/ 979 980static int 981macho_add (struct backtrace_state *state, const char *filename, int descriptor, 982 off_t offset, const unsigned char *match_uuid, 983 uintptr_t base_address, int skip_symtab, 984 backtrace_error_callback error_callback, void *data, 985 fileline *fileline_fn, int *found_sym) 986{ 987 struct backtrace_view header_view; 988 struct macho_header_32 header; 989 off_t hdroffset; 990 int is_64; 991 struct backtrace_view cmds_view; 992 int cmds_view_valid; 993 struct dwarf_sections dwarf_sections; 994 int have_dwarf; 995 unsigned char uuid[MACH_O_UUID_LEN]; 996 int have_uuid; 997 size_t cmdoffset; 998 unsigned int i; 999 1000 *found_sym = 0; 1001 1002 cmds_view_valid = 0; 1003 1004 /* The 32-bit and 64-bit file headers start out the same, so we can 1005 just always read the 32-bit version. A fat header is shorter but 1006 it will always be followed by data, so it's OK to read extra. */ 1007 1008 if (!backtrace_get_view (state, descriptor, offset, 1009 sizeof (struct macho_header_32), 1010 error_callback, data, &header_view)) 1011 goto fail; 1012 1013 memcpy (&header, header_view.data, sizeof header); 1014 1015 backtrace_release_view (state, &header_view, error_callback, data); 1016 1017 switch (header.magic) 1018 { 1019 case MACH_O_MH_MAGIC_32: 1020 is_64 = 0; 1021 hdroffset = offset + sizeof (struct macho_header_32); 1022 break; 1023 case MACH_O_MH_MAGIC_64: 1024 is_64 = 1; 1025 hdroffset = offset + sizeof (struct macho_header_64); 1026 break; 1027 case MACH_O_MH_MAGIC_FAT: 1028 case MACH_O_MH_MAGIC_FAT_64: 1029 { 1030 struct macho_header_fat fat_header; 1031 1032 hdroffset = offset + sizeof (struct macho_header_fat); 1033 memcpy (&fat_header, &header, sizeof fat_header); 1034 return macho_add_fat (state, filename, descriptor, 0, hdroffset, 1035 match_uuid, base_address, skip_symtab, 1036 fat_header.nfat_arch, 1037 header.magic == MACH_O_MH_MAGIC_FAT_64, 1038 error_callback, data, fileline_fn, found_sym); 1039 } 1040 case MACH_O_MH_CIGAM_FAT: 1041 case MACH_O_MH_CIGAM_FAT_64: 1042 { 1043 struct macho_header_fat fat_header; 1044 uint32_t nfat_arch; 1045 1046 hdroffset = offset + sizeof (struct macho_header_fat); 1047 memcpy (&fat_header, &header, sizeof fat_header); 1048 nfat_arch = __builtin_bswap32 (fat_header.nfat_arch); 1049 return macho_add_fat (state, filename, descriptor, 1, hdroffset, 1050 match_uuid, base_address, skip_symtab, 1051 nfat_arch, 1052 header.magic == MACH_O_MH_CIGAM_FAT_64, 1053 error_callback, data, fileline_fn, found_sym); 1054 } 1055 default: 1056 error_callback (data, "executable file is not in Mach-O format", 0); 1057 goto fail; 1058 } 1059 1060 switch (header.filetype) 1061 { 1062 case MACH_O_MH_EXECUTE: 1063 case MACH_O_MH_DYLIB: 1064 case MACH_O_MH_DSYM: 1065 break; 1066 default: 1067 error_callback (data, "executable file is not an executable", 0); 1068 goto fail; 1069 } 1070 1071 if (!backtrace_get_view (state, descriptor, hdroffset, header.sizeofcmds, 1072 error_callback, data, &cmds_view)) 1073 goto fail; 1074 cmds_view_valid = 1; 1075 1076 memset (&dwarf_sections, 0, sizeof dwarf_sections); 1077 have_dwarf = 0; 1078 memset (&uuid, 0, sizeof uuid); 1079 have_uuid = 0; 1080 1081 cmdoffset = 0; 1082 for (i = 0; i < header.ncmds; ++i) 1083 { 1084 const char *pcmd; 1085 struct macho_load_command load_command; 1086 1087 if (cmdoffset + sizeof load_command > header.sizeofcmds) 1088 break; 1089 1090 pcmd = (const char *) cmds_view.data + cmdoffset; 1091 memcpy (&load_command, pcmd, sizeof load_command); 1092 1093 switch (load_command.cmd) 1094 { 1095 case MACH_O_LC_SEGMENT: 1096 { 1097 struct macho_segment_command segcmd; 1098 1099 memcpy (&segcmd, pcmd, sizeof segcmd); 1100 if (memcmp (segcmd.segname, 1101 "__DWARF\0\0\0\0\0\0\0\0\0", 1102 MACH_O_NAMELEN) == 0) 1103 { 1104 if (!macho_add_dwarf_segment (state, descriptor, offset, 1105 load_command.cmd, 1106 pcmd + sizeof segcmd, 1107 (load_command.cmdsize 1108 - sizeof segcmd), 1109 segcmd.nsects, error_callback, 1110 data, &dwarf_sections)) 1111 goto fail; 1112 have_dwarf = 1; 1113 } 1114 } 1115 break; 1116 1117 case MACH_O_LC_SEGMENT_64: 1118 { 1119 struct macho_segment_64_command segcmd; 1120 1121 memcpy (&segcmd, pcmd, sizeof segcmd); 1122 if (memcmp (segcmd.segname, 1123 "__DWARF\0\0\0\0\0\0\0\0\0", 1124 MACH_O_NAMELEN) == 0) 1125 { 1126 if (!macho_add_dwarf_segment (state, descriptor, offset, 1127 load_command.cmd, 1128 pcmd + sizeof segcmd, 1129 (load_command.cmdsize 1130 - sizeof segcmd), 1131 segcmd.nsects, error_callback, 1132 data, &dwarf_sections)) 1133 goto fail; 1134 have_dwarf = 1; 1135 } 1136 } 1137 break; 1138 1139 case MACH_O_LC_SYMTAB: 1140 if (!skip_symtab) 1141 { 1142 struct macho_symtab_command symcmd; 1143 1144 memcpy (&symcmd, pcmd, sizeof symcmd); 1145 if (!macho_add_symtab (state, descriptor, base_address, is_64, 1146 offset + symcmd.symoff, symcmd.nsyms, 1147 offset + symcmd.stroff, symcmd.strsize, 1148 error_callback, data)) 1149 goto fail; 1150 1151 *found_sym = 1; 1152 } 1153 break; 1154 1155 case MACH_O_LC_UUID: 1156 { 1157 struct macho_uuid_command uuidcmd; 1158 1159 memcpy (&uuidcmd, pcmd, sizeof uuidcmd); 1160 memcpy (&uuid[0], &uuidcmd.uuid[0], MACH_O_UUID_LEN); 1161 have_uuid = 1; 1162 } 1163 break; 1164 1165 default: 1166 break; 1167 } 1168 1169 cmdoffset += load_command.cmdsize; 1170 } 1171 1172 if (!backtrace_close (descriptor, error_callback, data)) 1173 goto fail; 1174 descriptor = -1; 1175 1176 backtrace_release_view (state, &cmds_view, error_callback, data); 1177 cmds_view_valid = 0; 1178 1179 if (match_uuid != NULL) 1180 { 1181 /* If we don't have a UUID, or it doesn't match, just ignore 1182 this file. */ 1183 if (!have_uuid 1184 || memcmp (match_uuid, &uuid[0], MACH_O_UUID_LEN) != 0) 1185 return 1; 1186 } 1187 1188 if (have_dwarf) 1189 { 1190 int is_big_endian; 1191 1192 is_big_endian = 0; 1193#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) 1194#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 1195 is_big_endian = 1; 1196#endif 1197#endif 1198 1199 if (!backtrace_dwarf_add (state, base_address, &dwarf_sections, 1200 is_big_endian, NULL, error_callback, data, 1201 fileline_fn, NULL)) 1202 goto fail; 1203 } 1204 1205 if (!have_dwarf && have_uuid) 1206 { 1207 if (!macho_add_dsym (state, filename, base_address, &uuid[0], 1208 error_callback, data, fileline_fn)) 1209 goto fail; 1210 } 1211 1212 return 1; 1213 1214 fail: 1215 if (cmds_view_valid) 1216 backtrace_release_view (state, &cmds_view, error_callback, data); 1217 if (descriptor != -1) 1218 backtrace_close (descriptor, error_callback, data); 1219 return 0; 1220} 1221 1222#ifdef HAVE_MACH_O_DYLD_H 1223 1224/* Initialize the backtrace data we need from a Mach-O executable 1225 using the dyld support functions. This closes descriptor. */ 1226 1227int 1228backtrace_initialize (struct backtrace_state *state, const char *filename, 1229 int descriptor, backtrace_error_callback error_callback, 1230 void *data, fileline *fileline_fn) 1231{ 1232 uint32_t c; 1233 uint32_t i; 1234 int closed_descriptor; 1235 int found_sym; 1236 fileline macho_fileline_fn; 1237 1238 closed_descriptor = 0; 1239 found_sym = 0; 1240 macho_fileline_fn = macho_nodebug; 1241 1242 c = _dyld_image_count (); 1243 for (i = 0; i < c; ++i) 1244 { 1245 uintptr_t base_address; 1246 const char *name; 1247 int d; 1248 fileline mff; 1249 int mfs; 1250 1251 name = _dyld_get_image_name (i); 1252 if (name == NULL) 1253 continue; 1254 1255 if (strcmp (name, filename) == 0 && !closed_descriptor) 1256 { 1257 d = descriptor; 1258 closed_descriptor = 1; 1259 } 1260 else 1261 { 1262 int does_not_exist; 1263 1264 d = backtrace_open (name, error_callback, data, &does_not_exist); 1265 if (d < 0) 1266 continue; 1267 } 1268 1269 base_address = _dyld_get_image_vmaddr_slide (i); 1270 1271 mff = macho_nodebug; 1272 if (!macho_add (state, name, d, 0, NULL, base_address, 0, 1273 error_callback, data, &mff, &mfs)) 1274 continue; 1275 1276 if (mff != macho_nodebug) 1277 macho_fileline_fn = mff; 1278 if (mfs) 1279 found_sym = 1; 1280 } 1281 1282 if (!closed_descriptor) 1283 backtrace_close (descriptor, error_callback, data); 1284 1285 if (!state->threaded) 1286 { 1287 if (found_sym) 1288 state->syminfo_fn = macho_syminfo; 1289 else if (state->syminfo_fn == NULL) 1290 state->syminfo_fn = macho_nosyms; 1291 } 1292 else 1293 { 1294 if (found_sym) 1295 backtrace_atomic_store_pointer (&state->syminfo_fn, &macho_syminfo); 1296 else 1297 (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, 1298 macho_nosyms); 1299 } 1300 1301 if (!state->threaded) 1302 *fileline_fn = state->fileline_fn; 1303 else 1304 *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); 1305 1306 if (*fileline_fn == NULL || *fileline_fn == macho_nodebug) 1307 *fileline_fn = macho_fileline_fn; 1308 1309 return 1; 1310} 1311 1312#else /* !defined (HAVE_MACH_O_DYLD_H) */ 1313 1314/* Initialize the backtrace data we need from a Mach-O executable 1315 without using the dyld support functions. This closes 1316 descriptor. */ 1317 1318int 1319backtrace_initialize (struct backtrace_state *state, const char *filename, 1320 int descriptor, backtrace_error_callback error_callback, 1321 void *data, fileline *fileline_fn) 1322{ 1323 fileline macho_fileline_fn; 1324 int found_sym; 1325 1326 macho_fileline_fn = macho_nodebug; 1327 if (!macho_add (state, filename, descriptor, 0, NULL, 0, 0, 1328 error_callback, data, &macho_fileline_fn, &found_sym)) 1329 return 0; 1330 1331 if (!state->threaded) 1332 { 1333 if (found_sym) 1334 state->syminfo_fn = macho_syminfo; 1335 else if (state->syminfo_fn == NULL) 1336 state->syminfo_fn = macho_nosyms; 1337 } 1338 else 1339 { 1340 if (found_sym) 1341 backtrace_atomic_store_pointer (&state->syminfo_fn, &macho_syminfo); 1342 else 1343 (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, 1344 macho_nosyms); 1345 } 1346 1347 if (!state->threaded) 1348 *fileline_fn = state->fileline_fn; 1349 else 1350 *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); 1351 1352 if (*fileline_fn == NULL || *fileline_fn == macho_nodebug) 1353 *fileline_fn = macho_fileline_fn; 1354 1355 return 1; 1356} 1357 1358#endif /* !defined (HAVE_MACH_O_DYLD_H) */ 1359 1360}