add POSIX stacktrace crash handler and fix build script path
This commit is contained in:
2
build.sh
2
build.sh
@@ -4,6 +4,6 @@ if [ ! -d build ]; then
|
|||||||
mkdir build
|
mkdir build
|
||||||
fi
|
fi
|
||||||
cd build
|
cd build
|
||||||
clang ../src/testing/testing_main.c -o testing_main -I../src -g -Wall -Wextra -Werror -fdiagnostics-absolute-paths -Wno-single-bit-bitfield-constant-conversion -Wno-unsequenced -Wno-missing-field-initializers -Wno-missing-braces -ldl -lm -lbacktrace
|
clang $(realpath ../src/testing/testing_main.c) -o testing_main -I../src -g -Wall -Wextra -Werror -fdiagnostics-absolute-paths -Wno-single-bit-bitfield-constant-conversion -Wno-unsequenced -Wno-missing-field-initializers -Wno-missing-braces -ldl -lm -lbacktrace
|
||||||
./testing_main
|
./testing_main
|
||||||
cd ..
|
cd ..
|
||||||
|
|||||||
@@ -94,198 +94,6 @@ fn void os_core_init(void) {
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
typedef struct b_stacktrace_tag* b_stacktrace_handle;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Returns a stack-trace handle from the point of view of the caller which
|
|
||||||
can be expanded to a string via b_stacktrace_to_string.
|
|
||||||
The handle is allocated with `malloc` and needs to be freed with `free`
|
|
||||||
*/
|
|
||||||
fn b_stacktrace_handle b_stacktrace_get();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Converts a stack-trace handle to a human-readable string.
|
|
||||||
The string is allocated with `malloc` and needs to be freed with `free`
|
|
||||||
*/
|
|
||||||
fn char* b_stacktrace_to_string(b_stacktrace_handle stacktrace);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Returns a human-readable stack-trace string from the point of view of the
|
|
||||||
caller.
|
|
||||||
The string is allocated with `malloc` and needs to be freed with `free`
|
|
||||||
*/
|
|
||||||
fn char* b_stacktrace_get_string(void);
|
|
||||||
|
|
||||||
/* version */
|
|
||||||
|
|
||||||
typedef struct print_buf {
|
|
||||||
char* buf;
|
|
||||||
int pos;
|
|
||||||
int size;
|
|
||||||
} print_buf;
|
|
||||||
|
|
||||||
static print_buf buf_init(void) {
|
|
||||||
print_buf ret = {
|
|
||||||
(char*) malloc(1024),
|
|
||||||
0,
|
|
||||||
1024
|
|
||||||
};
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void buf_printf(print_buf* b, const char* fmt, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
const int len = stbsp_vsnprintf(NULL, 0, fmt, args) + 1;
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
const int new_end = b->pos + len;
|
|
||||||
|
|
||||||
if (new_end > b->size) {
|
|
||||||
while (new_end > b->size) b->size *= 2;
|
|
||||||
b->buf = (char*)realloc(b->buf, b->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
b->pos += stbsp_vsnprintf(b->buf + b->pos, len, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* b_stacktrace_get_string(void) {
|
|
||||||
b_stacktrace_handle h = b_stacktrace_get();
|
|
||||||
char* ret = b_stacktrace_to_string(h);
|
|
||||||
free(h);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define B_STACKTRACE_MAX_DEPTH 1024
|
|
||||||
#define B_STACKTRACE_ERROR_FLAG ((DWORD64)1 << 63)
|
|
||||||
|
|
||||||
typedef struct b_stacktrace_entry {
|
|
||||||
DWORD64 AddrPC_Offset;
|
|
||||||
DWORD64 AddrReturn_Offset;
|
|
||||||
} b_stacktrace_entry;
|
|
||||||
|
|
||||||
static int SymInitialize_called = 0;
|
|
||||||
|
|
||||||
b_stacktrace_handle b_stacktrace_get(void) {
|
|
||||||
HANDLE process = GetCurrentProcess();
|
|
||||||
HANDLE thread = GetCurrentThread();
|
|
||||||
CONTEXT context;
|
|
||||||
STACKFRAME64 frame; /* in/out stackframe */
|
|
||||||
DWORD imageType;
|
|
||||||
b_stacktrace_entry* ret = (b_stacktrace_entry*)malloc(B_STACKTRACE_MAX_DEPTH * sizeof(b_stacktrace_entry));
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (!SymInitialize_called) {
|
|
||||||
SymInitialize(process, NULL, TRUE);
|
|
||||||
SymInitialize_called = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtlCaptureContext(&context);
|
|
||||||
|
|
||||||
memset(&frame, 0, sizeof(frame));
|
|
||||||
#ifdef _M_IX86
|
|
||||||
imageType = IMAGE_FILE_MACHINE_I386;
|
|
||||||
frame.AddrPC.Offset = context.Eip;
|
|
||||||
frame.AddrPC.Mode = AddrModeFlat;
|
|
||||||
frame.AddrFrame.Offset = context.Ebp;
|
|
||||||
frame.AddrFrame.Mode = AddrModeFlat;
|
|
||||||
frame.AddrStack.Offset = context.Esp;
|
|
||||||
frame.AddrStack.Mode = AddrModeFlat;
|
|
||||||
#elif _M_X64
|
|
||||||
imageType = IMAGE_FILE_MACHINE_AMD64;
|
|
||||||
frame.AddrPC.Offset = context.Rip;
|
|
||||||
frame.AddrPC.Mode = AddrModeFlat;
|
|
||||||
frame.AddrFrame.Offset = context.Rsp;
|
|
||||||
frame.AddrFrame.Mode = AddrModeFlat;
|
|
||||||
frame.AddrStack.Offset = context.Rsp;
|
|
||||||
frame.AddrStack.Mode = AddrModeFlat;
|
|
||||||
#elif _M_IA64
|
|
||||||
imageType = IMAGE_FILE_MACHINE_IA64;
|
|
||||||
frame.AddrPC.Offset = context.StIIP;
|
|
||||||
frame.AddrPC.Mode = AddrModeFlat;
|
|
||||||
frame.AddrFrame.Offset = context.IntSp;
|
|
||||||
frame.AddrFrame.Mode = AddrModeFlat;
|
|
||||||
frame.AddrBStore.Offset = context.RsBSP;
|
|
||||||
frame.AddrBStore.Mode = AddrModeFlat;
|
|
||||||
frame.AddrStack.Offset = context.IntSp;
|
|
||||||
frame.AddrStack.Mode = AddrModeFlat;
|
|
||||||
#else
|
|
||||||
#error "Platform not supported!"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
b_stacktrace_entry* cur = ret + i++;
|
|
||||||
if (i == B_STACKTRACE_MAX_DEPTH) {
|
|
||||||
cur->AddrPC_Offset = 0;
|
|
||||||
cur->AddrReturn_Offset = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!StackWalk64(imageType, process, thread, &frame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
|
|
||||||
cur->AddrPC_Offset = frame.AddrPC.Offset;
|
|
||||||
cur->AddrReturn_Offset = B_STACKTRACE_ERROR_FLAG; /* mark error */
|
|
||||||
cur->AddrReturn_Offset |= GetLastError();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur->AddrPC_Offset = frame.AddrPC.Offset;
|
|
||||||
cur->AddrReturn_Offset = frame.AddrReturn.Offset;
|
|
||||||
|
|
||||||
if (frame.AddrReturn.Offset == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (b_stacktrace_handle)(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* b_stacktrace_to_string(b_stacktrace_handle h) {
|
|
||||||
const b_stacktrace_entry* entries = (b_stacktrace_entry*)h;
|
|
||||||
int i = 0;
|
|
||||||
HANDLE process = GetCurrentProcess();
|
|
||||||
print_buf out = buf_init();
|
|
||||||
IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + 1024);
|
|
||||||
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
|
||||||
symbol->MaxNameLength = 1024;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
IMAGEHLP_LINE64 lineData;
|
|
||||||
DWORD lineOffset = 0;
|
|
||||||
DWORD64 symOffset = 0;
|
|
||||||
const b_stacktrace_entry* cur = entries + i++;
|
|
||||||
|
|
||||||
if (cur->AddrReturn_Offset & B_STACKTRACE_ERROR_FLAG) {
|
|
||||||
DWORD error = cur->AddrReturn_Offset & 0xFFFFFFFF;
|
|
||||||
buf_printf(&out, "StackWalk64 error: %d @ %p\n", error, cur->AddrPC_Offset);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur->AddrPC_Offset == cur->AddrReturn_Offset) {
|
|
||||||
buf_printf(&out, "Stack overflow @ %p\n", cur->AddrPC_Offset);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SymGetLineFromAddr64(process, cur->AddrPC_Offset, &lineOffset, &lineData);
|
|
||||||
buf_printf(&out, "%s(%d): ", lineData.FileName, lineData.LineNumber);
|
|
||||||
|
|
||||||
if (SymGetSymFromAddr64(process, cur->AddrPC_Offset, &symOffset, symbol)) {
|
|
||||||
buf_printf(&out, "%s\n", symbol->Name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buf_printf(&out, " Unkown symbol @ %p\n", cur->AddrPC_Offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur->AddrReturn_Offset == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(symbol);
|
|
||||||
return out.buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn void *os_vmem_reserve(usize size) {
|
fn void *os_vmem_reserve(usize size) {
|
||||||
void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
|
void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
|
||||||
return result;
|
return result;
|
||||||
@@ -349,6 +157,9 @@ fn void os_core_init(void) {
|
|||||||
tcx->perm = perm;
|
tcx->perm = perm;
|
||||||
}
|
}
|
||||||
#elif PLATFORM_POSIX
|
#elif PLATFORM_POSIX
|
||||||
|
#if defined(__linux__) && !defined(_GNU_SOURCE)
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -357,13 +168,215 @@ fn void os_core_init(void) {
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <ucontext.h>
|
#include <ucontext.h>
|
||||||
|
#include <execinfo.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#if !PLATFORM_EMSCRIPTEN
|
#if !PLATFORM_EMSCRIPTEN
|
||||||
#include <execinfo.h>
|
|
||||||
#include <backtrace.h>
|
typedef struct b_stacktrace_tag* b_stacktrace_handle;
|
||||||
|
b_stacktrace_handle b_stacktrace_get();
|
||||||
|
int b_stacktrace_depth(b_stacktrace_handle stacktrace);
|
||||||
|
char* b_stacktrace_to_string(b_stacktrace_handle stacktrace);
|
||||||
|
char* malloc_backtrace(void);
|
||||||
|
|
||||||
|
typedef struct print_buf {
|
||||||
|
char* buf;
|
||||||
|
int pos;
|
||||||
|
int size;
|
||||||
|
} print_buf;
|
||||||
|
|
||||||
|
static print_buf buf_init(void) {
|
||||||
|
print_buf ret = {
|
||||||
|
(char*) malloc(1024),
|
||||||
|
0,
|
||||||
|
1024
|
||||||
|
};
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void buf_printf(print_buf* b, const char* fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
const int len = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
const int new_end = b->pos + len;
|
||||||
|
|
||||||
|
if (new_end > b->size) {
|
||||||
|
while (new_end > b->size) b->size *= 2;
|
||||||
|
b->buf = (char*)realloc(b->buf, b->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
b->pos += vsnprintf(b->buf + b->pos, len, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* malloc_backtrace(void) {
|
||||||
|
b_stacktrace_handle h = b_stacktrace_get();
|
||||||
|
char* ret = b_stacktrace_to_string(h);
|
||||||
|
free(h);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define B_STACKTRACE_MAX_DEPTH 1024
|
||||||
|
typedef struct b_stacktrace {
|
||||||
|
void* trace[B_STACKTRACE_MAX_DEPTH];
|
||||||
|
int trace_size;
|
||||||
|
} b_stacktrace;
|
||||||
|
|
||||||
|
b_stacktrace_handle b_stacktrace_get(void) {
|
||||||
|
b_stacktrace* ret = (b_stacktrace*)malloc(sizeof(b_stacktrace));
|
||||||
|
ret->trace_size = backtrace(ret->trace, B_STACKTRACE_MAX_DEPTH);
|
||||||
|
return (b_stacktrace_handle)(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int b_stacktrace_depth(b_stacktrace_handle h) {
|
||||||
|
const b_stacktrace* stacktrace = (b_stacktrace*)h;
|
||||||
|
return stacktrace->trace_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* b_stacktrace_to_string(b_stacktrace_handle h) {
|
||||||
|
const b_stacktrace* stacktrace = (b_stacktrace*)h;
|
||||||
|
char** messages = backtrace_symbols(stacktrace->trace, stacktrace->trace_size);
|
||||||
|
print_buf out = buf_init();
|
||||||
|
int i;
|
||||||
|
|
||||||
|
int skip_count = 5;
|
||||||
|
for (i = 0; i < stacktrace->trace_size; ++i) {
|
||||||
|
void* tracei = stacktrace->trace[i];
|
||||||
|
char* msg = messages[i];
|
||||||
|
|
||||||
|
if (i < skip_count) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate load offset */
|
||||||
|
Dl_info info;
|
||||||
|
dladdr(tracei, &info);
|
||||||
|
if (info.dli_fbase == (void*)0x400000) {
|
||||||
|
/* address from executable, so don't offset */
|
||||||
|
info.dli_fbase = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*msg && *msg != '(') ++msg;
|
||||||
|
*msg = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
char cmd[1024];
|
||||||
|
char line[2048];
|
||||||
|
|
||||||
|
FILE* fp;
|
||||||
|
snprintf(cmd, 1024, "addr2line -e %s -f -C -p %p 2>/dev/null", messages[i], (void*)((char*)tracei - (char*)info.dli_fbase));
|
||||||
|
|
||||||
|
fp = popen(cmd, "r");
|
||||||
|
if (!fp) {
|
||||||
|
buf_printf(&out, "Failed to generate trace further...\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
|
buf_printf(&out, " ");
|
||||||
|
if (strstr(line, "?? ")) {
|
||||||
|
/* just output address if nothing can be found */
|
||||||
|
buf_printf(&out, "%p\n", tracei);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int len = strlen(line);
|
||||||
|
char *at = strstr(line, " at ");
|
||||||
|
if (at) {
|
||||||
|
char *function = line;
|
||||||
|
int function_len = at - line;
|
||||||
|
char *file = at + 4;
|
||||||
|
int file_len = strlen(file) - 1;
|
||||||
|
buf_printf(&out, " %.*s %.*s (%s)\n", file_len, file, function_len, function, messages[i]);
|
||||||
|
} else {
|
||||||
|
buf_printf(&out, " %.*s (%s)\n", len - 1, line, messages[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(messages);
|
||||||
|
return out.buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_backtrace(void) {
|
||||||
|
char *backtrace = malloc_backtrace();
|
||||||
|
puts(backtrace);
|
||||||
|
free(backtrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *signal_to_string(int signal) {
|
||||||
|
switch (signal) {
|
||||||
|
case SIGINT: return "SIGINT";
|
||||||
|
case SIGILL: return "SIGILL";
|
||||||
|
case SIGABRT: return "SIGABRT";
|
||||||
|
case SIGFPE: return "SIGFPE";
|
||||||
|
case SIGSEGV: return "SIGSEGV";
|
||||||
|
case SIGTERM: return "SIGTERM";
|
||||||
|
case SIGHUP: return "SIGALRM";
|
||||||
|
case SIGQUIT: return "SIGQUIT";
|
||||||
|
case SIGTRAP: return "SIGTRAP";
|
||||||
|
case SIGKILL: return "SIGKILL";
|
||||||
|
case SIGPIPE: return "SIGPIPE";
|
||||||
|
case SIGALRM: return "SIGHUP";
|
||||||
|
case SIGPOLL: return "SIGPOLL";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backtrace_handle_signal(int signal, siginfo_t* info, void* context) {
|
||||||
|
(void)context; // unused
|
||||||
|
printf("Stack trace (%s/%d):", signal_to_string(signal), signal);
|
||||||
|
if (signal == SIGSEGV) {
|
||||||
|
printf(" at addr: %p", info->si_addr);
|
||||||
|
}
|
||||||
|
puts("");
|
||||||
|
print_backtrace();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void os__setup_backtrace() {
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_sigaction = backtrace_handle_signal;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||||
|
|
||||||
|
sigaction(SIGSEGV, &sa, NULL);
|
||||||
|
sigaction(SIGABRT, &sa, NULL);
|
||||||
|
sigaction(SIGFPE, &sa, NULL);
|
||||||
|
sigaction(SIGBUS, &sa, NULL);
|
||||||
|
sigaction(SIGILL, &sa, NULL);
|
||||||
|
sigaction(SIGTRAP, &sa, NULL);
|
||||||
|
#ifdef SIGSYS
|
||||||
|
sigaction(SIGSYS, &sa, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef SIGXCPU
|
||||||
|
sigaction(SIGXCPU, &sa, NULL);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGXFSZ
|
||||||
|
sigaction(SIGXFSZ, &sa, NULL);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGPIPE
|
||||||
|
sigaction(SIGPIPE, &sa, NULL);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGTERM
|
||||||
|
sigaction(SIGTERM, &sa, NULL);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGINT
|
||||||
|
sigaction(SIGINT, &sa, NULL);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGQUIT
|
||||||
|
sigaction(SIGQUIT, &sa, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
fn void *os_vmem_reserve(usize size) {
|
fn void *os_vmem_reserve(usize size) {
|
||||||
void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||||
return result == MAP_FAILED ? NULL : result;
|
return result == MAP_FAILED ? NULL : result;
|
||||||
@@ -399,68 +412,16 @@ fn f64 os_parse_float(char *str) {
|
|||||||
return strtod(str, NULL);
|
return strtod(str, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
gb struct backtrace_state *backtrace_state = NULL;
|
|
||||||
|
|
||||||
fn void os_core_backtrace_error_callback(void *data, const char *msg, int errnum) {
|
|
||||||
unused(data);
|
|
||||||
errorf("libbacktrace error: %s (errnum: %d)\n", msg, errnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn int os_core_backtrace_print_callback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function) {
|
|
||||||
unused(data);
|
|
||||||
unused(pc);
|
|
||||||
b32 printed = false;
|
|
||||||
if (filename != NULL) {
|
|
||||||
char buffer[512];
|
|
||||||
char *f = realpath(filename, buffer);
|
|
||||||
printf("%s:%d:1: ", f, lineno);
|
|
||||||
printed = true;
|
|
||||||
}
|
|
||||||
if (function != NULL) {
|
|
||||||
printf("%s", function);
|
|
||||||
printed = true;
|
|
||||||
}
|
|
||||||
if (printed) {
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !PLATFORM_EMSCRIPTEN
|
|
||||||
fn void os_unix_crash_handler(int signal, siginfo_t* info, void* context) {
|
|
||||||
unused(context);
|
|
||||||
unused(signal);
|
|
||||||
unused(info);
|
|
||||||
backtrace_full(backtrace_state, 2, os_core_backtrace_print_callback, os_core_backtrace_error_callback, NULL);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn void os_unix_register_crash_handler() {
|
|
||||||
backtrace_state = backtrace_create_state(NULL, 1, os_core_backtrace_error_callback, NULL);
|
|
||||||
|
|
||||||
struct sigaction sa;
|
|
||||||
sa.sa_sigaction = os_unix_crash_handler;
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
||||||
|
|
||||||
sigaction(SIGSEGV, &sa, NULL);
|
|
||||||
sigaction(SIGABRT, &sa, NULL);
|
|
||||||
sigaction(SIGBUS, &sa, NULL);
|
|
||||||
sigaction(SIGILL, &sa, NULL);
|
|
||||||
sigaction(SIGFPE, &sa, NULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fn void os_core_small_init(ma_arena_t *arena) {
|
fn void os_core_small_init(ma_arena_t *arena) {
|
||||||
|
#if !PLATFORM_EMSCRIPTEN
|
||||||
|
os__setup_backtrace();
|
||||||
|
#endif
|
||||||
tcx = ma_push_type(arena, thread_ctx_t);
|
tcx = ma_push_type(arena, thread_ctx_t);
|
||||||
tcx->log.break_on_error = true;
|
tcx->log.break_on_error = true;
|
||||||
tcx->log.break_on_fatal = true;
|
tcx->log.break_on_fatal = true;
|
||||||
tcx->log.break_on_warning = true;
|
tcx->log.break_on_warning = true;
|
||||||
tcx->log.print_file_and_line = true;
|
tcx->log.print_file_and_line = true;
|
||||||
tcx->log.log_proc = default_log_proc;
|
tcx->log.log_proc = default_log_proc;
|
||||||
#if !PLATFORM_EMSCRIPTEN
|
|
||||||
os_unix_register_crash_handler();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void os_core_init(void) {
|
fn void os_core_init(void) {
|
||||||
|
|||||||
Reference in New Issue
Block a user