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