pf2 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/README.md +11 -0
  4. data/Rakefile +9 -2
  5. data/doc/development.md +11 -0
  6. data/examples/mandelbrot.rb +69 -0
  7. data/examples/mandelbrot_ractor.rb +77 -0
  8. data/ext/pf2/build.rs +7 -0
  9. data/ext/pf2/src/ruby_c_api_helper.c +6 -0
  10. data/ext/pf2/src/serialization/profile.rs +1 -0
  11. data/ext/pf2/src/serialization/serializer.rs +4 -0
  12. data/ext/pf2/src/signal_scheduler.rs +1 -1
  13. data/ext/pf2/src/util.rs +2 -1
  14. data/ext/pf2c/backtrace_state.c +10 -0
  15. data/ext/pf2c/backtrace_state.h +10 -0
  16. data/ext/pf2c/configuration.c +90 -0
  17. data/ext/pf2c/configuration.h +23 -0
  18. data/ext/pf2c/extconf.rb +21 -0
  19. data/ext/pf2c/pf2.c +17 -0
  20. data/ext/pf2c/pf2.h +8 -0
  21. data/ext/pf2c/ringbuffer.c +74 -0
  22. data/ext/pf2c/ringbuffer.h +24 -0
  23. data/ext/pf2c/sample.c +70 -0
  24. data/ext/pf2c/sample.h +22 -0
  25. data/ext/pf2c/serializer.c +377 -0
  26. data/ext/pf2c/serializer.h +58 -0
  27. data/ext/pf2c/session.c +344 -0
  28. data/ext/pf2c/session.h +51 -0
  29. data/lib/pf2/cli.rb +33 -2
  30. data/lib/pf2/reporter/annotate.rb +101 -0
  31. data/lib/pf2/reporter/firefox_profiler.rb +1 -1
  32. data/lib/pf2/reporter/firefox_profiler_ser2.rb +308 -0
  33. data/lib/pf2/reporter.rb +2 -0
  34. data/lib/pf2/version.rb +1 -1
  35. data/vendor/libbacktrace/.gitignore +5 -0
  36. data/vendor/libbacktrace/Isaac.Newton-Opticks.txt +9286 -0
  37. data/vendor/libbacktrace/LICENSE +29 -0
  38. data/vendor/libbacktrace/Makefile.am +708 -0
  39. data/vendor/libbacktrace/Makefile.in +2820 -0
  40. data/vendor/libbacktrace/README.md +46 -0
  41. data/vendor/libbacktrace/aclocal.m4 +864 -0
  42. data/vendor/libbacktrace/alloc.c +167 -0
  43. data/vendor/libbacktrace/allocfail.c +136 -0
  44. data/vendor/libbacktrace/allocfail.sh +104 -0
  45. data/vendor/libbacktrace/atomic.c +113 -0
  46. data/vendor/libbacktrace/backtrace-supported.h.in +66 -0
  47. data/vendor/libbacktrace/backtrace.c +129 -0
  48. data/vendor/libbacktrace/backtrace.h +189 -0
  49. data/vendor/libbacktrace/btest.c +517 -0
  50. data/vendor/libbacktrace/compile +348 -0
  51. data/vendor/libbacktrace/config/enable.m4 +38 -0
  52. data/vendor/libbacktrace/config/lead-dot.m4 +31 -0
  53. data/vendor/libbacktrace/config/libtool.m4 +7545 -0
  54. data/vendor/libbacktrace/config/ltoptions.m4 +369 -0
  55. data/vendor/libbacktrace/config/ltsugar.m4 +123 -0
  56. data/vendor/libbacktrace/config/ltversion.m4 +23 -0
  57. data/vendor/libbacktrace/config/lt~obsolete.m4 +98 -0
  58. data/vendor/libbacktrace/config/multi.m4 +68 -0
  59. data/vendor/libbacktrace/config/override.m4 +117 -0
  60. data/vendor/libbacktrace/config/unwind_ipinfo.m4 +37 -0
  61. data/vendor/libbacktrace/config/warnings.m4 +227 -0
  62. data/vendor/libbacktrace/config.guess +1700 -0
  63. data/vendor/libbacktrace/config.h.in +185 -0
  64. data/vendor/libbacktrace/config.sub +1885 -0
  65. data/vendor/libbacktrace/configure +15952 -0
  66. data/vendor/libbacktrace/configure.ac +642 -0
  67. data/vendor/libbacktrace/dwarf.c +4593 -0
  68. data/vendor/libbacktrace/edtest.c +120 -0
  69. data/vendor/libbacktrace/edtest2.c +43 -0
  70. data/vendor/libbacktrace/elf.c +7471 -0
  71. data/vendor/libbacktrace/fileline.c +407 -0
  72. data/vendor/libbacktrace/filenames.h +52 -0
  73. data/vendor/libbacktrace/filetype.awk +13 -0
  74. data/vendor/libbacktrace/install-debuginfo-for-buildid.sh.in +65 -0
  75. data/vendor/libbacktrace/install-sh +501 -0
  76. data/vendor/libbacktrace/instrumented_alloc.c +114 -0
  77. data/vendor/libbacktrace/internal.h +428 -0
  78. data/vendor/libbacktrace/ltmain.sh +8636 -0
  79. data/vendor/libbacktrace/macho.c +1361 -0
  80. data/vendor/libbacktrace/missing +215 -0
  81. data/vendor/libbacktrace/mmap.c +331 -0
  82. data/vendor/libbacktrace/mmapio.c +110 -0
  83. data/vendor/libbacktrace/move-if-change +83 -0
  84. data/vendor/libbacktrace/mtest.c +410 -0
  85. data/vendor/libbacktrace/nounwind.c +66 -0
  86. data/vendor/libbacktrace/pecoff.c +1123 -0
  87. data/vendor/libbacktrace/posix.c +104 -0
  88. data/vendor/libbacktrace/print.c +117 -0
  89. data/vendor/libbacktrace/read.c +110 -0
  90. data/vendor/libbacktrace/simple.c +108 -0
  91. data/vendor/libbacktrace/sort.c +108 -0
  92. data/vendor/libbacktrace/state.c +72 -0
  93. data/vendor/libbacktrace/stest.c +137 -0
  94. data/vendor/libbacktrace/test-driver +148 -0
  95. data/vendor/libbacktrace/test_format.c +55 -0
  96. data/vendor/libbacktrace/testlib.c +234 -0
  97. data/vendor/libbacktrace/testlib.h +110 -0
  98. data/vendor/libbacktrace/ttest.c +161 -0
  99. data/vendor/libbacktrace/unittest.c +92 -0
  100. data/vendor/libbacktrace/unknown.c +65 -0
  101. data/vendor/libbacktrace/xcoff.c +1617 -0
  102. data/vendor/libbacktrace/xztest.c +508 -0
  103. data/vendor/libbacktrace/zstdtest.c +523 -0
  104. data/vendor/libbacktrace/ztest.c +541 -0
  105. metadata +122 -3
