libbacktrace: add Mach-O support
[official-gcc.git] / libbacktrace / macho.c
blob3aea70cdbbe9cde5306444b036bedd1336eea3a6
1 /* elf.c -- Get debug data from a Mach-O file for backtraces.
2 Copyright (C) 2020 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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.
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.
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE. */
33 #include "config.h"
35 #include <sys/types.h>
36 #include <dirent.h>
37 #include <stdlib.h>
38 #include <string.h>
40 #ifdef HAVE_MACH_O_DYLD_H
41 #include <mach-o/dyld.h>
42 #endif
44 #include "backtrace.h"
45 #include "internal.h"
47 /* Mach-O file header for a 32-bit executable. */
49 struct macho_header_32
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 */
60 /* Mach-O file header for a 64-bit executable. */
62 struct macho_header_64
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 */
74 /* Mach-O file header for a fat executable. */
76 struct macho_header_fat
78 uint32_t magic; /* Magic number (MACH_O_MH_MAGIC_FAT) */
79 uint32_t nfat_arch; /* Number of components */
82 /* Values for the header magic field. */
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
89 /* Value for the header filetype field. */
91 #define MACH_O_MH_EXECUTE 0x02
92 #define MACH_O_MH_DYLIB 0x06
93 #define MACH_O_MH_DSYM 0x0a
95 /* A component of a fat file. A fat file starts with a
96 macho_header_fat followed by nfat_arch instances of this
97 struct. */
99 struct macho_fat_arch
101 uint32_t cputype; /* CPU type */
102 uint32_t cpusubtype; /* CPU subtype */
103 uint32_t offset; /* File offset of this entry */
104 uint32_t size; /* Size of this entry */
105 uint32_t align; /* Alignment of this entry */
108 /* Values for the fat_arch cputype field (and the header cputype
109 field). */
111 #define MACH_O_CPU_ARCH_ABI64 0x01000000
113 #define MACH_O_CPU_TYPE_X86 7
114 #define MACH_O_CPU_TYPE_ARM 12
116 #define MACH_O_CPU_TYPE_X86_64 (MACH_O_CPU_TYPE_X86 | MACH_O_CPU_ARCH_ABI64)
117 #define MACH_O_CPU_TYPE_ARM64 (MACH_O_CPU_TYPE_ARM | MACH_O_CPU_ARCH_ABI64)
119 /* The header of a load command. */
121 struct macho_load_command
123 uint32_t cmd; /* The type of load command */
124 uint32_t cmdsize; /* Size in bytes of the entire command */
127 /* Values for the load_command cmd field. */
129 #define MACH_O_LC_SEGMENT 0x01
130 #define MACH_O_LC_SYMTAB 0x02
131 #define MACH_O_LC_SEGMENT_64 0x19
132 #define MACH_O_LC_UUID 0x1b
134 /* The length of a section of segment name. */
136 #define MACH_O_NAMELEN (16)
138 /* LC_SEGMENT load command. */
140 struct macho_segment_command
142 uint32_t cmd; /* The type of load command (LC_SEGMENT) */
143 uint32_t cmdsize; /* Size in bytes of the entire command */
144 char segname[MACH_O_NAMELEN]; /* Segment name */
145 uint32_t vmaddr; /* Virtual memory address */
146 uint32_t vmsize; /* Virtual memory size */
147 uint32_t fileoff; /* Offset of data to be mapped */
148 uint32_t filesize; /* Size of data in file */
149 uint32_t maxprot; /* Maximum permitted virtual protection */
150 uint32_t initprot; /* Initial virtual memory protection */
151 uint32_t nsects; /* Number of sections in this segment */
152 uint32_t flags; /* Flags */
155 /* LC_SEGMENT_64 load command. */
157 struct macho_segment_64_command
159 uint32_t cmd; /* The type of load command (LC_SEGMENT) */
160 uint32_t cmdsize; /* Size in bytes of the entire command */
161 char segname[MACH_O_NAMELEN]; /* Segment name */
162 uint64_t vmaddr; /* Virtual memory address */
163 uint64_t vmsize; /* Virtual memory size */
164 uint64_t fileoff; /* Offset of data to be mapped */
165 uint64_t filesize; /* Size of data in file */
166 uint32_t maxprot; /* Maximum permitted virtual protection */
167 uint32_t initprot; /* Initial virtual memory protection */
168 uint32_t nsects; /* Number of sections in this segment */
169 uint32_t flags; /* Flags */
172 /* LC_SYMTAB load command. */
174 struct macho_symtab_command
176 uint32_t cmd; /* The type of load command (LC_SEGMENT) */
177 uint32_t cmdsize; /* Size in bytes of the entire command */
178 uint32_t symoff; /* File offset of symbol table */
179 uint32_t nsyms; /* Number of symbols */
180 uint32_t stroff; /* File offset of string table */
181 uint32_t strsize; /* String table size */
184 /* The length of a Mach-O uuid. */
186 #define MACH_O_UUID_LEN (16)
188 /* LC_UUID load command. */
190 struct macho_uuid_command
192 uint32_t cmd; /* Type of load command (LC_UUID) */
193 uint32_t cmdsize; /* Size in bytes of command */
194 unsigned char uuid[MACH_O_UUID_LEN]; /* UUID */
197 /* 32-bit section header within a LC_SEGMENT segment. */
199 struct macho_section
201 char sectname[MACH_O_NAMELEN]; /* Section name */
202 char segment[MACH_O_NAMELEN]; /* Segment of this section */
203 uint32_t addr; /* Address in memory */
204 uint32_t size; /* Section size */
205 uint32_t offset; /* File offset */
206 uint32_t align; /* Log2 of section alignment */
207 uint32_t reloff; /* File offset of relocations */
208 uint32_t nreloc; /* Number of relocs for this section */
209 uint32_t flags; /* Flags */
210 uint32_t reserved1;
211 uint32_t reserved2;
214 /* 64-bit section header within a LC_SEGMENT_64 segment. */
216 struct macho_section_64
218 char sectname[MACH_O_NAMELEN]; /* Section name */
219 char segment[MACH_O_NAMELEN]; /* Segment of this section */
220 uint64_t addr; /* Address in memory */
221 uint64_t size; /* Section size */
222 uint32_t offset; /* File offset */
223 uint32_t align; /* Log2 of section alignment */
224 uint32_t reloff; /* File offset of section relocations */
225 uint32_t nreloc; /* Number of relocs for this section */
226 uint32_t flags; /* Flags */
227 uint32_t reserved1;
228 uint32_t reserved2;
229 uint32_t reserved3;
232 /* 32-bit symbol data. */
234 struct macho_nlist
236 uint32_t n_strx; /* Index of name in string table */
237 uint8_t n_type; /* Type flag */
238 uint8_t n_sect; /* Section number */
239 uint16_t n_desc; /* Stabs description field */
240 uint32_t n_value; /* Value */
243 /* 64-bit symbol data. */
245 struct macho_nlist_64
247 uint32_t n_strx; /* Index of name in string table */
248 uint8_t n_type; /* Type flag */
249 uint8_t n_sect; /* Section number */
250 uint16_t n_desc; /* Stabs description field */
251 uint64_t n_value; /* Value */
254 /* Value found in nlist n_type field. */
256 #define MACH_O_N_EXT 0x01 /* Extern symbol */
257 #define MACH_O_N_ABS 0x02 /* Absolute symbol */
258 #define MACH_O_N_SECT 0x0e /* Defined in section */
260 #define MACH_O_N_TYPE 0x0e /* Mask for type bits */
261 #define MACH_O_N_STAB 0xe0 /* Stabs debugging symbol */
263 /* Information we keep for a Mach-O symbol. */
265 struct macho_symbol
267 const char *name; /* Symbol name */
268 uintptr_t address; /* Symbol address */
271 /* Information to pass to macho_syminfo. */
273 struct macho_syminfo_data
275 struct macho_syminfo_data *next; /* Next module */
276 struct macho_symbol *symbols; /* Symbols sorted by address */
277 size_t count; /* Number of symbols */
280 /* Names of sections, indexed by enum dwarf_section in internal.h. */
282 static const char * const dwarf_section_names[DEBUG_MAX] =
284 "__debug_info",
285 "__debug_line",
286 "__debug_abbrev",
287 "__debug_ranges",
288 "__debug_str",
289 "", /* DEBUG_ADDR */
290 "__debug_str_offs",
291 "", /* DEBUG_LINE_STR */
292 "__debug_rnglists"
295 /* Forward declaration. */
297 static int macho_add (struct backtrace_state *, const char *, int, off_t,
298 const unsigned char *, uintptr_t, int,
299 backtrace_error_callback, void *, fileline *, int *);
301 /* A dummy callback function used when we can't find any debug info. */
303 static int
304 macho_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
305 uintptr_t pc ATTRIBUTE_UNUSED,
306 backtrace_full_callback callback ATTRIBUTE_UNUSED,
307 backtrace_error_callback error_callback, void *data)
309 error_callback (data, "no debug info in Mach-O executable", -1);
310 return 0;
313 /* A dummy callback function used when we can't find a symbol
314 table. */
316 static void
317 macho_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
318 uintptr_t addr ATTRIBUTE_UNUSED,
319 backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
320 backtrace_error_callback error_callback, void *data)
322 error_callback (data, "no symbol table in Mach-O executable", -1);
325 /* Add a single DWARF section to DWARF_SECTIONS, if we need the
326 section. Returns 1 on success, 0 on failure. */
328 static int
329 macho_add_dwarf_section (struct backtrace_state *state, int descriptor,
330 const char *sectname, uint32_t offset, uint64_t size,
331 backtrace_error_callback error_callback, void *data,
332 struct dwarf_sections *dwarf_sections)
334 int i;
336 for (i = 0; i < (int) DEBUG_MAX; ++i)
338 if (dwarf_section_names[i][0] != '\0'
339 && strncmp (sectname, dwarf_section_names[i], MACH_O_NAMELEN) == 0)
341 struct backtrace_view section_view;
343 /* FIXME: Perhaps it would be better to try to use a single
344 view to read all the DWARF data, as we try to do for
345 ELF. */
347 if (!backtrace_get_view (state, descriptor, offset, size,
348 error_callback, data, &section_view))
349 return 0;
350 dwarf_sections->data[i] = (const unsigned char *) section_view.data;
351 dwarf_sections->size[i] = size;
352 break;
355 return 1;
358 /* Collect DWARF sections from a DWARF segment. Returns 1 on success,
359 0 on failure. */
361 static int
362 macho_add_dwarf_segment (struct backtrace_state *state, int descriptor,
363 off_t offset, unsigned int cmd, const char *psecs,
364 size_t sizesecs, unsigned int nsects,
365 backtrace_error_callback error_callback, void *data,
366 struct dwarf_sections *dwarf_sections)
368 size_t sec_header_size;
369 size_t secoffset;
370 unsigned int i;
372 switch (cmd)
374 case MACH_O_LC_SEGMENT:
375 sec_header_size = sizeof (struct macho_section);
376 break;
377 case MACH_O_LC_SEGMENT_64:
378 sec_header_size = sizeof (struct macho_section_64);
379 break;
380 default:
381 abort ();
384 secoffset = 0;
385 for (i = 0; i < nsects; ++i)
387 if (secoffset + sec_header_size > sizesecs)
389 error_callback (data, "section overflow withing segment", 0);
390 return 0;
393 switch (cmd)
395 case MACH_O_LC_SEGMENT:
397 struct macho_section section;
399 memcpy (&section, psecs + secoffset, sizeof section);
400 macho_add_dwarf_section (state, descriptor, section.sectname,
401 offset + section.offset, section.size,
402 error_callback, data, dwarf_sections);
404 break;
406 case MACH_O_LC_SEGMENT_64:
408 struct macho_section_64 section;
410 memcpy (&section, psecs + secoffset, sizeof section);
411 macho_add_dwarf_section (state, descriptor, section.sectname,
412 offset + section.offset, section.size,
413 error_callback, data, dwarf_sections);
415 break;
417 default:
418 abort ();
421 secoffset += sec_header_size;
424 return 1;
427 /* Compare struct macho_symbol for qsort. */
429 static int
430 macho_symbol_compare (const void *v1, const void *v2)
432 const struct macho_symbol *m1 = (const struct macho_symbol *) v1;
433 const struct macho_symbol *m2 = (const struct macho_symbol *) v2;
435 if (m1->address < m2->address)
436 return -1;
437 else if (m1->address > m2->address)
438 return 1;
439 else
440 return 0;
443 /* Compare an address against a macho_symbol for bsearch. We allocate
444 one extra entry in the array so that this can safely look at the
445 next entry. */
447 static int
448 macho_symbol_search (const void *vkey, const void *ventry)
450 const uintptr_t *key = (const uintptr_t *) vkey;
451 const struct macho_symbol *entry = (const struct macho_symbol *) ventry;
452 uintptr_t addr;
454 addr = *key;
455 if (addr < entry->address)
456 return -1;
457 else if (entry->name[0] == '\0'
458 && entry->address == ~(uintptr_t) 0)
459 return -1;
460 else if ((entry + 1)->name[0] == '\0'
461 && (entry + 1)->address == ~(uintptr_t) 0)
462 return -1;
463 else if (addr >= (entry + 1)->address)
464 return 1;
465 else
466 return 0;
469 /* Return whether the symbol type field indicates a symbol table entry
470 that we care about: a function or data symbol. */
472 static int
473 macho_defined_symbol (uint8_t type)
475 if ((type & MACH_O_N_STAB) != 0)
476 return 0;
477 if ((type & MACH_O_N_EXT) != 0)
478 return 0;
479 switch (type & MACH_O_N_TYPE)
481 case MACH_O_N_ABS:
482 return 1;
483 case MACH_O_N_SECT:
484 return 1;
485 default:
486 return 0;
490 /* Add symbol table information for a Mach-O file. */
492 static int
493 macho_add_symtab (struct backtrace_state *state, int descriptor,
494 uintptr_t base_address, int is_64,
495 off_t symoff, unsigned int nsyms, off_t stroff,
496 unsigned int strsize,
497 backtrace_error_callback error_callback, void *data)
499 size_t symsize;
500 struct backtrace_view sym_view;
501 int sym_view_valid;
502 struct backtrace_view str_view;
503 int str_view_valid;
504 size_t ndefs;
505 size_t symtaboff;
506 unsigned int i;
507 size_t macho_symbol_size;
508 struct macho_symbol *macho_symbols;
509 unsigned int j;
510 struct macho_syminfo_data *sdata;
512 sym_view_valid = 0;
513 str_view_valid = 0;
514 macho_symbol_size = 0;
515 macho_symbols = NULL;
517 if (is_64)
518 symsize = sizeof (struct macho_nlist_64);
519 else
520 symsize = sizeof (struct macho_nlist);
522 if (!backtrace_get_view (state, descriptor, symoff, nsyms * symsize,
523 error_callback, data, &sym_view))
524 goto fail;
525 sym_view_valid = 1;
527 if (!backtrace_get_view (state, descriptor, stroff, strsize,
528 error_callback, data, &str_view))
529 return 0;
530 str_view_valid = 1;
532 ndefs = 0;
533 symtaboff = 0;
534 for (i = 0; i < nsyms; ++i, symtaboff += symsize)
536 if (is_64)
538 struct macho_nlist_64 nlist;
540 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
541 sizeof nlist);
542 if (macho_defined_symbol (nlist.n_type))
543 ++ndefs;
545 else
547 struct macho_nlist nlist;
549 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
550 sizeof nlist);
551 if (macho_defined_symbol (nlist.n_type))
552 ++ndefs;
556 /* Add 1 to ndefs to make room for a sentinel. */
557 macho_symbol_size = (ndefs + 1) * sizeof (struct macho_symbol);
558 macho_symbols = ((struct macho_symbol *)
559 backtrace_alloc (state, macho_symbol_size, error_callback,
560 data));
561 if (macho_symbols == NULL)
562 goto fail;
564 j = 0;
565 symtaboff = 0;
566 for (i = 0; i < nsyms; ++i, symtaboff += symsize)
568 uint32_t strx;
569 uint64_t value;
570 const char *name;
572 strx = 0;
573 value = 0;
574 if (is_64)
576 struct macho_nlist_64 nlist;
578 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
579 sizeof nlist);
580 if (!macho_defined_symbol (nlist.n_type))
581 continue;
583 strx = nlist.n_strx;
584 value = nlist.n_value;
586 else
588 struct macho_nlist nlist;
590 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
591 sizeof nlist);
592 if (!macho_defined_symbol (nlist.n_type))
593 continue;
595 strx = nlist.n_strx;
596 value = nlist.n_value;
599 if (strx >= strsize)
601 error_callback (data, "symbol string index out of range", 0);
602 goto fail;
605 name = (const char *) str_view.data + strx;
606 if (name[0] == '_')
607 ++name;
608 macho_symbols[j].name = name;
609 macho_symbols[j].address = value + base_address;
610 ++j;
613 sdata = ((struct macho_syminfo_data *)
614 backtrace_alloc (state, sizeof *sdata, error_callback, data));
615 if (sdata == NULL)
616 goto fail;
618 /* We need to keep the string table since it holds the names, but we
619 can release the symbol table. */
621 backtrace_release_view (state, &sym_view, error_callback, data);
622 sym_view_valid = 0;
623 str_view_valid = 0;
625 /* Add a trailing sentinel symbol. */
626 macho_symbols[j].name = "";
627 macho_symbols[j].address = ~(uintptr_t) 0;
629 backtrace_qsort (macho_symbols, ndefs + 1, sizeof (struct macho_symbol),
630 macho_symbol_compare);
632 sdata->next = NULL;
633 sdata->symbols = macho_symbols;
634 sdata->count = ndefs;
636 if (!state->threaded)
638 struct macho_syminfo_data **pp;
640 for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
641 *pp != NULL;
642 pp = &(*pp)->next)
644 *pp = sdata;
646 else
648 while (1)
650 struct macho_syminfo_data **pp;
652 pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
654 while (1)
656 struct macho_syminfo_data *p;
658 p = backtrace_atomic_load_pointer (pp);
660 if (p == NULL)
661 break;
663 pp = &p->next;
666 if (__sync_bool_compare_and_swap (pp, NULL, sdata))
667 break;
671 return 1;
673 fail:
674 if (macho_symbols != NULL)
675 backtrace_free (state, macho_symbols, macho_symbol_size,
676 error_callback, data);
677 if (sym_view_valid)
678 backtrace_release_view (state, &sym_view, error_callback, data);
679 if (str_view_valid)
680 backtrace_release_view (state, &str_view, error_callback, data);
681 return 0;
684 /* Return the symbol name and value for an ADDR. */
686 static void
687 macho_syminfo (struct backtrace_state *state, uintptr_t addr,
688 backtrace_syminfo_callback callback,
689 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
690 void *data)
692 struct macho_syminfo_data *sdata;
693 struct macho_symbol *sym;
695 sym = NULL;
696 if (!state->threaded)
698 for (sdata = (struct macho_syminfo_data *) state->syminfo_data;
699 sdata != NULL;
700 sdata = sdata->next)
702 sym = ((struct macho_symbol *)
703 bsearch (&addr, sdata->symbols, sdata->count,
704 sizeof (struct macho_symbol), macho_symbol_search));
705 if (sym != NULL)
706 break;
709 else
711 struct macho_syminfo_data **pp;
713 pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
714 while (1)
716 sdata = backtrace_atomic_load_pointer (pp);
717 if (sdata == NULL)
718 break;
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;
726 pp = &sdata->next;
730 if (sym == NULL)
731 callback (data, addr, NULL, 0, 0);
732 else
733 callback (data, addr, sym->name, sym->address, 0);
736 /* Look through a fat file to find the relevant executable. Returns 1
737 on success, 0 on failure (in both cases descriptor is closed). */
739 static int
740 macho_add_fat (struct backtrace_state *state, const char *filename,
741 int descriptor, int swapped, off_t offset,
742 const unsigned char *match_uuid, uintptr_t base_address,
743 int skip_symtab, uint32_t nfat_arch,
744 backtrace_error_callback error_callback, void *data,
745 fileline *fileline_fn, int *found_sym)
747 int arch_view_valid;
748 unsigned int cputype;
749 struct backtrace_view arch_view;
750 size_t archoffset;
751 unsigned int i;
753 arch_view_valid = 0;
755 #if defined (__x86_64__)
756 cputype = MACH_O_CPU_TYPE_X86_64;
757 #elif defined (__i386__)
758 cputype = MACH_O_CPU_TYPE_X86;
759 #elif defined (__aarch64__)
760 cputype = MACH_O_CPU_TYPE_ARM64;
761 #elif defined (__arm__)
762 cputype = MACH_O_CPU_TYPE_ARM;
763 #else
764 error_callback (data, "unknown Mach-O architecture", 0);
765 goto fail;
766 #endif
768 if (!backtrace_get_view (state, descriptor, offset,
769 nfat_arch * sizeof (struct macho_fat_arch),
770 error_callback, data, &arch_view))
771 goto fail;
773 archoffset = 0;
774 for (i = 0; i < nfat_arch; ++i)
776 struct macho_fat_arch fat_arch;
777 uint32_t fcputype;
779 memcpy (&fat_arch,
780 ((const char *) arch_view.data
781 + i * sizeof (struct macho_fat_arch)),
782 sizeof fat_arch);
784 fcputype = fat_arch.cputype;
785 if (swapped)
786 fcputype = __builtin_bswap32 (fcputype);
788 if (fcputype == cputype)
790 uint32_t foffset;
792 /* FIXME: What about cpusubtype? */
793 foffset = fat_arch.offset;
794 if (swapped)
795 foffset = __builtin_bswap32 (foffset);
796 backtrace_release_view (state, &arch_view, error_callback, data);
797 return macho_add (state, filename, descriptor, foffset, match_uuid,
798 base_address, skip_symtab, error_callback, data,
799 fileline_fn, found_sym);
802 archoffset += sizeof (struct macho_fat_arch);
805 error_callback (data, "could not find executable in fat file", 0);
807 fail:
808 if (arch_view_valid)
809 backtrace_release_view (state, &arch_view, error_callback, data);
810 if (descriptor != -1)
811 backtrace_close (descriptor, error_callback, data);
812 return 0;
815 /* Look for the dsym file for FILENAME. This is called if FILENAME
816 does not have debug info or a symbol table. Returns 1 on success,
817 0 on failure. */
819 static int
820 macho_add_dsym (struct backtrace_state *state, const char *filename,
821 uintptr_t base_address, const unsigned char *uuid,
822 backtrace_error_callback error_callback, void *data,
823 fileline* fileline_fn)
825 const char *p;
826 const char *dirname;
827 char *diralc;
828 size_t dirnamelen;
829 const char *basename;
830 size_t basenamelen;
831 const char *dsymsuffixdir;
832 size_t dsymsuffixdirlen;
833 size_t dsymlen;
834 char *dsym;
835 char *ps;
836 int d;
837 int does_not_exist;
838 int dummy_found_sym;
840 diralc = NULL;
841 dirnamelen = 0;
842 dsym = NULL;
843 dsymlen = 0;
845 p = strrchr (filename, '/');
846 if (p == NULL)
848 dirname = ".";
849 dirnamelen = 1;
850 basename = filename;
851 basenamelen = strlen (basename);
852 diralc = NULL;
854 else
856 dirnamelen = p - filename;
857 diralc = backtrace_alloc (state, dirnamelen + 1, error_callback, data);
858 if (diralc == NULL)
859 goto fail;
860 memcpy (diralc, filename, dirnamelen);
861 diralc[dirnamelen] = '\0';
862 dirname = diralc;
863 basename = p + 1;
864 basenamelen = strlen (basename);
867 dsymsuffixdir = ".dSYM/Contents/Resources/DWARF/";
868 dsymsuffixdirlen = strlen (dsymsuffixdir);
870 dsymlen = (dirnamelen
871 + basenamelen
872 + dsymsuffixdirlen
873 + basenamelen
874 + 1);
875 dsym = backtrace_alloc (state, dsymlen, error_callback, data);
876 if (dsym == NULL)
877 goto fail;
879 ps = dsym;
880 memcpy (ps, dirname, dirnamelen);
881 ps += dirnamelen;
882 *ps++ = '/';
883 memcpy (ps, basename, basenamelen);
884 ps += basenamelen;
885 memcpy (ps, dsymsuffixdir, dsymsuffixdirlen);
886 ps += dsymsuffixdirlen;
887 memcpy (ps, basename, basenamelen);
888 ps += basenamelen;
889 *ps = '\0';
891 if (diralc != NULL)
893 backtrace_free (state, diralc, dirnamelen, error_callback, data);
894 diralc = NULL;
897 d = backtrace_open (dsym, error_callback, data, &does_not_exist);
898 if (d < 0)
900 /* The file does not exist, so we can't read the debug info.
901 Just return success. */
902 backtrace_free (state, dsym, dsymlen, error_callback, data);
903 return 1;
906 if (!macho_add (state, dsym, d, 0, uuid, base_address, 1,
907 error_callback, data, fileline_fn, &dummy_found_sym))
908 goto fail;
910 backtrace_free (state, dsym, dsymlen, error_callback, data);
912 return 1;
914 fail:
915 if (dsym != NULL)
916 backtrace_free (state, dsym, dsymlen, error_callback, data);
917 if (diralc != NULL)
918 backtrace_free (state, diralc, dirnamelen, error_callback, data);
919 return 0;
922 /* Add the backtrace data for a Macho-O file. Returns 1 on success, 0
923 on failure (in both cases descriptor is closed).
925 FILENAME: the name of the executable.
926 DESCRIPTOR: an open descriptor for the executable, closed here.
927 OFFSET: the offset within the file of this executable, for fat files.
928 MATCH_UUID: if not NULL, UUID that must match.
929 BASE_ADDRESS: the load address of the executable.
930 SKIP_SYMTAB: if non-zero, ignore the symbol table; used for dSYM files.
931 FILELINE_FN: set to the fileline function, by backtrace_dwarf_add.
932 FOUND_SYM: set to non-zero if we found the symbol table.
935 static int
936 macho_add (struct backtrace_state *state, const char *filename, int descriptor,
937 off_t offset, const unsigned char *match_uuid,
938 uintptr_t base_address, int skip_symtab,
939 backtrace_error_callback error_callback, void *data,
940 fileline *fileline_fn, int *found_sym)
942 struct backtrace_view header_view;
943 struct macho_header_32 header;
944 off_t hdroffset;
945 int is_64;
946 struct backtrace_view cmds_view;
947 int cmds_view_valid;
948 struct dwarf_sections dwarf_sections;
949 int have_dwarf;
950 unsigned char uuid[MACH_O_UUID_LEN];
951 int have_uuid;
952 size_t cmdoffset;
953 unsigned int i;
955 *found_sym = 0;
957 cmds_view_valid = 0;
959 /* The 32-bit and 64-bit file headers start out the same, so we can
960 just always read the 32-bit version. A fat header is shorter but
961 it will always be followed by data, so it's OK to read extra. */
963 if (!backtrace_get_view (state, descriptor, offset,
964 sizeof (struct macho_header_32),
965 error_callback, data, &header_view))
966 goto fail;
968 memcpy (&header, header_view.data, sizeof header);
970 backtrace_release_view (state, &header_view, error_callback, data);
972 switch (header.magic)
974 case MACH_O_MH_MAGIC_32:
975 is_64 = 0;
976 hdroffset = offset + sizeof (struct macho_header_32);
977 break;
978 case MACH_O_MH_MAGIC_64:
979 is_64 = 1;
980 hdroffset = offset + sizeof (struct macho_header_64);
981 break;
982 case MACH_O_MH_MAGIC_FAT:
984 struct macho_header_fat fat_header;
986 hdroffset = offset + sizeof (struct macho_header_fat);
987 memcpy (&fat_header, &header, sizeof fat_header);
988 return macho_add_fat (state, filename, descriptor, 0, hdroffset,
989 match_uuid, base_address, skip_symtab,
990 fat_header.nfat_arch, error_callback, data,
991 fileline_fn, found_sym);
993 case MACH_O_MH_CIGAM_FAT:
995 struct macho_header_fat fat_header;
996 uint32_t nfat_arch;
998 hdroffset = offset + sizeof (struct macho_header_fat);
999 memcpy (&fat_header, &header, sizeof fat_header);
1000 nfat_arch = __builtin_bswap32 (fat_header.nfat_arch);
1001 return macho_add_fat (state, filename, descriptor, 1, hdroffset,
1002 match_uuid, base_address, skip_symtab,
1003 nfat_arch, error_callback, data,
1004 fileline_fn, found_sym);
1006 default:
1007 error_callback (data, "executable file is not in Mach-O format", 0);
1008 goto fail;
1011 switch (header.filetype)
1013 case MACH_O_MH_EXECUTE:
1014 case MACH_O_MH_DYLIB:
1015 case MACH_O_MH_DSYM:
1016 break;
1017 default:
1018 error_callback (data, "executable file is not an executable", 0);
1019 goto fail;
1022 if (!backtrace_get_view (state, descriptor, hdroffset, header.sizeofcmds,
1023 error_callback, data, &cmds_view))
1024 goto fail;
1025 cmds_view_valid = 1;
1027 memset (&dwarf_sections, 0, sizeof dwarf_sections);
1028 have_dwarf = 0;
1029 memset (&uuid, 0, sizeof uuid);
1030 have_uuid = 0;
1032 cmdoffset = 0;
1033 for (i = 0; i < header.ncmds; ++i)
1035 const char *pcmd;
1036 struct macho_load_command load_command;
1038 if (cmdoffset + sizeof load_command > header.sizeofcmds)
1039 break;
1041 pcmd = (const char *) cmds_view.data + cmdoffset;
1042 memcpy (&load_command, pcmd, sizeof load_command);
1044 switch (load_command.cmd)
1046 case MACH_O_LC_SEGMENT:
1048 struct macho_segment_command segcmd;
1050 memcpy (&segcmd, pcmd, sizeof segcmd);
1051 if (memcmp (segcmd.segname,
1052 "__DWARF\0\0\0\0\0\0\0\0\0",
1053 MACH_O_NAMELEN) == 0)
1055 if (!macho_add_dwarf_segment (state, descriptor, offset,
1056 load_command.cmd,
1057 pcmd + sizeof segcmd,
1058 (load_command.cmdsize
1059 - sizeof segcmd),
1060 segcmd.nsects, error_callback,
1061 data, &dwarf_sections))
1062 goto fail;
1063 have_dwarf = 1;
1066 break;
1068 case MACH_O_LC_SEGMENT_64:
1070 struct macho_segment_64_command segcmd;
1072 memcpy (&segcmd, pcmd, sizeof segcmd);
1073 if (memcmp (segcmd.segname,
1074 "__DWARF\0\0\0\0\0\0\0\0\0",
1075 MACH_O_NAMELEN) == 0)
1077 if (!macho_add_dwarf_segment (state, descriptor, offset,
1078 load_command.cmd,
1079 pcmd + sizeof segcmd,
1080 (load_command.cmdsize
1081 - sizeof segcmd),
1082 segcmd.nsects, error_callback,
1083 data, &dwarf_sections))
1084 goto fail;
1085 have_dwarf = 1;
1088 break;
1090 case MACH_O_LC_SYMTAB:
1091 if (!skip_symtab)
1093 struct macho_symtab_command symcmd;
1095 memcpy (&symcmd, pcmd, sizeof symcmd);
1096 if (!macho_add_symtab (state, descriptor, base_address, is_64,
1097 offset + symcmd.symoff, symcmd.nsyms,
1098 offset + symcmd.stroff, symcmd.strsize,
1099 error_callback, data))
1100 goto fail;
1102 *found_sym = 1;
1104 break;
1106 case MACH_O_LC_UUID:
1108 struct macho_uuid_command uuidcmd;
1110 memcpy (&uuidcmd, pcmd, sizeof uuidcmd);
1111 memcpy (&uuid[0], &uuidcmd.uuid[0], MACH_O_UUID_LEN);
1112 have_uuid = 1;
1114 break;
1116 default:
1117 break;
1120 cmdoffset += load_command.cmdsize;
1123 if (!backtrace_close (descriptor, error_callback, data))
1124 goto fail;
1125 descriptor = -1;
1127 backtrace_release_view (state, &cmds_view, error_callback, data);
1128 cmds_view_valid = 0;
1130 if (match_uuid != NULL)
1132 /* If we don't have a UUID, or it doesn't match, just ignore
1133 this file. */
1134 if (!have_uuid
1135 || memcmp (match_uuid, &uuid[0], MACH_O_UUID_LEN) != 0)
1136 return 1;
1139 if (have_dwarf)
1141 int is_big_endian;
1143 is_big_endian = 0;
1144 #if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
1145 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
1146 is_big_endian = 1;
1147 #endif
1148 #endif
1150 if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,
1151 is_big_endian, NULL, error_callback, data,
1152 fileline_fn, NULL))
1153 goto fail;
1156 if (!have_dwarf && have_uuid)
1158 if (!macho_add_dsym (state, filename, base_address, &uuid[0],
1159 error_callback, data, fileline_fn))
1160 goto fail;
1163 return 1;
1165 fail:
1166 if (cmds_view_valid)
1167 backtrace_release_view (state, &cmds_view, error_callback, data);
1168 if (descriptor != -1)
1169 backtrace_close (descriptor, error_callback, data);
1170 return 0;
1173 #ifdef HAVE_MACH_O_DYLD_H
1175 /* Initialize the backtrace data we need from a Mach-O executable
1176 using the dyld support functions. This closes descriptor. */
1179 backtrace_initialize (struct backtrace_state *state, const char *filename,
1180 int descriptor, backtrace_error_callback error_callback,
1181 void *data, fileline *fileline_fn)
1183 uint32_t c;
1184 uint32_t i;
1185 int closed_descriptor;
1186 int found_sym;
1187 fileline macho_fileline_fn;
1189 closed_descriptor = 0;
1190 found_sym = 0;
1191 macho_fileline_fn = macho_nodebug;
1193 c = _dyld_image_count ();
1194 for (i = 0; i < c; ++i)
1196 uintptr_t base_address;
1197 const char *name;
1198 int d;
1199 fileline mff;
1200 int mfs;
1202 name = _dyld_get_image_name (i);
1203 if (name == NULL)
1204 continue;
1206 if (strcmp (name, filename) == 0 && !closed_descriptor)
1208 d = descriptor;
1209 closed_descriptor = 1;
1211 else
1213 int does_not_exist;
1215 d = backtrace_open (name, error_callback, data, &does_not_exist);
1216 if (d < 0)
1217 continue;
1220 base_address = _dyld_get_image_vmaddr_slide (i);
1222 mff = macho_nodebug;
1223 if (!macho_add (state, name, d, 0, NULL, base_address, 0,
1224 error_callback, data, &mff, &mfs))
1225 return 0;
1227 if (mff != macho_nodebug)
1228 macho_fileline_fn = mff;
1229 if (mfs)
1230 found_sym = 1;
1233 if (!closed_descriptor)
1234 backtrace_close (descriptor, error_callback, data);
1236 if (!state->threaded)
1238 if (found_sym)
1239 state->syminfo_fn = macho_syminfo;
1240 else if (state->syminfo_fn == NULL)
1241 state->syminfo_fn = macho_nosyms;
1243 else
1245 if (found_sym)
1246 backtrace_atomic_store_pointer (&state->syminfo_fn, macho_syminfo);
1247 else
1248 (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
1249 macho_nosyms);
1252 if (!state->threaded)
1253 *fileline_fn = state->fileline_fn;
1254 else
1255 *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
1257 if (*fileline_fn == NULL || *fileline_fn == macho_nodebug)
1258 *fileline_fn = macho_fileline_fn;
1260 return 1;
1263 #else /* !defined (HAVE_MACH_O_DYLD_H) */
1265 /* Initialize the backtrace data we need from a Mach-O executable
1266 without using the dyld support functions. This closes
1267 descriptor. */
1270 backtrace_initialize (struct backtrace_state *state, const char *filename,
1271 int descriptor, backtrace_error_callback error_callback,
1272 void *data, fileline *fileline_fn)
1274 fileline macho_fileline_fn;
1275 int found_sym;
1277 macho_fileline_fn = macho_nodebug;
1278 if (!macho_add (state, filename, descriptor, 0, NULL, 0, 0,
1279 error_callback, data, &macho_fileline_fn, &found_sym))
1280 return 0;
1282 if (!state->threaded)
1284 if (found_sym)
1285 state->syminfo_fn = macho_syminfo;
1286 else if (state->syminfo_fn == NULL)
1287 state->syminfo_fn = macho_nosyms;
1289 else
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);
1298 if (!state->threaded)
1299 *fileline_fn = state->fileline_fn;
1300 else
1301 *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
1303 if (*fileline_fn == NULL || *fileline_fn == macho_nodebug)
1304 *fileline_fn = macho_fileline_fn;
1306 return 1;
1309 #endif /* !defined (HAVE_MACH_O_DYLD_H) */