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