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