Skip to content
This repository has been archived by the owner on Oct 4, 2024. It is now read-only.

Commit

Permalink
log: use dwarfstack to print crash stack traces
Browse files Browse the repository at this point in the history
  • Loading branch information
rr- committed Aug 20, 2024
1 parent e4c4f6d commit ac6a343
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 89 deletions.
5 changes: 4 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ build_opts = [
'-fmacro-prefix-map=@0@/src=libtrx'.format(relative_dir),
'-Wno-unused',
'-DMESON_BUILD',
'-DDWST_STATIC',
'-DPCRE2_STATIC',
'-DPCRE2_CODE_UNIT_WIDTH=8',
]
Expand Down Expand Up @@ -76,8 +77,10 @@ if dep_backtrace.found() and host_machine.system() == 'linux'
sources += ['src/log_linux.c']
elif host_machine.system() == 'windows'
sources += ['src/log_windows.c']
dwarfstack = subproject('dwarfstack', default_options: ['warning_level=0'])
dep_dwarfstack = dwarfstack.get_variable('dep_dwarfstack')
dep_dbghelp = c_compiler.find_library('dbghelp')
dependencies += [dep_dbghelp]
dependencies += [dep_dbghelp, dep_dwarfstack]
else
sources += ['src/log_unknown.c']
endif
Expand Down
14 changes: 7 additions & 7 deletions src/log_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@
#include <stdlib.h>

static void Log_ErrorCallback(void *data, const char *msg, int errnum);
static int Log_FullTrace(
static int Log_StackTrace(
void *data, uintptr_t pc, const char *filename, int lineno,
const char *function);
const char *func_name);
static void Log_SignalHandler(int sig);

static void Log_ErrorCallback(void *data, const char *msg, int errnum)
{
LOG_ERROR("%s", msg);
}

static int Log_FullTrace(
static int Log_StackTrace(
void *data, uintptr_t pc, const char *filename, int lineno,
const char *function)
const char *func_name)
{
if (filename) {
LOG_INFO(
"0x%08X: %s (%s:%d)", pc, function ? function : "???",
"0x%08X: %s (%s:%d)", pc, func_name ? func_name : "???",
filename ? filename : "???", lineno);
} else {
LOG_INFO("0x%08X: %s", pc, function ? function : "???");
LOG_INFO("0x%08X: %s", pc, func_name ? func_name : "???");
}
return 0;
}
Expand All @@ -38,7 +38,7 @@ static void Log_SignalHandler(int sig)
LOG_INFO("STACK TRACE:");
struct backtrace_state *state = backtrace_create_state(
NULL, BACKTRACE_SUPPORTS_THREADS, Log_ErrorCallback, NULL);
backtrace_full(state, 0, Log_FullTrace, Log_ErrorCallback, NULL);
backtrace_full(state, 0, Log_StackTrace, Log_ErrorCallback, NULL);
exit(EXIT_FAILURE);
}

Expand Down
126 changes: 45 additions & 81 deletions src/log_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "memory.h"

#include <dwarfstack.h>
#include <process.h>
#include <signal.h>
#include <stdio.h>
Expand All @@ -13,7 +14,9 @@
static char *m_MiniDumpPath = NULL;
static char *Log_GetMiniDumpPath(const char *log_path);
static void Log_CreateMiniDump(EXCEPTION_POINTERS *ex, const char *path);
static void Log_LogStackTraces(EXCEPTION_POINTERS *ex);
static void Log_StackTrace(
uint64_t addr, const char *filename, int line_no, const char *func_name,
void *context, int column_no);

static char *Log_GetMiniDumpPath(const char *const log_path)
{
Expand All @@ -31,6 +34,40 @@ static char *Log_GetMiniDumpPath(const char *const log_path)
return minidump_path;
}

static void Log_StackTrace(
const uint64_t addr, const char *filename, const int line_no,
const char *const func_name, void *const context, const int column_no)
{
int32_t *count = context;
void *ptr = (void *)(uintptr_t)addr;

switch (line_no) {
case DWST_BASE_ADDR:
LOG_INFO("--- 0x%p: %s", ptr, filename);
break;

case DWST_NOT_FOUND:
case DWST_NO_DBG_SYM:
case DWST_NO_SRC_FILE:
LOG_INFO("%02d. 0x%p: %s", *count, ptr, filename);
(*count)++;
break;

default:
if (ptr != NULL) {
LOG_INFO(
"%02d. 0x%p: (%s:%d:%d) %s", *count, ptr, filename, line_no,
column_no, func_name);
} else {
LOG_INFO(
"%02d. %*s (%s:%d:%d) %s", *count, (int32_t)sizeof(void *) * 2,
"", filename, line_no, column_no, func_name);
}
(*count)++;
break;
}
}

