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, §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