Home | History | Annotate | Line # | Download | only in libbacktrace
macho.c revision 1.1.1.2
      1 /* elf.c -- Get debug data from a Mach-O file for backtraces.
      2    Copyright (C) 2020-2024 Free Software Foundation, Inc.
      3    Written by Ian Lance Taylor, Google.
      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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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 	continue;
   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
   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