annotate libbacktrace/pecoff.c @ 118:fd00160c1b76

ifdef TARGET_64BIT
author mir3636
date Tue, 27 Feb 2018 15:01:35 +0900
parents 04ced10e8804
children 84e7813d76e9
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.
kono
parents:
diff changeset
2 Copyright (C) 2015-2017 Free Software Foundation, Inc.
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
kono
parents:
diff changeset
136 /* An index of sections we care about. */
kono
parents:
diff changeset
137
kono
parents:
diff changeset
138 enum debug_section
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,
kono
parents:
diff changeset
144 DEBUG_STR,
kono
parents:
diff changeset
145 DEBUG_MAX
kono
parents:
diff changeset
146 };
kono
parents:
diff changeset
147
kono
parents:
diff changeset
148 /* Names of sections, indexed by enum debug_section. */
kono
parents:
diff changeset
149
kono
parents:
diff changeset
150 static const char * const debug_section_names[DEBUG_MAX] =
kono
parents:
diff changeset
151 {
kono
parents:
diff changeset
152 ".debug_info",
kono
parents:
diff changeset
153 ".debug_line",
kono
parents:
diff changeset
154 ".debug_abbrev",
kono
parents:
diff changeset
155 ".debug_ranges",
kono
parents:
diff changeset
156 ".debug_str"
kono
parents:
diff changeset
157 };
kono
parents:
diff changeset
158
kono
parents:
diff changeset
159 /* Information we gather for the sections we care about. */
kono
parents:
diff changeset
160
kono
parents:
diff changeset
161 struct debug_section_info
kono
parents:
diff changeset
162 {
kono
parents:
diff changeset
163 /* Section file offset. */
kono
parents:
diff changeset
164 off_t offset;
kono
parents:
diff changeset
165 /* Section size. */
kono
parents:
diff changeset
166 size_t size;
kono
parents:
diff changeset
167 /* Section contents, after read from file. */
kono
parents:
diff changeset
168 const unsigned char *data;
kono
parents:
diff changeset
169 };
kono
parents:
diff changeset
170
kono
parents:
diff changeset
171 /* Information we keep for an coff symbol. */
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 struct coff_symbol
kono
parents:
diff changeset
174 {
kono
parents:
diff changeset
175 /* The name of the symbol. */
kono
parents:
diff changeset
176 const char *name;
kono
parents:
diff changeset
177 /* The address of the symbol. */
kono
parents:
diff changeset
178 uintptr_t address;
kono
parents:
diff changeset
179 };
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 /* Information to pass to coff_syminfo. */
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 struct coff_syminfo_data
kono
parents:
diff changeset
184 {
kono
parents:
diff changeset
185 /* Symbols for the next module. */
kono
parents:
diff changeset
186 struct coff_syminfo_data *next;
kono
parents:
diff changeset
187 /* The COFF symbols, sorted by address. */
kono
parents:
diff changeset
188 struct coff_symbol *symbols;
kono
parents:
diff changeset
189 /* The number of symbols. */
kono
parents:
diff changeset
190 size_t count;
kono
parents:
diff changeset
191 };
kono
parents:
diff changeset
192
kono
parents:
diff changeset
193 /* A dummy callback function used when we can't find any debug info. */
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 static int
kono
parents:
diff changeset
196 coff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
197 uintptr_t pc ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
198 backtrace_full_callback callback ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
199 backtrace_error_callback error_callback, void *data)
kono
parents:
diff changeset
200 {
kono
parents:
diff changeset
201 error_callback (data, "no debug info in PE/COFF executable", -1);
kono
parents:
diff changeset
202 return 0;
kono
parents:
diff changeset
203 }
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 /* A dummy callback function used when we can't find a symbol
kono
parents:
diff changeset
206 table. */
kono
parents:
diff changeset
207
kono
parents:
diff changeset
208 static void
kono
parents:
diff changeset
209 coff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
210 uintptr_t addr ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
211 backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
212 backtrace_error_callback error_callback, void *data)
kono
parents:
diff changeset
213 {
kono
parents:
diff changeset
214 error_callback (data, "no symbol table in PE/COFF executable", -1);
kono
parents:
diff changeset
215 }
kono
parents:
diff changeset
216
kono
parents:
diff changeset
217 /* Read a potentially unaligned 4 byte word at P, using native endianness. */
kono
parents:
diff changeset
218
kono
parents:
diff changeset
219 static uint32_t
kono
parents:
diff changeset
220 coff_read4 (const unsigned char *p)
kono
parents:
diff changeset
221 {
kono
parents:
diff changeset
222 uint32_t res;
kono
parents:
diff changeset
223
kono
parents:
diff changeset
224 memcpy (&res, p, 4);
kono
parents:
diff changeset
225 return res;
kono
parents:
diff changeset
226 }
kono
parents:
diff changeset
227
kono
parents:
diff changeset
228 /* Read a potentially unaligned 2 byte word at P, using native endianness.
kono
parents:
diff changeset
229 All 2 byte word in symbols are always aligned, but for coherency all
kono
parents:
diff changeset
230 fields are declared as char arrays. */
kono
parents:
diff changeset
231
kono
parents:
diff changeset
232 static uint16_t
kono
parents:
diff changeset
233 coff_read2 (const unsigned char *p)
kono
parents:
diff changeset
234 {
kono
parents:
diff changeset
235 uint16_t res;
kono
parents:
diff changeset
236
kono
parents:
diff changeset
237 memcpy (&res, p, sizeof (res));
kono
parents:
diff changeset
238 return res;
kono
parents:
diff changeset
239 }
kono
parents:
diff changeset
240
kono
parents:
diff changeset
241 /* Return the length (without the trailing 0) of a COFF short name. */
kono
parents:
diff changeset
242
kono
parents:
diff changeset
243 static size_t
kono
parents:
diff changeset
244 coff_short_name_len (const char *name)
kono
parents:
diff changeset
245 {
kono
parents:
diff changeset
246 int i;
kono
parents:
diff changeset
247
kono
parents:
diff changeset
248 for (i = 0; i < 8; i++)
kono
parents:
diff changeset
249 if (name[i] == 0)
kono
parents:
diff changeset
250 return i;
kono
parents:
diff changeset
251 return 8;
kono
parents:
diff changeset
252 }
kono
parents:
diff changeset
253
kono
parents:
diff changeset
254 /* Return true iff COFF short name CNAME is the same as NAME (a NUL-terminated
kono
parents:
diff changeset
255 string). */
kono
parents:
diff changeset
256
kono
parents:
diff changeset
257 static int
kono
parents:
diff changeset
258 coff_short_name_eq (const char *name, const char *cname)
kono
parents:
diff changeset
259 {
kono
parents:
diff changeset
260 int i;
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 for (i = 0; i < 8; i++)
kono
parents:
diff changeset
263 {
kono
parents:
diff changeset
264 if (name[i] != cname[i])
kono
parents:
diff changeset
265 return 0;
kono
parents:
diff changeset
266 if (name[i] == 0)
kono
parents:
diff changeset
267 return 1;
kono
parents:
diff changeset
268 }
kono
parents:
diff changeset
269 return name[8] == 0;
kono
parents:
diff changeset
270 }
kono
parents:
diff changeset
271
kono
parents:
diff changeset
272 /* Return true iff NAME is the same as string at offset OFF. */
kono
parents:
diff changeset
273
kono
parents:
diff changeset
274 static int
kono
parents:
diff changeset
275 coff_long_name_eq (const char *name, unsigned int off,
kono
parents:
diff changeset
276 struct backtrace_view *str_view)
kono
parents:
diff changeset
277 {
kono
parents:
diff changeset
278 if (off >= str_view->len)
kono
parents:
diff changeset
279 return 0;
kono
parents:
diff changeset
280 return strcmp (name, (const char *)str_view->data + off) == 0;
kono
parents:
diff changeset
281 }
kono
parents:
diff changeset
282
kono
parents:
diff changeset
283 /* Compare struct coff_symbol for qsort. */
kono
parents:
diff changeset
284
kono
parents:
diff changeset
285 static int
kono
parents:
diff changeset
286 coff_symbol_compare (const void *v1, const void *v2)
kono
parents:
diff changeset
287 {
kono
parents:
diff changeset
288 const struct coff_symbol *e1 = (const struct coff_symbol *) v1;
kono
parents:
diff changeset
289 const struct coff_symbol *e2 = (const struct coff_symbol *) v2;
kono
parents:
diff changeset
290
kono
parents:
diff changeset
291 if (e1->address < e2->address)
kono
parents:
diff changeset
292 return -1;
kono
parents:
diff changeset
293 else if (e1->address > e2->address)
kono
parents:
diff changeset
294 return 1;
kono
parents:
diff changeset
295 else
kono
parents:
diff changeset
296 return 0;
kono
parents:
diff changeset
297 }
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 /* Convert SYM to internal (and aligned) format ISYM, using string table
kono
parents:
diff changeset
300 from STRTAB and STRTAB_SIZE, and number of sections SECTS_NUM.
kono
parents:
diff changeset
301 Return -1 in case of error (invalid section number or string index). */
kono
parents:
diff changeset
302
kono
parents:
diff changeset
303 static int
kono
parents:
diff changeset
304 coff_expand_symbol (b_coff_internal_symbol *isym,
kono
parents:
diff changeset
305 const b_coff_external_symbol *sym,
kono
parents:
diff changeset
306 uint16_t sects_num,
kono
parents:
diff changeset
307 const unsigned char *strtab, size_t strtab_size)
kono
parents:
diff changeset
308 {
kono
parents:
diff changeset
309 isym->type = coff_read2 (sym->type);
kono
parents:
diff changeset
310 isym->sec = coff_read2 (sym->section_number);
kono
parents:
diff changeset
311 isym->sc = sym->storage_class;
kono
parents:
diff changeset
312
kono
parents:
diff changeset
313 if (isym->sec > 0 && (uint16_t) isym->sec > sects_num)
kono
parents:
diff changeset
314 return -1;
kono
parents:
diff changeset
315 if (sym->name.short_name[0] != 0)
kono
parents:
diff changeset
316 isym->name = sym->name.short_name;
kono
parents:
diff changeset
317 else
kono
parents:
diff changeset
318 {
kono
parents:
diff changeset
319 uint32_t off = coff_read4 (sym->name.long_name.off);
kono
parents:
diff changeset
320
kono
parents:
diff changeset
321 if (off >= strtab_size)
kono
parents:
diff changeset
322 return -1;
kono
parents:
diff changeset
323 isym->name = (const char *) strtab + off;
kono
parents:
diff changeset
324 }
kono
parents:
diff changeset
325 return 0;
kono
parents:
diff changeset
326 }
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 /* Return true iff SYM is a defined symbol for a function. Data symbols
kono
parents:
diff changeset
329 aren't considered because they aren't easily identified (same type as
kono
parents:
diff changeset
330 section names, presence of symbols defined by the linker script). */
kono
parents:
diff changeset
331
kono
parents:
diff changeset
332 static int
kono
parents:
diff changeset
333 coff_is_function_symbol (const b_coff_internal_symbol *isym)
kono
parents:
diff changeset
334 {
kono
parents:
diff changeset
335 return (isym->type >> N_TBSHFT) == IMAGE_SYM_DTYPE_FUNCTION
kono
parents:
diff changeset
336 && isym->sec > 0;
kono
parents:
diff changeset
337 }
kono
parents:
diff changeset
338
kono
parents:
diff changeset
339 /* Initialize the symbol table info for coff_syminfo. */
kono
parents:
diff changeset
340
kono
parents:
diff changeset
341 static int
kono
parents:
diff changeset
342 coff_initialize_syminfo (struct backtrace_state *state,
kono
parents:
diff changeset
343 uintptr_t base_address,
kono
parents:
diff changeset
344 const b_coff_section_header *sects, size_t sects_num,
kono
parents:
diff changeset
345 const b_coff_external_symbol *syms, size_t syms_size,
kono
parents:
diff changeset
346 const unsigned char *strtab, size_t strtab_size,
kono
parents:
diff changeset
347 backtrace_error_callback error_callback,
kono
parents:
diff changeset
348 void *data, struct coff_syminfo_data *sdata)
kono
parents:
diff changeset
349 {
kono
parents:
diff changeset
350 size_t syms_count;
kono
parents:
diff changeset
351 char *coff_symstr;
kono
parents:
diff changeset
352 size_t coff_symstr_len;
kono
parents:
diff changeset
353 size_t coff_symbol_count;
kono
parents:
diff changeset
354 size_t coff_symbol_size;
kono
parents:
diff changeset
355 struct coff_symbol *coff_symbols;
kono
parents:
diff changeset
356 struct coff_symbol *coff_sym;
kono
parents:
diff changeset
357 char *coff_str;
kono
parents:
diff changeset
358 size_t i;
kono
parents:
diff changeset
359
kono
parents:
diff changeset
360 syms_count = syms_size / SYM_SZ;
kono
parents:
diff changeset
361
kono
parents:
diff changeset
362 /* We only care about function symbols. Count them. Also count size of
kono
parents:
diff changeset
363 strings for in-symbol names. */
kono
parents:
diff changeset
364 coff_symbol_count = 0;
kono
parents:
diff changeset
365 coff_symstr_len = 0;
kono
parents:
diff changeset
366 for (i = 0; i < syms_count; ++i)
kono
parents:
diff changeset
367 {
kono
parents:
diff changeset
368 const b_coff_external_symbol *asym = &syms[i];
kono
parents:
diff changeset
369 b_coff_internal_symbol isym;
kono
parents:
diff changeset
370
kono
parents:
diff changeset
371 if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size) < 0)
kono
parents:
diff changeset
372 {
kono
parents:
diff changeset
373 error_callback (data, "invalid section or offset in coff symbol", 0);
kono
parents:
diff changeset
374 return 0;
kono
parents:
diff changeset
375 }
kono
parents:
diff changeset
376 if (coff_is_function_symbol (&isym))
kono
parents:
diff changeset
377 {
kono
parents:
diff changeset
378 ++coff_symbol_count;
kono
parents:
diff changeset
379 if (asym->name.short_name[0] != 0)
kono
parents:
diff changeset
380 coff_symstr_len += coff_short_name_len (asym->name.short_name) + 1;
kono
parents:
diff changeset
381 }
kono
parents:
diff changeset
382
kono
parents:
diff changeset
383 i += asym->number_of_aux_symbols;
kono
parents:
diff changeset
384 }
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 coff_symbol_size = (coff_symbol_count + 1) * sizeof (struct coff_symbol);
kono
parents:
diff changeset
387 coff_symbols = ((struct coff_symbol *)
kono
parents:
diff changeset
388 backtrace_alloc (state, coff_symbol_size, error_callback,
kono
parents:
diff changeset
389 data));
kono
parents:
diff changeset
390 if (coff_symbols == NULL)
kono
parents:
diff changeset
391 return 0;
kono
parents:
diff changeset
392
kono
parents:
diff changeset
393 /* Allocate memory for symbols strings. */
kono
parents:
diff changeset
394 if (coff_symstr_len > 0)
kono
parents:
diff changeset
395 {
kono
parents:
diff changeset
396 coff_symstr = ((char *)
kono
parents:
diff changeset
397 backtrace_alloc (state, coff_symstr_len, error_callback,
kono
parents:
diff changeset
398 data));
kono
parents:
diff changeset
399 if (coff_symstr == NULL)
kono
parents:
diff changeset
400 {
kono
parents:
diff changeset
401 backtrace_free (state, coff_symbols, coff_symbol_size,
kono
parents:
diff changeset
402 error_callback, data);
kono
parents:
diff changeset
403 return 0;
kono
parents:
diff changeset
404 }
kono
parents:
diff changeset
405 }
kono
parents:
diff changeset
406 else
kono
parents:
diff changeset
407 coff_symstr = NULL;
kono
parents:
diff changeset
408
kono
parents:
diff changeset
409 /* Copy symbols. */
kono
parents:
diff changeset
410 coff_sym = coff_symbols;
kono
parents:
diff changeset
411 coff_str = coff_symstr;
kono
parents:
diff changeset
412 for (i = 0; i < syms_count; ++i)
kono
parents:
diff changeset
413 {
kono
parents:
diff changeset
414 const b_coff_external_symbol *asym = &syms[i];
kono
parents:
diff changeset
415 b_coff_internal_symbol isym;
kono
parents:
diff changeset
416
kono
parents:
diff changeset
417 if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size))
kono
parents:
diff changeset
418 {
kono
parents:
diff changeset
419 /* Should not fail, as it was already tested in the previous
kono
parents:
diff changeset
420 loop. */
kono
parents:
diff changeset
421 abort ();
kono
parents:
diff changeset
422 }
kono
parents:
diff changeset
423 if (coff_is_function_symbol (&isym))
kono
parents:
diff changeset
424 {
kono
parents:
diff changeset
425 const char *name;
kono
parents:
diff changeset
426 int16_t secnum;
kono
parents:
diff changeset
427
kono
parents:
diff changeset
428 if (asym->name.short_name[0] != 0)
kono
parents:
diff changeset
429 {
kono
parents:
diff changeset
430 size_t len = coff_short_name_len (isym.name);
kono
parents:
diff changeset
431 name = coff_str;
kono
parents:
diff changeset
432 memcpy (coff_str, isym.name, len);
kono
parents:
diff changeset
433 coff_str[len] = 0;
kono
parents:
diff changeset
434 coff_str += len + 1;
kono
parents:
diff changeset
435 }
kono
parents:
diff changeset
436 else
kono
parents:
diff changeset
437 name = isym.name;
kono
parents:
diff changeset
438
kono
parents:
diff changeset
439 /* Strip leading '_'. */
kono
parents:
diff changeset
440 if (name[0] == '_')
kono
parents:
diff changeset
441 name++;
kono
parents:
diff changeset
442
kono
parents:
diff changeset
443 /* Symbol value is section relative, so we need to read the address
kono
parents:
diff changeset
444 of its section. */
kono
parents:
diff changeset
445 secnum = coff_read2 (asym->section_number);
kono
parents:
diff changeset
446
kono
parents:
diff changeset
447 coff_sym->name = name;
kono
parents:
diff changeset
448 coff_sym->address = (coff_read4 (asym->value)
kono
parents:
diff changeset
449 + sects[secnum - 1].virtual_address
kono
parents:
diff changeset
450 + base_address);
kono
parents:
diff changeset
451 coff_sym++;
kono
parents:
diff changeset
452 }
kono
parents:
diff changeset
453
kono
parents:
diff changeset
454 i += asym->number_of_aux_symbols;
kono
parents:
diff changeset
455 }
kono
parents:
diff changeset
456
kono
parents:
diff changeset
457 /* End of symbols marker. */
kono
parents:
diff changeset
458 coff_sym->name = NULL;
kono
parents:
diff changeset
459 coff_sym->address = -1;
kono
parents:
diff changeset
460
kono
parents:
diff changeset
461 backtrace_qsort (coff_symbols, coff_symbol_count,
kono
parents:
diff changeset
462 sizeof (struct coff_symbol), coff_symbol_compare);
kono
parents:
diff changeset
463
kono
parents:
diff changeset
464 sdata->next = NULL;
kono
parents:
diff changeset
465 sdata->symbols = coff_symbols;
kono
parents:
diff changeset
466 sdata->count = coff_symbol_count;
kono
parents:
diff changeset
467
kono
parents:
diff changeset
468 return 1;
kono
parents:
diff changeset
469 }
kono
parents:
diff changeset
470
kono
parents:
diff changeset
471 /* Add EDATA to the list in STATE. */
kono
parents:
diff changeset
472
kono
parents:
diff changeset
473 static void
kono
parents:
diff changeset
474 coff_add_syminfo_data (struct backtrace_state *state,
kono
parents:
diff changeset
475 struct coff_syminfo_data *sdata)
kono
parents:
diff changeset
476 {
kono
parents:
diff changeset
477 if (!state->threaded)
kono
parents:
diff changeset
478 {
kono
parents:
diff changeset
479 struct coff_syminfo_data **pp;
kono
parents:
diff changeset
480
kono
parents:
diff changeset
481 for (pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
kono
parents:
diff changeset
482 *pp != NULL;
kono
parents:
diff changeset
483 pp = &(*pp)->next)
kono
parents:
diff changeset
484 ;
kono
parents:
diff changeset
485 *pp = sdata;
kono
parents:
diff changeset
486 }
kono
parents:
diff changeset
487 else
kono
parents:
diff changeset
488 {
kono
parents:
diff changeset
489 while (1)
kono
parents:
diff changeset
490 {
kono
parents:
diff changeset
491 struct coff_syminfo_data **pp;
kono
parents:
diff changeset
492
kono
parents:
diff changeset
493 pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
kono
parents:
diff changeset
494
kono
parents:
diff changeset
495 while (1)
kono
parents:
diff changeset
496 {
kono
parents:
diff changeset
497 struct coff_syminfo_data *p;
kono
parents:
diff changeset
498
kono
parents:
diff changeset
499 p = backtrace_atomic_load_pointer (pp);
kono
parents:
diff changeset
500
kono
parents:
diff changeset
501 if (p == NULL)
kono
parents:
diff changeset
502 break;
kono
parents:
diff changeset
503
kono
parents:
diff changeset
504 pp = &p->next;
kono
parents:
diff changeset
505 }
kono
parents:
diff changeset
506
kono
parents:
diff changeset
507 if (__sync_bool_compare_and_swap (pp, NULL, sdata))
kono
parents:
diff changeset
508 break;
kono
parents:
diff changeset
509 }
kono
parents:
diff changeset
510 }
kono
parents:
diff changeset
511 }
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513 /* Compare an ADDR against an elf_symbol for bsearch. We allocate one
kono
parents:
diff changeset
514 extra entry in the array so that this can look safely at the next
kono
parents:
diff changeset
515 entry. */
kono
parents:
diff changeset
516
kono
parents:
diff changeset
517 static int
kono
parents:
diff changeset
518 coff_symbol_search (const void *vkey, const void *ventry)
kono
parents:
diff changeset
519 {
kono
parents:
diff changeset
520 const uintptr_t *key = (const uintptr_t *) vkey;
kono
parents:
diff changeset
521 const struct coff_symbol *entry = (const struct coff_symbol *) ventry;
kono
parents:
diff changeset
522 uintptr_t addr;
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 addr = *key;
kono
parents:
diff changeset
525 if (addr < entry->address)
kono
parents:
diff changeset
526 return -1;
kono
parents:
diff changeset
527 else if (addr >= entry[1].address)
kono
parents:
diff changeset
528 return 1;
kono
parents:
diff changeset
529 else
kono
parents:
diff changeset
530 return 0;
kono
parents:
diff changeset
531 }
kono
parents:
diff changeset
532
kono
parents:
diff changeset
533 /* Return the symbol name and value for an ADDR. */
kono
parents:
diff changeset
534
kono
parents:
diff changeset
535 static void
kono
parents:
diff changeset
536 coff_syminfo (struct backtrace_state *state, uintptr_t addr,
kono
parents:
diff changeset
537 backtrace_syminfo_callback callback,
kono
parents:
diff changeset
538 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
539 void *data)
kono
parents:
diff changeset
540 {
kono
parents:
diff changeset
541 struct coff_syminfo_data *sdata;
kono
parents:
diff changeset
542 struct coff_symbol *sym = NULL;
kono
parents:
diff changeset
543
kono
parents:
diff changeset
544 if (!state->threaded)
kono
parents:
diff changeset
545 {
kono
parents:
diff changeset
546 for (sdata = (struct coff_syminfo_data *) state->syminfo_data;
kono
parents:
diff changeset
547 sdata != NULL;
kono
parents:
diff changeset
548 sdata = sdata->next)
kono
parents:
diff changeset
549 {
kono
parents:
diff changeset
550 sym = ((struct coff_symbol *)
kono
parents:
diff changeset
551 bsearch (&addr, sdata->symbols, sdata->count,
kono
parents:
diff changeset
552 sizeof (struct coff_symbol), coff_symbol_search));
kono
parents:
diff changeset
553 if (sym != NULL)
kono
parents:
diff changeset
554 break;
kono
parents:
diff changeset
555 }
kono
parents:
diff changeset
556 }
kono
parents:
diff changeset
557 else
kono
parents:
diff changeset
558 {
kono
parents:
diff changeset
559 struct coff_syminfo_data **pp;
kono
parents:
diff changeset
560
kono
parents:
diff changeset
561 pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
kono
parents:
diff changeset
562 while (1)
kono
parents:
diff changeset
563 {
kono
parents:
diff changeset
564 sdata = backtrace_atomic_load_pointer (pp);
kono
parents:
diff changeset
565 if (sdata == NULL)
kono
parents:
diff changeset
566 break;
kono
parents:
diff changeset
567
kono
parents:
diff changeset
568 sym = ((struct coff_symbol *)
kono
parents:
diff changeset
569 bsearch (&addr, sdata->symbols, sdata->count,
kono
parents:
diff changeset
570 sizeof (struct coff_symbol), coff_symbol_search));
kono
parents:
diff changeset
571 if (sym != NULL)
kono
parents:
diff changeset
572 break;
kono
parents:
diff changeset
573
kono
parents:
diff changeset
574 pp = &sdata->next;
kono
parents:
diff changeset
575 }
kono
parents:
diff changeset
576 }
kono
parents:
diff changeset
577
kono
parents:
diff changeset
578 if (sym == NULL)
kono
parents:
diff changeset
579 callback (data, addr, NULL, 0, 0);
kono
parents:
diff changeset
580 else
kono
parents:
diff changeset
581 callback (data, addr, sym->name, sym->address, 0);
kono
parents:
diff changeset
582 }
kono
parents:
diff changeset
583
kono
parents:
diff changeset
584 /* Add the backtrace data for one PE/COFF file. Returns 1 on success,
kono
parents:
diff changeset
585 0 on failure (in both cases descriptor is closed). */
kono
parents:
diff changeset
586
kono
parents:
diff changeset
587 static int
kono
parents:
diff changeset
588 coff_add (struct backtrace_state *state, int descriptor,
kono
parents:
diff changeset
589 backtrace_error_callback error_callback, void *data,
kono
parents:
diff changeset
590 fileline *fileline_fn, int *found_sym, int *found_dwarf)
kono
parents:
diff changeset
591 {
kono
parents:
diff changeset
592 struct backtrace_view fhdr_view;
kono
parents:
diff changeset
593 off_t fhdr_off;
kono
parents:
diff changeset
594 int magic_ok;
kono
parents:
diff changeset
595 b_coff_file_header fhdr;
kono
parents:
diff changeset
596 off_t opt_sects_off;
kono
parents:
diff changeset
597 size_t opt_sects_size;
kono
parents:
diff changeset
598 unsigned int sects_num;
kono
parents:
diff changeset
599 struct backtrace_view sects_view;
kono
parents:
diff changeset
600 int sects_view_valid;
kono
parents:
diff changeset
601 const b_coff_optional_header *opt_hdr;
kono
parents:
diff changeset
602 const b_coff_section_header *sects;
kono
parents:
diff changeset
603 struct backtrace_view str_view;
kono
parents:
diff changeset
604 int str_view_valid;
kono
parents:
diff changeset
605 size_t str_size;
kono
parents:
diff changeset
606 off_t str_off;
kono
parents:
diff changeset
607 struct backtrace_view syms_view;
kono
parents:
diff changeset
608 off_t syms_off;
kono
parents:
diff changeset
609 size_t syms_size;
kono
parents:
diff changeset
610 int syms_view_valid;
kono
parents:
diff changeset
611 unsigned int syms_num;
kono
parents:
diff changeset
612 unsigned int i;
kono
parents:
diff changeset
613 struct debug_section_info sections[DEBUG_MAX];
kono
parents:
diff changeset
614 off_t min_offset;
kono
parents:
diff changeset
615 off_t max_offset;
kono
parents:
diff changeset
616 struct backtrace_view debug_view;
kono
parents:
diff changeset
617 int debug_view_valid;
kono
parents:
diff changeset
618 uintptr_t image_base;
kono
parents:
diff changeset
619
kono
parents:
diff changeset
620 *found_sym = 0;
kono
parents:
diff changeset
621 *found_dwarf = 0;
kono
parents:
diff changeset
622
kono
parents:
diff changeset
623 sects_view_valid = 0;
kono
parents:
diff changeset
624 syms_view_valid = 0;
kono
parents:
diff changeset
625 str_view_valid = 0;
kono
parents:
diff changeset
626 debug_view_valid = 0;
kono
parents:
diff changeset
627
kono
parents:
diff changeset
628 /* Map the MS-DOS stub (if any) and extract file header offset. */
kono
parents:
diff changeset
629 if (!backtrace_get_view (state, descriptor, 0, 0x40, error_callback,
kono
parents:
diff changeset
630 data, &fhdr_view))
kono
parents:
diff changeset
631 goto fail;
kono
parents:
diff changeset
632
kono
parents:
diff changeset
633 {
kono
parents:
diff changeset
634 const char *vptr = (const char *)fhdr_view.data;
kono
parents:
diff changeset
635
kono
parents:
diff changeset
636 if (vptr[0] == 'M' && vptr[1] == 'Z')
kono
parents:
diff changeset
637 memcpy (&fhdr_off, vptr + 0x3c, 4);
kono
parents:
diff changeset
638 else
kono
parents:
diff changeset
639 fhdr_off = 0;
kono
parents:
diff changeset
640 }
kono
parents:
diff changeset
641
kono
parents:
diff changeset
642 backtrace_release_view (state, &fhdr_view, error_callback, data);
kono
parents:
diff changeset
643
kono
parents:
diff changeset
644 /* Map the coff file header. */
kono
parents:
diff changeset
645 if (!backtrace_get_view (state, descriptor, fhdr_off,
kono
parents:
diff changeset
646 sizeof (b_coff_file_header) + 4,
kono
parents:
diff changeset
647 error_callback, data, &fhdr_view))
kono
parents:
diff changeset
648 goto fail;
kono
parents:
diff changeset
649
kono
parents:
diff changeset
650 if (fhdr_off != 0)
kono
parents:
diff changeset
651 {
kono
parents:
diff changeset
652 const char *magic = (const char *) fhdr_view.data;
kono
parents:
diff changeset
653 magic_ok = memcmp (magic, "PE\0", 4) == 0;
kono
parents:
diff changeset
654 fhdr_off += 4;
kono
parents:
diff changeset
655
kono
parents:
diff changeset
656 memcpy (&fhdr, fhdr_view.data + 4, sizeof fhdr);
kono
parents:
diff changeset
657 }
kono
parents:
diff changeset
658 else
kono
parents:
diff changeset
659 {
kono
parents:
diff changeset
660 memcpy (&fhdr, fhdr_view.data, sizeof fhdr);
kono
parents:
diff changeset
661 /* TODO: test fhdr.machine for coff but non-PE platforms. */
kono
parents:
diff changeset
662 magic_ok = 0;
kono
parents:
diff changeset
663 }
kono
parents:
diff changeset
664 backtrace_release_view (state, &fhdr_view, error_callback, data);
kono
parents:
diff changeset
665
kono
parents:
diff changeset
666 if (!magic_ok)
kono
parents:
diff changeset
667 {
kono
parents:
diff changeset
668 error_callback (data, "executable file is not COFF", 0);
kono
parents:
diff changeset
669 goto fail;
kono
parents:
diff changeset
670 }
kono
parents:
diff changeset
671
kono
parents:
diff changeset
672 sects_num = fhdr.number_of_sections;
kono
parents:
diff changeset
673 syms_num = fhdr.number_of_symbols;
kono
parents:
diff changeset
674
kono
parents:
diff changeset
675 opt_sects_off = fhdr_off + sizeof (fhdr);
kono
parents:
diff changeset
676 opt_sects_size = (fhdr.size_of_optional_header
kono
parents:
diff changeset
677 + sects_num * sizeof (b_coff_section_header));
kono
parents:
diff changeset
678
kono
parents:
diff changeset
679 /* To translate PC to file/line when using DWARF, we need to find
kono
parents:
diff changeset
680 the .debug_info and .debug_line sections. */
kono
parents:
diff changeset
681
kono
parents:
diff changeset
682 /* Read the optional header and the section headers. */
kono
parents:
diff changeset
683
kono
parents:
diff changeset
684 if (!backtrace_get_view (state, descriptor, opt_sects_off, opt_sects_size,
kono
parents:
diff changeset
685 error_callback, data, &sects_view))
kono
parents:
diff changeset
686 goto fail;
kono
parents:
diff changeset
687 sects_view_valid = 1;
kono
parents:
diff changeset
688 opt_hdr = (const b_coff_optional_header *) sects_view.data;
kono
parents:
diff changeset
689 sects = (const b_coff_section_header *)
kono
parents:
diff changeset
690 (sects_view.data + fhdr.size_of_optional_header);
kono
parents:
diff changeset
691
kono
parents:
diff changeset
692 if (fhdr.size_of_optional_header > sizeof (*opt_hdr))
kono
parents:
diff changeset
693 {
kono
parents:
diff changeset
694 if (opt_hdr->magic == PE_MAGIC)
kono
parents:
diff changeset
695 image_base = opt_hdr->u.pe.image_base;
kono
parents:
diff changeset
696 else if (opt_hdr->magic == PEP_MAGIC)
kono
parents:
diff changeset
697 image_base = opt_hdr->u.pep.image_base;
kono
parents:
diff changeset
698 else
kono
parents:
diff changeset
699 {
kono
parents:
diff changeset
700 error_callback (data, "bad magic in PE optional header", 0);
kono
parents:
diff changeset
701 goto fail;
kono
parents:
diff changeset
702 }
kono
parents:
diff changeset
703 }
kono
parents:
diff changeset
704 else
kono
parents:
diff changeset
705 image_base = 0;
kono
parents:
diff changeset
706
kono
parents:
diff changeset
707 /* Read the symbol table and the string table. */
kono
parents:
diff changeset
708
kono
parents:
diff changeset
709 if (fhdr.pointer_to_symbol_table == 0)
kono
parents:
diff changeset
710 {
kono
parents:
diff changeset
711 /* No symbol table, no string table. */
kono
parents:
diff changeset
712 str_off = 0;
kono
parents:
diff changeset
713 str_size = 0;
kono
parents:
diff changeset
714 syms_num = 0;
kono
parents:
diff changeset
715 syms_size = 0;
kono
parents:
diff changeset
716 }
kono
parents:
diff changeset
717 else
kono
parents:
diff changeset
718 {
kono
parents:
diff changeset
719 /* Symbol table is followed by the string table. The string table
kono
parents:
diff changeset
720 starts with its length (on 4 bytes).
kono
parents:
diff changeset
721 Map the symbol table and the length of the string table. */
kono
parents:
diff changeset
722 syms_off = fhdr.pointer_to_symbol_table;
kono
parents:
diff changeset
723 syms_size = syms_num * SYM_SZ;
kono
parents:
diff changeset
724
kono
parents:
diff changeset
725 if (!backtrace_get_view (state, descriptor, syms_off, syms_size + 4,
kono
parents:
diff changeset
726 error_callback, data, &syms_view))
kono
parents:
diff changeset
727 goto fail;
kono
parents:
diff changeset
728 syms_view_valid = 1;
kono
parents:
diff changeset
729
kono
parents:
diff changeset
730 memcpy (&str_size, syms_view.data + syms_size, 4);
kono
parents:
diff changeset
731
kono
parents:
diff changeset
732 str_off = syms_off + syms_size;
kono
parents:
diff changeset
733
kono
parents:
diff changeset
734 if (str_size > 4)
kono
parents:
diff changeset
735 {
kono
parents:
diff changeset
736 /* Map string table (including the length word). */
kono
parents:
diff changeset
737
kono
parents:
diff changeset
738 if (!backtrace_get_view (state, descriptor, str_off, str_size,
kono
parents:
diff changeset
739 error_callback, data, &str_view))
kono
parents:
diff changeset
740 goto fail;
kono
parents:
diff changeset
741 str_view_valid = 1;
kono
parents:
diff changeset
742 }
kono
parents:
diff changeset
743 }
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 memset (sections, 0, sizeof sections);
kono
parents:
diff changeset
746
kono
parents:
diff changeset
747 /* Look for the symbol table. */
kono
parents:
diff changeset
748 for (i = 0; i < sects_num; ++i)
kono
parents:
diff changeset
749 {
kono
parents:
diff changeset
750 const b_coff_section_header *s = sects + i;
kono
parents:
diff changeset
751 unsigned int str_off;
kono
parents:
diff changeset
752 int j;
kono
parents:
diff changeset
753
kono
parents:
diff changeset
754 if (s->name[0] == '/')
kono
parents:
diff changeset
755 {
kono
parents:
diff changeset
756 /* Extended section name. */
kono
parents:
diff changeset
757 str_off = atoi (s->name + 1);
kono
parents:
diff changeset
758 }
kono
parents:
diff changeset
759 else
kono
parents:
diff changeset
760 str_off = 0;
kono
parents:
diff changeset
761
kono
parents:
diff changeset
762 for (j = 0; j < (int) DEBUG_MAX; ++j)
kono
parents:
diff changeset
763 {
kono
parents:
diff changeset
764 const char *dbg_name = debug_section_names[j];
kono
parents:
diff changeset
765 int match;
kono
parents:
diff changeset
766
kono
parents:
diff changeset
767 if (str_off != 0)
kono
parents:
diff changeset
768 match = coff_long_name_eq (dbg_name, str_off, &str_view);
kono
parents:
diff changeset
769 else
kono
parents:
diff changeset
770 match = coff_short_name_eq (dbg_name, s->name);
kono
parents:
diff changeset
771 if (match)
kono
parents:
diff changeset
772 {
kono
parents:
diff changeset
773 sections[j].offset = s->pointer_to_raw_data;
kono
parents:
diff changeset
774 sections[j].size = s->virtual_size <= s->size_of_raw_data ?
kono
parents:
diff changeset
775 s->virtual_size : s->size_of_raw_data;
kono
parents:
diff changeset
776 break;
kono
parents:
diff changeset
777 }
kono
parents:
diff changeset
778 }
kono
parents:
diff changeset
779 }
kono
parents:
diff changeset
780
kono
parents:
diff changeset
781 if (syms_num != 0)
kono
parents:
diff changeset
782 {
kono
parents:
diff changeset
783 struct coff_syminfo_data *sdata;
kono
parents:
diff changeset
784
kono
parents:
diff changeset
785 sdata = ((struct coff_syminfo_data *)
kono
parents:
diff changeset
786 backtrace_alloc (state, sizeof *sdata, error_callback, data));
kono
parents:
diff changeset
787 if (sdata == NULL)
kono
parents:
diff changeset
788 goto fail;
kono
parents:
diff changeset
789
kono
parents:
diff changeset
790 if (!coff_initialize_syminfo (state, image_base,
kono
parents:
diff changeset
791 sects, sects_num,
kono
parents:
diff changeset
792 syms_view.data, syms_size,
kono
parents:
diff changeset
793 str_view.data, str_size,
kono
parents:
diff changeset
794 error_callback, data, sdata))
kono
parents:
diff changeset
795 {
kono
parents:
diff changeset
796 backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
kono
parents:
diff changeset
797 goto fail;
kono
parents:
diff changeset
798 }
kono
parents:
diff changeset
799
kono
parents:
diff changeset
800 *found_sym = 1;
kono
parents:
diff changeset
801
kono
parents:
diff changeset
802 coff_add_syminfo_data (state, sdata);
kono
parents:
diff changeset
803 }
kono
parents:
diff changeset
804
kono
parents:
diff changeset
805 backtrace_release_view (state, &sects_view, error_callback, data);
kono
parents:
diff changeset
806 sects_view_valid = 0;
kono
parents:
diff changeset
807 backtrace_release_view (state, &syms_view, error_callback, data);
kono
parents:
diff changeset
808 syms_view_valid = 0;
kono
parents:
diff changeset
809
kono
parents:
diff changeset
810 /* Read all the debug sections in a single view, since they are
kono
parents:
diff changeset
811 probably adjacent in the file. We never release this view. */
kono
parents:
diff changeset
812
kono
parents:
diff changeset
813 min_offset = 0;
kono
parents:
diff changeset
814 max_offset = 0;
kono
parents:
diff changeset
815 for (i = 0; i < (int) DEBUG_MAX; ++i)
kono
parents:
diff changeset
816 {
kono
parents:
diff changeset
817 off_t end;
kono
parents:
diff changeset
818
kono
parents:
diff changeset
819 if (sections[i].size == 0)
kono
parents:
diff changeset
820 continue;
kono
parents:
diff changeset
821 if (min_offset == 0 || sections[i].offset < min_offset)
kono
parents:
diff changeset
822 min_offset = sections[i].offset;
kono
parents:
diff changeset
823 end = sections[i].offset + sections[i].size;
kono
parents:
diff changeset
824 if (end > max_offset)
kono
parents:
diff changeset
825 max_offset = end;
kono
parents:
diff changeset
826 }
kono
parents:
diff changeset
827 if (min_offset == 0 || max_offset == 0)
kono
parents:
diff changeset
828 {
kono
parents:
diff changeset
829 if (!backtrace_close (descriptor, error_callback, data))
kono
parents:
diff changeset
830 goto fail;
kono
parents:
diff changeset
831 *fileline_fn = coff_nodebug;
kono
parents:
diff changeset
832 return 1;
kono
parents:
diff changeset
833 }
kono
parents:
diff changeset
834
kono
parents:
diff changeset
835 if (!backtrace_get_view (state, descriptor, min_offset,
kono
parents:
diff changeset
836 max_offset - min_offset,
kono
parents:
diff changeset
837 error_callback, data, &debug_view))
kono
parents:
diff changeset
838 goto fail;
kono
parents:
diff changeset
839 debug_view_valid = 1;
kono
parents:
diff changeset
840
kono
parents:
diff changeset
841 /* We've read all we need from the executable. */
kono
parents:
diff changeset
842 if (!backtrace_close (descriptor, error_callback, data))
kono
parents:
diff changeset
843 goto fail;
kono
parents:
diff changeset
844 descriptor = -1;
kono
parents:
diff changeset
845
kono
parents:
diff changeset
846 for (i = 0; i < (int) DEBUG_MAX; ++i)
kono
parents:
diff changeset
847 {
kono
parents:
diff changeset
848 if (sections[i].size == 0)
kono
parents:
diff changeset
849 sections[i].data = NULL;
kono
parents:
diff changeset
850 else
kono
parents:
diff changeset
851 sections[i].data = ((const unsigned char *) debug_view.data
kono
parents:
diff changeset
852 + (sections[i].offset - min_offset));
kono
parents:
diff changeset
853 }
kono
parents:
diff changeset
854
kono
parents:
diff changeset
855 if (!backtrace_dwarf_add (state, /* base_address */ 0,
kono
parents:
diff changeset
856 sections[DEBUG_INFO].data,
kono
parents:
diff changeset
857 sections[DEBUG_INFO].size,
kono
parents:
diff changeset
858 sections[DEBUG_LINE].data,
kono
parents:
diff changeset
859 sections[DEBUG_LINE].size,
kono
parents:
diff changeset
860 sections[DEBUG_ABBREV].data,
kono
parents:
diff changeset
861 sections[DEBUG_ABBREV].size,
kono
parents:
diff changeset
862 sections[DEBUG_RANGES].data,
kono
parents:
diff changeset
863 sections[DEBUG_RANGES].size,
kono
parents:
diff changeset
864 sections[DEBUG_STR].data,
kono
parents:
diff changeset
865 sections[DEBUG_STR].size,
kono
parents:
diff changeset
866 0, /* FIXME */
kono
parents:
diff changeset
867 error_callback, data, fileline_fn))
kono
parents:
diff changeset
868 goto fail;
kono
parents:
diff changeset
869
kono
parents:
diff changeset
870 *found_dwarf = 1;
kono
parents:
diff changeset
871
kono
parents:
diff changeset
872 return 1;
kono
parents:
diff changeset
873
kono
parents:
diff changeset
874 fail:
kono
parents:
diff changeset
875 if (sects_view_valid)
kono
parents:
diff changeset
876 backtrace_release_view (state, &sects_view, error_callback, data);
kono
parents:
diff changeset
877 if (str_view_valid)
kono
parents:
diff changeset
878 backtrace_release_view (state, &str_view, error_callback, data);
kono
parents:
diff changeset
879 if (syms_view_valid)
kono
parents:
diff changeset
880 backtrace_release_view (state, &syms_view, error_callback, data);
kono
parents:
diff changeset
881 if (debug_view_valid)
kono
parents:
diff changeset
882 backtrace_release_view (state, &debug_view, error_callback, data);
kono
parents:
diff changeset
883 if (descriptor != -1)
kono
parents:
diff changeset
884 backtrace_close (descriptor, error_callback, data);
kono
parents:
diff changeset
885 return 0;
kono
parents:
diff changeset
886 }
kono
parents:
diff changeset
887
kono
parents:
diff changeset
888 /* Initialize the backtrace data we need from an ELF executable. At
kono
parents:
diff changeset
889 the ELF level, all we need to do is find the debug info
kono
parents:
diff changeset
890 sections. */
kono
parents:
diff changeset
891
kono
parents:
diff changeset
892 int
kono
parents:
diff changeset
893 backtrace_initialize (struct backtrace_state *state,
kono
parents:
diff changeset
894 const char *filename ATTRIBUTE_UNUSED, int descriptor,
kono
parents:
diff changeset
895 backtrace_error_callback error_callback,
kono
parents:
diff changeset
896 void *data, fileline *fileline_fn)
kono
parents:
diff changeset
897 {
kono
parents:
diff changeset
898 int ret;
kono
parents:
diff changeset
899 int found_sym;
kono
parents:
diff changeset
900 int found_dwarf;
kono
parents:
diff changeset
901 fileline coff_fileline_fn;
kono
parents:
diff changeset
902
kono
parents:
diff changeset
903 ret = coff_add (state, descriptor, error_callback, data,
kono
parents:
diff changeset
904 &coff_fileline_fn, &found_sym, &found_dwarf);
kono
parents:
diff changeset
905 if (!ret)
kono
parents:
diff changeset
906 return 0;
kono
parents:
diff changeset
907
kono
parents:
diff changeset
908 if (!state->threaded)
kono
parents:
diff changeset
909 {
kono
parents:
diff changeset
910 if (found_sym)
kono
parents:
diff changeset
911 state->syminfo_fn = coff_syminfo;
kono
parents:
diff changeset
912 else if (state->syminfo_fn == NULL)
kono
parents:
diff changeset
913 state->syminfo_fn = coff_nosyms;
kono
parents:
diff changeset
914 }
kono
parents:
diff changeset
915 else
kono
parents:
diff changeset
916 {
kono
parents:
diff changeset
917 if (found_sym)
kono
parents:
diff changeset
918 backtrace_atomic_store_pointer (&state->syminfo_fn, coff_syminfo);
kono
parents:
diff changeset
919 else
kono
parents:
diff changeset
920 __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, coff_nosyms);
kono
parents:
diff changeset
921 }
kono
parents:
diff changeset
922
kono
parents:
diff changeset
923 if (!state->threaded)
kono
parents:
diff changeset
924 {
kono
parents:
diff changeset
925 if (state->fileline_fn == NULL || state->fileline_fn == coff_nodebug)
kono
parents:
diff changeset
926 *fileline_fn = coff_fileline_fn;
kono
parents:
diff changeset
927 }
kono
parents:
diff changeset
928 else
kono
parents:
diff changeset
929 {
kono
parents:
diff changeset
930 fileline current_fn;
kono
parents:
diff changeset
931
kono
parents:
diff changeset
932 current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
kono
parents:
diff changeset
933 if (current_fn == NULL || current_fn == coff_nodebug)
kono
parents:
diff changeset
934 *fileline_fn = coff_fileline_fn;
kono
parents:
diff changeset
935 }
kono
parents:
diff changeset
936
kono
parents:
diff changeset
937 return 1;
kono
parents:
diff changeset
938 }