static void Log_CreateMiniDump(
EXCEPTION_POINTERS *const ex, const char *const path)
{
Expand All @@ -49,91 +86,18 @@ static void Log_CreateMiniDump(
LOG_INFO("Crash dump info put in %s", path);
}

static void Log_LogStackTraces(EXCEPTION_POINTERS *const ex)
LONG WINAPI Log_CrashHandler(EXCEPTION_POINTERS *ex)
{
LOG_ERROR("== CRASH REPORT ==");
LOG_INFO("EXCEPTION CODE: %x", ex->ExceptionRecord->ExceptionCode);
LOG_INFO("EXCEPTION ADDRESS: %x", ex->ExceptionRecord->ExceptionAddress);
LOG_INFO("STACK TRACE:");

HANDLE thread = GetCurrentThread();
HANDLE process = GetCurrentProcess();

CONTEXT context = {};
context.ContextFlags = CONTEXT_FULL;

if (thread != GetCurrentThread()) {
SuspendThread(thread);
if (GetThreadContext(thread, &context) == FALSE) {
printf("Failed to get context\n");
return;
}
ResumeThread(thread);
}
RtlCaptureContext(&context);

SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
int32_t count = 0;
dwstOfException(ex->ContextRecord, &Log_StackTrace, &count);

if (!SymInitialize(process, 0, TRUE)) {
LOG_ERROR("Failed to call SymInitialize");
return;
}

DWORD image;
STACKFRAME64 stackframe;
ZeroMemory(&stackframe, sizeof(STACKFRAME64));

#ifdef _M_IX86
image = IMAGE_FILE_MACHINE_I386;
stackframe.AddrPC.Offset = context.Eip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Ebp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Esp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
image = IMAGE_FILE_MACHINE_AMD64;
stackframe.AddrPC.Offset = context.Rip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Rsp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Rsp;
stackframe.AddrStack.Mode = AddrModeFlat;
#endif

while (StackWalk64(
image, process, thread, &stackframe, &context, 0,
SymFunctionTableAccess64, SymGetModuleBase64, 0)) {
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;

symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;

DWORD64 displacement64 = 0;
if (SymFromAddr(
process, stackframe.AddrPC.Offset, &displacement64, symbol)) {
IMAGEHLP_LINE64 line;
DWORD displacement32;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymGetLineFromAddr64(
process, stackframe.AddrPC.Offset, &displacement32,
&line)) {
LOG_INFO(
"0x%08llX: %s (%s:%d)", symbol->Address, symbol->Name,
line.FileName, line.LineNumber);
} else {
LOG_INFO("0x%08llX: %s", symbol->Address, symbol->Name);
}
} else {
LOG_INFO("0x%08llX: ???", symbol->Address);
}
}

SymCleanup(process);
}

LONG WINAPI Log_CrashHandler(EXCEPTION_POINTERS *ex)
{
Log_CreateMiniDump(ex, m_MiniDumpPath);
Log_LogStackTraces(ex);

return EXCEPTION_EXECUTE_HANDLER;
}

Expand Down
9 changes: 9 additions & 0 deletions subprojects/dwarfstack.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[wrap-file]
directory = dwarfstack-2.2
source_url = https://github.com/ssbssa/dwarfstack/archive/refs/tags/2.2.tar.gz
source_filename = dwarfstack-2.2.tar.gz
source_hash = 1fca1d12756941c4c932b50f9abe56a3756f012a1e93deef553e141a78cc2709
patch_directory = dwarfstack

[provide]
dwarfstack = dragonbox_dep
84 changes: 84 additions & 0 deletions subprojects/packagefiles/dwarfstack/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
project(
'dwarfstack',
'c',
default_options: [
'c_std=c2x',
'warning_level=2',
],
)

c_compiler = meson.get_compiler('c')
build_opts = [
'-Wno-unused',
'-DDWST_STATIC',
'-DNO_DBGHELP',
'-DLIBDWARF_STATIC',
]
add_project_arguments(build_opts, language: 'c')
dep_zlib = dependency('zlib')

sources = [
'mgwhelp/dwarf_pe.c',
'src/dwst-exception-dialog.c',
'src/dwst-exception.c',
'src/dwst-process.c',
'src/dwst-location.c',
'src/dwst-file.c',
'libdwarf/dwarf_debugnames.c',
'libdwarf/dwarf_dsc.c',
'libdwarf/dwarf_alloc.c',
'libdwarf/dwarf_loclists.c',
'libdwarf/dwarf_macro5.c',
'libdwarf/dwarf_harmless.c',
'libdwarf/dwarf_locationop_read.c',
'libdwarf/dwarf_gnu_index.c',
'libdwarf/dwarf_rnglists.c',
'libdwarf/dwarf_error.c',
'libdwarf/dwarf_init_finish.c',
'libdwarf/dwarf_abbrev.c',
'libdwarf/dwarf_xu_index.c',
'libdwarf/dwarf_names.c',
'libdwarf/dwarf_str_offsets.c',
'libdwarf/dwarf_tsearchhash.c',
'libdwarf/dwarf_die_deliv.c',
'libdwarf/dwarf_frame.c',
'libdwarf/dwarf_query.c',
'libdwarf/dwarf_global.c',
'libdwarf/dwarf_loc.c',
'libdwarf/dwarf_tied.c',
'libdwarf/dwarf_util.c',
'libdwarf/dwarf_form.c',
'libdwarf/dwarf_groups.c',
'libdwarf/dwarf_frame2.c',
'libdwarf/dwarf_memcpy_swap.c',
'libdwarf/dwarf_leb.c',
'libdwarf/dwarf_debuglink.c',
'libdwarf/dwarf_string.c',
'libdwarf/dwarf_line.c',
'libdwarf/dwarf_fission_to_cu.c',
'libdwarf/dwarf_find_sigref.c',
'libdwarf/dwarf_ranges.c',
]

dependencies = [
dep_zlib,
]

libdwarfstack = static_library(
'libdwarfstack',
sources,
dependencies: dependencies,
include_directories: [
'include/',
'mgwhelp/',
'src/',
'libdwarf/',
]
)

dep_dwarfstack = declare_dependency(
link_whole: libdwarfstack,
include_directories: [
include_directories('include', is_system: true)
]
)

0 comments on commit ac6a343

Please sign in to comment.