pf2 0.1.0 → 0.3.0

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