From 486446be2b64f7168b4d40838d9b9c48c220cfa1 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 17 Jan 2024 17:47:31 +0100 Subject: [PATCH 1/2] windows: use unhandled exception handler API instead of `libc.signal` --- back.odin | 19 +----------------- back_unix.odin | 28 +++++++++++++++++++++++++++ back_windows.odin | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 18 deletions(-) create mode 100644 back_unix.odin diff --git a/back.odin b/back.odin index 1306db9..adf6b9d 100644 --- a/back.odin +++ b/back.odin @@ -1,6 +1,5 @@ package back -import "core:c/libc" import "core:fmt" import "core:io" import "core:os" @@ -107,23 +106,7 @@ assertion_failure_proc :: proc(prefix, message: string, loc: runtime.Source_Code } register_segfault_handler :: proc() { - libc.signal(libc.SIGSEGV, proc "c" (code: i32) { - context = runtime.default_context() - - backtrace: { - t := trace() - lines, err := lines(t.trace[:t.len]) - if err != nil { - fmt.eprintf("Segmentation Fault\nCould not get backtrace: %v\n", err) - break backtrace - } - - fmt.eprintln("Segmentation Fault\n[back trace]") - print(lines) - } - - os.exit(int(code)) - }) + _register_segfault_handler() } print :: proc(lines: []Line, padding := " ", w: Maybe(io.Writer) = nil, no_temp_guard := false) { diff --git a/back_unix.odin b/back_unix.odin new file mode 100644 index 0000000..a4dfee6 --- /dev/null +++ b/back_unix.odin @@ -0,0 +1,28 @@ +//+build linux, darwin +package back + +import "core:c/libc" +import "core:fmt" +import "core:os" +import "core:runtime" + +_register_segfault_handler :: proc() { + libc.signal(libc.SIGSEGV, proc "c" (code: i32) { + context = runtime.default_context() + context.allocator = context.temp_allocator + + backtrace: { + t := trace() + lines, err := lines(t.trace[:t.len]) + if err != nil { + fmt.eprintf("Exception (Code: %i)\nCould not get backtrace: %v\n", code, err) + break backtrace + } + + fmt.eprintf("Exception (Code: %i)\n[back trace]\n", code) + print(lines) + } + + os.exit(int(code)) + }) +} diff --git a/back_windows.odin b/back_windows.odin index be1a74f..b41a145 100644 --- a/back_windows.odin +++ b/back_windows.odin @@ -1,9 +1,12 @@ //+private package back +import "core:fmt" import "core:runtime" import "core:strings" +import win "core:sys/windows" + import "vendor/pdb/pdb" _Trace_Entry :: pdb.StackFrame @@ -54,3 +57,49 @@ _lines :: proc(bt: Trace) -> (out: []Line, err: Lines_Error) { return } + +_register_segfault_handler :: proc() { + pdb.SetUnhandledExceptionFilter(proc "stdcall" (exception_info: ^win.EXCEPTION_POINTERS) -> win.LONG { + context = runtime.default_context() + context.allocator = context.temp_allocator + + fmt.eprint("Exception ") + if exception_info.ExceptionRecord != nil { + fmt.eprintf("(Type: %x, Flags: %x)\n", exception_info.ExceptionRecord.ExceptionCode, exception_info.ExceptionRecord.ExceptionFlags) + } + + ctxt := cast(^pdb.CONTEXT)exception_info.ContextRecord + + trace_buf: [BACKTRACE_SIZE]pdb.StackFrame + trace_count := pdb.capture_stack_trace_from_context(ctxt, trace_buf[:]) + + src_code_locs: pdb.RingBuffer(runtime.Source_Code_Location) + pdb.init_rb(&src_code_locs, BACKTRACE_SIZE) + + no_debug_info_found := pdb.parse_stack_trace(trace_buf[:trace_count], true, &src_code_locs) + if no_debug_info_found { + fmt.eprintln("Could not get backtrace: pdb file not found, compile with `-debug` to generate pdb files and get a back trace.") + return win.EXCEPTION_CONTINUE_SEARCH + } + + fmt.eprintln("[back trace]") + + lines: [BACKTRACE_SIZE]Line + for i in 0.. Date: Wed, 17 Jan 2024 21:37:27 +0100 Subject: [PATCH 2/2] windows: fix weird crash in allocator print results by short-circuiting when not debug --- allocator.odin | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/allocator.odin b/allocator.odin index 31faafe..0651c19 100644 --- a/allocator.odin +++ b/allocator.odin @@ -184,6 +184,25 @@ Result_Type :: enum { } tracking_allocator_print_results :: proc(t: ^Tracking_Allocator, type: Result_Type = .Both) { + when ODIN_OS == .Windows && !ODIN_DEBUG { + if type == .Both || type == .Leaks { + for _, leak in t.allocation_map { + fmt.eprintf("\x1b[31m%v leaked %m\x1b[0m\n\tCompile with `-debug` to get a back trace\n", leak.location, leak.size) + } + } + + if type == .Both || type == .Bad_Frees { + for bad_free, fi in t.bad_free_array { + fmt.eprintf( + "\x1b[31m%v allocation %p was freed badly\x1b[0m\n\tCompile with `-debug` to get a back trace\n", + bad_free.location, + bad_free.memory, + ) + } + } + return + } + context.allocator = t.internals_allocator Work :: struct { @@ -221,7 +240,6 @@ tracking_allocator_print_results :: proc(t: ^Tracking_Allocator, type: Result_Ty } extra_threads := max(0, min(os.processor_core_count() - 1, trace_count - 1)) - extra_threads_done: sync.Wait_Group sync.wait_group_add(&extra_threads_done, extra_threads + 1)