@@ -0,0 +1,1123 @@
1
+ /* pecoff.c -- Get debug data from a PE/COFFF file for backtraces.
2
+ Copyright (C) 2015-2024 Free Software Foundation, Inc.
3
+ Adapted from elf.c by Tristan Gingold, AdaCore.
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 <stdlib.h>
36
+ #include <string.h>
37
+ #include <sys/types.h>
38
+
39
+ #include "backtrace.h"
40
+ #include "internal.h"
41
+
42
+ #ifdef HAVE_WINDOWS_H
43
+ #ifndef WIN32_LEAN_AND_MEAN
44
+ #define WIN32_LEAN_AND_MEAN
45
+ #endif
46
+
47
+ #ifndef NOMINMAX
48
+ #define NOMINMAX
49
+ #endif
50
+
51
+ #include <windows.h>
52
+
53
+ #ifdef HAVE_TLHELP32_H
54
+ #include <tlhelp32.h>
55
+
56
+ #ifdef UNICODE
57
+ /* If UNICODE is defined, all the symbols are replaced by a macro to use the
58
+ wide variant. But we need the ansi variant, so undef the macros. */
59
+ #undef MODULEENTRY32
60
+ #undef Module32First
61
+ #undef Module32Next
62
+ #endif
63
+ #endif
64
+
65
+ #if defined(_ARM_)
66
+ #define NTAPI
67
+ #else
68
+ #define NTAPI __stdcall
69
+ #endif
70
+
71
+ /* This is a simplified (but binary compatible) version of what Microsoft
72
+ defines in their documentation. */
73
+ struct dll_notification_data
74
+ {
75
+ ULONG reserved;
76
+ /* The name as UNICODE_STRING struct. */
77
+ PVOID full_dll_name;
78
+ PVOID base_dll_name;
79
+ PVOID dll_base;
80
+ ULONG size_of_image;
81
+ };
82
+
83
+ #define LDR_DLL_NOTIFICATION_REASON_LOADED 1
84
+
85
+ typedef LONG NTSTATUS;
86
+ typedef VOID (CALLBACK *LDR_DLL_NOTIFICATION)(ULONG,
87
+ struct dll_notification_data*,
88
+ PVOID);
89
+ typedef NTSTATUS (NTAPI *LDR_REGISTER_FUNCTION)(ULONG,
90
+ LDR_DLL_NOTIFICATION, PVOID,
91
+ PVOID*);
92
+ #endif
93
+
94
+ /* Coff file header. */
95
+
96
+ typedef struct {
97
+ uint16_t machine;
98
+ uint16_t number_of_sections;
99
+ uint32_t time_date_stamp;
100
+ uint32_t pointer_to_symbol_table;
101
+ uint32_t number_of_symbols;
102
+ uint16_t size_of_optional_header;
103
+ uint16_t characteristics;
104
+ } b_coff_file_header;
105
+
106
+ /* Coff optional header. */
107
+
108
+ typedef struct {
109
+ uint16_t magic;
110
+ uint8_t major_linker_version;
111
+ uint8_t minor_linker_version;
112
+ uint32_t size_of_code;
113
+ uint32_t size_of_initialized_data;
114
+ uint32_t size_of_uninitialized_data;
115
+ uint32_t address_of_entry_point;
116
+ uint32_t base_of_code;
117
+ union {
118
+ struct {
119
+ uint32_t base_of_data;
120
+ uint32_t image_base;
121
+ } pe;
122
+ struct {
123
+ uint64_t image_base;
124
+ } pep;
125
+ } u;
126
+ } b_coff_optional_header;
127
+
128
+ /* Values of magic in optional header. */
129
+
130
+ #define PE_MAGIC 0x10b /* PE32 executable. */
131
+ #define PEP_MAGIC 0x20b /* PE32+ executable (for 64bit targets). */
132
+
133
+ /* Coff section header. */
134
+
135
+ typedef struct {
136
+ char name[8];
137
+ uint32_t virtual_size;
138
+ uint32_t virtual_address;
139
+ uint32_t size_of_raw_data;
140
+ uint32_t pointer_to_raw_data;
141
+ uint32_t pointer_to_relocations;
142
+ uint32_t pointer_to_line_numbers;
143
+ uint16_t number_of_relocations;
144
+ uint16_t number_of_line_numbers;
145
+ uint32_t characteristics;
146
+ } b_coff_section_header;
147
+
148
+ /* Coff symbol name. */
149
+
150
+ typedef union {
151
+ char short_name[8];
152
+ struct {
153
+ unsigned char zeroes[4];
154
+ unsigned char off[4];
155
+ } long_name;
156
+ } b_coff_name;
157
+
158
+ /* Coff symbol (external representation which is unaligned). */
159
+
160
+ typedef struct {
161
+ b_coff_name name;
162
+ unsigned char value[4];
163
+ unsigned char section_number[2];
164
+ unsigned char type[2];
165
+ unsigned char storage_class;
166
+ unsigned char number_of_aux_symbols;
167
+ } b_coff_external_symbol;
168
+
169
+ /* Symbol types. */
170
+
171
+ #define N_TBSHFT 4 /* Shift for the derived type. */
172
+ #define IMAGE_SYM_DTYPE_FUNCTION 2 /* Function derived type. */
173
+
174
+ /* Size of a coff symbol. */
175
+
176
+ #define SYM_SZ 18
177
+
178
+ /* Coff symbol, internal representation (aligned). */
179
+
180
+ typedef struct {
181
+ const char *name;
182
+ uint32_t value;
183
+ int16_t sec;
184
+ uint16_t type;
185
+ uint16_t sc;
186
+ } b_coff_internal_symbol;
187
+
188
+ /* Names of sections, indexed by enum dwarf_section in internal.h. */
189
+
190
+ static const char * const debug_section_names[DEBUG_MAX] =
191
+ {
192
+ ".debug_info",
193
+ ".debug_line",
194
+ ".debug_abbrev",
195
+ ".debug_ranges",
196
+ ".debug_str",
197
+ ".debug_addr",
198
+ ".debug_str_offsets",
199
+ ".debug_line_str",
200
+ ".debug_rnglists"
201
+ };
202
+
203
+ /* Information we gather for the sections we care about. */
204
+
205
+ struct debug_section_info
206
+ {
207
+ /* Section file offset. */
208
+ off_t offset;
209
+ /* Section size. */
210
+ size_t size;
211
+ };
212
+
213
+ /* Information we keep for an coff symbol. */
214
+
215
+ struct coff_symbol
216
+ {
217
+ /* The name of the symbol. */
218
+ const char *name;
219
+ /* The address of the symbol. */
220
+ uintptr_t address;
221
+ };
222
+
223
+ /* Information to pass to coff_syminfo. */
224
+
225
+ struct coff_syminfo_data
226
+ {
227
+ /* Symbols for the next module. */
228
+ struct coff_syminfo_data *next;
229
+ /* The COFF symbols, sorted by address. */
230
+ struct coff_symbol *symbols;
231
+ /* The number of symbols. */
232
+ size_t count;
233
+ };
234
+
235
+ /* A dummy callback function used when we can't find any debug info. */
236
+
237
+ static int
238
+ coff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
239
+ uintptr_t pc ATTRIBUTE_UNUSED,
240
+ backtrace_full_callback callback ATTRIBUTE_UNUSED,
241
+ backtrace_error_callback error_callback, void *data)
242
+ {
243
+ error_callback (data, "no debug info in PE/COFF executable (make sure to compile with -g)", -1);
244
+ return 0;
245
+ }
246
+
247
+ /* A dummy callback function used when we can't find a symbol
248
+ table. */
249
+
250
+ static void
251
+ coff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
252
+ uintptr_t addr ATTRIBUTE_UNUSED,
253
+ backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
254
+ backtrace_error_callback error_callback, void *data)
255
+ {
256
+ error_callback (data, "no symbol table in PE/COFF executable", -1);
257
+ }
258
+
259
+ /* Read a potentially unaligned 4 byte word at P, using native endianness. */
260
+
261
+ static uint32_t
262
+ coff_read4 (const unsigned char *p)
263
+ {
264
+ uint32_t res;
265
+
266
+ memcpy (&res, p, 4);
267
+ return res;
268
+ }
269
+
270
+ /* Read a potentially unaligned 2 byte word at P, using native endianness.
271
+ All 2 byte word in symbols are always aligned, but for coherency all
272
+ fields are declared as char arrays. */
273
+
274
+ static uint16_t
275
+ coff_read2 (const unsigned char *p)
276
+ {
277
+ uint16_t res;
278
+
279
+ memcpy (&res, p, sizeof (res));
280
+ return res;
281
+ }
282
+
283
+ /* Return the length (without the trailing 0) of a COFF short name. */
284
+
285
+ static size_t
286
+ coff_short_name_len (const char *name)
287
+ {
288
+ int i;
289
+
290
+ for (i = 0; i < 8; i++)
291
+ if (name[i] == 0)
292
+ return i;
293
+ return 8;
294
+ }
295
+
296
+ /* Return true iff COFF short name CNAME is the same as NAME (a NUL-terminated
297
+ string). */
298
+
299
+ static int
300
+ coff_short_name_eq (const char *name, const char *cname)
301
+ {
302
+ int i;
303
+
304
+ for (i = 0; i < 8; i++)
305
+ {
306
+ if (name[i] != cname[i])
307
+ return 0;
308
+ if (name[i] == 0)
309
+ return 1;
310
+ }
311
+ return name[8] == 0;
312
+ }
313
+
314
+ /* Return true iff NAME is the same as string at offset OFF. */
315
+
316
+ static int
317
+ coff_long_name_eq (const char *name, unsigned int off,
318
+ struct backtrace_view *str_view)
319
+ {
320
+ if (off >= str_view->len)
321
+ return 0;
322
+ return strcmp (name, (const char *)str_view->data + off) == 0;
323
+ }
324
+
325
+ /* Compare struct coff_symbol for qsort. */
326
+
327
+ static int
328
+ coff_symbol_compare (const void *v1, const void *v2)
329
+ {
330
+ const struct coff_symbol *e1 = (const struct coff_symbol *) v1;
331
+ const struct coff_symbol *e2 = (const struct coff_symbol *) v2;
332
+
333
+ if (e1->address < e2->address)
334
+ return -1;
335
+ else if (e1->address > e2->address)
336
+ return 1;
337
+ else
338
+ return 0;
339
+ }
340
+
341
+ /* Convert SYM to internal (and aligned) format ISYM, using string table
342
+ from STRTAB and STRTAB_SIZE, and number of sections SECTS_NUM.
343
+ Return -1 in case of error (invalid section number or string index). */
344
+
345
+ static int
346
+ coff_expand_symbol (b_coff_internal_symbol *isym,
347
+ const b_coff_external_symbol *sym,
348
+ uint16_t sects_num,
349
+ const unsigned char *strtab, size_t strtab_size)
350
+ {
351
+ isym->type = coff_read2 (sym->type);
352
+ isym->sec = coff_read2 (sym->section_number);
353
+ isym->sc = sym->storage_class;
354
+
355
+ if (isym->sec > 0 && (uint16_t) isym->sec > sects_num)
356
+ return -1;
357
+ if (sym->name.short_name[0] != 0)
358
+ isym->name = sym->name.short_name;
359
+ else
360
+ {
361
+ uint32_t off = coff_read4 (sym->name.long_name.off);
362
+
363
+ if (off >= strtab_size)
364
+ return -1;
365
+ isym->name = (const char *) strtab + off;
366
+ }
367
+ return 0;
368
+ }
369
+
370
+ /* Return true iff SYM is a defined symbol for a function. Data symbols
371
+ aren't considered because they aren't easily identified (same type as
372
+ section names, presence of symbols defined by the linker script). */
373
+
374
+ static int
375
+ coff_is_function_symbol (const b_coff_internal_symbol *isym)
376
+ {
377
+ return (isym->type >> N_TBSHFT) == IMAGE_SYM_DTYPE_FUNCTION
378
+ && isym->sec > 0;
379
+ }
380
+
381
+ /* Initialize the symbol table info for coff_syminfo. */
382
+
383
+ static int
384
+ coff_initialize_syminfo (struct backtrace_state *state,
385
+ struct libbacktrace_base_address base_address,
386
+ int is_64, const b_coff_section_header *sects,
387
+ size_t sects_num, const b_coff_external_symbol *syms,
388
+ size_t syms_size, const unsigned char *strtab,
389
+ size_t strtab_size,
390
+ backtrace_error_callback error_callback,
391
+ void *data, struct coff_syminfo_data *sdata)
392
+ {
393
+ size_t syms_count;
394
+ char *coff_symstr;
395
+ size_t coff_symstr_len;
396
+ size_t coff_symbol_count;
397
+ size_t coff_symbol_size;
398
+ struct coff_symbol *coff_symbols;
399
+ struct coff_symbol *coff_sym;
400
+ char *coff_str;
401
+ size_t i;
402
+
403
+ syms_count = syms_size / SYM_SZ;
404
+
405
+ /* We only care about function symbols. Count them. Also count size of
406
+ strings for in-symbol names. */
407
+ coff_symbol_count = 0;
408
+ coff_symstr_len = 0;
409
+ for (i = 0; i < syms_count; ++i)
410
+ {
411
+ const b_coff_external_symbol *asym = &syms[i];
412
+ b_coff_internal_symbol isym;
413
+
414
+ if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size) < 0)
415
+ {
416
+ error_callback (data, "invalid section or offset in coff symbol", 0);
417
+ return 0;
418
+ }
419
+ if (coff_is_function_symbol (&isym))
420
+ {
421
+ ++coff_symbol_count;
422
+ if (asym->name.short_name[0] != 0)
423
+ coff_symstr_len += coff_short_name_len (asym->name.short_name) + 1;
424
+ }
425
+
426
+ i += asym->number_of_aux_symbols;
427
+ }
428
+
429
+ coff_symbol_size = (coff_symbol_count + 1) * sizeof (struct coff_symbol);
430
+ coff_symbols = ((struct coff_symbol *)
431
+ backtrace_alloc (state, coff_symbol_size, error_callback,
432
+ data));
433
+ if (coff_symbols == NULL)
434
+ return 0;
435
+
436
+ /* Allocate memory for symbols strings. */
437
+ if (coff_symstr_len > 0)
438
+ {
439
+ coff_symstr = ((char *)
440
+ backtrace_alloc (state, coff_symstr_len, error_callback,
441
+ data));
442
+ if (coff_symstr == NULL)
443
+ {
444
+ backtrace_free (state, coff_symbols, coff_symbol_size,
445
+ error_callback, data);
446
+ return 0;
447
+ }
448
+ }
449
+ else
450
+ coff_symstr = NULL;
451
+
452
+ /* Copy symbols. */
453
+ coff_sym = coff_symbols;
454
+ coff_str = coff_symstr;
455
+ for (i = 0; i < syms_count; ++i)
456
+ {
457
+ const b_coff_external_symbol *asym = &syms[i];
458
+ b_coff_internal_symbol isym;
459
+
460
+ if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size))
461
+ {
462
+ /* Should not fail, as it was already tested in the previous
463
+ loop. */
464
+ abort ();
465
+ }
466
+ if (coff_is_function_symbol (&isym))
467
+ {
468
+ const char *name;
469
+ int16_t secnum;
470
+
471
+ if (asym->name.short_name[0] != 0)
472
+ {
473
+ size_t len = coff_short_name_len (isym.name);
474
+ name = coff_str;
475
+ memcpy (coff_str, isym.name, len);
476
+ coff_str[len] = 0;
477
+ coff_str += len + 1;
478
+ }
479
+ else
480
+ name = isym.name;
481
+
482
+ if (!is_64)
483
+ {
484
+ /* Strip leading '_'. */
485
+ if (name[0] == '_')
486
+ name++;
487
+ }
488
+
489
+ /* Symbol value is section relative, so we need to read the address
490
+ of its section. */
491
+ secnum = coff_read2 (asym->section_number);
492
+
493
+ coff_sym->name = name;
494
+ coff_sym->address =
495
+ libbacktrace_add_base ((coff_read4 (asym->value)
496
+ + sects[secnum - 1].virtual_address),
497
+ base_address);
498
+ coff_sym++;
499
+ }
500
+
501
+ i += asym->number_of_aux_symbols;
502
+ }
503
+
504
+ /* End of symbols marker. */
505
+ coff_sym->name = NULL;
506
+ coff_sym->address = -1;
507
+
508
+ backtrace_qsort (coff_symbols, coff_symbol_count,
509
+ sizeof (struct coff_symbol), coff_symbol_compare);
510
+
511
+ sdata->next = NULL;
512
+ sdata->symbols = coff_symbols;
513
+ sdata->count = coff_symbol_count;
514
+
515
+ return 1;
516
+ }
517
+
518
+ /* Add EDATA to the list in STATE. */
519
+
520
+ static void
521
+ coff_add_syminfo_data (struct backtrace_state *state,
522
+ struct coff_syminfo_data *sdata)
523
+ {
524
+ if (!state->threaded)
525
+ {
526
+ struct coff_syminfo_data **pp;
527
+
528
+ for (pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
529
+ *pp != NULL;
530
+ pp = &(*pp)->next)
531
+ ;
532
+ *pp = sdata;
533
+ }
534
+ else
535
+ {
536
+ while (1)
537
+ {
538
+ struct coff_syminfo_data **pp;
539
+
540
+ pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
541
+
542
+ while (1)
543
+ {
544
+ struct coff_syminfo_data *p;
545
+
546
+ p = backtrace_atomic_load_pointer (pp);
547
+
548
+ if (p == NULL)
549
+ break;
550
+
551
+ pp = &p->next;
552
+ }
553
+
554
+ if (__sync_bool_compare_and_swap (pp, NULL, sdata))
555
+ break;
556
+ }
557
+ }
558
+ }
559
+
560
+ /* Compare an ADDR against an elf_symbol for bsearch. We allocate one
561
+ extra entry in the array so that this can look safely at the next
562
+ entry. */
563
+
564
+ static int
565
+ coff_symbol_search (const void *vkey, const void *ventry)
566
+ {
567
+ const uintptr_t *key = (const uintptr_t *) vkey;
568
+ const struct coff_symbol *entry = (const struct coff_symbol *) ventry;
569
+ uintptr_t addr;
570
+
571
+ addr = *key;
572
+ if (addr < entry->address)
573
+ return -1;
574
+ else if (addr >= entry[1].address)
575
+ return 1;
576
+ else
577
+ return 0;
578
+ }
579
+
580
+ /* Return the symbol name and value for an ADDR. */
581
+
582
+ static void
583
+ coff_syminfo (struct backtrace_state *state, uintptr_t addr,
584
+ backtrace_syminfo_callback callback,
585
+ backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
586
+ void *data)
587
+ {
588
+ struct coff_syminfo_data *sdata;
589
+ struct coff_symbol *sym = NULL;
590
+
591
+ if (!state->threaded)
592
+ {
593
+ for (sdata = (struct coff_syminfo_data *) state->syminfo_data;
594
+ sdata != NULL;
595
+ sdata = sdata->next)
596
+ {
597
+ sym = ((struct coff_symbol *)
598
+ bsearch (&addr, sdata->symbols, sdata->count,
599
+ sizeof (struct coff_symbol), coff_symbol_search));
600
+ if (sym != NULL)
601
+ break;
602
+ }
603
+ }
604
+ else
605
+ {
606
+ struct coff_syminfo_data **pp;
607
+
608
+ pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
609
+ while (1)
610
+ {
611
+ sdata = backtrace_atomic_load_pointer (pp);
612
+ if (sdata == NULL)
613
+ break;
614
+
615
+ sym = ((struct coff_symbol *)
616
+ bsearch (&addr, sdata->symbols, sdata->count,
617
+ sizeof (struct coff_symbol), coff_symbol_search));
618
+ if (sym != NULL)
619
+ break;
620
+
621
+ pp = &sdata->next;
622
+ }
623
+ }
624
+
625
+ if (sym == NULL)
626
+ callback (data, addr, NULL, 0, 0);
627
+ else
628
+ callback (data, addr, sym->name, sym->address, 0);
629
+ }
630
+
631
+ /* Add the backtrace data for one PE/COFF file. Returns 1 on success,
632
+ 0 on failure (in both cases descriptor is closed). */
633
+
634
+ static int
635
+ coff_add (struct backtrace_state *state, int descriptor,
636
+ backtrace_error_callback error_callback, void *data,
637
+ fileline *fileline_fn, int *found_sym, int *found_dwarf,
638
+ uintptr_t module_handle ATTRIBUTE_UNUSED)
639
+ {
640
+ struct backtrace_view fhdr_view;
641
+ off_t fhdr_off;
642
+ int magic_ok;
643
+ b_coff_file_header fhdr;
644
+ off_t opt_sects_off;
645
+ size_t opt_sects_size;
646
+ unsigned int sects_num;
647
+ struct backtrace_view sects_view;
648
+ int sects_view_valid;
649
+ const b_coff_optional_header *opt_hdr;
650
+ const b_coff_section_header *sects;
651
+ struct backtrace_view str_view;
652
+ int str_view_valid;
653
+ size_t str_size;
654
+ off_t str_off;
655
+ struct backtrace_view syms_view;
656
+ off_t syms_off;
657
+ size_t syms_size;
658
+ int syms_view_valid;
659
+ unsigned int syms_num;
660
+ unsigned int i;
661
+ struct debug_section_info sections[DEBUG_MAX];
662
+ off_t min_offset;
663
+ off_t max_offset;
664
+ struct backtrace_view debug_view;
665
+ int debug_view_valid;
666
+ int is_64;
667
+ struct libbacktrace_base_address image_base;
668
+ struct libbacktrace_base_address base_address;
669
+ struct dwarf_sections dwarf_sections;
670
+
671
+ *found_sym = 0;
672
+ *found_dwarf = 0;
673
+
674
+ sects_view_valid = 0;
675
+ syms_view_valid = 0;
676
+ str_view_valid = 0;
677
+ debug_view_valid = 0;
678
+
679
+ /* Map the MS-DOS stub (if any) and extract file header offset. */
680
+ if (!backtrace_get_view (state, descriptor, 0, 0x40, error_callback,
681
+ data, &fhdr_view))
682
+ goto fail;
683
+
684
+ {
685
+ const unsigned char *vptr = fhdr_view.data;
686
+
687
+ if (vptr[0] == 'M' && vptr[1] == 'Z')
688
+ fhdr_off = coff_read4 (vptr + 0x3c);
689
+ else
690
+ fhdr_off = 0;
691
+ }
692
+
693
+ backtrace_release_view (state, &fhdr_view, error_callback, data);
694
+
695
+ /* Map the coff file header. */
696
+ if (!backtrace_get_view (state, descriptor, fhdr_off,
697
+ sizeof (b_coff_file_header) + 4,
698
+ error_callback, data, &fhdr_view))
699
+ goto fail;
700
+
701
+ if (fhdr_off != 0)
702
+ {
703
+ const char *magic = (const char *) fhdr_view.data;
704
+ magic_ok = memcmp (magic, "PE\0", 4) == 0;
705
+ fhdr_off += 4;
706
+
707
+ memcpy (&fhdr, (const unsigned char *) fhdr_view.data + 4, sizeof fhdr);
708
+ }
709
+ else
710
+ {
711
+ memcpy (&fhdr, fhdr_view.data, sizeof fhdr);
712
+ /* TODO: test fhdr.machine for coff but non-PE platforms. */
713
+ magic_ok = 0;
714
+ }
715
+ backtrace_release_view (state, &fhdr_view, error_callback, data);
716
+
717
+ if (!magic_ok)
718
+ {
719
+ error_callback (data, "executable file is not COFF", 0);
720
+ goto fail;
721
+ }
722
+
723
+ sects_num = fhdr.number_of_sections;
724
+ syms_num = fhdr.number_of_symbols;
725
+
726
+ opt_sects_off = fhdr_off + sizeof (fhdr);
727
+ opt_sects_size = (fhdr.size_of_optional_header
728
+ + sects_num * sizeof (b_coff_section_header));
729
+
730
+ /* To translate PC to file/line when using DWARF, we need to find
731
+ the .debug_info and .debug_line sections. */
732
+
733
+ /* Read the optional header and the section headers. */
734
+
735
+ if (!backtrace_get_view (state, descriptor, opt_sects_off, opt_sects_size,
736
+ error_callback, data, &sects_view))
737
+ goto fail;
738
+ sects_view_valid = 1;
739
+ opt_hdr = (const b_coff_optional_header *) sects_view.data;
740
+ sects = (const b_coff_section_header *)
741
+ ((const unsigned char *) sects_view.data + fhdr.size_of_optional_header);
742
+
743
+ is_64 = 0;
744
+ memset (&image_base, 0, sizeof image_base);
745
+ if (fhdr.size_of_optional_header > sizeof (*opt_hdr))
746
+ {
747
+ if (opt_hdr->magic == PE_MAGIC)
748
+ image_base.m = opt_hdr->u.pe.image_base;
749
+ else if (opt_hdr->magic == PEP_MAGIC)
750
+ {
751
+ image_base.m = opt_hdr->u.pep.image_base;
752
+ is_64 = 1;
753
+ }
754
+ else
755
+ {
756
+ error_callback (data, "bad magic in PE optional header", 0);
757
+ goto fail;
758
+ }
759
+ }
760
+
761
+ /* Read the symbol table and the string table. */
762
+
763
+ if (fhdr.pointer_to_symbol_table == 0)
764
+ {
765
+ /* No symbol table, no string table. */
766
+ str_off = 0;
767
+ str_size = 0;
768
+ syms_num = 0;
769
+ syms_size = 0;
770
+ }
771
+ else
772
+ {
773
+ /* Symbol table is followed by the string table. The string table
774
+ starts with its length (on 4 bytes).
775
+ Map the symbol table and the length of the string table. */
776
+ syms_off = fhdr.pointer_to_symbol_table;
777
+ syms_size = syms_num * SYM_SZ;
778
+
779
+ if (!backtrace_get_view (state, descriptor, syms_off, syms_size + 4,
780
+ error_callback, data, &syms_view))
781
+ goto fail;
782
+ syms_view_valid = 1;
783
+
784
+ str_size = coff_read4 ((const unsigned char *) syms_view.data
785
+ + syms_size);
786
+
787
+ str_off = syms_off + syms_size;
788
+
789
+ if (str_size > 4)
790
+ {
791
+ /* Map string table (including the length word). */
792
+
793
+ if (!backtrace_get_view (state, descriptor, str_off, str_size,
794
+ error_callback, data, &str_view))
795
+ goto fail;
796
+ str_view_valid = 1;
797
+ }
798
+ }
799
+
800
+ memset (sections, 0, sizeof sections);
801
+
802
+ /* Look for the symbol table. */
803
+ for (i = 0; i < sects_num; ++i)
804
+ {
805
+ const b_coff_section_header *s = sects + i;
806
+ unsigned int str_off;
807
+ int j;
808
+
809
+ if (s->name[0] == '/')
810
+ {
811
+ /* Extended section name. */
812
+ str_off = atoi (s->name + 1);
813
+ }
814
+ else
815
+ str_off = 0;
816
+
817
+ for (j = 0; j < (int) DEBUG_MAX; ++j)
818
+ {
819
+ const char *dbg_name = debug_section_names[j];
820
+ int match;
821
+
822
+ if (str_off != 0)
823
+ match = coff_long_name_eq (dbg_name, str_off, &str_view);
824
+ else
825
+ match = coff_short_name_eq (dbg_name, s->name);
826
+ if (match)
827
+ {
828
+ sections[j].offset = s->pointer_to_raw_data;
829
+ sections[j].size = s->virtual_size <= s->size_of_raw_data ?
830
+ s->virtual_size : s->size_of_raw_data;
831
+ break;
832
+ }
833
+ }
834
+ }
835
+
836
+ if (syms_num != 0)
837
+ {
838
+ struct coff_syminfo_data *sdata;
839
+
840
+ sdata = ((struct coff_syminfo_data *)
841
+ backtrace_alloc (state, sizeof *sdata, error_callback, data));
842
+ if (sdata == NULL)
843
+ goto fail;
844
+
845
+ if (!coff_initialize_syminfo (state, image_base, is_64,
846
+ sects, sects_num,
847
+ syms_view.data, syms_size,
848
+ str_view.data, str_size,
849
+ error_callback, data, sdata))
850
+ {
851
+ backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
852
+ goto fail;
853
+ }
854
+
855
+ *found_sym = 1;
856
+
857
+ coff_add_syminfo_data (state, sdata);
858
+ }
859
+
860
+ backtrace_release_view (state, &sects_view, error_callback, data);
861
+ sects_view_valid = 0;
862
+ if (syms_view_valid)
863
+ {
864
+ backtrace_release_view (state, &syms_view, error_callback, data);
865
+ syms_view_valid = 0;
866
+ }
867
+
868
+ /* Read all the debug sections in a single view, since they are
869
+ probably adjacent in the file. We never release this view. */
870
+
871
+ min_offset = 0;
872
+ max_offset = 0;
873
+ for (i = 0; i < (int) DEBUG_MAX; ++i)
874
+ {
875
+ off_t end;
876
+
877
+ if (sections[i].size == 0)
878
+ continue;
879
+ if (min_offset == 0 || sections[i].offset < min_offset)
880
+ min_offset = sections[i].offset;
881
+ end = sections[i].offset + sections[i].size;
882
+ if (end > max_offset)
883
+ max_offset = end;
884
+ }
885
+ if (min_offset == 0 || max_offset == 0)
886
+ {
887
+ if (!backtrace_close (descriptor, error_callback, data))
888
+ goto fail;
889
+ *fileline_fn = coff_nodebug;
890
+ return 1;
891
+ }
892
+
893
+ if (!backtrace_get_view (state, descriptor, min_offset,
894
+ max_offset - min_offset,
895
+ error_callback, data, &debug_view))
896
+ goto fail;
897
+ debug_view_valid = 1;
898
+
899
+ /* We've read all we need from the executable. */
900
+ if (!backtrace_close (descriptor, error_callback, data))
901
+ goto fail;
902
+ descriptor = -1;
903
+
904
+ for (i = 0; i < (int) DEBUG_MAX; ++i)
905
+ {
906
+ size_t size = sections[i].size;
907
+ dwarf_sections.size[i] = size;
908
+ if (size == 0)
909
+ dwarf_sections.data[i] = NULL;
910
+ else
911
+ dwarf_sections.data[i] = ((const unsigned char *) debug_view.data
912
+ + (sections[i].offset - min_offset));
913
+ }
914
+
915
+ memset (&base_address, 0, sizeof base_address);
916
+ #ifdef HAVE_WINDOWS_H
917
+ base_address.m = module_handle - image_base.m;
918
+ #endif
919
+
920
+ if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,
921
+ 0, /* FIXME: is_bigendian */
922
+ NULL, /* altlink */
923
+ error_callback, data, fileline_fn,
924
+ NULL /* returned fileline_entry */))
925
+ goto fail;
926
+
927
+ *found_dwarf = 1;
928
+
929
+ return 1;
930
+
931
+ fail:
932
+ if (sects_view_valid)
933
+ backtrace_release_view (state, &sects_view, error_callback, data);
934
+ if (str_view_valid)
935
+ backtrace_release_view (state, &str_view, error_callback, data);
936
+ if (syms_view_valid)
937
+ backtrace_release_view (state, &syms_view, error_callback, data);
938
+ if (debug_view_valid)
939
+ backtrace_release_view (state, &debug_view, error_callback, data);
940
+ if (descriptor != -1)
941
+ backtrace_close (descriptor, error_callback, data);
942
+ return 0;
943
+ }
944
+
945
+ #ifdef HAVE_WINDOWS_H
946
+ struct dll_notification_context
947
+ {
948
+ struct backtrace_state *state;
949
+ backtrace_error_callback error_callback;
950
+ void *data;
951
+ };
952
+
953
+ static VOID CALLBACK
954
+ dll_notification (ULONG reason,
955
+ struct dll_notification_data *notification_data,
956
+ PVOID context)
957
+ {
958
+ char module_name[MAX_PATH];
959
+ int descriptor;
960
+ struct dll_notification_context* dll_context =
961
+ (struct dll_notification_context*) context;
962
+ struct backtrace_state *state = dll_context->state;
963
+ void *data = dll_context->data;
964
+ backtrace_error_callback error_callback = dll_context->data;
965
+ fileline fileline;
966
+ int found_sym;
967
+ int found_dwarf;
968
+ HMODULE module_handle;
969
+
970
+ if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
971
+ return;
972
+
973
+ if (!GetModuleHandleExW ((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
974
+ | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
975
+ (wchar_t*) notification_data->dll_base,
976
+ &module_handle))
977
+ return;
978
+
979
+ if (!GetModuleFileNameA ((HMODULE) module_handle, module_name, MAX_PATH - 1))
980
+ return;
981
+
982
+ descriptor = backtrace_open (module_name, error_callback, data, NULL);
983
+
984
+ if (descriptor < 0)
985
+ return;
986
+
987
+ coff_add (state, descriptor, error_callback, data, &fileline, &found_sym,
988
+ &found_dwarf, (uintptr_t) module_handle);
989
+ }
990
+ #endif /* defined(HAVE_WINDOWS_H) */
991
+
992
+ /* Initialize the backtrace data we need from an ELF executable. At
993
+ the ELF level, all we need to do is find the debug info
994
+ sections. */
995
+
996
+ int
997
+ backtrace_initialize (struct backtrace_state *state,
998
+ const char *filename ATTRIBUTE_UNUSED, int descriptor,
999
+ backtrace_error_callback error_callback,
1000
+ void *data, fileline *fileline_fn)
1001
+ {
1002
+ int ret;
1003
+ int found_sym;
1004
+ int found_dwarf;
1005
+ fileline coff_fileline_fn;
1006
+ uintptr_t module_handle = 0;
1007
+ #ifdef HAVE_TLHELP32_H
1008
+ fileline module_fileline_fn;
1009
+ int module_found_sym;
1010
+ HANDLE snapshot;
1011
+ #endif
1012
+
1013
+ #ifdef HAVE_WINDOWS_H
1014
+ HMODULE nt_dll_handle;
1015
+
1016
+ module_handle = (uintptr_t) GetModuleHandle (NULL);
1017
+ #endif
1018
+
1019
+ ret = coff_add (state, descriptor, error_callback, data,
1020
+ &coff_fileline_fn, &found_sym, &found_dwarf, module_handle);
1021
+ if (!ret)
1022
+ return 0;
1023
+
1024
+ #ifdef HAVE_TLHELP32_H
1025
+ do
1026
+ {
1027
+ snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
1028
+ }
1029
+ while (snapshot == INVALID_HANDLE_VALUE
1030
+ && GetLastError () == ERROR_BAD_LENGTH);
1031
+
1032
+ if (snapshot != INVALID_HANDLE_VALUE)
1033
+ {
1034
+ MODULEENTRY32 entry;
1035
+ BOOL ok;
1036
+ entry.dwSize = sizeof (MODULEENTRY32);
1037
+
1038
+ for (ok = Module32First (snapshot, &entry); ok; ok = Module32Next (snapshot, &entry))
1039
+ {
1040
+ if (strcmp (filename, entry.szExePath) == 0)
1041
+ continue;
1042
+
1043
+ module_handle = (uintptr_t) entry.hModule;
1044
+ if (module_handle == 0)
1045
+ continue;
1046
+
1047
+ descriptor = backtrace_open (entry.szExePath, error_callback, data,
1048
+ NULL);
1049
+ if (descriptor < 0)
1050
+ continue;
1051
+
1052
+ coff_add (state, descriptor, error_callback, data,
1053
+ &module_fileline_fn, &module_found_sym, &found_dwarf,
1054
+ module_handle);
1055
+ if (module_found_sym)
1056
+ found_sym = 1;
1057
+ }
1058
+
1059
+ CloseHandle (snapshot);
1060
+ }
1061
+ #endif
1062
+
1063
+ #ifdef HAVE_WINDOWS_H
1064
+ nt_dll_handle = GetModuleHandleW (L"ntdll.dll");
1065
+ if (nt_dll_handle)
1066
+ {
1067
+ LDR_REGISTER_FUNCTION register_func;
1068
+ const char register_name[] = "LdrRegisterDllNotification";
1069
+ register_func = (void*) GetProcAddress (nt_dll_handle,
1070
+ register_name);
1071
+
1072
+ if (register_func)
1073
+ {
1074
+ PVOID cookie;
1075
+ struct dll_notification_context *context
1076
+ = backtrace_alloc (state,
1077
+ sizeof (struct dll_notification_context),
1078
+ error_callback, data);
1079
+
1080
+ if (context)
1081
+ {
1082
+ context->state = state;
1083
+ context->data = data;
1084
+ context->error_callback = error_callback;
1085
+
1086
+ register_func (0, &dll_notification, context, &cookie);
1087
+ }
1088
+ }
1089
+ }
1090
+ #endif /* defined(HAVE_WINDOWS_H) */
1091
+
1092
+ if (!state->threaded)
1093
+ {
1094
+ if (found_sym)
1095
+ state->syminfo_fn = coff_syminfo;
1096
+ else if (state->syminfo_fn == NULL)
1097
+ state->syminfo_fn = coff_nosyms;
1098
+ }
1099
+ else
1100
+ {
1101
+ if (found_sym)
1102
+ backtrace_atomic_store_pointer (&state->syminfo_fn, coff_syminfo);
1103
+ else
1104
+ (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
1105
+ coff_nosyms);
1106
+ }
1107
+
1108
+ if (!state->threaded)
1109
+ {
1110
+ if (state->fileline_fn == NULL || state->fileline_fn == coff_nodebug)
1111
+ *fileline_fn = coff_fileline_fn;
1112
+ }
1113
+ else
1114
+ {
1115
+ fileline current_fn;
1116
+
1117
+ current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
1118
+ if (current_fn == NULL || current_fn == coff_nodebug)
1119
+ *fileline_fn = coff_fileline_fn;
1120
+ }
1121
+
1122
+ return 1;
1123
+ }