Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

windows: use unhandled exception handler API instead of libc.signal and fix CI #5

Merged
merged 2 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion allocator.odin
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)

Expand Down
19 changes: 1 addition & 18 deletions back.odin
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package back

import "core:c/libc"
import "core:fmt"
import "core:io"
import "core:os"
Expand Down Expand Up @@ -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) {
Expand Down
28 changes: 28 additions & 0 deletions back_unix.odin
Original file line number Diff line number Diff line change
@@ -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))
})
}
49 changes: 49 additions & 0 deletions back_windows.odin
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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..<src_code_locs.len {
loc := pdb.get_rb(&src_code_locs, i)

lb := strings.builder_make_len_cap(0, len(loc.file_path) + 5)
strings.write_string(&lb, loc.file_path)
strings.write_byte(&lb, ':')
strings.write_int(&lb, int(loc.line))

lines[i] = {
location = strings.to_string(lb),
symbol = loc.procedure,
}
}
print(lines[:src_code_locs.len])

return win.EXCEPTION_CONTINUE_SEARCH
})
}