]> git.ipfire.org Git - thirdparty/gcc.git/blob - libbacktrace/macho.c
Fix parsing of SVN commits in PRs.
[thirdparty/gcc.git] / libbacktrace / macho.c
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.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
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
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. */
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
49 struct 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
62 struct 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
76 struct macho_header_fat
77 {
78 uint32_t magic; /* Magic number (MACH_O_MH_MAGIC_FAT) */
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
89 /* Value for the header filetype field. */
90
91 #define MACH_O_MH_EXECUTE 0x02
92 #define MACH_O_MH_DYLIB 0x06
93 #define MACH_O_MH_DSYM 0x0a
94
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. */
98
99 struct macho_fat_arch
100 {
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 */
106 };
107
108 /* Values for the fat_arch cputype field (and the header cputype
109 field). */
110
111 #define MACH_O_CPU_ARCH_ABI64 0x01000000
112
113 #define MACH_O_CPU_TYPE_X86 7
114 #define MACH_O_CPU_TYPE_ARM 12
115
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)
118
119 /* The header of a load command. */
120
121 struct macho_load_command
122 {
123 uint32_t cmd; /* The type of load command */
124 uint32_t cmdsize; /* Size in bytes of the entire command */
125 };
126
127 /* Values for the load_command cmd field. */
128
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
133
134 /* The length of a section of segment name. */
135
136 #define MACH_O_NAMELEN (16)
137
138 /* LC_SEGMENT load command. */
139
140 struct macho_segment_command
141 {
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 */
153 };
154
155 /* LC_SEGMENT_64 load command. */
156
157 struct macho_segment_64_command
158 {
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 */
170 };
171
172 /* LC_SYMTAB load command. */
173
174 struct macho_symtab_command
175 {
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 */
182 };
183
184 /* The length of a Mach-O uuid. */
185
186 #define MACH_O_UUID_LEN (16)
187
188 /* LC_UUID load command. */
189
190 struct macho_uuid_command
191 {
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 */
195 };
196
197 /* 32-bit section header within a LC_SEGMENT segment. */
198
199 struct macho_section
200 {
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;
212 };
213
214 /* 64-bit section header within a LC_SEGMENT_64 segment. */
215
216 struct macho_section_64
217 {
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;
230 };
231
232 /* 32-bit symbol data. */
233
234 struct macho_nlist
235 {
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 */
241 };
242
243 /* 64-bit symbol data. */
244
245 struct macho_nlist_64
246 {
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 */
252 };
253
254 /* Value found in nlist n_type field. */
255
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 */
259
260 #define MACH_O_N_TYPE 0x0e /* Mask for type bits */
261 #define MACH_O_N_STAB 0xe0 /* Stabs debugging symbol */
262
263 /* Information we keep for a Mach-O symbol. */
264
265 struct macho_symbol
266 {
267 const char *name; /* Symbol name */
268 uintptr_t address; /* Symbol address */
269 };
270
271 /* Information to pass to macho_syminfo. */
272
273 struct macho_syminfo_data
274 {
275 struct macho_syminfo_data *next; /* Next module */
276 struct macho_symbol *symbols; /* Symbols sorted by address */
277 size_t count; /* Number of symbols */
278 };
279
280 /* Names of sections, indexed by enum dwarf_section in internal.h. */
281
282 static const char * const dwarf_section_names[DEBUG_MAX] =
283 {
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"
293 };
294
295 /* Forward declaration. */
296
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 *);
300
301 /* A dummy callback function used when we can't find any debug info. */
302
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)
308 {
309 error_callback (data, "no debug info in Mach-O executable", -1);
310 return 0;
311 }
312
313 /* A dummy callback function used when we can't find a symbol
314 table. */
315
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)
321 {
322 error_callback (data, "no symbol table in Mach-O executable", -1);
323 }
324
325 /* Add a single DWARF section to DWARF_SECTIONS, if we need the
326 section. Returns 1 on success, 0 on failure. */
327
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)
333 {
334 int i;
335
336 for (i = 0; i < (int) DEBUG_MAX; ++i)
337 {
338 if (dwarf_section_names[i][0] != '\0'
339 && strncmp (sectname, dwarf_section_names[i], MACH_O_NAMELEN) == 0)
340 {
341 struct backtrace_view section_view;
342
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. */
346
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;
353 }
354 }
355 return 1;
356 }
357
358 /* Collect DWARF sections from a DWARF segment. Returns 1 on success,
359 0 on failure. */
360
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)
367 {
368 size_t sec_header_size;
369 size_t secoffset;
370 unsigned int i;
371
372 switch (cmd)
373 {
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 ();
382 }
383
384 secoffset = 0;
385 for (i = 0; i < nsects; ++i)
386 {
387 if (secoffset + sec_header_size > sizesecs)
388 {
389 error_callback (data, "section overflow withing segment", 0);
390 return 0;
391 }
392
393 switch (cmd)
394 {
395 case MACH_O_LC_SEGMENT:
396 {
397 struct macho_section section;
398
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);
403 }
404 break;
405
406 case MACH_O_LC_SEGMENT_64:
407 {
408 struct macho_section_64 section;
409
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);
414 }
415 break;
416
417 default:
418 abort ();
419 }
420
421 secoffset += sec_header_size;
422 }
423
424 return 1;
425 }
426
427 /* Compare struct macho_symbol for qsort. */
428
429 static int
430 macho_symbol_compare (const void *v1, const void *v2)
431 {
432 const struct macho_symbol *m1 = (const struct macho_symbol *) v1;
433 const struct macho_symbol *m2 = (const struct macho_symbol *) v2;
434
435 if (m1->address < m2->address)
436 return -1;
437 else if (m1->address > m2->address)
438 return 1;
439 else
440 return 0;
441 }
442
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. */
446
447 static int
448 macho_symbol_search (const void *vkey, const void *ventry)
449 {
450 const uintptr_t *key = (const uintptr_t *) vkey;
451 const struct macho_symbol *entry = (const struct macho_symbol *) ventry;
452 uintptr_t addr;
453
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;
467 }
468
469 /* Return whether the symbol type field indicates a symbol table entry
470 that we care about: a function or data symbol. */
471
472 static int
473 macho_defined_symbol (uint8_t type)
474 {
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)
480 {
481 case MACH_O_N_ABS:
482 return 1;
483 case MACH_O_N_SECT:
484 return 1;
485 default:
486 return 0;
487 }
488 }
489
490 /* Add symbol table information for a Mach-O file. */
491
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)
498 {
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;
511
512 sym_view_valid = 0;
513 str_view_valid = 0;
514 macho_symbol_size = 0;
515 macho_symbols = NULL;
516
517 if (is_64)
518 symsize = sizeof (struct macho_nlist_64);
519 else
520 symsize = sizeof (struct macho_nlist);
521
522 if (!backtrace_get_view (state, descriptor, symoff, nsyms * symsize,
523 error_callback, data, &sym_view))
524 goto fail;
525 sym_view_valid = 1;
526
527 if (!backtrace_get_view (state, descriptor, stroff, strsize,
528 error_callback, data, &str_view))
529 return 0;
530 str_view_valid = 1;
531
532 ndefs = 0;
533 symtaboff = 0;
534 for (i = 0; i < nsyms; ++i, symtaboff += symsize)
535 {
536 if (is_64)
537 {
538 struct macho_nlist_64 nlist;
539
540 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
541 sizeof nlist);
542 if (macho_defined_symbol (nlist.n_type))
543 ++ndefs;
544 }
545 else
546 {
547 struct macho_nlist nlist;
548
549 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
550 sizeof nlist);
551 if (macho_defined_symbol (nlist.n_type))
552 ++ndefs;
553 }
554 }
555
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;
563
564 j = 0;
565 symtaboff = 0;
566 for (i = 0; i < nsyms; ++i, symtaboff += symsize)
567 {
568 uint32_t strx;
569 uint64_t value;
570 const char *name;
571
572 strx = 0;
573 value = 0;
574 if (is_64)
575 {
576 struct macho_nlist_64 nlist;
577
578 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
579 sizeof nlist);
580 if (!macho_defined_symbol (nlist.n_type))
581 continue;
582
583 strx = nlist.n_strx;
584 value = nlist.n_value;
585 }
586 else
587 {
588 struct macho_nlist nlist;
589
590 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
591 sizeof nlist);
592 if (!macho_defined_symbol (nlist.n_type))
593 continue;
594
595 strx = nlist.n_strx;
596 value = nlist.n_value;
597 }
598
599 if (strx >= strsize)
600 {
601 error_callback (data, "symbol string index out of range", 0);
602 goto fail;
603 }
604
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;
611 }
612
613 sdata = ((struct macho_syminfo_data *)
614 backtrace_alloc (state, sizeof *sdata, error_callback, data));
615 if (sdata == NULL)
616 goto fail;
617
618 /* We need to keep the string table since it holds the names, but we
619 can release the symbol table. */
620
621 backtrace_release_view (state, &sym_view, error_callback, data);
622 sym_view_valid = 0;
623 str_view_valid = 0;
624
625 /* Add a trailing sentinel symbol. */
626 macho_symbols[j].name = "";
627 macho_symbols[j].address = ~(uintptr_t) 0;
628
629 backtrace_qsort (macho_symbols, ndefs + 1, sizeof (struct macho_symbol),
630 macho_symbol_compare);
631
632 sdata->next = NULL;
633 sdata->symbols = macho_symbols;
634 sdata->count = ndefs;
635
636 if (!state->threaded)
637 {
638 struct macho_syminfo_data **pp;
639
640 for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
641 *pp != NULL;
642 pp = &(*pp)->next)
643 ;
644 *pp = sdata;
645 }
646 else
647 {
648 while (1)
649 {
650 struct macho_syminfo_data **pp;
651
652 pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
653
654 while (1)
655 {
656 struct macho_syminfo_data *p;
657
658 p = backtrace_atomic_load_pointer (pp);
659
660 if (p == NULL)
661 break;
662
663 pp = &p->next;
664 }
665
666 if (__sync_bool_compare_and_swap (pp, NULL, sdata))
667 break;
668 }
669 }
670
671 return 1;
672
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;
682 }
683
684 /* Return the symbol name and value for an ADDR. */
685
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)
691 {
692 struct macho_syminfo_data *sdata;
693 struct macho_symbol *sym;
694
695 sym = NULL;
696 if (!state->threaded)
697 {
698 for (sdata = (struct macho_syminfo_data *) state->syminfo_data;
699 sdata != NULL;
700 sdata = sdata->next)
701 {
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;
707 }
708 }
709 else
710 {
711 struct macho_syminfo_data **pp;
712
713 pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
714 while (1)
715 {
716 sdata = backtrace_atomic_load_pointer (pp);
717 if (sdata == NULL)
718 break;
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 pp = &sdata->next;
727 }
728 }
729
730 if (sym == NULL)
731 callback (data, addr, NULL, 0, 0);
732 else
733 callback (data, addr, sym->name, sym->address, 0);
734 }
735
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). */
738
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)
746 {
747 int arch_view_valid;
748 unsigned int cputype;
749 struct backtrace_view arch_view;
750 size_t archoffset;
751 unsigned int i;
752
753 arch_view_valid = 0;
754
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
767
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;
772
773 archoffset = 0;
774 for (i = 0; i < nfat_arch; ++i)
775 {
776 struct macho_fat_arch fat_arch;
777 uint32_t fcputype;
778
779 memcpy (&fat_arch,
780 ((const char *) arch_view.data
781 + i * sizeof (struct macho_fat_arch)),
782 sizeof fat_arch);
783
784 fcputype = fat_arch.cputype;
785 if (swapped)
786 fcputype = __builtin_bswap32 (fcputype);
787
788 if (fcputype == cputype)
789 {
790 uint32_t foffset;
791
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);
800 }
801
802 archoffset += sizeof (struct macho_fat_arch);
803 }
804
805 error_callback (data, "could not find executable in fat file", 0);
806
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;
813 }
814
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. */
818
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)
824 {
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;
839
840 diralc = NULL;
841 dirnamelen = 0;
842 dsym = NULL;
843 dsymlen = 0;
844
845 p = strrchr (filename, '/');
846 if (p == NULL)
847 {
848 dirname = ".";
849 dirnamelen = 1;
850 basename = filename;
851 basenamelen = strlen (basename);
852 diralc = NULL;
853 }
854 else
855 {
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);
865 }
866
867 dsymsuffixdir = ".dSYM/Contents/Resources/DWARF/";
868 dsymsuffixdirlen = strlen (dsymsuffixdir);
869
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;
878
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';
890
891 if (diralc != NULL)
892 {
893 backtrace_free (state, diralc, dirnamelen, error_callback, data);
894 diralc = NULL;
895 }
896
897 d = backtrace_open (dsym, error_callback, data, &does_not_exist);
898 if (d < 0)
899 {
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;
904 }
905
906 if (!macho_add (state, dsym, d, 0, uuid, base_address, 1,
907 error_callback, data, fileline_fn, &dummy_found_sym))
908 goto fail;
909
910 backtrace_free (state, dsym, dsymlen, error_callback, data);
911
912 return 1;
913
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;
920 }
921
922 /* Add the backtrace data for a Macho-O file. Returns 1 on success, 0
923 on failure (in both cases descriptor is closed).
924
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.
933 */
934
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)
941 {
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;
954
955 *found_sym = 0;
956
957 cmds_view_valid = 0;
958
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. */
962
963 if (!backtrace_get_view (state, descriptor, offset,
964 sizeof (struct macho_header_32),
965 error_callback, data, &header_view))
966 goto fail;
967
968 memcpy (&header, header_view.data, sizeof header);
969
970 backtrace_release_view (state, &header_view, error_callback, data);
971
972 switch (header.magic)
973 {
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:
983 {
984 struct macho_header_fat fat_header;
985
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);
992 }
993 case MACH_O_MH_CIGAM_FAT:
994 {
995 struct macho_header_fat fat_header;
996 uint32_t nfat_arch;
997
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);
1005 }
1006 default:
1007 error_callback (data, "executable file is not in Mach-O format", 0);
1008 goto fail;
1009 }
1010
1011 switch (header.filetype)
1012 {
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;
1020 }
1021
1022 if (!backtrace_get_view (state, descriptor, hdroffset, header.sizeofcmds,
1023 error_callback, data, &cmds_view))
1024 goto fail;
1025 cmds_view_valid = 1;
1026
1027 memset (&dwarf_sections, 0, sizeof dwarf_sections);
1028 have_dwarf = 0;
1029 memset (&uuid, 0, sizeof uuid);
1030 have_uuid = 0;
1031
1032 cmdoffset = 0;
1033 for (i = 0; i < header.ncmds; ++i)
1034 {
1035 const char *pcmd;
1036 struct macho_load_command load_command;
1037
1038 if (cmdoffset + sizeof load_command > header.sizeofcmds)
1039 break;
1040
1041 pcmd = (const char *) cmds_view.data + cmdoffset;
1042 memcpy (&load_command, pcmd, sizeof load_command);
1043
1044 switch (load_command.cmd)
1045 {
1046 case MACH_O_LC_SEGMENT:
1047 {
1048 struct macho_segment_command segcmd;
1049
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)
1054 {
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;
1064 }
1065 }
1066 break;
1067
1068 case MACH_O_LC_SEGMENT_64:
1069 {
1070 struct macho_segment_64_command segcmd;
1071
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)
1076 {
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;
1086 }
1087 }
1088 break;
1089
1090 case MACH_O_LC_SYMTAB:
1091 if (!skip_symtab)
1092 {
1093 struct macho_symtab_command symcmd;
1094
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;
1101
1102 *found_sym = 1;
1103 }
1104 break;
1105
1106 case MACH_O_LC_UUID:
1107 {
1108 struct macho_uuid_command uuidcmd;
1109
1110 memcpy (&uuidcmd, pcmd, sizeof uuidcmd);
1111 memcpy (&uuid[0], &uuidcmd.uuid[0], MACH_O_UUID_LEN);
1112 have_uuid = 1;
1113 }
1114 break;
1115
1116 default:
1117 break;
1118 }
1119
1120 cmdoffset += load_command.cmdsize;
1121 }
1122
1123 if (!backtrace_close (descriptor, error_callback, data))
1124 goto fail;
1125 descriptor = -1;
1126
1127 backtrace_release_view (state, &cmds_view, error_callback, data);
1128 cmds_view_valid = 0;
1129
1130 if (match_uuid != NULL)
1131 {
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;
1137 }
1138
1139 if (have_dwarf)
1140 {
1141 int is_big_endian;
1142
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
1149
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;
1154 }
1155
1156 if (!have_dwarf && have_uuid)
1157 {
1158 if (!macho_add_dsym (state, filename, base_address, &uuid[0],
1159 error_callback, data, fileline_fn))
1160 goto fail;
1161 }
1162
1163 return 1;
1164
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;
1171 }
1172
1173 #ifdef HAVE_MACH_O_DYLD_H
1174
1175 /* Initialize the backtrace data we need from a Mach-O executable
1176 using the dyld support functions. This closes descriptor. */
1177
1178 int
1179 backtrace_initialize (struct backtrace_state *state, const char *filename,
1180 int descriptor, backtrace_error_callback error_callback,
1181 void *data, fileline *fileline_fn)
1182 {
1183 uint32_t c;
1184 uint32_t i;
1185 int closed_descriptor;
1186 int found_sym;
1187 fileline macho_fileline_fn;
1188
1189 closed_descriptor = 0;
1190 found_sym = 0;
1191 macho_fileline_fn = macho_nodebug;
1192
1193 c = _dyld_image_count ();
1194 for (i = 0; i < c; ++i)
1195 {
1196 uintptr_t base_address;
1197 const char *name;
1198 int d;
1199 fileline mff;
1200 int mfs;
1201
1202 name = _dyld_get_image_name (i);
1203 if (name == NULL)
1204 continue;
1205
1206 if (strcmp (name, filename) == 0 && !closed_descriptor)
1207 {
1208 d = descriptor;
1209 closed_descriptor = 1;
1210 }
1211 else
1212 {
1213 int does_not_exist;
1214
1215 d = backtrace_open (name, error_callback, data, &does_not_exist);
1216 if (d < 0)
1217 continue;
1218 }
1219
1220 base_address = _dyld_get_image_vmaddr_slide (i);
1221
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;
1226
1227 if (mff != macho_nodebug)
1228 macho_fileline_fn = mff;
1229 if (mfs)
1230 found_sym = 1;
1231 }
1232
1233 if (!closed_descriptor)
1234 backtrace_close (descriptor, error_callback, data);
1235
1236 if (!state->threaded)
1237 {
1238 if (found_sym)
1239 state->syminfo_fn = macho_syminfo;
1240 else if (state->syminfo_fn == NULL)
1241 state->syminfo_fn = macho_nosyms;
1242 }
1243 else
1244 {
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);
1250 }
1251
1252 if (!state->threaded)
1253 *fileline_fn = state->fileline_fn;
1254 else
1255 *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
1256
1257 if (*fileline_fn == NULL || *fileline_fn == macho_nodebug)
1258 *fileline_fn = macho_fileline_fn;
1259
1260 return 1;
1261 }
1262
1263 #else /* !defined (HAVE_MACH_O_DYLD_H) */
1264
1265 /* Initialize the backtrace data we need from a Mach-O executable
1266 without using the dyld support functions. This closes
1267 descriptor. */
1268
1269 int
1270 backtrace_initialize (struct backtrace_state *state, const char *filename,
1271 int descriptor, backtrace_error_callback error_callback,
1272 void *data, fileline *fileline_fn)
1273 {
1274 fileline macho_fileline_fn;
1275 int found_sym;
1276
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;
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 #endif /* !defined (HAVE_MACH_O_DYLD_H) */