From b00d3d9041697b556eae3ac1787b614f52033d1c Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 4 Nov 2025 13:40:00 -0800 Subject: [PATCH] print out call stacks on crashes --- build.sh | 4 +- src/os/core/linux/os_core_linux.c | 69 +++++++++++++++++++++++++++++++ src/os/core/linux/os_core_linux.h | 5 ++- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/build.sh b/build.sh index f7ea6139..ecd0ce6e 100644 --- a/build.sh +++ b/build.sh @@ -19,12 +19,12 @@ git_hash=$(git describe --always --dirty) git_hash_full=$(git rev-parse HEAD) # --- Compile/Link Line Definitions ------------------------------------------- -clang_common="-I../src/ -I/usr/include/freetype2/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf" +clang_common="-I../src/ -I/usr/include/freetype2/ -I../local/ -D_GNU_SOURCE -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf" clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}" clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}" clang_link="-lpthread -lm -lrt -ldl" clang_out="-o" -gcc_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf" +gcc_common="-I../src/ -I../local/ -g -D_GNU_SOURCE -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf" gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common} ${auto_compile_flags}" gcc_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${gcc_common} ${auto_compile_flags}" gcc_link="-lpthread -lm -lrt -ldl" diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index 872bd1b9..1e6b71e5 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -1399,9 +1399,78 @@ os_make_guid(void) //////////////////////////////// //~ rjf: @os_hooks Entry Points (Implemented Per-OS) +internal void +lnx_signal_handler(int sig, siginfo_t *info, void *arg) +{ + local_persist volatile U32 first = 0; + if (ins_atomic_u32_eval_cond_assign(&first, 1, 0) != 0) + { + for(;;) + { + sleep(UINT32_MAX); + } + } + + local_persist void *ips[4096]; + int ips_count = backtrace(ips, ArrayCount(ips)); + + fprintf(stderr, "A fatal signal was received: %s (%d). The process is terminating.\n", strsignal(sig), sig); + fprintf(stderr, "Create a new issue with this report at %s.\n\n", BUILD_ISSUES_LINK_STRING_LITERAL); + fprintf(stderr, "Callstack:\n"); + for EachIndex(i, ips_count) + { + Dl_info info = {0}; + dladdr(ips[i], &info); + + char cmd[2048]; + snprintf(cmd, sizeof(cmd), "llvm-symbolizer --relative-address -f -e %s %lu", info.dli_fname, (unsigned long)ips[i] - (unsigned long)info.dli_fbase); + FILE *f = popen(cmd, "r"); + if(f) + { + char func_name[256], file_name[256]; + if(fgets(func_name, sizeof(func_name), f) && fgets(file_name, sizeof(file_name), f)) + { + String8 func = str8_cstring(func_name); + if(func.size > 0) func.size -= 1; + String8 module = str8_skip_last_slash(str8_cstring(info.dli_fname)); + String8 file = str8_skip_last_slash(str8_cstring_capped(file_name, file_name + sizeof(file_name))); + if(file.size > 0) file.size -= 1; + + B32 no_func = str8_match(func, str8_lit("??"), StringMatchFlag_RightSideSloppy); + B32 no_file = str8_match(file, str8_lit("??"), StringMatchFlag_RightSideSloppy); + if(no_func) { func = str8_zero(); } + if(no_file) { file = str8_zero(); } + + fprintf(stderr, "%ld. [0x%016lx] %.*s%s%.*s %.*s\n", i+1, (unsigned long)ips[i], (int)module.size, module.str, (!no_func || !no_file) ? ", " : "", (int)func.size, func.str, (int)file.size, file.str); + } + pclose(f); + } + else + { + fprintf(stderr, "%ld. [0x%016lx] %s\n", i+1, (unsigned long)ips[i], info.dli_fname); + } + } + fprintf(stderr, "\nVersion: %s%s\n\n", BUILD_VERSION_STRING_LITERAL, BUILD_GIT_HASH_STRING_LITERAL_APPEND); + + _exit(0); +} + int main(int argc, char **argv) { + // install signal handler for the crash call stacks + { + struct sigaction handler = { .sa_sigaction = lnx_signal_handler, .sa_flags = SA_SIGINFO, }; + sigfillset(&handler.sa_mask); + sigaction(SIGILL, &handler, NULL); + sigaction(SIGTRAP, &handler, NULL); + sigaction(SIGABRT, &handler, NULL); + sigaction(SIGFPE, &handler, NULL); + sigaction(SIGBUS, &handler, NULL); + sigaction(SIGSEGV, &handler, NULL); + sigaction(SIGQUIT, &handler, NULL); + } + //- rjf: set up OS layer { //- rjf: get statically-allocated system/process info diff --git a/src/os/core/linux/os_core_linux.h b/src/os/core/linux/os_core_linux.h index c3136d3b..2a351674 100644 --- a/src/os/core/linux/os_core_linux.h +++ b/src/os/core/linux/os_core_linux.h @@ -7,7 +7,6 @@ //////////////////////////////// //~ rjf: Includes -#define _GNU_SOURCE #include #include #include @@ -17,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -27,7 +27,8 @@ #include #include #include -#include +#include +#include pid_t gettid(void); int pthread_setname_np(pthread_t thread, const char *name);