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