libstdc++: Avoid -Wmaybe-uninitialized warnings in text_encoding.cc
[official-gcc.git] / libbacktrace / macho.c
blobb4856346ccc225b22272ff335700bf539f83f55e
1 /* elf.c -- Get debug data from a Mach-O file for backtraces.
2 Copyright (C) 2020-2024 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|CIGAM)_FAT(_64)?) */
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
88 #define MACH_O_MH_MAGIC_FAT_64 0xcafebabf
89 #define MACH_O_MH_CIGAM_FAT_64 0xbfbafeca
91 /* Value for the header filetype field. */
93 #define MACH_O_MH_EXECUTE 0x02
94 #define MACH_O_MH_DYLIB 0x06
95 #define MACH_O_MH_DSYM 0x0a
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. */
101 struct macho_fat_arch
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 */
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. */
114 struct macho_fat_arch_64
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 */
124 /* Values for the fat_arch cputype field (and the header cputype
125 field). */
127 #define MACH_O_CPU_ARCH_ABI64 0x01000000
129 #define MACH_O_CPU_TYPE_X86 7
130 #define MACH_O_CPU_TYPE_ARM 12
131 #define MACH_O_CPU_TYPE_PPC 18
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)
137 /* The header of a load command. */
139 struct macho_load_command
141 uint32_t cmd; /* The type of load command */
142 uint32_t cmdsize; /* Size in bytes of the entire command */
145 /* Values for the load_command cmd field. */
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
152 /* The length of a section of segment name. */
154 #define MACH_O_NAMELEN (16)
156 /* LC_SEGMENT load command. */
158 struct macho_segment_command
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 */
173 /* LC_SEGMENT_64 load command. */
175 struct macho_segment_64_command
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 */
190 /* LC_SYMTAB load command. */
192 struct macho_symtab_command
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 */
202 /* The length of a Mach-O uuid. */
204 #define MACH_O_UUID_LEN (16)
206 /* LC_UUID load command. */
208 struct macho_uuid_command
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 */
215 /* 32-bit section header within a LC_SEGMENT segment. */
217 struct macho_section
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;
232 /* 64-bit section header within a LC_SEGMENT_64 segment. */
234 struct macho_section_64
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;
250 /* 32-bit symbol data. */
252 struct macho_nlist
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 */
261 /* 64-bit symbol data. */
263 struct macho_nlist_64
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 */
272 /* Value found in nlist n_type field. */
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 */
278 #define MACH_O_N_TYPE 0x0e /* Mask for type bits */
279 #define MACH_O_N_STAB 0xe0 /* Stabs debugging symbol */
281 /* Information we keep for a Mach-O symbol. */
283 struct macho_symbol
285 const char *name; /* Symbol name */
286 uintptr_t address; /* Symbol address */
289 /* Information to pass to macho_syminfo. */
291 struct macho_syminfo_data
293 struct macho_syminfo_data *next; /* Next module */
294 struct macho_symbol *symbols; /* Symbols sorted by address */
295 size_t count; /* Number of symbols */
298 /* Names of sections, indexed by enum dwarf_section in internal.h. */
300 static const char * const dwarf_section_names[DEBUG_MAX] =
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"
313 /* Forward declaration. */
315 static 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 *);
319 /* A dummy callback function used when we can't find any debug info. */
321 static int
322 macho_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)
327 error_callback (data, "no debug info in Mach-O executable", -1);
328 return 0;
331 /* A dummy callback function used when we can't find a symbol
332 table. */
334 static void
335 macho_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)
340 error_callback (data, "no symbol table in Mach-O executable", -1);
343 /* Add a single DWARF section to DWARF_SECTIONS, if we need the
344 section. Returns 1 on success, 0 on failure. */
346 static int
347 macho_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)
352 int i;
354 for (i = 0; i < (int) DEBUG_MAX; ++i)
356 if (dwarf_section_names[i][0] != '\0'
357 && strncmp (sectname, dwarf_section_names[i], MACH_O_NAMELEN) == 0)
359 struct backtrace_view section_view;
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. */
365 if (!backtrace_get_view (state, descriptor, offset, size,
366 error_callback, data, &section_view))
367 return 0;
368 dwarf_sections->data[i] = (const unsigned char *) section_view.data;
369 dwarf_sections->size[i] = size;
370 break;
373 return 1;
376 /* Collect DWARF sections from a DWARF segment. Returns 1 on success,
377 0 on failure. */
379 static int
380 macho_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)
386 size_t sec_header_size;
387 size_t secoffset;
388 unsigned int i;
390 switch (cmd)
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 ();
402 secoffset = 0;
403 for (i = 0; i < nsects; ++i)
405 if (secoffset + sec_header_size > sizesecs)
407 error_callback (data, "section overflow withing segment", 0);
408 return 0;
411 switch (cmd)
413 case MACH_O_LC_SEGMENT:
415 struct macho_section section;
417 memcpy (&section, 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);
422 break;
424 case MACH_O_LC_SEGMENT_64:
426 struct macho_section_64 section;
428 memcpy (&section, 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);
433 break;
435 default:
436 abort ();
439 secoffset += sec_header_size;
442 return 1;
445 /* Compare struct macho_symbol for qsort. */
447 static int
448 macho_symbol_compare (const void *v1, const void *v2)
450 const struct macho_symbol *m1 = (const struct macho_symbol *) v1;
451 const struct macho_symbol *m2 = (const struct macho_symbol *) v2;
453 if (m1->address < m2->address)
454 return -1;
455 else if (m1->address > m2->address)
456 return 1;
457 else
458 return 0;
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. */
465 static int
466 macho_symbol_search (const void *vkey, const void *ventry)
468 const uintptr_t *key = (const uintptr_t *) vkey;
469 const struct macho_symbol *entry = (const struct macho_symbol *) ventry;
470 uintptr_t addr;
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;
487 /* Return whether the symbol type field indicates a symbol table entry
488 that we care about: a function or data symbol. */
490 static int
491 macho_defined_symbol (uint8_t type)
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)
499 case MACH_O_N_ABS:
500 return 1;
501 case MACH_O_N_SECT:
502 return 1;
503 default:
504 return 0;
508 /* Add symbol table information for a Mach-O file. */
510 static int
511 macho_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)
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;
530 sym_view_valid = 0;
531 str_view_valid = 0;
532 macho_symbol_size = 0;
533 macho_symbols = NULL;
535 if (is_64)
536 symsize = sizeof (struct macho_nlist_64);
537 else
538 symsize = sizeof (struct macho_nlist);
540 if (!backtrace_get_view (state, descriptor, symoff, nsyms * symsize,
541 error_callback, data, &sym_view))
542 goto fail;
543 sym_view_valid = 1;
545 if (!backtrace_get_view (state, descriptor, stroff, strsize,
546 error_callback, data, &str_view))
547 return 0;
548 str_view_valid = 1;
550 ndefs = 0;
551 symtaboff = 0;
552 for (i = 0; i < nsyms; ++i, symtaboff += symsize)
554 if (is_64)
556 struct macho_nlist_64 nlist;
558 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
559 sizeof nlist);
560 if (macho_defined_symbol (nlist.n_type))
561 ++ndefs;
563 else
565 struct macho_nlist nlist;
567 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
568 sizeof nlist);
569 if (macho_defined_symbol (nlist.n_type))
570 ++ndefs;
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;
582 j = 0;
583 symtaboff = 0;
584 for (i = 0; i < nsyms; ++i, symtaboff += symsize)
586 uint32_t strx;
587 uint64_t value;
588 const char *name;
590 strx = 0;
591 value = 0;
592 if (is_64)
594 struct macho_nlist_64 nlist;
596 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
597 sizeof nlist);
598 if (!macho_defined_symbol (nlist.n_type))
599 continue;
601 strx = nlist.n_strx;
602 value = nlist.n_value;
604 else
606 struct macho_nlist nlist;
608 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
609 sizeof nlist);
610 if (!macho_defined_symbol (nlist.n_type))
611 continue;
613 strx = nlist.n_strx;
614 value = nlist.n_value;
617 if (strx >= strsize)
619 error_callback (data, "symbol string index out of range", 0);
620 goto fail;
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;
631 sdata = ((struct macho_syminfo_data *)
632 backtrace_alloc (state, sizeof *sdata, error_callback, data));
633 if (sdata == NULL)
634 goto fail;
636 /* We need to keep the string table since it holds the names, but we
637 can release the symbol table. */
639 backtrace_release_view (state, &sym_view, error_callback, data);
640 sym_view_valid = 0;
641 str_view_valid = 0;
643 /* Add a trailing sentinel symbol. */
644 macho_symbols[j].name = "";
645 macho_symbols[j].address = ~(uintptr_t) 0;
647 backtrace_qsort (macho_symbols, ndefs + 1, sizeof (struct macho_symbol),
648 macho_symbol_compare);
650 sdata->next = NULL;
651 sdata->symbols = macho_symbols;
652 sdata->count = ndefs;
654 if (!state->threaded)
656 struct macho_syminfo_data **pp;
658 for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
659 *pp != NULL;
660 pp = &(*pp)->next)
662 *pp = sdata;
664 else
666 while (1)
668 struct macho_syminfo_data **pp;
670 pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
672 while (1)
674 struct macho_syminfo_data *p;
676 p = backtrace_atomic_load_pointer (pp);
678 if (p == NULL)
679 break;
681 pp = &p->next;
684 if (__sync_bool_compare_and_swap (pp, NULL, sdata))
685 break;
689 return 1;
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;
702 /* Return the symbol name and value for an ADDR. */
704 static void
705 macho_syminfo (struct backtrace_state *state, uintptr_t addr,
706 backtrace_syminfo_callback callback,
707 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
708 void *data)
710 struct macho_syminfo_data *sdata;
711 struct macho_symbol *sym;
713 sym = NULL;
714 if (!state->threaded)
716 for (sdata = (struct macho_syminfo_data *) state->syminfo_data;
717 sdata != NULL;
718 sdata = sdata->next)
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;
727 else
729 struct macho_syminfo_data **pp;
731 pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
732 while (1)
734 sdata = backtrace_atomic_load_pointer (pp);
735 if (sdata == NULL)
736 break;
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;
744 pp = &sdata->next;
748 if (sym == NULL)
749 callback (data, addr, NULL, 0, 0);
750 else
751 callback (data, addr, sym->name, sym->address, 0);
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). */
757 static int
758 macho_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)
765 int arch_view_valid;
766 unsigned int cputype;
767 size_t arch_size;
768 struct backtrace_view arch_view;
769 unsigned int i;
771 arch_view_valid = 0;
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
790 if (is_64)
791 arch_size = sizeof (struct macho_fat_arch_64);
792 else
793 arch_size = sizeof (struct macho_fat_arch);
795 if (!backtrace_get_view (state, descriptor, offset,
796 nfat_arch * arch_size,
797 error_callback, data, &arch_view))
798 goto fail;
800 for (i = 0; i < nfat_arch; ++i)
802 uint32_t fcputype;
803 uint64_t foffset;
805 if (is_64)
807 struct macho_fat_arch_64 fat_arch_64;
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)
816 fcputype = __builtin_bswap32 (fcputype);
817 foffset = __builtin_bswap64 (foffset);
820 else
822 struct macho_fat_arch fat_arch_32;
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)
831 fcputype = __builtin_bswap32 (fcputype);
832 foffset = (uint64_t) __builtin_bswap32 ((uint32_t) foffset);
836 if (fcputype == cputype)
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);
846 error_callback (data, "could not find executable in fat file", 0);
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;
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. */
860 static int
861 macho_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)
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;
881 diralc = NULL;
882 dirnamelen = 0;
883 dsym = NULL;
884 dsymlen = 0;
886 p = strrchr (filename, '/');
887 if (p == NULL)
889 dirname = ".";
890 dirnamelen = 1;
891 basename = filename;
892 basenamelen = strlen (basename);
893 diralc = NULL;
895 else
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);
908 dsymsuffixdir = ".dSYM/Contents/Resources/DWARF/";
909 dsymsuffixdirlen = strlen (dsymsuffixdir);
911 dsymlen = (dirnamelen
913 + basenamelen
914 + dsymsuffixdirlen
915 + basenamelen
916 + 1);
917 dsym = backtrace_alloc (state, dsymlen, error_callback, data);
918 if (dsym == NULL)
919 goto fail;
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';
933 if (diralc != NULL)
935 backtrace_free (state, diralc, dirnamelen + 1, error_callback, data);
936 diralc = NULL;
939 d = backtrace_open (dsym, error_callback, data, &does_not_exist);
940 if (d < 0)
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;
948 if (!macho_add (state, dsym, d, 0, uuid, base_address, 1,
949 error_callback, data, fileline_fn, &dummy_found_sym))
950 goto fail;
952 backtrace_free (state, dsym, dsymlen, error_callback, data);
954 return 1;
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;
964 /* Add the backtrace data for a Macho-O file. Returns 1 on success, 0
965 on failure (in both cases descriptor is closed).
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.
977 static int
978 macho_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)
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;
997 *found_sym = 0;
999 cmds_view_valid = 0;
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. */
1005 if (!backtrace_get_view (state, descriptor, offset,
1006 sizeof (struct macho_header_32),
1007 error_callback, data, &header_view))
1008 goto fail;
1010 memcpy (&header, header_view.data, sizeof header);
1012 backtrace_release_view (state, &header_view, error_callback, data);
1014 switch (header.magic)
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:
1027 struct macho_header_fat fat_header;
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);
1037 case MACH_O_MH_CIGAM_FAT:
1038 case MACH_O_MH_CIGAM_FAT_64:
1040 struct macho_header_fat fat_header;
1041 uint32_t nfat_arch;
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);
1052 default:
1053 error_callback (data, "executable file is not in Mach-O format", 0);
1054 goto fail;
1057 switch (header.filetype)
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;
1068 if (!backtrace_get_view (state, descriptor, hdroffset, header.sizeofcmds,
1069 error_callback, data, &cmds_view))
1070 goto fail;
1071 cmds_view_valid = 1;
1073 memset (&dwarf_sections, 0, sizeof dwarf_sections);
1074 have_dwarf = 0;
1075 memset (&uuid, 0, sizeof uuid);
1076 have_uuid = 0;
1078 cmdoffset = 0;
1079 for (i = 0; i < header.ncmds; ++i)
1081 const char *pcmd;
1082 struct macho_load_command load_command;
1084 if (cmdoffset + sizeof load_command > header.sizeofcmds)
1085 break;
1087 pcmd = (const char *) cmds_view.data + cmdoffset;
1088 memcpy (&load_command, pcmd, sizeof load_command);
1090 switch (load_command.cmd)
1092 case MACH_O_LC_SEGMENT:
1094 struct macho_segment_command segcmd;
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)
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;
1112 break;
1114 case MACH_O_LC_SEGMENT_64:
1116 struct macho_segment_64_command segcmd;
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)
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;
1134 break;
1136 case MACH_O_LC_SYMTAB:
1137 if (!skip_symtab)
1139 struct macho_symtab_command symcmd;
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;
1148 *found_sym = 1;
1150 break;
1152 case MACH_O_LC_UUID:
1154 struct macho_uuid_command uuidcmd;
1156 memcpy (&uuidcmd, pcmd, sizeof uuidcmd);
1157 memcpy (&uuid[0], &uuidcmd.uuid[0], MACH_O_UUID_LEN);
1158 have_uuid = 1;
1160 break;
1162 default:
1163 break;
1166 cmdoffset += load_command.cmdsize;
1169 if (!backtrace_close (descriptor, error_callback, data))
1170 goto fail;
1171 descriptor = -1;
1173 backtrace_release_view (state, &cmds_view, error_callback, data);
1174 cmds_view_valid = 0;
1176 if (match_uuid != NULL)
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;
1185 if (have_dwarf)
1187 int is_big_endian;
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
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;
1202 if (!have_dwarf && have_uuid)
1204 if (!macho_add_dsym (state, filename, base_address, &uuid[0],
1205 error_callback, data, fileline_fn))
1206 goto fail;
1209 return 1;
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;
1219 #ifdef HAVE_MACH_O_DYLD_H
1221 /* Initialize the backtrace data we need from a Mach-O executable
1222 using the dyld support functions. This closes descriptor. */
1225 backtrace_initialize (struct backtrace_state *state, const char *filename,
1226 int descriptor, backtrace_error_callback error_callback,
1227 void *data, fileline *fileline_fn)
1229 uint32_t c;
1230 uint32_t i;
1231 int closed_descriptor;
1232 int found_sym;
1233 fileline macho_fileline_fn;
1235 closed_descriptor = 0;
1236 found_sym = 0;
1237 macho_fileline_fn = macho_nodebug;
1239 c = _dyld_image_count ();
1240 for (i = 0; i < c; ++i)
1242 uintptr_t base_address;
1243 const char *name;
1244 int d;
1245 fileline mff;
1246 int mfs;
1248 name = _dyld_get_image_name (i);
1249 if (name == NULL)
1250 continue;
1252 if (strcmp (name, filename) == 0 && !closed_descriptor)
1254 d = descriptor;
1255 closed_descriptor = 1;
1257 else
1259 int does_not_exist;
1261 d = backtrace_open (name, error_callback, data, &does_not_exist);
1262 if (d < 0)
1263 continue;
1266 base_address = _dyld_get_image_vmaddr_slide (i);
1268 mff = macho_nodebug;
1269 if (!macho_add (state, name, d, 0, NULL, base_address, 0,
1270 error_callback, data, &mff, &mfs))
1271 continue;
1273 if (mff != macho_nodebug)
1274 macho_fileline_fn = mff;
1275 if (mfs)
1276 found_sym = 1;
1279 if (!closed_descriptor)
1280 backtrace_close (descriptor, error_callback, data);
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 #else /* !defined (HAVE_MACH_O_DYLD_H) */
1311 /* Initialize the backtrace data we need from a Mach-O executable
1312 without using the dyld support functions. This closes
1313 descriptor. */
1316 backtrace_initialize (struct backtrace_state *state, const char *filename,
1317 int descriptor, backtrace_error_callback error_callback,
1318 void *data, fileline *fileline_fn)
1320 fileline macho_fileline_fn;
1321 int found_sym;
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;
1328 if (!state->threaded)
1330 if (found_sym)
1331 state->syminfo_fn = macho_syminfo;
1332 else if (state->syminfo_fn == NULL)
1333 state->syminfo_fn = macho_nosyms;
1335 else
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);
1344 if (!state->threaded)
1345 *fileline_fn = state->fileline_fn;
1346 else
1347 *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
1349 if (*fileline_fn == NULL || *fileline_fn == macho_nodebug)
1350 *fileline_fn = macho_fileline_fn;
1352 return 1;
1355 #endif /* !defined (HAVE_MACH_O_DYLD_H) */