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