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, §ion_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 (§ion, 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 (§ion, 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