]> git.proxmox.com Git - rustc.git/blame - library/backtrace/crates/backtrace-sys/src/libbacktrace/macho.c
New upstream version 1.55.0+dfsg1
[rustc.git] / library / backtrace / crates / backtrace-sys / src / libbacktrace / macho.c
CommitLineData
ba9703b0
XL
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.
ea8adc8c
XL
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
ea8adc8c 35#include <sys/types.h>
ea8adc8c
XL
36#include <dirent.h>
37#include <stdlib.h>
ba9703b0
XL
38#include <string.h>
39
40#ifdef HAVE_MACH_O_DYLD_H
41#include <mach-o/dyld.h>
42#endif
ea8adc8c
XL
43
44#include "backtrace.h"
45#include "internal.h"
46
ba9703b0
XL
47/* Mach-O file header for a 32-bit executable. */
48
49struct macho_header_32
ea8adc8c 50{
ba9703b0
XL
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 */
ea8adc8c
XL
58};
59
ba9703b0
XL
60/* Mach-O file header for a 64-bit executable. */
61
62struct macho_header_64
ea8adc8c 63{
ba9703b0
XL
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 */
ea8adc8c
XL
72};
73
ba9703b0
XL
74/* Mach-O file header for a fat executable. */
75
76struct macho_header_fat
77{
78 uint32_t magic; /* Magic number (MACH_O_MH_MAGIC_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
99struct 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
121struct 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
140struct 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
157struct 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
174struct 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
190struct macho_uuid_command
ea8adc8c 191{
ba9703b0
XL
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 */
ea8adc8c
XL
195};
196
ba9703b0
XL
197/* 32-bit section header within a LC_SEGMENT segment. */
198
199struct 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
216struct 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
234struct 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
245struct 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
ea8adc8c
XL
265struct macho_symbol
266{
ba9703b0
XL
267 const char *name; /* Symbol name */
268 uintptr_t address; /* Symbol address */
ea8adc8c
XL
269};
270
ba9703b0
XL
271/* Information to pass to macho_syminfo. */
272
ea8adc8c
XL
273struct macho_syminfo_data
274{
ba9703b0
XL
275 struct macho_syminfo_data *next; /* Next module */
276 struct macho_symbol *symbols; /* Symbols sorted by address */
277 size_t count; /* Number of symbols */
ea8adc8c
XL
278};
279
ba9703b0
XL
280/* Names of sections, indexed by enum dwarf_section in internal.h. */
281
282static const char * const dwarf_section_names[DEBUG_MAX] =
ea8adc8c 283{
ba9703b0
XL
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
297static 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
303static int
304macho_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;
ea8adc8c
XL
311}
312
ba9703b0
XL
313/* A dummy callback function used when we can't find a symbol
314 table. */
315
316static void
317macho_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)
ea8adc8c 321{
ba9703b0 322 error_callback (data, "no symbol table in Mach-O executable", -1);
ea8adc8c
XL
323}
324
ba9703b0
XL
325/* Add a single DWARF section to DWARF_SECTIONS, if we need the
326 section. Returns 1 on success, 0 on failure. */
327
328static int
329macho_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)
ea8adc8c 333{
ba9703b0
XL
334 int i;
335
336 for (i = 0; i < (int) DEBUG_MAX; ++i)
ea8adc8c 337 {
ba9703b0
XL
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 }
ea8adc8c 354 }
ba9703b0 355 return 1;
ea8adc8c
XL
356}
357
ba9703b0
XL
358/* Collect DWARF sections from a DWARF segment. Returns 1 on success,
359 0 on failure. */
ea8adc8c 360
ba9703b0
XL
361static int
362macho_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)
ea8adc8c 367{
ba9703b0
XL
368 size_t sec_header_size;
369 size_t secoffset;
370 unsigned int i;
ea8adc8c 371
ba9703b0 372 switch (cmd)
ea8adc8c 373 {
ba9703b0
XL
374 case MACH_O_LC_SEGMENT:
375 sec_header_size = sizeof (struct macho_section);
ea8adc8c 376 break;
ba9703b0
XL
377 case MACH_O_LC_SEGMENT_64:
378 sec_header_size = sizeof (struct macho_section_64);
ea8adc8c 379 break;
ba9703b0
XL
380 default:
381 abort ();
ea8adc8c
XL
382 }
383
ba9703b0
XL
384 secoffset = 0;
385 for (i = 0; i < nsects; ++i)
ea8adc8c 386 {
ba9703b0
XL
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;
ea8adc8c 422 }
ea8adc8c 423
ba9703b0 424 return 1;
ea8adc8c
XL
425}
426
ba9703b0 427/* Compare struct macho_symbol for qsort. */
ea8adc8c 428
ba9703b0
XL
429static int
430macho_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;
ea8adc8c 434
ba9703b0
XL
435 if (m1->address < m2->address)
436 return -1;
437 else if (m1->address > m2->address)
ea8adc8c
XL
438 return 1;
439 else
ba9703b0 440 return 0;
ea8adc8c
XL
441}
442
ba9703b0
XL
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
ea8adc8c 447static int
ba9703b0 448macho_symbol_search (const void *vkey, const void *ventry)
ea8adc8c 449{
ba9703b0
XL
450 const uintptr_t *key = (const uintptr_t *) vkey;
451 const struct macho_symbol *entry = (const struct macho_symbol *) ventry;
452 uintptr_t addr;
ea8adc8c 453
ba9703b0
XL
454 addr = *key;
455 if (addr < entry->address)
ea8adc8c 456 return -1;
ba9703b0
XL
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;
ea8adc8c
XL
465 else
466 return 0;
467}
468
ba9703b0
XL
469/* Return whether the symbol type field indicates a symbol table entry
470 that we care about: a function or data symbol. */
ea8adc8c 471
ba9703b0
XL
472static int
473macho_defined_symbol (uint8_t type)
474{
475 if ((type & MACH_O_N_STAB) != 0)
476 return 0;
477 switch (type & MACH_O_N_TYPE)
478 {
479 case MACH_O_N_ABS:
480 return 1;
481 case MACH_O_N_SECT:
482 return 1;
483 default:
484 return 0;
485 }
ea8adc8c
XL
486}
487
ba9703b0
XL
488/* Add symbol table information for a Mach-O file. */
489
490static int
491macho_add_symtab (struct backtrace_state *state, int descriptor,
492 uintptr_t base_address, int is_64,
493 off_t symoff, unsigned int nsyms, off_t stroff,
494 unsigned int strsize,
495 backtrace_error_callback error_callback, void *data)
ea8adc8c 496{
ba9703b0
XL
497 size_t symsize;
498 struct backtrace_view sym_view;
499 int sym_view_valid;
500 struct backtrace_view str_view;
501 int str_view_valid;
502 size_t ndefs;
503 size_t symtaboff;
504 unsigned int i;
505 size_t macho_symbol_size;
506 struct macho_symbol *macho_symbols;
507 unsigned int j;
508 struct macho_syminfo_data *sdata;
509
510 sym_view_valid = 0;
511 str_view_valid = 0;
512 macho_symbol_size = 0;
513 macho_symbols = NULL;
514
515 if (is_64)
516 symsize = sizeof (struct macho_nlist_64);
517 else
518 symsize = sizeof (struct macho_nlist);
ea8adc8c 519
ba9703b0
XL
520 if (!backtrace_get_view (state, descriptor, symoff, nsyms * symsize,
521 error_callback, data, &sym_view))
522 goto fail;
523 sym_view_valid = 1;
524
525 if (!backtrace_get_view (state, descriptor, stroff, strsize,
526 error_callback, data, &str_view))
527 return 0;
528 str_view_valid = 1;
529
530 ndefs = 0;
531 symtaboff = 0;
532 for (i = 0; i < nsyms; ++i, symtaboff += symsize)
533 {
534 if (is_64)
535 {
536 struct macho_nlist_64 nlist;
537
538 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
539 sizeof nlist);
540 if (macho_defined_symbol (nlist.n_type))
541 ++ndefs;
542 }
543 else
544 {
545 struct macho_nlist nlist;
546
547 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
548 sizeof nlist);
549 if (macho_defined_symbol (nlist.n_type))
550 ++ndefs;
551 }
552 }
ea8adc8c 553
ba9703b0
XL
554 /* Add 1 to ndefs to make room for a sentinel. */
555 macho_symbol_size = (ndefs + 1) * sizeof (struct macho_symbol);
556 macho_symbols = ((struct macho_symbol *)
557 backtrace_alloc (state, macho_symbol_size, error_callback,
558 data));
559 if (macho_symbols == NULL)
560 goto fail;
561
562 j = 0;
563 symtaboff = 0;
564 for (i = 0; i < nsyms; ++i, symtaboff += symsize)
ea8adc8c 565 {
ba9703b0
XL
566 uint32_t strx;
567 uint64_t value;
568 const char *name;
569
570 strx = 0;
571 value = 0;
572 if (is_64)
573 {
574 struct macho_nlist_64 nlist;
575
576 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
577 sizeof nlist);
578 if (!macho_defined_symbol (nlist.n_type))
579 continue;
580
581 strx = nlist.n_strx;
582 value = nlist.n_value;
583 }
584 else
585 {
586 struct macho_nlist nlist;
587
588 memcpy (&nlist, (const char *) sym_view.data + symtaboff,
589 sizeof nlist);
590 if (!macho_defined_symbol (nlist.n_type))
591 continue;
592
593 strx = nlist.n_strx;
594 value = nlist.n_value;
595 }
596
597 if (strx >= strsize)
598 {
599 error_callback (data, "symbol string index out of range", 0);
600 goto fail;
601 }
602
603 name = (const char *) str_view.data + strx;
604 if (name[0] == '_')
605 ++name;
606 macho_symbols[j].name = name;
607 macho_symbols[j].address = value + base_address;
608 ++j;
ea8adc8c
XL
609 }
610
ba9703b0
XL
611 sdata = ((struct macho_syminfo_data *)
612 backtrace_alloc (state, sizeof *sdata, error_callback, data));
613 if (sdata == NULL)
614 goto fail;
ea8adc8c 615
ba9703b0
XL
616 /* We need to keep the string table since it holds the names, but we
617 can release the symbol table. */
ea8adc8c 618
ba9703b0
XL
619 backtrace_release_view (state, &sym_view, error_callback, data);
620 sym_view_valid = 0;
621 str_view_valid = 0;
622
623 /* Add a trailing sentinel symbol. */
624 macho_symbols[j].name = "";
625 macho_symbols[j].address = ~(uintptr_t) 0;
626
627 backtrace_qsort (macho_symbols, ndefs + 1, sizeof (struct macho_symbol),
628 macho_symbol_compare);
ea8adc8c 629
ba9703b0
XL
630 sdata->next = NULL;
631 sdata->symbols = macho_symbols;
632 sdata->count = ndefs;
ea8adc8c 633
ba9703b0 634 if (!state->threaded)
ea8adc8c 635 {
ba9703b0
XL
636 struct macho_syminfo_data **pp;
637
638 for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
639 *pp != NULL;
640 pp = &(*pp)->next)
641 ;
642 *pp = sdata;
ea8adc8c 643 }
ba9703b0
XL
644 else
645 {
646 while (1)
647 {
648 struct macho_syminfo_data **pp;
649
650 pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
651
652 while (1)
653 {
654 struct macho_syminfo_data *p;
655
656 p = backtrace_atomic_load_pointer (pp);
657
658 if (p == NULL)
659 break;
660
661 pp = &p->next;
662 }
ea8adc8c 663
ba9703b0
XL
664 if (__sync_bool_compare_and_swap (pp, NULL, sdata))
665 break;
666 }
667 }
668
669 return 1;
670
671 fail:
672 if (macho_symbols != NULL)
673 backtrace_free (state, macho_symbols, macho_symbol_size,
674 error_callback, data);
675 if (sym_view_valid)
676 backtrace_release_view (state, &sym_view, error_callback, data);
677 if (str_view_valid)
678 backtrace_release_view (state, &str_view, error_callback, data);
679 return 0;
680}
681
682/* Return the symbol name and value for an ADDR. */
683
684static void
685macho_syminfo (struct backtrace_state *state, uintptr_t addr,
686 backtrace_syminfo_callback callback,
687 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
688 void *data)
689{
690 struct macho_syminfo_data *sdata;
691 struct macho_symbol *sym;
692
693 sym = NULL;
694 if (!state->threaded)
ea8adc8c 695 {
ba9703b0
XL
696 for (sdata = (struct macho_syminfo_data *) state->syminfo_data;
697 sdata != NULL;
698 sdata = sdata->next)
699 {
700 sym = ((struct macho_symbol *)
701 bsearch (&addr, sdata->symbols, sdata->count,
702 sizeof (struct macho_symbol), macho_symbol_search));
703 if (sym != NULL)
704 break;
705 }
ea8adc8c 706 }
ba9703b0 707 else
ea8adc8c 708 {
ba9703b0
XL
709 struct macho_syminfo_data **pp;
710
711 pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
712 while (1)
713 {
714 sdata = backtrace_atomic_load_pointer (pp);
715 if (sdata == NULL)
716 break;
717
718 sym = ((struct macho_symbol *)
719 bsearch (&addr, sdata->symbols, sdata->count,
720 sizeof (struct macho_symbol), macho_symbol_search));
721 if (sym != NULL)
722 break;
723
724 pp = &sdata->next;
725 }
ea8adc8c
XL
726 }
727
ba9703b0
XL
728 if (sym == NULL)
729 callback (data, addr, NULL, 0, 0);
730 else
731 callback (data, addr, sym->name, sym->address, 0);
732}
ea8adc8c 733
ba9703b0
XL
734/* Look through a fat file to find the relevant executable. Returns 1
735 on success, 0 on failure (in both cases descriptor is closed). */
ea8adc8c 736
ba9703b0
XL
737static int
738macho_add_fat (struct backtrace_state *state, const char *filename,
739 int descriptor, int swapped, off_t offset,
740 const unsigned char *match_uuid, uintptr_t base_address,
741 int skip_symtab, uint32_t nfat_arch,
742 backtrace_error_callback error_callback, void *data,
743 fileline *fileline_fn, int *found_sym)
744{
745 int arch_view_valid;
746 unsigned int cputype;
747 struct backtrace_view arch_view;
748 size_t archoffset;
749 unsigned int i;
750
751 arch_view_valid = 0;
752
753#if defined (__x86_64__)
754 cputype = MACH_O_CPU_TYPE_X86_64;
755#elif defined (__i386__)
756 cputype = MACH_O_CPU_TYPE_X86;
757#elif defined (__aarch64__)
758 cputype = MACH_O_CPU_TYPE_ARM64;
759#elif defined (__arm__)
760 cputype = MACH_O_CPU_TYPE_ARM;
761#else
762 error_callback (data, "unknown Mach-O architecture", 0);
763 goto fail;
764#endif
765
766 if (!backtrace_get_view (state, descriptor, offset,
767 nfat_arch * sizeof (struct macho_fat_arch),
768 error_callback, data, &arch_view))
769 goto fail;
ea8adc8c 770
ba9703b0
XL
771 archoffset = 0;
772 for (i = 0; i < nfat_arch; ++i)
ea8adc8c 773 {
ba9703b0
XL
774 struct macho_fat_arch fat_arch;
775 uint32_t fcputype;
776
777 memcpy (&fat_arch,
778 ((const char *) arch_view.data
779 + i * sizeof (struct macho_fat_arch)),
780 sizeof fat_arch);
781
782 fcputype = fat_arch.cputype;
783 if (swapped)
784 fcputype = __builtin_bswap32 (fcputype);
785
786 if (fcputype == cputype)
787 {
788 uint32_t foffset;
789
790 /* FIXME: What about cpusubtype? */
791 foffset = fat_arch.offset;
792 if (swapped)
793 foffset = __builtin_bswap32 (foffset);
794 backtrace_release_view (state, &arch_view, error_callback, data);
795 return macho_add (state, filename, descriptor, foffset, match_uuid,
796 base_address, skip_symtab, error_callback, data,
797 fileline_fn, found_sym);
798 }
799
800 archoffset += sizeof (struct macho_fat_arch);
ea8adc8c
XL
801 }
802
ba9703b0
XL
803 error_callback (data, "could not find executable in fat file", 0);
804
805 fail:
806 if (arch_view_valid)
807 backtrace_release_view (state, &arch_view, error_callback, data);
808 if (descriptor != -1)
809 backtrace_close (descriptor, error_callback, data);
810 return 0;
811}
812
813/* Look for the dsym file for FILENAME. This is called if FILENAME
814 does not have debug info or a symbol table. Returns 1 on success,
815 0 on failure. */
816
817static int
818macho_add_dsym (struct backtrace_state *state, const char *filename,
819 uintptr_t base_address, const unsigned char *uuid,
820 backtrace_error_callback error_callback, void *data,
821 fileline* fileline_fn)
822{
823 const char *p;
824 const char *dirname;
825 char *diralc;
826 size_t dirnamelen;
827 const char *basename;
828 size_t basenamelen;
829 const char *dsymsuffixdir;
830 size_t dsymsuffixdirlen;
831 size_t dsymlen;
832 char *dsym;
833 char *ps;
834 int d;
835 int does_not_exist;
836 int dummy_found_sym;
837
838 diralc = NULL;
839 dirnamelen = 0;
840 dsym = NULL;
841 dsymlen = 0;
842
843 p = strrchr (filename, '/');
844 if (p == NULL)
ea8adc8c 845 {
ba9703b0
XL
846 dirname = ".";
847 dirnamelen = 1;
848 basename = filename;
849 basenamelen = strlen (basename);
850 diralc = NULL;
851 }
852 else
853 {
854 dirnamelen = p - filename;
855 diralc = backtrace_alloc (state, dirnamelen + 1, error_callback, data);
856 if (diralc == NULL)
857 goto fail;
858 memcpy (diralc, filename, dirnamelen);
859 diralc[dirnamelen] = '\0';
860 dirname = diralc;
861 basename = p + 1;
862 basenamelen = strlen (basename);
ea8adc8c
XL
863 }
864
ba9703b0
XL
865 dsymsuffixdir = ".dSYM/Contents/Resources/DWARF/";
866 dsymsuffixdirlen = strlen (dsymsuffixdir);
867
868 dsymlen = (dirnamelen
869 + basenamelen
870 + dsymsuffixdirlen
871 + basenamelen
872 + 2);
873 dsym = backtrace_alloc (state, dsymlen, error_callback, data);
874 if (dsym == NULL)
875 goto fail;
876
877 ps = dsym;
878 memcpy (ps, dirname, dirnamelen);
879 ps += dirnamelen;
880 *ps++ = '/';
881 memcpy (ps, basename, basenamelen);
882 ps += basenamelen;
883 memcpy (ps, dsymsuffixdir, dsymsuffixdirlen);
884 ps += dsymsuffixdirlen;
885 memcpy (ps, basename, basenamelen);
886 ps += basenamelen;
887 *ps = '\0';
888
889 if (diralc != NULL)
890 {
891 backtrace_free (state, diralc, dirnamelen, error_callback, data);
892 diralc = NULL;
893 }
ea8adc8c 894
ba9703b0
XL
895 d = backtrace_open (dsym, error_callback, data, &does_not_exist);
896 if (d < 0)
ea8adc8c 897 {
ba9703b0
XL
898 /* The file does not exist, so we can't read the debug info.
899 Just return success. */
900 backtrace_free (state, dsym, dsymlen, error_callback, data);
901 return 1;
ea8adc8c
XL
902 }
903
ba9703b0
XL
904 if (!macho_add (state, dsym, d, 0, uuid, base_address, 1,
905 error_callback, data, fileline_fn, &dummy_found_sym))
906 goto fail;
907
908 backtrace_free (state, dsym, dsymlen, error_callback, data);
909
910 return 1;
911
912 fail:
913 if (dsym != NULL)
914 backtrace_free (state, dsym, dsymlen, error_callback, data);
915 if (diralc != NULL)
916 backtrace_free (state, diralc, dirnamelen, error_callback, data);
917 return 0;
ea8adc8c
XL
918}
919
ba9703b0
XL
920/* Add the backtrace data for a Macho-O file. Returns 1 on success, 0
921 on failure (in both cases descriptor is closed).
922
923 FILENAME: the name of the executable.
924 DESCRIPTOR: an open descriptor for the executable, closed here.
925 OFFSET: the offset within the file of this executable, for fat files.
926 MATCH_UUID: if not NULL, UUID that must match.
927 BASE_ADDRESS: the load address of the executable.
928 SKIP_SYMTAB: if non-zero, ignore the symbol table; used for dSYM files.
929 FILELINE_FN: set to the fileline function, by backtrace_dwarf_add.
930 FOUND_SYM: set to non-zero if we found the symbol table.
931*/
932
933static int
934macho_add (struct backtrace_state *state, const char *filename, int descriptor,
935 off_t offset, const unsigned char *match_uuid,
936 uintptr_t base_address, int skip_symtab,
937 backtrace_error_callback error_callback, void *data,
938 fileline *fileline_fn, int *found_sym)
ea8adc8c 939{
ba9703b0
XL
940 struct backtrace_view header_view;
941 struct macho_header_32 header;
942 off_t hdroffset;
943 int is_64;
944 struct backtrace_view cmds_view;
945 int cmds_view_valid;
946 struct dwarf_sections dwarf_sections;
947 int have_dwarf;
948 unsigned char uuid[MACH_O_UUID_LEN];
949 int have_uuid;
950 size_t cmdoffset;
951 unsigned int i;
952
ea8adc8c 953 *found_sym = 0;
ea8adc8c 954
ba9703b0
XL
955 cmds_view_valid = 0;
956
957 /* The 32-bit and 64-bit file headers start out the same, so we can
958 just always read the 32-bit version. A fat header is shorter but
959 it will always be followed by data, so it's OK to read extra. */
960
961 if (!backtrace_get_view (state, descriptor, offset,
962 sizeof (struct macho_header_32),
963 error_callback, data, &header_view))
964 goto fail;
965
966 memcpy (&header, header_view.data, sizeof header);
ea8adc8c 967
ba9703b0
XL
968 backtrace_release_view (state, &header_view, error_callback, data);
969
970 switch (header.magic)
ea8adc8c 971 {
ba9703b0
XL
972 case MACH_O_MH_MAGIC_32:
973 is_64 = 0;
974 hdroffset = offset + sizeof (struct macho_header_32);
975 break;
976 case MACH_O_MH_MAGIC_64:
977 is_64 = 1;
978 hdroffset = offset + sizeof (struct macho_header_64);
979 break;
980 case MACH_O_MH_MAGIC_FAT:
981 {
982 struct macho_header_fat fat_header;
983
984 hdroffset = offset + sizeof (struct macho_header_fat);
985 memcpy (&fat_header, &header, sizeof fat_header);
986 return macho_add_fat (state, filename, descriptor, 0, hdroffset,
987 match_uuid, base_address, skip_symtab,
988 fat_header.nfat_arch, error_callback, data,
989 fileline_fn, found_sym);
990 }
991 case MACH_O_MH_CIGAM_FAT:
992 {
993 struct macho_header_fat fat_header;
994 uint32_t nfat_arch;
995
996 hdroffset = offset + sizeof (struct macho_header_fat);
997 memcpy (&fat_header, &header, sizeof fat_header);
998 nfat_arch = __builtin_bswap32 (fat_header.nfat_arch);
999 return macho_add_fat (state, filename, descriptor, 1, hdroffset,
1000 match_uuid, base_address, skip_symtab,
1001 nfat_arch, error_callback, data,
1002 fileline_fn, found_sym);
1003 }
1004 default:
1005 error_callback (data, "executable file is not in Mach-O format", 0);
1006 goto fail;
ea8adc8c 1007 }
ea8adc8c 1008
ba9703b0 1009 switch (header.filetype)
ea8adc8c 1010 {
ba9703b0
XL
1011 case MACH_O_MH_EXECUTE:
1012 case MACH_O_MH_DYLIB:
1013 case MACH_O_MH_DSYM:
1014 break;
1015 default:
1016 error_callback (data, "executable file is not an executable", 0);
1017 goto fail;
ea8adc8c
XL
1018 }
1019
ba9703b0
XL
1020 if (!backtrace_get_view (state, descriptor, hdroffset, header.sizeofcmds,
1021 error_callback, data, &cmds_view))
1022 goto fail;
1023 cmds_view_valid = 1;
ea8adc8c 1024
ba9703b0
XL
1025 memset (&dwarf_sections, 0, sizeof dwarf_sections);
1026 have_dwarf = 0;
1027 memset (&uuid, 0, sizeof uuid);
1028 have_uuid = 0;
ea8adc8c 1029
ba9703b0
XL
1030 cmdoffset = 0;
1031 for (i = 0; i < header.ncmds; ++i)
ea8adc8c 1032 {
ba9703b0
XL
1033 const char *pcmd;
1034 struct macho_load_command load_command;
1035
1036 if (cmdoffset + sizeof load_command > header.sizeofcmds)
1037 break;
1038
1039 pcmd = (const char *) cmds_view.data + cmdoffset;
1040 memcpy (&load_command, pcmd, sizeof load_command);
1041
1042 switch (load_command.cmd)
1043 {
1044 case MACH_O_LC_SEGMENT:
1045 {
1046 struct macho_segment_command segcmd;
1047
1048 memcpy (&segcmd, pcmd, sizeof segcmd);
1049 if (memcmp (segcmd.segname,
1050 "__DWARF\0\0\0\0\0\0\0\0\0",
1051 MACH_O_NAMELEN) == 0)
1052 {
1053 if (!macho_add_dwarf_segment (state, descriptor, offset,
1054 load_command.cmd,
1055 pcmd + sizeof segcmd,
1056 (load_command.cmdsize
1057 - sizeof segcmd),
1058 segcmd.nsects, error_callback,
1059 data, &dwarf_sections))
1060 goto fail;
1061 have_dwarf = 1;
1062 }
1063 }
1064 break;
1065
1066 case MACH_O_LC_SEGMENT_64:
1067 {
1068 struct macho_segment_64_command segcmd;
1069
1070 memcpy (&segcmd, pcmd, sizeof segcmd);
1071 if (memcmp (segcmd.segname,
1072 "__DWARF\0\0\0\0\0\0\0\0\0",
1073 MACH_O_NAMELEN) == 0)
1074 {
1075 if (!macho_add_dwarf_segment (state, descriptor, offset,
1076 load_command.cmd,
1077 pcmd + sizeof segcmd,
1078 (load_command.cmdsize
1079 - sizeof segcmd),
1080 segcmd.nsects, error_callback,
1081 data, &dwarf_sections))
1082 goto fail;
1083 have_dwarf = 1;
1084 }
1085 }
1086 break;
1087
1088 case MACH_O_LC_SYMTAB:
1089 if (!skip_symtab)
1090 {
1091 struct macho_symtab_command symcmd;
1092
1093 memcpy (&symcmd, pcmd, sizeof symcmd);
1094 if (!macho_add_symtab (state, descriptor, base_address, is_64,
1095 offset + symcmd.symoff, symcmd.nsyms,
1096 offset + symcmd.stroff, symcmd.strsize,
1097 error_callback, data))
1098 goto fail;
1099
1100 *found_sym = 1;
1101 }
1102 break;
1103
1104 case MACH_O_LC_UUID:
1105 {
1106 struct macho_uuid_command uuidcmd;
1107
1108 memcpy (&uuidcmd, pcmd, sizeof uuidcmd);
1109 memcpy (&uuid[0], &uuidcmd.uuid[0], MACH_O_UUID_LEN);
1110 have_uuid = 1;
1111 }
1112 break;
1113
1114 default:
1115 break;
1116 }
1117
1118 cmdoffset += load_command.cmdsize;
ea8adc8c
XL
1119 }
1120
ba9703b0
XL
1121 if (!backtrace_close (descriptor, error_callback, data))
1122 goto fail;
1123 descriptor = -1;
1124
1125 backtrace_release_view (state, &cmds_view, error_callback, data);
1126 cmds_view_valid = 0;
1127
1128 if (match_uuid != NULL)
ea8adc8c 1129 {
ba9703b0
XL
1130 /* If we don't have a UUID, or it doesn't match, just ignore
1131 this file. */
1132 if (!have_uuid
1133 || memcmp (match_uuid, &uuid[0], MACH_O_UUID_LEN) != 0)
1134 return 1;
ea8adc8c
XL
1135 }
1136
ba9703b0 1137 if (have_dwarf)
ea8adc8c 1138 {
ba9703b0
XL
1139 int is_big_endian;
1140
1141 is_big_endian = 0;
1142#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
1143#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
1144 is_big_endian = 1;
1145#endif
1146#endif
1147
1148 if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,
1149 is_big_endian, NULL, error_callback, data,
1150 fileline_fn, NULL))
1151 goto fail;
ea8adc8c 1152 }
ea8adc8c 1153
ba9703b0 1154 if (!have_dwarf && have_uuid)
ea8adc8c 1155 {
ba9703b0
XL
1156 if (!macho_add_dsym (state, filename, base_address, &uuid[0],
1157 error_callback, data, fileline_fn))
1158 goto fail;
ea8adc8c
XL
1159 }
1160
ba9703b0
XL
1161 return 1;
1162
1163 fail:
1164 if (cmds_view_valid)
1165 backtrace_release_view (state, &cmds_view, error_callback, data);
1166 if (descriptor != -1)
1167 backtrace_close (descriptor, error_callback, data);
1168 return 0;
ea8adc8c
XL
1169}
1170
ba9703b0 1171#ifdef HAVE_MACH_O_DYLD_H
ea8adc8c 1172
ba9703b0
XL
1173/* Initialize the backtrace data we need from a Mach-O executable
1174 using the dyld support functions. This closes descriptor. */
ea8adc8c 1175
ba9703b0
XL
1176int
1177backtrace_initialize (struct backtrace_state *state, const char *filename,
1178 int descriptor, backtrace_error_callback error_callback,
1179 void *data, fileline *fileline_fn)
ea8adc8c 1180{
ba9703b0
XL
1181 uint32_t c;
1182 uint32_t i;
1183 int closed_descriptor;
1184 int found_sym;
1185 fileline macho_fileline_fn;
1186
1187 closed_descriptor = 0;
1188 found_sym = 0;
1189 macho_fileline_fn = macho_nodebug;
1190
1191 c = _dyld_image_count ();
1192 for (i = 0; i < c; ++i)
1193 {
1194 uintptr_t base_address;
1195 const char *name;
1196 int d;
1197 fileline mff;
1198 int mfs;
1199
1200 name = _dyld_get_image_name (i);
1201 if (name == NULL)
1202 continue;
1203
1204 if (strcmp (name, filename) == 0 && !closed_descriptor)
1205 {
1206 d = descriptor;
1207 closed_descriptor = 1;
1208 }
1209 else
1210 {
1211 int does_not_exist;
1212
1213 d = backtrace_open (name, error_callback, data, &does_not_exist);
1214 if (d < 0)
1215 continue;
1216 }
1217
1218 base_address = _dyld_get_image_vmaddr_slide (i);
1219
1220 mff = macho_nodebug;
1221 if (!macho_add (state, name, d, 0, NULL, base_address, 0,
1222 error_callback, data, &mff, &mfs))
1223 return 0;
1224
1225 if (mff != macho_nodebug)
1226 macho_fileline_fn = mff;
1227 if (mfs)
1228 found_sym = 1;
1229 }
1230
1231 if (!closed_descriptor)
1232 backtrace_close (descriptor, error_callback, data);
ea8adc8c
XL
1233
1234 if (!state->threaded)
1235 {
ba9703b0
XL
1236 if (found_sym)
1237 state->syminfo_fn = macho_syminfo;
1238 else if (state->syminfo_fn == NULL)
1239 state->syminfo_fn = macho_nosyms;
ea8adc8c
XL
1240 }
1241 else
1242 {
ba9703b0
XL
1243 if (found_sym)
1244 backtrace_atomic_store_pointer (&state->syminfo_fn, macho_syminfo);
1245 else
1246 (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
1247 macho_nosyms);
ea8adc8c
XL
1248 }
1249
ba9703b0
XL
1250 if (!state->threaded)
1251 *fileline_fn = state->fileline_fn;
ea8adc8c 1252 else
ba9703b0 1253 *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
ea8adc8c 1254
ba9703b0
XL
1255 if (*fileline_fn == NULL || *fileline_fn == macho_nodebug)
1256 *fileline_fn = macho_fileline_fn;
ea8adc8c 1257
ba9703b0 1258 return 1;
ea8adc8c
XL
1259}
1260
ba9703b0
XL
1261#else /* !defined (HAVE_MACH_O_DYLD_H) */
1262
1263/* Initialize the backtrace data we need from a Mach-O executable
1264 without using the dyld support functions. This closes
1265 descriptor. */
ea8adc8c
XL
1266
1267int
ba9703b0
XL
1268backtrace_initialize (struct backtrace_state *state, const char *filename,
1269 int descriptor, backtrace_error_callback error_callback,
1270 void *data, fileline *fileline_fn)
ea8adc8c 1271{
ba9703b0
XL
1272 fileline macho_fileline_fn;
1273 int found_sym;
1274
1275 macho_fileline_fn = macho_nodebug;
1276 if (!macho_add (state, filename, descriptor, 0, NULL, 0, 0,
1277 error_callback, data, &macho_fileline_fn, &found_sym))
1278 return 0;
ea8adc8c
XL
1279
1280 if (!state->threaded)
1281 {
1282 if (found_sym)
ba9703b0 1283 state->syminfo_fn = macho_syminfo;
ea8adc8c 1284 else if (state->syminfo_fn == NULL)
ba9703b0 1285 state->syminfo_fn = macho_nosyms;
ea8adc8c
XL
1286 }
1287 else
1288 {
1289 if (found_sym)
ba9703b0 1290 backtrace_atomic_store_pointer (&state->syminfo_fn, macho_syminfo);
ea8adc8c 1291 else
ba9703b0
XL
1292 (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
1293 macho_nosyms);
ea8adc8c
XL
1294 }
1295
1296 if (!state->threaded)
ba9703b0 1297 *fileline_fn = state->fileline_fn;
ea8adc8c 1298 else
ba9703b0 1299 *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
ea8adc8c 1300
ba9703b0
XL
1301 if (*fileline_fn == NULL || *fileline_fn == macho_nodebug)
1302 *fileline_fn = macho_fileline_fn;
ea8adc8c
XL
1303
1304 return 1;
1305}
1306
ba9703b0 1307#endif /* !defined (HAVE_MACH_O_DYLD_H) */