1 /* pecoff.c -- Get debug data from a PE/COFFF file for backtraces.
2 Copyright (C) 2015-2024 Free Software Foundation, Inc.
3 Adapted from elf.c by Tristan Gingold, AdaCore.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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
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.
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE. */
37 #include <sys/types.h>
39 #include "backtrace.h"
43 #ifndef WIN32_MEAN_AND_LEAN
44 #define WIN32_MEAN_AND_LEAN
53 #ifdef HAVE_TLHELP32_H
57 /* If UNICODE is defined, all the symbols are replaced by a macro to use the
58 wide variant. But we need the ansi variant, so undef the macros. */
68 #define NTAPI __stdcall
71 /* This is a simplified (but binary compatible) version of what Microsoft
72 defines in their documentation. */
73 struct dll_notification_data
76 /* The name as UNICODE_STRING struct. */
83 #define LDR_DLL_NOTIFICATION_REASON_LOADED 1
85 typedef LONG NTSTATUS
;
86 typedef VOID
CALLBACK (*LDR_DLL_NOTIFICATION
)(ULONG
,
87 struct dll_notification_data
*,
89 typedef NTSTATUS
NTAPI (*LDR_REGISTER_FUNCTION
)(ULONG
,
90 LDR_DLL_NOTIFICATION
, PVOID
,
94 /* Coff file header. */
98 uint16_t number_of_sections
;
99 uint32_t time_date_stamp
;
100 uint32_t pointer_to_symbol_table
;
101 uint32_t number_of_symbols
;
102 uint16_t size_of_optional_header
;
103 uint16_t characteristics
;
104 } b_coff_file_header
;
106 /* Coff optional header. */
110 uint8_t major_linker_version
;
111 uint8_t minor_linker_version
;
112 uint32_t size_of_code
;
113 uint32_t size_of_initialized_data
;
114 uint32_t size_of_uninitialized_data
;
115 uint32_t address_of_entry_point
;
116 uint32_t base_of_code
;
119 uint32_t base_of_data
;
126 } b_coff_optional_header
;
128 /* Values of magic in optional header. */
130 #define PE_MAGIC 0x10b /* PE32 executable. */
131 #define PEP_MAGIC 0x20b /* PE32+ executable (for 64bit targets). */
133 /* Coff section header. */
137 uint32_t virtual_size
;
138 uint32_t virtual_address
;
139 uint32_t size_of_raw_data
;
140 uint32_t pointer_to_raw_data
;
141 uint32_t pointer_to_relocations
;
142 uint32_t pointer_to_line_numbers
;
143 uint16_t number_of_relocations
;
144 uint16_t number_of_line_numbers
;
145 uint32_t characteristics
;
146 } b_coff_section_header
;
148 /* Coff symbol name. */
153 unsigned char zeroes
[4];
154 unsigned char off
[4];
158 /* Coff symbol (external representation which is unaligned). */
162 unsigned char value
[4];
163 unsigned char section_number
[2];
164 unsigned char type
[2];
165 unsigned char storage_class
;
166 unsigned char number_of_aux_symbols
;
167 } b_coff_external_symbol
;
171 #define N_TBSHFT 4 /* Shift for the derived type. */
172 #define IMAGE_SYM_DTYPE_FUNCTION 2 /* Function derived type. */
174 /* Size of a coff symbol. */
178 /* Coff symbol, internal representation (aligned). */
186 } b_coff_internal_symbol
;
188 /* Names of sections, indexed by enum dwarf_section in internal.h. */
190 static const char * const debug_section_names
[DEBUG_MAX
] =
198 ".debug_str_offsets",
203 /* Information we gather for the sections we care about. */
205 struct debug_section_info
207 /* Section file offset. */
213 /* Information we keep for an coff symbol. */
217 /* The name of the symbol. */
219 /* The address of the symbol. */
223 /* Information to pass to coff_syminfo. */
225 struct coff_syminfo_data
227 /* Symbols for the next module. */
228 struct coff_syminfo_data
*next
;
229 /* The COFF symbols, sorted by address. */
230 struct coff_symbol
*symbols
;
231 /* The number of symbols. */
235 /* A dummy callback function used when we can't find any debug info. */
238 coff_nodebug (struct backtrace_state
*state ATTRIBUTE_UNUSED
,
239 uintptr_t pc ATTRIBUTE_UNUSED
,
240 backtrace_full_callback callback ATTRIBUTE_UNUSED
,
241 backtrace_error_callback error_callback
, void *data
)
243 error_callback (data
, "no debug info in PE/COFF executable", -1);
247 /* A dummy callback function used when we can't find a symbol
251 coff_nosyms (struct backtrace_state
*state ATTRIBUTE_UNUSED
,
252 uintptr_t addr ATTRIBUTE_UNUSED
,
253 backtrace_syminfo_callback callback ATTRIBUTE_UNUSED
,
254 backtrace_error_callback error_callback
, void *data
)
256 error_callback (data
, "no symbol table in PE/COFF executable", -1);
259 /* Read a potentially unaligned 4 byte word at P, using native endianness. */
262 coff_read4 (const unsigned char *p
)
270 /* Read a potentially unaligned 2 byte word at P, using native endianness.
271 All 2 byte word in symbols are always aligned, but for coherency all
272 fields are declared as char arrays. */
275 coff_read2 (const unsigned char *p
)
279 memcpy (&res
, p
, sizeof (res
));
283 /* Return the length (without the trailing 0) of a COFF short name. */
286 coff_short_name_len (const char *name
)
290 for (i
= 0; i
< 8; i
++)
296 /* Return true iff COFF short name CNAME is the same as NAME (a NUL-terminated
300 coff_short_name_eq (const char *name
, const char *cname
)
304 for (i
= 0; i
< 8; i
++)
306 if (name
[i
] != cname
[i
])
314 /* Return true iff NAME is the same as string at offset OFF. */
317 coff_long_name_eq (const char *name
, unsigned int off
,
318 struct backtrace_view
*str_view
)
320 if (off
>= str_view
->len
)
322 return strcmp (name
, (const char *)str_view
->data
+ off
) == 0;
325 /* Compare struct coff_symbol for qsort. */
328 coff_symbol_compare (const void *v1
, const void *v2
)
330 const struct coff_symbol
*e1
= (const struct coff_symbol
*) v1
;
331 const struct coff_symbol
*e2
= (const struct coff_symbol
*) v2
;
333 if (e1
->address
< e2
->address
)
335 else if (e1
->address
> e2
->address
)
341 /* Convert SYM to internal (and aligned) format ISYM, using string table
342 from STRTAB and STRTAB_SIZE, and number of sections SECTS_NUM.
343 Return -1 in case of error (invalid section number or string index). */
346 coff_expand_symbol (b_coff_internal_symbol
*isym
,
347 const b_coff_external_symbol
*sym
,
349 const unsigned char *strtab
, size_t strtab_size
)
351 isym
->type
= coff_read2 (sym
->type
);
352 isym
->sec
= coff_read2 (sym
->section_number
);
353 isym
->sc
= sym
->storage_class
;
355 if (isym
->sec
> 0 && (uint16_t) isym
->sec
> sects_num
)
357 if (sym
->name
.short_name
[0] != 0)
358 isym
->name
= sym
->name
.short_name
;
361 uint32_t off
= coff_read4 (sym
->name
.long_name
.off
);
363 if (off
>= strtab_size
)
365 isym
->name
= (const char *) strtab
+ off
;
370 /* Return true iff SYM is a defined symbol for a function. Data symbols
371 aren't considered because they aren't easily identified (same type as
372 section names, presence of symbols defined by the linker script). */
375 coff_is_function_symbol (const b_coff_internal_symbol
*isym
)
377 return (isym
->type
>> N_TBSHFT
) == IMAGE_SYM_DTYPE_FUNCTION
381 /* Initialize the symbol table info for coff_syminfo. */
384 coff_initialize_syminfo (struct backtrace_state
*state
,
385 uintptr_t base_address
, int is_64
,
386 const b_coff_section_header
*sects
, size_t sects_num
,
387 const b_coff_external_symbol
*syms
, size_t syms_size
,
388 const unsigned char *strtab
, size_t strtab_size
,
389 backtrace_error_callback error_callback
,
390 void *data
, struct coff_syminfo_data
*sdata
)
394 size_t coff_symstr_len
;
395 size_t coff_symbol_count
;
396 size_t coff_symbol_size
;
397 struct coff_symbol
*coff_symbols
;
398 struct coff_symbol
*coff_sym
;
402 syms_count
= syms_size
/ SYM_SZ
;
404 /* We only care about function symbols. Count them. Also count size of
405 strings for in-symbol names. */
406 coff_symbol_count
= 0;
408 for (i
= 0; i
< syms_count
; ++i
)
410 const b_coff_external_symbol
*asym
= &syms
[i
];
411 b_coff_internal_symbol isym
;
413 if (coff_expand_symbol (&isym
, asym
, sects_num
, strtab
, strtab_size
) < 0)
415 error_callback (data
, "invalid section or offset in coff symbol", 0);
418 if (coff_is_function_symbol (&isym
))
421 if (asym
->name
.short_name
[0] != 0)
422 coff_symstr_len
+= coff_short_name_len (asym
->name
.short_name
) + 1;
425 i
+= asym
->number_of_aux_symbols
;
428 coff_symbol_size
= (coff_symbol_count
+ 1) * sizeof (struct coff_symbol
);
429 coff_symbols
= ((struct coff_symbol
*)
430 backtrace_alloc (state
, coff_symbol_size
, error_callback
,
432 if (coff_symbols
== NULL
)
435 /* Allocate memory for symbols strings. */
436 if (coff_symstr_len
> 0)
438 coff_symstr
= ((char *)
439 backtrace_alloc (state
, coff_symstr_len
, error_callback
,
441 if (coff_symstr
== NULL
)
443 backtrace_free (state
, coff_symbols
, coff_symbol_size
,
444 error_callback
, data
);
452 coff_sym
= coff_symbols
;
453 coff_str
= coff_symstr
;
454 for (i
= 0; i
< syms_count
; ++i
)
456 const b_coff_external_symbol
*asym
= &syms
[i
];
457 b_coff_internal_symbol isym
;
459 if (coff_expand_symbol (&isym
, asym
, sects_num
, strtab
, strtab_size
))
461 /* Should not fail, as it was already tested in the previous
465 if (coff_is_function_symbol (&isym
))
470 if (asym
->name
.short_name
[0] != 0)
472 size_t len
= coff_short_name_len (isym
.name
);
474 memcpy (coff_str
, isym
.name
, len
);
483 /* Strip leading '_'. */
488 /* Symbol value is section relative, so we need to read the address
490 secnum
= coff_read2 (asym
->section_number
);
492 coff_sym
->name
= name
;
493 coff_sym
->address
= (coff_read4 (asym
->value
)
494 + sects
[secnum
- 1].virtual_address
499 i
+= asym
->number_of_aux_symbols
;
502 /* End of symbols marker. */
503 coff_sym
->name
= NULL
;
504 coff_sym
->address
= -1;
506 backtrace_qsort (coff_symbols
, coff_symbol_count
,
507 sizeof (struct coff_symbol
), coff_symbol_compare
);
510 sdata
->symbols
= coff_symbols
;
511 sdata
->count
= coff_symbol_count
;
516 /* Add EDATA to the list in STATE. */
519 coff_add_syminfo_data (struct backtrace_state
*state
,
520 struct coff_syminfo_data
*sdata
)
522 if (!state
->threaded
)
524 struct coff_syminfo_data
**pp
;
526 for (pp
= (struct coff_syminfo_data
**) (void *) &state
->syminfo_data
;
536 struct coff_syminfo_data
**pp
;
538 pp
= (struct coff_syminfo_data
**) (void *) &state
->syminfo_data
;
542 struct coff_syminfo_data
*p
;
544 p
= backtrace_atomic_load_pointer (pp
);
552 if (__sync_bool_compare_and_swap (pp
, NULL
, sdata
))
558 /* Compare an ADDR against an elf_symbol for bsearch. We allocate one
559 extra entry in the array so that this can look safely at the next
563 coff_symbol_search (const void *vkey
, const void *ventry
)
565 const uintptr_t *key
= (const uintptr_t *) vkey
;
566 const struct coff_symbol
*entry
= (const struct coff_symbol
*) ventry
;
570 if (addr
< entry
->address
)
572 else if (addr
>= entry
[1].address
)
578 /* Return the symbol name and value for an ADDR. */
581 coff_syminfo (struct backtrace_state
*state
, uintptr_t addr
,
582 backtrace_syminfo_callback callback
,
583 backtrace_error_callback error_callback ATTRIBUTE_UNUSED
,
586 struct coff_syminfo_data
*sdata
;
587 struct coff_symbol
*sym
= NULL
;
589 if (!state
->threaded
)
591 for (sdata
= (struct coff_syminfo_data
*) state
->syminfo_data
;
595 sym
= ((struct coff_symbol
*)
596 bsearch (&addr
, sdata
->symbols
, sdata
->count
,
597 sizeof (struct coff_symbol
), coff_symbol_search
));
604 struct coff_syminfo_data
**pp
;
606 pp
= (struct coff_syminfo_data
**) (void *) &state
->syminfo_data
;
609 sdata
= backtrace_atomic_load_pointer (pp
);
613 sym
= ((struct coff_symbol
*)
614 bsearch (&addr
, sdata
->symbols
, sdata
->count
,
615 sizeof (struct coff_symbol
), coff_symbol_search
));
624 callback (data
, addr
, NULL
, 0, 0);
626 callback (data
, addr
, sym
->name
, sym
->address
, 0);
629 /* Add the backtrace data for one PE/COFF file. Returns 1 on success,
630 0 on failure (in both cases descriptor is closed). */
633 coff_add (struct backtrace_state
*state
, int descriptor
,
634 backtrace_error_callback error_callback
, void *data
,
635 fileline
*fileline_fn
, int *found_sym
, int *found_dwarf
,
636 uintptr_t module_handle ATTRIBUTE_UNUSED
)
638 struct backtrace_view fhdr_view
;
641 b_coff_file_header fhdr
;
643 size_t opt_sects_size
;
644 unsigned int sects_num
;
645 struct backtrace_view sects_view
;
646 int sects_view_valid
;
647 const b_coff_optional_header
*opt_hdr
;
648 const b_coff_section_header
*sects
;
649 struct backtrace_view str_view
;
653 struct backtrace_view syms_view
;
657 unsigned int syms_num
;
659 struct debug_section_info sections
[DEBUG_MAX
];
662 struct backtrace_view debug_view
;
663 int debug_view_valid
;
665 uintptr_t image_base
;
666 uintptr_t base_address
= 0;
667 struct dwarf_sections dwarf_sections
;
672 sects_view_valid
= 0;
675 debug_view_valid
= 0;
677 /* Map the MS-DOS stub (if any) and extract file header offset. */
678 if (!backtrace_get_view (state
, descriptor
, 0, 0x40, error_callback
,
683 const unsigned char *vptr
= fhdr_view
.data
;
685 if (vptr
[0] == 'M' && vptr
[1] == 'Z')
686 fhdr_off
= coff_read4 (vptr
+ 0x3c);
691 backtrace_release_view (state
, &fhdr_view
, error_callback
, data
);
693 /* Map the coff file header. */
694 if (!backtrace_get_view (state
, descriptor
, fhdr_off
,
695 sizeof (b_coff_file_header
) + 4,
696 error_callback
, data
, &fhdr_view
))
701 const char *magic
= (const char *) fhdr_view
.data
;
702 magic_ok
= memcmp (magic
, "PE\0", 4) == 0;
705 memcpy (&fhdr
, fhdr_view
.data
+ 4, sizeof fhdr
);
709 memcpy (&fhdr
, fhdr_view
.data
, sizeof fhdr
);
710 /* TODO: test fhdr.machine for coff but non-PE platforms. */
713 backtrace_release_view (state
, &fhdr_view
, error_callback
, data
);
717 error_callback (data
, "executable file is not COFF", 0);
721 sects_num
= fhdr
.number_of_sections
;
722 syms_num
= fhdr
.number_of_symbols
;
724 opt_sects_off
= fhdr_off
+ sizeof (fhdr
);
725 opt_sects_size
= (fhdr
.size_of_optional_header
726 + sects_num
* sizeof (b_coff_section_header
));
728 /* To translate PC to file/line when using DWARF, we need to find
729 the .debug_info and .debug_line sections. */
731 /* Read the optional header and the section headers. */
733 if (!backtrace_get_view (state
, descriptor
, opt_sects_off
, opt_sects_size
,
734 error_callback
, data
, §s_view
))
736 sects_view_valid
= 1;
737 opt_hdr
= (const b_coff_optional_header
*) sects_view
.data
;
738 sects
= (const b_coff_section_header
*)
739 (sects_view
.data
+ fhdr
.size_of_optional_header
);
742 if (fhdr
.size_of_optional_header
> sizeof (*opt_hdr
))
744 if (opt_hdr
->magic
== PE_MAGIC
)
745 image_base
= opt_hdr
->u
.pe
.image_base
;
746 else if (opt_hdr
->magic
== PEP_MAGIC
)
748 image_base
= opt_hdr
->u
.pep
.image_base
;
753 error_callback (data
, "bad magic in PE optional header", 0);
760 /* Read the symbol table and the string table. */
762 if (fhdr
.pointer_to_symbol_table
== 0)
764 /* No symbol table, no string table. */
772 /* Symbol table is followed by the string table. The string table
773 starts with its length (on 4 bytes).
774 Map the symbol table and the length of the string table. */
775 syms_off
= fhdr
.pointer_to_symbol_table
;
776 syms_size
= syms_num
* SYM_SZ
;
778 if (!backtrace_get_view (state
, descriptor
, syms_off
, syms_size
+ 4,
779 error_callback
, data
, &syms_view
))
783 str_size
= coff_read4 (syms_view
.data
+ syms_size
);
785 str_off
= syms_off
+ syms_size
;
789 /* Map string table (including the length word). */
791 if (!backtrace_get_view (state
, descriptor
, str_off
, str_size
,
792 error_callback
, data
, &str_view
))
798 memset (sections
, 0, sizeof sections
);
800 /* Look for the symbol table. */
801 for (i
= 0; i
< sects_num
; ++i
)
803 const b_coff_section_header
*s
= sects
+ i
;
804 unsigned int str_off
;
807 if (s
->name
[0] == '/')
809 /* Extended section name. */
810 str_off
= atoi (s
->name
+ 1);
815 for (j
= 0; j
< (int) DEBUG_MAX
; ++j
)
817 const char *dbg_name
= debug_section_names
[j
];
821 match
= coff_long_name_eq (dbg_name
, str_off
, &str_view
);
823 match
= coff_short_name_eq (dbg_name
, s
->name
);
826 sections
[j
].offset
= s
->pointer_to_raw_data
;
827 sections
[j
].size
= s
->virtual_size
<= s
->size_of_raw_data
?
828 s
->virtual_size
: s
->size_of_raw_data
;
836 struct coff_syminfo_data
*sdata
;
838 sdata
= ((struct coff_syminfo_data
*)
839 backtrace_alloc (state
, sizeof *sdata
, error_callback
, data
));
843 if (!coff_initialize_syminfo (state
, image_base
, is_64
,
845 syms_view
.data
, syms_size
,
846 str_view
.data
, str_size
,
847 error_callback
, data
, sdata
))
849 backtrace_free (state
, sdata
, sizeof *sdata
, error_callback
, data
);
855 coff_add_syminfo_data (state
, sdata
);
858 backtrace_release_view (state
, §s_view
, error_callback
, data
);
859 sects_view_valid
= 0;
862 backtrace_release_view (state
, &syms_view
, error_callback
, data
);
866 /* Read all the debug sections in a single view, since they are
867 probably adjacent in the file. We never release this view. */
871 for (i
= 0; i
< (int) DEBUG_MAX
; ++i
)
875 if (sections
[i
].size
== 0)
877 if (min_offset
== 0 || sections
[i
].offset
< min_offset
)
878 min_offset
= sections
[i
].offset
;
879 end
= sections
[i
].offset
+ sections
[i
].size
;
880 if (end
> max_offset
)
883 if (min_offset
== 0 || max_offset
== 0)
885 if (!backtrace_close (descriptor
, error_callback
, data
))
887 *fileline_fn
= coff_nodebug
;
891 if (!backtrace_get_view (state
, descriptor
, min_offset
,
892 max_offset
- min_offset
,
893 error_callback
, data
, &debug_view
))
895 debug_view_valid
= 1;
897 /* We've read all we need from the executable. */
898 if (!backtrace_close (descriptor
, error_callback
, data
))
902 for (i
= 0; i
< (int) DEBUG_MAX
; ++i
)
904 size_t size
= sections
[i
].size
;
905 dwarf_sections
.size
[i
] = size
;
907 dwarf_sections
.data
[i
] = NULL
;
909 dwarf_sections
.data
[i
] = ((const unsigned char *) debug_view
.data
910 + (sections
[i
].offset
- min_offset
));
913 #ifdef HAVE_WINDOWS_H
914 base_address
= module_handle
- image_base
;
917 if (!backtrace_dwarf_add (state
, base_address
, &dwarf_sections
,
918 0, /* FIXME: is_bigendian */
920 error_callback
, data
, fileline_fn
,
921 NULL
/* returned fileline_entry */))
929 if (sects_view_valid
)
930 backtrace_release_view (state
, §s_view
, error_callback
, data
);
932 backtrace_release_view (state
, &str_view
, error_callback
, data
);
934 backtrace_release_view (state
, &syms_view
, error_callback
, data
);
935 if (debug_view_valid
)
936 backtrace_release_view (state
, &debug_view
, error_callback
, data
);
937 if (descriptor
!= -1)
938 backtrace_close (descriptor
, error_callback
, data
);
942 #ifdef HAVE_WINDOWS_H
943 struct dll_notification_context
945 struct backtrace_state
*state
;
946 backtrace_error_callback error_callback
;
951 dll_notification (ULONG reason
,
952 struct dll_notification_data
*notification_data
,
955 char module_name
[MAX_PATH
];
957 struct dll_notification_context
* dll_context
=
958 (struct dll_notification_context
*) context
;
959 struct backtrace_state
*state
= dll_context
->state
;
960 void *data
= dll_context
->data
;
961 backtrace_error_callback error_callback
= dll_context
->data
;
965 HMODULE module_handle
;
967 if (reason
!= LDR_DLL_NOTIFICATION_REASON_LOADED
)
970 if (!GetModuleHandleExW ((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
971 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
),
972 (wchar_t*) notification_data
->dll_base
,
976 if (!GetModuleFileNameA ((HMODULE
) module_handle
, module_name
, MAX_PATH
- 1))
979 descriptor
= backtrace_open (module_name
, error_callback
, data
, NULL
);
984 coff_add (state
, descriptor
, error_callback
, data
, &fileline
, &found_sym
,
985 &found_dwarf
, (uintptr_t) module_handle
);
987 #endif /* defined(HAVE_WINDOWS_H) */
989 /* Initialize the backtrace data we need from an ELF executable. At
990 the ELF level, all we need to do is find the debug info
994 backtrace_initialize (struct backtrace_state
*state
,
995 const char *filename ATTRIBUTE_UNUSED
, int descriptor
,
996 backtrace_error_callback error_callback
,
997 void *data
, fileline
*fileline_fn
)
1002 fileline coff_fileline_fn
;
1003 uintptr_t module_handle
= 0;
1004 #ifdef HAVE_TLHELP32_H
1005 fileline module_fileline_fn
;
1006 int module_found_sym
;
1010 #ifdef HAVE_WINDOWS_H
1011 HMODULE nt_dll_handle
;
1013 module_handle
= (uintptr_t) GetModuleHandle (NULL
);
1016 ret
= coff_add (state
, descriptor
, error_callback
, data
,
1017 &coff_fileline_fn
, &found_sym
, &found_dwarf
, module_handle
);
1021 #ifdef HAVE_TLHELP32_H
1024 snapshot
= CreateToolhelp32Snapshot (TH32CS_SNAPMODULE
, 0);
1026 while (snapshot
== INVALID_HANDLE_VALUE
1027 && GetLastError () == ERROR_BAD_LENGTH
);
1029 if (snapshot
!= INVALID_HANDLE_VALUE
)
1031 MODULEENTRY32 entry
;
1033 entry
.dwSize
= sizeof (MODULEENTRY32
);
1035 for (ok
= Module32First (snapshot
, &entry
); ok
; ok
= Module32Next (snapshot
, &entry
))
1037 if (strcmp (filename
, entry
.szExePath
) == 0)
1040 module_handle
= (uintptr_t) entry
.hModule
;
1041 if (module_handle
== 0)
1044 descriptor
= backtrace_open (entry
.szExePath
, error_callback
, data
,
1049 coff_add (state
, descriptor
, error_callback
, data
,
1050 &module_fileline_fn
, &module_found_sym
, &found_dwarf
,
1052 if (module_found_sym
)
1056 CloseHandle (snapshot
);
1060 #ifdef HAVE_WINDOWS_H
1061 nt_dll_handle
= GetModuleHandleW (L
"ntdll.dll");
1064 LDR_REGISTER_FUNCTION register_func
;
1065 const char register_name
[] = "LdrRegisterDllNotification";
1066 register_func
= (void*) GetProcAddress (nt_dll_handle
,
1072 struct dll_notification_context
*context
1073 = backtrace_alloc (state
,
1074 sizeof (struct dll_notification_context
),
1075 error_callback
, data
);
1079 context
->state
= state
;
1080 context
->data
= data
;
1081 context
->error_callback
= error_callback
;
1083 register_func (0, &dll_notification
, context
, &cookie
);
1087 #endif /* defined(HAVE_WINDOWS_H) */
1089 if (!state
->threaded
)
1092 state
->syminfo_fn
= coff_syminfo
;
1093 else if (state
->syminfo_fn
== NULL
)
1094 state
->syminfo_fn
= coff_nosyms
;
1099 backtrace_atomic_store_pointer (&state
->syminfo_fn
, coff_syminfo
);
1101 (void) __sync_bool_compare_and_swap (&state
->syminfo_fn
, NULL
,
1105 if (!state
->threaded
)
1107 if (state
->fileline_fn
== NULL
|| state
->fileline_fn
== coff_nodebug
)
1108 *fileline_fn
= coff_fileline_fn
;
1112 fileline current_fn
;
1114 current_fn
= backtrace_atomic_load_pointer (&state
->fileline_fn
);
1115 if (current_fn
== NULL
|| current_fn
== coff_nodebug
)
1116 *fileline_fn
= coff_fileline_fn
;