libbacktrace: Update to upstream commit 1db85642e

1db85642e3
This commit is contained in:
Rémi Verschelde
2024-12-11 13:06:03 +01:00
parent c2e4ae782a
commit 51730391c6
17 changed files with 678 additions and 147 deletions

View File

@ -1,5 +1,5 @@
/* pecoff.c -- Get debug data from a PE/COFFF file for backtraces.
Copyright (C) 2015-2021 Free Software Foundation, Inc.
Copyright (C) 2015-2024 Free Software Foundation, Inc.
Adapted from elf.c by Tristan Gingold, AdaCore.
Redistribution and use in source and binary forms, with or without
@ -39,6 +39,58 @@ POSSIBILITY OF SUCH DAMAGE. */
#include "backtrace.h"
#include "internal.h"
#ifdef HAVE_WINDOWS_H
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#ifdef HAVE_TLHELP32_H
#include <tlhelp32.h>
#ifdef UNICODE
/* If UNICODE is defined, all the symbols are replaced by a macro to use the
wide variant. But we need the ansi variant, so undef the macros. */
#undef MODULEENTRY32
#undef Module32First
#undef Module32Next
#endif
#endif
#if defined(_ARM_)
#define NTAPI
#else
#define NTAPI __stdcall
#endif
/* This is a simplified (but binary compatible) version of what Microsoft
defines in their documentation. */
struct dll_notification_data
{
ULONG reserved;
/* The name as UNICODE_STRING struct. */
PVOID full_dll_name;
PVOID base_dll_name;
PVOID dll_base;
ULONG size_of_image;
};
#define LDR_DLL_NOTIFICATION_REASON_LOADED 1
typedef LONG NTSTATUS;
typedef VOID (CALLBACK *LDR_DLL_NOTIFICATION)(ULONG,
struct dll_notification_data*,
PVOID);
typedef NTSTATUS (NTAPI *LDR_REGISTER_FUNCTION)(ULONG,
LDR_DLL_NOTIFICATION, PVOID,
PVOID*);
#endif
/* Coff file header. */
typedef struct {
@ -188,7 +240,7 @@ coff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
backtrace_full_callback callback ATTRIBUTE_UNUSED,
backtrace_error_callback error_callback, void *data)
{
error_callback (data, "no debug info in PE/COFF executable", -1);
error_callback (data, "no debug info in PE/COFF executable (make sure to compile with -g)", -1);
return 0;
}
@ -330,10 +382,11 @@ coff_is_function_symbol (const b_coff_internal_symbol *isym)
static int
coff_initialize_syminfo (struct backtrace_state *state,
uintptr_t base_address, int is_64,
const b_coff_section_header *sects, size_t sects_num,
const b_coff_external_symbol *syms, size_t syms_size,
const unsigned char *strtab, size_t strtab_size,
struct libbacktrace_base_address base_address,
int is_64, const b_coff_section_header *sects,
size_t sects_num, const b_coff_external_symbol *syms,
size_t syms_size, const unsigned char *strtab,
size_t strtab_size,
backtrace_error_callback error_callback,
void *data, struct coff_syminfo_data *sdata)
{
@ -438,9 +491,10 @@ coff_initialize_syminfo (struct backtrace_state *state,
secnum = coff_read2 (asym->section_number);
coff_sym->name = name;
coff_sym->address = (coff_read4 (asym->value)
+ sects[secnum - 1].virtual_address
+ base_address);
coff_sym->address =
libbacktrace_add_base ((coff_read4 (asym->value)
+ sects[secnum - 1].virtual_address),
base_address);
coff_sym++;
}
@ -580,7 +634,8 @@ coff_syminfo (struct backtrace_state *state, uintptr_t addr,
static int
coff_add (struct backtrace_state *state, int descriptor,
backtrace_error_callback error_callback, void *data,
fileline *fileline_fn, int *found_sym, int *found_dwarf)
fileline *fileline_fn, int *found_sym, int *found_dwarf,
uintptr_t module_handle ATTRIBUTE_UNUSED)
{
struct backtrace_view fhdr_view;
off_t fhdr_off;
@ -609,7 +664,8 @@ coff_add (struct backtrace_state *state, int descriptor,
struct backtrace_view debug_view;
int debug_view_valid;
int is_64;
uintptr_t image_base;
struct libbacktrace_base_address image_base;
struct libbacktrace_base_address base_address;
struct dwarf_sections dwarf_sections;
*found_sym = 0;
@ -648,7 +704,7 @@ coff_add (struct backtrace_state *state, int descriptor,
magic_ok = memcmp (magic, "PE\0", 4) == 0;
fhdr_off += 4;
memcpy (&fhdr, fhdr_view.data + 4, sizeof fhdr);
memcpy (&fhdr, (const unsigned char *) fhdr_view.data + 4, sizeof fhdr);
}
else
{
@ -682,16 +738,17 @@ coff_add (struct backtrace_state *state, int descriptor,
sects_view_valid = 1;
opt_hdr = (const b_coff_optional_header *) sects_view.data;
sects = (const b_coff_section_header *)
(sects_view.data + fhdr.size_of_optional_header);
((const unsigned char *) sects_view.data + fhdr.size_of_optional_header);
is_64 = 0;
memset (&image_base, 0, sizeof image_base);
if (fhdr.size_of_optional_header > sizeof (*opt_hdr))
{
if (opt_hdr->magic == PE_MAGIC)
image_base = opt_hdr->u.pe.image_base;
image_base.m = opt_hdr->u.pe.image_base;
else if (opt_hdr->magic == PEP_MAGIC)
{
image_base = opt_hdr->u.pep.image_base;
image_base.m = opt_hdr->u.pep.image_base;
is_64 = 1;
}
else
@ -700,8 +757,6 @@ coff_add (struct backtrace_state *state, int descriptor,
goto fail;
}
}
else
image_base = 0;
/* Read the symbol table and the string table. */
@ -726,7 +781,8 @@ coff_add (struct backtrace_state *state, int descriptor,
goto fail;
syms_view_valid = 1;
str_size = coff_read4 (syms_view.data + syms_size);
str_size = coff_read4 ((const unsigned char *) syms_view.data
+ syms_size);
str_off = syms_off + syms_size;
@ -856,7 +912,12 @@ coff_add (struct backtrace_state *state, int descriptor,
+ (sections[i].offset - min_offset));
}
if (!backtrace_dwarf_add (state, /* base_address */ 0, &dwarf_sections,
memset (&base_address, 0, sizeof base_address);
#ifdef HAVE_WINDOWS_H
base_address.m = module_handle - image_base.m;
#endif
if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,
0, /* FIXME: is_bigendian */
NULL, /* altlink */
error_callback, data, fileline_fn,
@ -881,6 +942,53 @@ coff_add (struct backtrace_state *state, int descriptor,
return 0;
}
#ifdef HAVE_WINDOWS_H
struct dll_notification_context
{
struct backtrace_state *state;
backtrace_error_callback error_callback;
void *data;
};
static VOID CALLBACK
dll_notification (ULONG reason,
struct dll_notification_data *notification_data,
PVOID context)
{
char module_name[MAX_PATH];
int descriptor;
struct dll_notification_context* dll_context =
(struct dll_notification_context*) context;
struct backtrace_state *state = dll_context->state;
void *data = dll_context->data;
backtrace_error_callback error_callback = dll_context->data;
fileline fileline;
int found_sym;
int found_dwarf;
HMODULE module_handle;
if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
return;
if (!GetModuleHandleExW ((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
(wchar_t*) notification_data->dll_base,
&module_handle))
return;
if (!GetModuleFileNameA ((HMODULE) module_handle, module_name, MAX_PATH - 1))
return;
descriptor = backtrace_open (module_name, error_callback, data, NULL);
if (descriptor < 0)
return;
coff_add (state, descriptor, error_callback, data, &fileline, &found_sym,
&found_dwarf, (uintptr_t) module_handle);
}
#endif /* defined(HAVE_WINDOWS_H) */
/* Initialize the backtrace data we need from an ELF executable. At
the ELF level, all we need to do is find the debug info
sections. */
@ -895,12 +1003,92 @@ backtrace_initialize (struct backtrace_state *state,
int found_sym;
int found_dwarf;
fileline coff_fileline_fn;
uintptr_t module_handle = 0;
#ifdef HAVE_TLHELP32_H
fileline module_fileline_fn;
int module_found_sym;
HANDLE snapshot;
#endif
#ifdef HAVE_WINDOWS_H
HMODULE nt_dll_handle;
module_handle = (uintptr_t) GetModuleHandle (NULL);
#endif
ret = coff_add (state, descriptor, error_callback, data,
&coff_fileline_fn, &found_sym, &found_dwarf);
&coff_fileline_fn, &found_sym, &found_dwarf, module_handle);
if (!ret)
return 0;
#ifdef HAVE_TLHELP32_H
do
{
snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
}
while (snapshot == INVALID_HANDLE_VALUE
&& GetLastError () == ERROR_BAD_LENGTH);
if (snapshot != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 entry;
BOOL ok;
entry.dwSize = sizeof (MODULEENTRY32);
for (ok = Module32First (snapshot, &entry); ok; ok = Module32Next (snapshot, &entry))
{
if (strcmp (filename, entry.szExePath) == 0)
continue;
module_handle = (uintptr_t) entry.hModule;
if (module_handle == 0)
continue;
descriptor = backtrace_open (entry.szExePath, error_callback, data,
NULL);
if (descriptor < 0)
continue;
coff_add (state, descriptor, error_callback, data,
&module_fileline_fn, &module_found_sym, &found_dwarf,
module_handle);
if (module_found_sym)
found_sym = 1;
}
CloseHandle (snapshot);
}
#endif
#ifdef HAVE_WINDOWS_H
nt_dll_handle = GetModuleHandleW (L"ntdll.dll");
if (nt_dll_handle)
{
LDR_REGISTER_FUNCTION register_func;
const char register_name[] = "LdrRegisterDllNotification";
register_func = (void*) GetProcAddress (nt_dll_handle,
register_name);
if (register_func)
{
PVOID cookie;
struct dll_notification_context *context
= backtrace_alloc (state,
sizeof (struct dll_notification_context),
error_callback, data);
if (context)
{
context->state = state;
context->data = data;
context->error_callback = error_callback;
register_func (0, &dll_notification, context, &cookie);
}
}
}
#endif /* defined(HAVE_WINDOWS_H) */
if (!state->threaded)
{
if (found_sym)