annotate libbacktrace/pecoff.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* pecoff.c -- Get debug data from a PE/COFFF file for backtraces.
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2 Copyright (C) 2015-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
3 Adapted from elf.c by Tristan Gingold, AdaCore.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 Redistribution and use in source and binary forms, with or without
kono
parents:
diff changeset
6 modification, are permitted provided that the following conditions are
kono
parents:
diff changeset
7 met:
kono
parents:
diff changeset
8
kono
parents:
diff changeset
9 (1) Redistributions of source code must retain the above copyright
kono
parents:
diff changeset
10 notice, this list of conditions and the following disclaimer.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 (2) Redistributions in binary form must reproduce the above copyright
kono
parents:
diff changeset
13 notice, this list of conditions and the following disclaimer in
kono
parents:
diff changeset
14 the documentation and/or other materials provided with the
kono
parents:
diff changeset
15 distribution.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 (3) The name of the author may not be used to
kono
parents:
diff changeset
18 endorse or promote products derived from this software without
kono
parents:
diff changeset
19 specific prior written permission.
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
kono
parents:
diff changeset
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
kono
parents:
diff changeset
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
kono
parents:
diff changeset
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
kono
parents:
diff changeset
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
kono
parents:
diff changeset
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
kono
parents:
diff changeset
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
kono
parents:
diff changeset
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
kono
parents:
diff changeset
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
kono
parents:
diff changeset
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
kono
parents:
diff changeset
31 POSSIBILITY OF SUCH DAMAGE. */
kono
parents:
diff changeset
32
kono
parents:
diff changeset
33 #include "config.h"
kono
parents:
diff changeset
34
kono
parents:
diff changeset
35 #include <stdlib.h>
kono
parents:
diff changeset
36 #include <string.h>
kono
parents:
diff changeset
37 #include <sys/types.h>
kono
parents:
diff changeset
38
kono
parents:
diff changeset
39 #include "backtrace.h"
kono
parents:
diff changeset
40 #include "internal.h"
kono
parents:
diff changeset
41
kono
parents:
diff changeset
42 /* Coff file header. */
kono
parents:
diff changeset
43
kono
parents:
diff changeset
44 typedef struct {
kono
parents:
diff changeset
45 uint16_t machine;
kono
parents:
diff changeset
46 uint16_t number_of_sections;
kono
parents:
diff changeset
47 uint32_t time_date_stamp;
kono
parents:
diff changeset
48 uint32_t pointer_to_symbol_table;
kono
parents:
diff changeset
49 uint32_t number_of_symbols;
kono
parents:
diff changeset
50 uint16_t size_of_optional_header;
kono
parents:
diff changeset
51 uint16_t characteristics;
kono
parents:
diff changeset
52 } b_coff_file_header;
kono
parents:
diff changeset
53
kono
parents:
diff changeset
54 /* Coff optional header. */
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 typedef struct {
kono
parents:
diff changeset
57 uint16_t magic;
kono
parents:
diff changeset
58 uint8_t major_linker_version;
kono
parents:
diff changeset
59 uint8_t minor_linker_version;
kono
parents:
diff changeset
60 uint32_t size_of_code;
kono
parents:
diff changeset
61 uint32_t size_of_initialized_data;
kono
parents:
diff changeset
62 uint32_t size_of_uninitialized_data;
kono
parents:
diff changeset
63 uint32_t address_of_entry_point;
kono
parents:
diff changeset
64 uint32_t base_of_code;
kono
parents:
diff changeset
65 union {
kono
parents:
diff changeset
66 struct {
kono
parents:
diff changeset
67 uint32_t base_of_data;
kono
parents:
diff changeset
68 uint32_t image_base;
kono
parents:
diff changeset
69 } pe;
kono
parents:
diff changeset
70 struct {
kono
parents:
diff changeset
71 uint64_t image_base;
kono
parents:
diff changeset
72 } pep;
kono
parents:
diff changeset
73 } u;
kono
parents:
diff changeset
74 } b_coff_optional_header;
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 /* Values of magic in optional header. */
kono
parents:
diff changeset
77
kono
parents:
diff changeset
78 #define PE_MAGIC 0x10b /* PE32 executable. */
kono
parents:
diff changeset
79 #define PEP_MAGIC 0x20b /* PE32+ executable (for 64bit targets). */
kono
parents:
diff changeset
80
kono
parents:
diff changeset
81 /* Coff section header. */
kono
parents:
diff changeset
82
kono
parents:
diff changeset
83 typedef struct {
kono
parents:
diff changeset
84 char name[8];
kono
parents:
diff changeset
85 uint32_t virtual_size;
kono
parents:
diff changeset
86 uint32_t virtual_address;
kono
parents:
diff changeset
87 uint32_t size_of_raw_data;
kono
parents:
diff changeset
88 uint32_t pointer_to_raw_data;
kono
parents:
diff changeset
89 uint32_t pointer_to_relocations;
kono
parents:
diff changeset
90 uint32_t pointer_to_line_numbers;
kono
parents:
diff changeset
91 uint16_t number_of_relocations;
kono
parents:
diff changeset
92 uint16_t number_of_line_numbers;
kono
parents:
diff changeset
93 uint32_t characteristics;
kono
parents:
diff changeset
94 } b_coff_section_header;
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 /* Coff symbol name. */
kono
parents:
diff changeset
97
kono
parents:
diff changeset
98 typedef union {
kono
parents:
diff changeset
99 char short_name[8];
kono
parents:
diff changeset
100 struct {
kono
parents:
diff changeset
101 unsigned char zeroes[4];
kono
parents:
diff changeset
102 unsigned char off[4];
kono
parents:
diff changeset
103 } long_name;
kono
parents:
diff changeset
104 } b_coff_name;
kono
parents:
diff changeset
105
kono
parents:
diff changeset
106 /* Coff symbol (external representation which is unaligned). */
kono
parents:
diff changeset
107
kono
parents:
diff changeset
108 typedef struct {
kono
parents:
diff changeset
109 b_coff_name name;
kono
parents:
diff changeset
110 unsigned char value[4];
kono
parents:
diff changeset
111 unsigned char section_number[2];
kono
parents:
diff changeset
112 unsigned char type[2];
kono
parents:
diff changeset
113 unsigned char storage_class;
kono
parents:
diff changeset
114 unsigned char number_of_aux_symbols;
kono
parents:
diff changeset
115 } b_coff_external_symbol;
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 /* Symbol types. */
kono
parents:
diff changeset
118
kono
parents:
diff changeset
119 #define N_TBSHFT 4 /* Shift for the derived type. */
kono
parents:
diff changeset
120 #define IMAGE_SYM_DTYPE_FUNCTION 2 /* Function derived type. */
kono
parents:
diff changeset
121
kono
parents:
diff changeset
122 /* Size of a coff symbol. */
kono
parents:
diff changeset
123
kono
parents:
diff changeset
124 #define SYM_SZ 18
kono
parents:
diff changeset
125
kono
parents:
diff changeset
126 /* Coff symbol, internal representation (aligned). */
kono
parents:
diff changeset
127
kono
parents:
diff changeset
128 typedef struct {
kono
parents:
diff changeset
129 const char *name;
kono
parents:
diff changeset
130 uint32_t value;
kono
parents:
diff changeset
131 int16_t sec;
kono
parents:
diff changeset
132 uint16_t type;
kono
parents:
diff changeset
133 uint16_t sc;
kono
parents:
diff changeset
134 } b_coff_internal_symbol;
kono
parents:
diff changeset
135
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
136 /* Names of sections, indexed by enum dwarf_section in internal.h. */
111
kono
parents:
diff changeset
137
kono
parents:
diff changeset
138 static const char * const debug_section_names[DEBUG_MAX] =
kono
parents:
diff changeset
139 {
kono
parents:
diff changeset
140 ".debug_info",
kono
parents:
diff changeset
141 ".debug_line",
kono
parents:
diff changeset
142 ".debug_abbrev",
kono
parents:
diff changeset
143 ".debug_ranges",
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
144 ".debug_str",
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
145 ".debug_addr",
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
146 ".debug_str_offsets",
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
147 ".debug_line_str",
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
148 ".debug_rnglists"
111
kono
parents:
diff changeset
149 };
kono
parents:
diff changeset
150
kono
parents:
diff changeset
151 /* Information we gather for the sections we care about. */
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 struct debug_section_info
kono
parents:
diff changeset
154 {
kono
parents:
diff changeset
155 /* Section file offset. */
kono
parents:
diff changeset
156 off_t offset;
kono
parents:
diff changeset
157 /* Section size. */
kono
parents:
diff changeset
158 size_t size;
kono
parents:
diff changeset
159 };
kono
parents:
diff changeset
160
kono
parents:
diff changeset
161 /* Information we keep for an coff symbol. */
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 struct coff_symbol
kono
parents:
diff changeset
164 {
kono
parents:
diff changeset
165 /* The name of the symbol. */
kono
parents:
diff changeset
166 const char *name;
kono
parents:
diff changeset
167 /* The address of the symbol. */
kono
parents:
diff changeset
168 uintptr_t address;
kono
parents:
diff changeset
169 };
kono
parents:
diff changeset
170
kono
parents:
diff changeset
171 /* Information to pass to coff_syminfo. */
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 struct coff_syminfo_data
kono
parents:
diff changeset
174 {
kono
parents:
diff changeset
175 /* Symbols for the next module. */
kono
parents:
diff changeset
176 struct coff_syminfo_data *next;
kono
parents:
diff changeset
177 /* The COFF symbols, sorted by address. */
kono
parents:
diff changeset
178 struct coff_symbol *symbols;
kono
parents:
diff changeset
179 /* The number of symbols. */
kono
parents:
diff changeset
180 size_t count;
kono
parents:
diff changeset
181 };
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 /* A dummy callback function used when we can't find any debug info. */
kono
parents:
diff changeset
184
kono
parents:
diff changeset
185 static int
kono
parents:
diff changeset
186 coff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
187 uintptr_t pc ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
188 backtrace_full_callback callback ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
189 backtrace_error_callback error_callback, void *data)
kono
parents:
diff changeset
190 {
kono
parents:
diff changeset
191 error_callback (data, "no debug info in PE/COFF executable", -1);
kono
parents:
diff changeset
192 return 0;
kono
parents:
diff changeset
193 }
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 /* A dummy callback function used when we can't find a symbol
kono
parents:
diff changeset
196 table. */
kono
parents:
diff changeset
197
kono
parents:
diff changeset
198 static void
kono
parents:
diff changeset
199 coff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
200 uintptr_t addr ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
201 backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
202 backtrace_error_callback error_callback, void *data)
kono
parents:
diff changeset
203 {
kono
parents:
diff changeset
204 error_callback (data, "no symbol table in PE/COFF executable", -1);
kono
parents:
diff changeset
205 }
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 /* Read a potentially unaligned 4 byte word at P, using native endianness. */
kono
parents:
diff changeset
208
kono
parents:
diff changeset
209 static uint32_t
kono
parents:
diff changeset
210 coff_read4 (const unsigned char *p)
kono
parents:
diff changeset
211 {
kono
parents:
diff changeset
212 uint32_t res;
kono
parents:
diff changeset
213
kono
parents:
diff changeset
214 memcpy (&res, p, 4);
kono
parents:
diff changeset
215 return res;
kono
parents:
diff changeset
216 }
kono
parents:
diff changeset
217
kono
parents:
diff changeset
218 /* Read a potentially unaligned 2 byte word at P, using native endianness.
kono
parents:
diff changeset
219 All 2 byte word in symbols are always aligned, but for coherency all
kono
parents:
diff changeset
220 fields are declared as char arrays. */
kono
parents:
diff changeset
221
kono
parents:
diff changeset
222 static uint16_t
kono
parents:
diff changeset
223 coff_read2 (const unsigned char *p)
kono
parents:
diff changeset
224 {
kono
parents:
diff changeset
225 uint16_t res;
kono
parents:
diff changeset
226
kono
parents:
diff changeset
227 memcpy (&res, p, sizeof (res));
kono
parents:
diff changeset
228 return res;
kono
parents:
diff changeset
229 }
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 /* Return the length (without the trailing 0) of a COFF short name. */
kono
parents:
diff changeset
232
kono
parents:
diff changeset
233 static size_t
kono
parents:
diff changeset
234 coff_short_name_len (const char *name)
kono
parents:
diff changeset
235 {
kono
parents:
diff changeset
236 int i;
kono
parents:
diff changeset
237
kono
parents:
diff changeset
238 for (i = 0; i < 8; i++)
kono
parents:
diff changeset
239 if (name[i] == 0)
kono
parents:
diff changeset
240 return i;
kono
parents:
diff changeset
241 return 8;
kono
parents:
diff changeset
242 }
kono
parents:
diff changeset
243
kono
parents:
diff changeset
244 /* Return true iff COFF short name CNAME is the same as NAME (a NUL-terminated
kono
parents:
diff changeset
245 string). */
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 static int
kono
parents:
diff changeset
248 coff_short_name_eq (const char *name, const char *cname)
kono
parents:
diff changeset
249 {
kono
parents:
diff changeset
250 int i;
kono
parents:
diff changeset
251
kono
parents:
diff changeset
252 for (i = 0; i < 8; i++)
kono
parents:
diff changeset
253 {
kono
parents:
diff changeset
254 if (name[i] != cname[i])
kono
parents:
diff changeset
255 return 0;
kono
parents:
diff changeset
256 if (name[i] == 0)
kono
parents:
diff changeset
257 return 1;
kono
parents:
diff changeset
258 }
kono
parents:
diff changeset
259 return name[8] == 0;
kono
parents:
diff changeset
260 }
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 /* Return true iff NAME is the same as string at offset OFF. */
kono
parents:
diff changeset
263
kono
parents:
diff changeset
264 static int
kono
parents:
diff changeset
265 coff_long_name_eq (const char *name, unsigned int off,
kono
parents:
diff changeset
266 struct backtrace_view *str_view)
kono
parents:
diff changeset
267 {
kono
parents:
diff changeset
268 if (off >= str_view->len)
kono
parents:
diff changeset
269 return 0;
kono
parents:
diff changeset
270 return strcmp (name, (const char *)str_view->data + off) == 0;
kono
parents:
diff changeset
271 }
kono
parents:
diff changeset
272
kono
parents:
diff changeset
273 /* Compare struct coff_symbol for qsort. */
kono
parents:
diff changeset
274
kono
parents:
diff changeset
275 static int
kono
parents:
diff changeset
276 coff_symbol_compare (const void *v1, const void *v2)
kono
parents:
diff changeset
277 {
kono
parents:
diff changeset
278 const struct coff_symbol *e1 = (const struct coff_symbol *) v1;
kono
parents:
diff changeset
279 const struct coff_symbol *e2 = (const struct coff_symbol *) v2;
kono
parents:
diff changeset
280
kono
parents:
diff changeset
281 if (e1->address < e2->address)
kono
parents:
diff changeset
282 return -1;
kono
parents:
diff changeset
283 else if (e1->address > e2->address)
kono
parents:
diff changeset
284 return 1;
kono
parents:
diff changeset
285 else
kono
parents:
diff changeset
286 return 0;
kono
parents:
diff changeset
287 }
kono
parents:
diff changeset
288
kono
parents:
diff changeset
289 /* Convert SYM to internal (and aligned) format ISYM, using string table
kono
parents:
diff changeset
290 from STRTAB and STRTAB_SIZE, and number of sections SECTS_NUM.
kono
parents:
diff changeset
291 Return -1 in case of error (invalid section number or string index). */
kono
parents:
diff changeset
292
kono
parents:
diff changeset
293 static int
kono
parents:
diff changeset
294 coff_expand_symbol (b_coff_internal_symbol *isym,
kono
parents:
diff changeset
295 const b_coff_external_symbol *sym,
kono
parents:
diff changeset
296 uint16_t sects_num,
kono
parents:
diff changeset
297 const unsigned char *strtab, size_t strtab_size)
kono
parents:
diff changeset
298 {
kono
parents:
diff changeset
299 isym->type = coff_read2 (sym->type);
kono
parents:
diff changeset
300 isym->sec = coff_read2 (sym->section_number);
kono
parents:
diff changeset
301 isym->sc = sym->storage_class;
kono
parents:
diff changeset
302
kono
parents:
diff changeset
303 if (isym->sec > 0 && (uint16_t) isym->sec > sects_num)
kono
parents:
diff changeset
304 return -1;
kono
parents:
diff changeset
305 if (sym->name.short_name[0] != 0)
kono
parents:
diff changeset
306 isym->name = sym->name.short_name;
kono
parents:
diff changeset
307 else
kono
parents:
diff changeset
308 {
kono
parents:
diff changeset
309 uint32_t off = coff_read4 (sym->name.long_name.off);
kono
parents:
diff changeset
310
kono
parents:
diff changeset
311 if (off >= strtab_size)
kono
parents:
diff changeset
312 return -1;
kono
parents:
diff changeset
313 isym->name = (const char *) strtab + off;
kono
parents:
diff changeset
314 }
kono
parents:
diff changeset
315 return 0;
kono
parents:
diff changeset
316 }
kono
parents:
diff changeset
317
kono
parents:
diff changeset
318 /* Return true iff SYM is a defined symbol for a function. Data symbols
kono
parents:
diff changeset
319 aren't considered because they aren't easily identified (same type as
kono
parents:
diff changeset
320 section names, presence of symbols defined by the linker script). */
kono
parents:
diff changeset
321
kono
parents:
diff changeset
322 static int
kono
parents:
diff changeset
323 coff_is_function_symbol (const b_coff_internal_symbol *isym)
kono
parents:
diff changeset
324 {
kono
parents:
diff changeset
325 return (isym->type >> N_TBSHFT) == IMAGE_SYM_DTYPE_FUNCTION
kono
parents:
diff changeset
326 && isym->sec > 0;
kono
parents:
diff changeset
327 }
kono
parents:
diff changeset
328
kono
parents:
diff changeset
329 /* Initialize the symbol table info for coff_syminfo. */
kono
parents:
diff changeset
330
kono
parents:
diff changeset
331 static int
kono
parents:
diff changeset
332 coff_initialize_syminfo (struct backtrace_state *state,
kono
parents:
diff changeset
333 uintptr_t base_address,
kono
parents:
diff changeset
334 const b_coff_section_header *sects, size_t sects_num,
kono
parents:
diff changeset
335 const b_coff_external_symbol *syms, size_t syms_size,
kono
parents:
diff changeset
336 const unsigned char *strtab, size_t strtab_size,
kono
parents:
diff changeset
337 backtrace_error_callback error_callback,
kono
parents:
diff changeset
338 void *data, struct coff_syminfo_data *sdata)
kono
parents:
diff changeset
339 {
kono
parents:
diff changeset
340 size_t syms_count;
kono
parents:
diff changeset
341 char *coff_symstr;
kono
parents:
diff changeset
342 size_t coff_symstr_len;
kono
parents:
diff changeset
343 size_t coff_symbol_count;
kono
parents:
diff changeset
344 size_t coff_symbol_size;
kono
parents:
diff changeset
345 struct coff_symbol *coff_symbols;
kono
parents:
diff changeset
346 struct coff_symbol *coff_sym;
kono
parents:
diff changeset
347 char *coff_str;
kono
parents:
diff changeset
348 size_t i;
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 syms_count = syms_size / SYM_SZ;
kono
parents:
diff changeset
351
kono
parents:
diff changeset
352 /* We only care about function symbols. Count them. Also count size of
kono
parents:
diff changeset
353 strings for in-symbol names. */
kono
parents:
diff changeset
354 coff_symbol_count = 0;
kono
parents:
diff changeset
355 coff_symstr_len = 0;
kono
parents:
diff changeset
356 for (i = 0; i < syms_count; ++i)
kono
parents:
diff changeset
357 {
kono
parents:
diff changeset
358 const b_coff_external_symbol *asym = &syms[i];
kono
parents:
diff changeset
359 b_coff_internal_symbol isym;
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size) < 0)
kono
parents:
diff changeset
362 {
kono
parents:
diff changeset
363 error_callback (data, "invalid section or offset in coff symbol", 0);
kono
parents:
diff changeset
364 return 0;
kono
parents:
diff changeset
365 }
kono
parents:
diff changeset
366 if (coff_is_function_symbol (&isym))
kono
parents:
diff changeset
367 {
kono
parents:
diff changeset
368 ++coff_symbol_count;
kono
parents:
diff changeset
369 if (asym->name.short_name[0] != 0)
kono
parents:
diff changeset
370 coff_symstr_len += coff_short_name_len (asym->name.short_name) + 1;
kono
parents:
diff changeset
371 }
kono
parents:
diff changeset
372
kono
parents:
diff changeset
373 i += asym->number_of_aux_symbols;
kono
parents:
diff changeset
374 }
kono
parents:
diff changeset
375
kono
parents:
diff changeset
376 coff_symbol_size = (coff_symbol_count + 1) * sizeof (struct coff_symbol);
kono
parents:
diff changeset
377 coff_symbols = ((struct coff_symbol *)
kono
parents:
diff changeset
378 backtrace_alloc (state, coff_symbol_size, error_callback,
kono
parents:
diff changeset
379 data));
kono
parents:
diff changeset
380 if (coff_symbols == NULL)
kono
parents:
diff changeset
381 return 0;
kono
parents:
diff changeset
382
kono
parents:
diff changeset
383 /* Allocate memory for symbols strings. */
kono
parents:
diff changeset
384 if (coff_symstr_len > 0)
kono
parents:
diff changeset
385 {
kono
parents:
diff changeset
386 coff_symstr = ((char *)
kono
parents:
diff changeset
387 backtrace_alloc (state, coff_symstr_len, error_callback,
kono
parents:
diff changeset
388 data));
kono
parents:
diff changeset
389 if (coff_symstr == NULL)
kono
parents:
diff changeset
390 {
kono
parents:
diff changeset
391 backtrace_free (state, coff_symbols, coff_symbol_size,
kono
parents:
diff changeset
392 error_callback, data);
kono
parents:
diff changeset
393 return 0;
kono
parents:
diff changeset
394 }
kono
parents:
diff changeset
395 }
kono
parents:
diff changeset
396 else
kono
parents:
diff changeset
397 coff_symstr = NULL;
kono
parents:
diff changeset
398
kono
parents:
diff changeset
399 /* Copy symbols. */
kono
parents:
diff changeset
400 coff_sym = coff_symbols;
kono
parents:
diff changeset
401 coff_str = coff_symstr;
kono
parents:
diff changeset
402 for (i = 0; i < syms_count; ++i)
kono
parents:
diff changeset
403 {
kono
parents:
diff changeset
404 const b_coff_external_symbol *asym = &syms[i];
kono
parents:
diff changeset
405 b_coff_internal_symbol isym;
kono
parents:
diff changeset
406
kono
parents:
diff changeset
407 if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size))
kono
parents:
diff changeset
408 {
kono
parents:
diff changeset
409 /* Should not fail, as it was already tested in the previous
kono
parents:
diff changeset
410 loop. */
kono
parents:
diff changeset
411 abort ();
kono
parents:
diff changeset
412 }
kono
parents:
diff changeset
413 if (coff_is_function_symbol (&isym))
kono
parents:
diff changeset
414 {
kono
parents:
diff changeset
415 const char *name;
kono
parents:
diff changeset
416 int16_t secnum;
kono
parents:
diff changeset
417
kono
parents:
diff changeset
418 if (asym->name.short_name[0] != 0)
kono
parents:
diff changeset
419 {
kono
parents:
diff changeset
420 size_t len = coff_short_name_len (isym.name);
kono
parents:
diff changeset
421 name = coff_str;
kono
parents:
diff changeset
422 memcpy (coff_str, isym.name, len);
kono
parents:
diff changeset
423 coff_str[len] = 0;
kono
parents:
diff changeset
424 coff_str += len + 1;
kono
parents:
diff changeset
425 }
kono
parents:
diff changeset
426 else
kono
parents:
diff changeset
427 name = isym.name;
kono
parents:
diff changeset
428
kono
parents:
diff changeset
429 /* Strip leading '_'. */
kono
parents:
diff changeset
430 if (name[0] == '_')
kono
parents:
diff changeset
431 name++;
kono
parents:
diff changeset
432
kono
parents:
diff changeset
433 /* Symbol value is section relative, so we need to read the address
kono
parents:
diff changeset
434 of its section. */
kono
parents:
diff changeset
435 secnum = coff_read2 (asym->section_number);
kono
parents:
diff changeset
436
kono
parents:
diff changeset
437 coff_sym->name = name;
kono
parents:
diff changeset
438 coff_sym->address = (coff_read4 (asym->value)
kono
parents:
diff changeset
439 + sects[secnum - 1].virtual_address
kono
parents:
diff changeset
440 + base_address);
kono
parents:
diff changeset
441 coff_sym++;
kono
parents:
diff changeset
442 }
kono
parents:
diff changeset
443
kono
parents:
diff changeset
444 i += asym->number_of_aux_symbols;
kono
parents:
diff changeset
445 }
kono
parents:
diff changeset
446
kono
parents:
diff changeset
447 /* End of symbols marker. */
kono
parents:
diff changeset
448 coff_sym->name = NULL;
kono
parents:
diff changeset
449 coff_sym->address = -1;
kono
parents:
diff changeset
450
kono
parents:
diff changeset
451 backtrace_qsort (coff_symbols, coff_symbol_count,
kono
parents:
diff changeset
452 sizeof (struct coff_symbol), coff_symbol_compare);
kono
parents:
diff changeset
453
kono
parents:
diff changeset
454 sdata->next = NULL;
kono
parents:
diff changeset
455 sdata->symbols = coff_symbols;
kono
parents:
diff changeset
456 sdata->count = coff_symbol_count;
kono
parents:
diff changeset
457
kono
parents:
diff changeset
458 return 1;
kono
parents:
diff changeset
459 }
kono
parents:
diff changeset
460
kono
parents:
diff changeset
461 /* Add EDATA to the list in STATE. */
kono
parents:
diff changeset
462
kono
parents:
diff changeset
463 static void
kono
parents:
diff changeset
464 coff_add_syminfo_data (struct backtrace_state *state,
kono
parents:
diff changeset
465 struct coff_syminfo_data *sdata)
kono
parents:
diff changeset
466 {
kono
parents:
diff changeset
467 if (!state->threaded)
kono
parents:
diff changeset
468 {
kono
parents:
diff changeset
469 struct coff_syminfo_data **pp;
kono
parents:
diff changeset
470
kono
parents:
diff changeset
471 for (pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
kono
parents:
diff changeset
472 *pp != NULL;
kono
parents:
diff changeset
473 pp = &(*pp)->next)
kono
parents:
diff changeset
474 ;
kono
parents:
diff changeset
475 *pp = sdata;
kono
parents:
diff changeset
476 }
kono
parents:
diff changeset
477 else
kono
parents:
diff changeset
478 {
kono
parents:
diff changeset
479 while (1)
kono
parents:
diff changeset
480 {
kono
parents:
diff changeset
481 struct coff_syminfo_data **pp;
kono
parents:
diff changeset
482
kono
parents:
diff changeset
483 pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
kono
parents:
diff changeset
484
kono
parents:
diff changeset
485 while (1)
kono
parents:
diff changeset
486 {
kono
parents:
diff changeset
487 struct coff_syminfo_data *p;
kono
parents:
diff changeset
488
kono
parents:
diff changeset
489 p = backtrace_atomic_load_pointer (pp);
kono
parents:
diff changeset
490
kono
parents:
diff changeset
491 if (p == NULL)
kono
parents:
diff changeset
492 break;
kono
parents:
diff changeset
493
kono
parents:
diff changeset
494 pp = &p->next;
kono
parents:
diff changeset
495 }
kono
parents:
diff changeset
496
kono
parents:
diff changeset
497 if (__sync_bool_compare_and_swap (pp, NULL, sdata))
kono
parents:
diff changeset
498 break;
kono
parents:
diff changeset
499 }
kono
parents:
diff changeset
500 }
kono
parents:
diff changeset
501 }
kono
parents:
diff changeset
502
kono
parents:
diff changeset
503 /* Compare an ADDR against an elf_symbol for bsearch. We allocate one
kono
parents:
diff changeset
504 extra entry in the array so that this can look safely at the next
kono
parents:
diff changeset
505 entry. */
kono
parents:
diff changeset
506
kono
parents:
diff changeset
507 static int
kono
parents:
diff changeset
508 coff_symbol_search (const void *vkey, const void *ventry)
kono
parents:
diff changeset
509 {
kono
parents:
diff changeset
510 const uintptr_t *key = (const uintptr_t *) vkey;
kono
parents:
diff changeset
511 const struct coff_symbol *entry = (const struct coff_symbol *) ventry;
kono
parents:
diff changeset
512 uintptr_t addr;
kono
parents:
diff changeset
513
kono
parents:
diff changeset
514 addr = *key;
kono
parents:
diff changeset
515 if (addr < entry->address)
kono
parents:
diff changeset
516 return -1;
kono
parents:
diff changeset
517 else if (addr >= entry[1].address)
kono
parents:
diff changeset
518 return 1;
kono
parents:
diff changeset
519 else
kono
parents:
diff changeset
520 return 0;
kono
parents:
diff changeset
521 }
kono
parents:
diff changeset
522
kono
parents:
diff changeset
523 /* Return the symbol name and value for an ADDR. */
kono
parents:
diff changeset
524
kono
parents:
diff changeset
525 static void
kono
parents:
diff changeset
526 coff_syminfo (struct backtrace_state *state, uintptr_t addr,
kono
parents:
diff changeset
527 backtrace_syminfo_callback callback,
kono
parents:
diff changeset
528 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
529 void *data)
kono
parents:
diff changeset
530 {
kono
parents:
diff changeset
531 struct coff_syminfo_data *sdata;
kono
parents:
diff changeset
532 struct coff_symbol *sym = NULL;
kono
parents:
diff changeset
533
kono
parents:
diff changeset
534 if (!state->threaded)
kono
parents:
diff changeset
535 {
kono
parents:
diff changeset
536 for (sdata = (struct coff_syminfo_data *) state->syminfo_data;
kono
parents:
diff changeset
537 sdata != NULL;
kono
parents:
diff changeset
538 sdata = sdata->next)
kono
parents:
diff changeset
539 {
kono
parents:
diff changeset
540 sym = ((struct coff_symbol *)
kono
parents:
diff changeset
541 bsearch (&addr, sdata->symbols, sdata->count,
kono
parents:
diff changeset
542 sizeof (struct coff_symbol), coff_symbol_search));
kono
parents:
diff changeset
543 if (sym != NULL)
kono
parents:
diff changeset
544 break;
kono
parents:
diff changeset
545 }
kono
parents:
diff changeset
546 }
kono
parents:
diff changeset
547 else
kono
parents:
diff changeset
548 {
kono
parents:
diff changeset
549 struct coff_syminfo_data **pp;
kono
parents:
diff changeset
550
kono
parents:
diff changeset
551 pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
kono
parents:
diff changeset
552 while (1)
kono
parents:
diff changeset
553 {
kono
parents:
diff changeset
554 sdata = backtrace_atomic_load_pointer (pp);
kono
parents:
diff changeset
555 if (sdata == NULL)
kono
parents:
diff changeset
556 break;
kono
parents:
diff changeset
557
kono
parents:
diff changeset
558 sym = ((struct coff_symbol *)
kono
parents:
diff changeset
559 bsearch (&addr, sdata->symbols, sdata->count,
kono
parents:
diff changeset
560 sizeof (struct coff_symbol), coff_symbol_search));
kono
parents:
diff changeset
561 if (sym != NULL)
kono
parents:
diff changeset
562 break;
kono
parents:
diff changeset
563
kono
parents:
diff changeset
564 pp = &sdata->next;
kono
parents:
diff changeset
565 }
kono
parents:
diff changeset
566 }
kono
parents:
diff changeset
567
kono
parents:
diff changeset
568 if (sym == NULL)
kono
parents:
diff changeset
569 callback (data, addr, NULL, 0, 0);
kono
parents:
diff changeset
570 else
kono
parents:
diff changeset
571 callback (data, addr, sym->name, sym->address, 0);
kono
parents:
diff changeset
572 }
kono
parents:
diff changeset
573
kono
parents:
diff changeset
574 /* Add the backtrace data for one PE/COFF file. Returns 1 on success,
kono
parents:
diff changeset
575 0 on failure (in both cases descriptor is closed). */
kono
parents:
diff changeset
576
kono
parents:
diff changeset
577 static int
kono
parents:
diff changeset
578 coff_add (struct backtrace_state *state, int descriptor,
kono
parents:
diff changeset
579 backtrace_error_callback error_callback, void *data,
kono
parents:
diff changeset
580 fileline *fileline_fn, int *found_sym, int *found_dwarf)
kono
parents:
diff changeset
581 {
kono
parents:
diff changeset
582 struct backtrace_view fhdr_view;
kono
parents:
diff changeset
583 off_t fhdr_off;
kono
parents:
diff changeset
584 int magic_ok;
kono
parents:
diff changeset
585 b_coff_file_header fhdr;
kono
parents:
diff changeset
586 off_t opt_sects_off;
kono
parents:
diff changeset
587 size_t opt_sects_size;
kono
parents:
diff changeset
588 unsigned int sects_num;
kono
parents:
diff changeset
589 struct backtrace_view sects_view;
kono
parents:
diff changeset
590 int sects_view_valid;
kono
parents:
diff changeset
591 const b_coff_optional_header *opt_hdr;
kono
parents:
diff changeset
592 const b_coff_section_header *sects;
kono
parents:
diff changeset
593 struct backtrace_view str_view;
kono
parents:
diff changeset
594 int str_view_valid;
kono
parents:
diff changeset
595 size_t str_size;
kono
parents:
diff changeset
596 off_t str_off;
kono
parents:
diff changeset
597 struct backtrace_view syms_view;
kono
parents:
diff changeset
598 off_t syms_off;
kono
parents:
diff changeset
599 size_t syms_size;
kono
parents:
diff changeset
600 int syms_view_valid;
kono
parents:
diff changeset
601 unsigned int syms_num;
kono
parents:
diff changeset
602 unsigned int i;
kono
parents:
diff changeset
603 struct debug_section_info sections[DEBUG_MAX];
kono
parents:
diff changeset
604 off_t min_offset;
kono
parents:
diff changeset
605 off_t max_offset;
kono
parents:
diff changeset
606 struct backtrace_view debug_view;
kono
parents:
diff changeset
607 int debug_view_valid;
kono
parents:
diff changeset
608 uintptr_t image_base;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
609 struct dwarf_sections dwarf_sections;
111
kono
parents:
diff changeset
610
kono
parents:
diff changeset
611 *found_sym = 0;
kono
parents:
diff changeset
612 *found_dwarf = 0;
kono
parents:
diff changeset
613
kono
parents:
diff changeset
614 sects_view_valid = 0;
kono
parents:
diff changeset
615 syms_view_valid = 0;
kono
parents:
diff changeset
616 str_view_valid = 0;
kono
parents:
diff changeset
617 debug_view_valid = 0;
kono
parents:
diff changeset
618
kono
parents:
diff changeset
619 /* Map the MS-DOS stub (if any) and extract file header offset. */
kono
parents:
diff changeset
620 if (!backtrace_get_view (state, descriptor, 0, 0x40, error_callback,
kono
parents:
diff changeset
621 data, &fhdr_view))
kono
parents:
diff changeset
622 goto fail;
kono
parents:
diff changeset
623
kono
parents:
diff changeset
624 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
625 const unsigned char *vptr = fhdr_view.data;
111
kono
parents:
diff changeset
626
kono
parents:
diff changeset
627 if (vptr[0] == 'M' && vptr[1] == 'Z')
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
628 fhdr_off = coff_read4 (vptr + 0x3c);
111
kono
parents:
diff changeset
629 else
kono
parents:
diff changeset
630 fhdr_off = 0;
kono
parents:
diff changeset
631 }
kono
parents:
diff changeset
632
kono
parents:
diff changeset
633 backtrace_release_view (state, &fhdr_view, error_callback, data);
kono
parents:
diff changeset
634
kono
parents:
diff changeset
635 /* Map the coff file header. */
kono
parents:
diff changeset
636 if (!backtrace_get_view (state, descriptor, fhdr_off,
kono
parents:
diff changeset
637 sizeof (b_coff_file_header) + 4,
kono
parents:
diff changeset
638 error_callback, data, &fhdr_view))
kono
parents:
diff changeset
639 goto fail;
kono
parents:
diff changeset
640
kono
parents:
diff changeset
641 if (fhdr_off != 0)
kono
parents:
diff changeset
642 {
kono
parents:
diff changeset
643 const char *magic = (const char *) fhdr_view.data;
kono
parents:
diff changeset
644 magic_ok = memcmp (magic, "PE\0", 4) == 0;
kono
parents:
diff changeset
645 fhdr_off += 4;
kono
parents:
diff changeset
646
kono
parents:
diff changeset
647 memcpy (&fhdr, fhdr_view.data + 4, sizeof fhdr);
kono
parents:
diff changeset
648 }
kono
parents:
diff changeset
649 else
kono
parents:
diff changeset
650 {
kono
parents:
diff changeset
651 memcpy (&fhdr, fhdr_view.data, sizeof fhdr);
kono
parents:
diff changeset
652 /* TODO: test fhdr.machine for coff but non-PE platforms. */
kono
parents:
diff changeset
653 magic_ok = 0;
kono
parents:
diff changeset
654 }
kono
parents:
diff changeset
655 backtrace_release_view (state, &fhdr_view, error_callback, data);
kono
parents:
diff changeset
656
kono
parents:
diff changeset
657 if (!magic_ok)
kono
parents:
diff changeset
658 {
kono
parents:
diff changeset
659 error_callback (data, "executable file is not COFF", 0);
kono
parents:
diff changeset
660 goto fail;
kono
parents:
diff changeset
661 }
kono
parents:
diff changeset
662
kono
parents:
diff changeset
663 sects_num = fhdr.number_of_sections;
kono
parents:
diff changeset
664 syms_num = fhdr.number_of_symbols;
kono
parents:
diff changeset
665
kono
parents:
diff changeset
666 opt_sects_off = fhdr_off + sizeof (fhdr);
kono
parents:
diff changeset
667 opt_sects_size = (fhdr.size_of_optional_header
kono
parents:
diff changeset
668 + sects_num * sizeof (b_coff_section_header));
kono
parents:
diff changeset
669
kono
parents:
diff changeset
670 /* To translate PC to file/line when using DWARF, we need to find
kono
parents:
diff changeset
671 the .debug_info and .debug_line sections. */
kono
parents:
diff changeset
672
kono
parents:
diff changeset
673 /* Read the optional header and the section headers. */
kono
parents:
diff changeset
674
kono
parents:
diff changeset
675 if (!backtrace_get_view (state, descriptor, opt_sects_off, opt_sects_size,
kono
parents:
diff changeset
676 error_callback, data, &sects_view))
kono
parents:
diff changeset
677 goto fail;
kono
parents:
diff changeset
678 sects_view_valid = 1;
kono
parents:
diff changeset
679 opt_hdr = (const b_coff_optional_header *) sects_view.data;
kono
parents:
diff changeset
680 sects = (const b_coff_section_header *)
kono
parents:
diff changeset
681 (sects_view.data + fhdr.size_of_optional_header);
kono
parents:
diff changeset
682
kono
parents:
diff changeset
683 if (fhdr.size_of_optional_header > sizeof (*opt_hdr))
kono
parents:
diff changeset
684 {
kono
parents:
diff changeset
685 if (opt_hdr->magic == PE_MAGIC)
kono
parents:
diff changeset
686 image_base = opt_hdr->u.pe.image_base;
kono
parents:
diff changeset
687 else if (opt_hdr->magic == PEP_MAGIC)
kono
parents:
diff changeset
688 image_base = opt_hdr->u.pep.image_base;
kono
parents:
diff changeset
689 else
kono
parents:
diff changeset
690 {
kono
parents:
diff changeset
691 error_callback (data, "bad magic in PE optional header", 0);
kono
parents:
diff changeset
692 goto fail;
kono
parents:
diff changeset
693 }
kono
parents:
diff changeset
694 }
kono
parents:
diff changeset
695 else
kono
parents:
diff changeset
696 image_base = 0;
kono
parents:
diff changeset
697
kono
parents:
diff changeset
698 /* Read the symbol table and the string table. */
kono
parents:
diff changeset
699
kono
parents:
diff changeset
700 if (fhdr.pointer_to_symbol_table == 0)
kono
parents:
diff changeset
701 {
kono
parents:
diff changeset
702 /* No symbol table, no string table. */
kono
parents:
diff changeset
703 str_off = 0;
kono
parents:
diff changeset
704 str_size = 0;
kono
parents:
diff changeset
705 syms_num = 0;
kono
parents:
diff changeset
706 syms_size = 0;
kono
parents:
diff changeset
707 }
kono
parents:
diff changeset
708 else
kono
parents:
diff changeset
709 {
kono
parents:
diff changeset
710 /* Symbol table is followed by the string table. The string table
kono
parents:
diff changeset
711 starts with its length (on 4 bytes).
kono
parents:
diff changeset
712 Map the symbol table and the length of the string table. */
kono
parents:
diff changeset
713 syms_off = fhdr.pointer_to_symbol_table;
kono
parents:
diff changeset
714 syms_size = syms_num * SYM_SZ;
kono
parents:
diff changeset
715
kono
parents:
diff changeset
716 if (!backtrace_get_view (state, descriptor, syms_off, syms_size + 4,
kono
parents:
diff changeset
717 error_callback, data, &syms_view))
kono
parents:
diff changeset
718 goto fail;
kono
parents:
diff changeset
719 syms_view_valid = 1;
kono
parents:
diff changeset
720
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
721 str_size = coff_read4 (syms_view.data + syms_size);
111
kono
parents:
diff changeset
722
kono
parents:
diff changeset
723 str_off = syms_off + syms_size;
kono
parents:
diff changeset
724
kono
parents:
diff changeset
725 if (str_size > 4)
kono
parents:
diff changeset
726 {
kono
parents:
diff changeset
727 /* Map string table (including the length word). */
kono
parents:
diff changeset
728
kono
parents:
diff changeset
729 if (!backtrace_get_view (state, descriptor, str_off, str_size,
kono
parents:
diff changeset
730 error_callback, data, &str_view))
kono
parents:
diff changeset
731 goto fail;
kono
parents:
diff changeset
732 str_view_valid = 1;
kono
parents:
diff changeset
733 }
kono
parents:
diff changeset
734 }
kono
parents:
diff changeset
735
kono
parents:
diff changeset
736 memset (sections, 0, sizeof sections);
kono
parents:
diff changeset
737
kono
parents:
diff changeset
738 /* Look for the symbol table. */
kono
parents:
diff changeset
739 for (i = 0; i < sects_num; ++i)
kono
parents:
diff changeset
740 {
kono
parents:
diff changeset
741 const b_coff_section_header *s = sects + i;
kono
parents:
diff changeset
742 unsigned int str_off;
kono
parents:
diff changeset
743 int j;
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 if (s->name[0] == '/')
kono
parents:
diff changeset
746 {
kono
parents:
diff changeset
747 /* Extended section name. */
kono
parents:
diff changeset
748 str_off = atoi (s->name + 1);
kono
parents:
diff changeset
749 }
kono
parents:
diff changeset
750 else
kono
parents:
diff changeset
751 str_off = 0;
kono
parents:
diff changeset
752
kono
parents:
diff changeset
753 for (j = 0; j < (int) DEBUG_MAX; ++j)
kono
parents:
diff changeset
754 {
kono
parents:
diff changeset
755 const char *dbg_name = debug_section_names[j];
kono
parents:
diff changeset
756 int match;
kono
parents:
diff changeset
757
kono
parents:
diff changeset
758 if (str_off != 0)
kono
parents:
diff changeset
759 match = coff_long_name_eq (dbg_name, str_off, &str_view);
kono
parents:
diff changeset
760 else
kono
parents:
diff changeset
761 match = coff_short_name_eq (dbg_name, s->name);
kono
parents:
diff changeset
762 if (match)
kono
parents:
diff changeset
763 {
kono
parents:
diff changeset
764 sections[j].offset = s->pointer_to_raw_data;
kono
parents:
diff changeset
765 sections[j].size = s->virtual_size <= s->size_of_raw_data ?
kono
parents:
diff changeset
766 s->virtual_size : s->size_of_raw_data;
kono
parents:
diff changeset
767 break;
kono
parents:
diff changeset
768 }
kono
parents:
diff changeset
769 }
kono
parents:
diff changeset
770 }
kono
parents:
diff changeset
771
kono
parents:
diff changeset
772 if (syms_num != 0)
kono
parents:
diff changeset
773 {
kono
parents:
diff changeset
774 struct coff_syminfo_data *sdata;
kono
parents:
diff changeset
775
kono
parents:
diff changeset
776 sdata = ((struct coff_syminfo_data *)
kono
parents:
diff changeset
777 backtrace_alloc (state, sizeof *sdata, error_callback, data));
kono
parents:
diff changeset
778 if (sdata == NULL)
kono
parents:
diff changeset
779 goto fail;
kono
parents:
diff changeset
780
kono
parents:
diff changeset
781 if (!coff_initialize_syminfo (state, image_base,
kono
parents:
diff changeset
782 sects, sects_num,
kono
parents:
diff changeset
783 syms_view.data, syms_size,
kono
parents:
diff changeset
784 str_view.data, str_size,
kono
parents:
diff changeset
785 error_callback, data, sdata))
kono
parents:
diff changeset
786 {
kono
parents:
diff changeset
787 backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
kono
parents:
diff changeset
788 goto fail;
kono
parents:
diff changeset
789 }
kono
parents:
diff changeset
790
kono
parents:
diff changeset
791 *found_sym = 1;
kono
parents:
diff changeset
792
kono
parents:
diff changeset
793 coff_add_syminfo_data (state, sdata);
kono
parents:
diff changeset
794 }
kono
parents:
diff changeset
795
kono
parents:
diff changeset
796 backtrace_release_view (state, &sects_view, error_callback, data);
kono
parents:
diff changeset
797 sects_view_valid = 0;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
798 if (syms_view_valid)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
799 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
800 backtrace_release_view (state, &syms_view, error_callback, data);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
801 syms_view_valid = 0;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
802 }
111
kono
parents:
diff changeset
803
kono
parents:
diff changeset
804 /* Read all the debug sections in a single view, since they are
kono
parents:
diff changeset
805 probably adjacent in the file. We never release this view. */
kono
parents:
diff changeset
806
kono
parents:
diff changeset
807 min_offset = 0;
kono
parents:
diff changeset
808 max_offset = 0;
kono
parents:
diff changeset
809 for (i = 0; i < (int) DEBUG_MAX; ++i)
kono
parents:
diff changeset
810 {
kono
parents:
diff changeset
811 off_t end;
kono
parents:
diff changeset
812
kono
parents:
diff changeset
813 if (sections[i].size == 0)
kono
parents:
diff changeset
814 continue;
kono
parents:
diff changeset
815 if (min_offset == 0 || sections[i].offset < min_offset)
kono
parents:
diff changeset
816 min_offset = sections[i].offset;
kono
parents:
diff changeset
817 end = sections[i].offset + sections[i].size;
kono
parents:
diff changeset
818 if (end > max_offset)
kono
parents:
diff changeset
819 max_offset = end;
kono
parents:
diff changeset
820 }
kono
parents:
diff changeset
821 if (min_offset == 0 || max_offset == 0)
kono
parents:
diff changeset
822 {
kono
parents:
diff changeset
823 if (!backtrace_close (descriptor, error_callback, data))
kono
parents:
diff changeset
824 goto fail;
kono
parents:
diff changeset
825 *fileline_fn = coff_nodebug;
kono
parents:
diff changeset
826 return 1;
kono
parents:
diff changeset
827 }
kono
parents:
diff changeset
828
kono
parents:
diff changeset
829 if (!backtrace_get_view (state, descriptor, min_offset,
kono
parents:
diff changeset
830 max_offset - min_offset,
kono
parents:
diff changeset
831 error_callback, data, &debug_view))
kono
parents:
diff changeset
832 goto fail;
kono
parents:
diff changeset
833 debug_view_valid = 1;
kono
parents:
diff changeset
834
kono
parents:
diff changeset
835 /* We've read all we need from the executable. */
kono
parents:
diff changeset
836 if (!backtrace_close (descriptor, error_callback, data))
kono
parents:
diff changeset
837 goto fail;
kono
parents:
diff changeset
838 descriptor = -1;
kono
parents:
diff changeset
839
kono
parents:
diff changeset
840 for (i = 0; i < (int) DEBUG_MAX; ++i)
kono
parents:
diff changeset
841 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
842 size_t size = sections[i].size;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
843 dwarf_sections.size[i] = size;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
844 if (size == 0)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
845 dwarf_sections.data[i] = NULL;
111
kono
parents:
diff changeset
846 else
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
847 dwarf_sections.data[i] = ((const unsigned char *) debug_view.data
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
848 + (sections[i].offset - min_offset));
111
kono
parents:
diff changeset
849 }
kono
parents:
diff changeset
850
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
851 if (!backtrace_dwarf_add (state, /* base_address */ 0, &dwarf_sections,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
852 0, /* FIXME: is_bigendian */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
853 NULL, /* altlink */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
854 error_callback, data, fileline_fn,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
855 NULL /* returned fileline_entry */))
111
kono
parents:
diff changeset
856 goto fail;
kono
parents:
diff changeset
857
kono
parents:
diff changeset
858 *found_dwarf = 1;
kono
parents:
diff changeset
859
kono
parents:
diff changeset
860 return 1;
kono
parents:
diff changeset
861
kono
parents:
diff changeset
862 fail:
kono
parents:
diff changeset
863 if (sects_view_valid)
kono
parents:
diff changeset
864 backtrace_release_view (state, &sects_view, error_callback, data);
kono
parents:
diff changeset
865 if (str_view_valid)
kono
parents:
diff changeset
866 backtrace_release_view (state, &str_view, error_callback, data);
kono
parents:
diff changeset
867 if (syms_view_valid)
kono
parents:
diff changeset
868 backtrace_release_view (state, &syms_view, error_callback, data);
kono
parents:
diff changeset
869 if (debug_view_valid)
kono
parents:
diff changeset
870 backtrace_release_view (state, &debug_view, error_callback, data);
kono
parents:
diff changeset
871 if (descriptor != -1)
kono
parents:
diff changeset
872 backtrace_close (descriptor, error_callback, data);
kono
parents:
diff changeset
873 return 0;
kono
parents:
diff changeset
874 }
kono
parents:
diff changeset
875
kono
parents:
diff changeset
876 /* Initialize the backtrace data we need from an ELF executable. At
kono
parents:
diff changeset
877 the ELF level, all we need to do is find the debug info
kono
parents:
diff changeset
878 sections. */
kono
parents:
diff changeset
879
kono
parents:
diff changeset
880 int
kono
parents:
diff changeset
881 backtrace_initialize (struct backtrace_state *state,
kono
parents:
diff changeset
882 const char *filename ATTRIBUTE_UNUSED, int descriptor,
kono
parents:
diff changeset
883 backtrace_error_callback error_callback,
kono
parents:
diff changeset
884 void *data, fileline *fileline_fn)
kono
parents:
diff changeset
885 {
kono
parents:
diff changeset
886 int ret;
kono
parents:
diff changeset
887 int found_sym;
kono
parents:
diff changeset
888 int found_dwarf;
kono
parents:
diff changeset
889 fileline coff_fileline_fn;
kono
parents:
diff changeset
890
kono
parents:
diff changeset
891 ret = coff_add (state, descriptor, error_callback, data,
kono
parents:
diff changeset
892 &coff_fileline_fn, &found_sym, &found_dwarf);
kono
parents:
diff changeset
893 if (!ret)
kono
parents:
diff changeset
894 return 0;
kono
parents:
diff changeset
895
kono
parents:
diff changeset
896 if (!state->threaded)
kono
parents:
diff changeset
897 {
kono
parents:
diff changeset
898 if (found_sym)
kono
parents:
diff changeset
899 state->syminfo_fn = coff_syminfo;
kono
parents:
diff changeset
900 else if (state->syminfo_fn == NULL)
kono
parents:
diff changeset
901 state->syminfo_fn = coff_nosyms;
kono
parents:
diff changeset
902 }
kono
parents:
diff changeset
903 else
kono
parents:
diff changeset
904 {
kono
parents:
diff changeset
905 if (found_sym)
kono
parents:
diff changeset
906 backtrace_atomic_store_pointer (&state->syminfo_fn, coff_syminfo);
kono
parents:
diff changeset
907 else
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
908 (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
909 coff_nosyms);
111
kono
parents:
diff changeset
910 }
kono
parents:
diff changeset
911
kono
parents:
diff changeset
912 if (!state->threaded)
kono
parents:
diff changeset
913 {
kono
parents:
diff changeset
914 if (state->fileline_fn == NULL || state->fileline_fn == coff_nodebug)
kono
parents:
diff changeset
915 *fileline_fn = coff_fileline_fn;
kono
parents:
diff changeset
916 }
kono
parents:
diff changeset
917 else
kono
parents:
diff changeset
918 {
kono
parents:
diff changeset
919 fileline current_fn;
kono
parents:
diff changeset
920
kono
parents:
diff changeset
921 current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
kono
parents:
diff changeset
922 if (current_fn == NULL || current_fn == coff_nodebug)
kono
parents:
diff changeset
923 *fileline_fn = coff_fileline_fn;
kono
parents:
diff changeset
924 }
kono
parents:
diff changeset
925
kono
parents:
diff changeset
926 return 1;
kono
parents:
diff changeset
927 }