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