fuck submodules part 3

This commit is contained in:
Synthasmagoria 2026-07-30 20:16:09 +02:00
commit 88dee75f7d
26 changed files with 2962 additions and 0 deletions

View file

@ -0,0 +1,169 @@
#+vet explicit-allocators
#+private file
package back
@require import "base:runtime"
@require import "base:intrinsics"
@require import "core:c"
@require import "core:c/libc"
@require import "core:os"
@require import "core:strings"
when !USE_FALLBACK {
foreign import lib "system:c"
@(private="package")
_Trace_Entry :: rawptr
@(private="package")
_trace :: #force_no_inline proc(buf: Trace) -> (n: int) {
// In order to omit this function's frame and the caller, we alloca a temp buffer with 2 extra slots.
bigger_buf := ([^]Trace_Entry)(intrinsics.alloca((2 + len(buf)) * size_of(Trace_Entry), align_of(Trace_Entry)))[:len(buf)+2]
_n := int(backtrace(raw_data(bigger_buf), i32(len(bigger_buf))))
if _n > 2 {
copy(buf, bigger_buf[2:])
return _n-2
}
return 0
}
@(private="package")
_lines_destroy :: proc(msgs: []Line, allocator: runtime.Allocator) {
for msg in msgs {
delete(msg.location, allocator)
if msg.symbol != "??OOM" && msg.symbol != "??" { delete(msg.symbol, allocator) }
}
delete(msgs, allocator)
}
@(private="package")
_lines :: proc(bt: Trace, allocator, temp_allocator: runtime.Allocator) -> (out: []Line, err: Lines_Error) {
msgs := backtrace_symbols(raw_data(bt), i32(len(bt)))[:len(bt)]
defer libc.free(raw_data(msgs))
out = make([]Line, len(bt), allocator)
defer if err != nil { _lines_destroy(out, allocator) }
// Debug info is needed.
when !ODIN_DEBUG {
for msg, i in msgs {
location, mem_err := strings.clone_from(msg, allocator)
if mem_err != nil { return out, .Out_Of_Memory }
out[i] = Line {
location = location,
symbol = "??",
}
}
return
}
i := 0
command := make([dynamic]string, temp_allocator)
defer delete(command)
if _, err := append(&command, ADDR2LINE_PATH, "--functions", "--exe", ""); err != nil { return out, .Out_Of_Memory }
COMMAND_EXE_POS :: 3
COMMAND_START_LEN :: 4
for msg in msgs {
exe, addr := parse_address(msg) or_return
if command[COMMAND_EXE_POS] == "" {
command[COMMAND_EXE_POS] = exe
} else if command[COMMAND_EXE_POS] != exe {
i += exec_and_fill(command[:], out[i:], msgs[i:], allocator, temp_allocator) or_return
command[COMMAND_EXE_POS] = exe
resize(&command, COMMAND_START_LEN)
}
if _, err := append(&command, addr); err != nil { return out, .Out_Of_Memory }
}
if len(command) > COMMAND_START_LEN {
i += exec_and_fill(command[:], out[i:], msgs[i:], allocator, temp_allocator) or_return
}
return
// Parses the exe and address out of a backtrace line.
// Example: .../main(+0x20) [0x100000] -> .../main, +0x20, nil
parse_address :: proc(cmsg: cstring) -> (string, string, Lines_Error) {
msg := string(cmsg)
close_idx := strings.last_index_byte(msg, ')')
if close_idx < 1 {
return "", "", .Parse_Address_Fail
}
open_idx := strings.last_index_byte(msg[:close_idx], '(')
if open_idx < 0 {
return "", "", .Parse_Address_Fail
}
return msg[:open_idx], msg[open_idx+1:close_idx], nil
}
exec_and_fill :: proc(command: []string, out: []Line, msgs: []cstring, allocator, temp_allocator: runtime.Allocator) -> (filled: int, err: Lines_Error) {
state, stdout, stderr, perr := os.process_exec({command = command}, temp_allocator)
defer delete(stdout, temp_allocator)
defer delete(stderr, temp_allocator)
if perr != nil || !state.success {
return 0, .Addr2line_Process_Error
}
count := len(command)-COMMAND_START_LEN
sstdout := string(stdout)
for i in 0..<count {
out[i].symbol, err = process_line(strings.split_lines_iterator(&sstdout), allocator)
if err == .Out_Of_Memory {
out[i].symbol = "??OOM"
} else if err != nil {
return
}
// TODO: parse location and transform to ODIN_ERROR_POS_STYLE
out[i].location, err = process_line(strings.split_lines_iterator(&sstdout), allocator)
if err == .Out_Of_Memory {
out[i].location = "??OOM"
} else if err != nil {
return
}
if out[i].location == "" || out[i].location == "??" {
fallback, mem_err := strings.clone_from(msgs[i], allocator)
if mem_err != nil { return 0, .Out_Of_Memory }
out[i].location = fallback
}
}
return count, nil
}
process_line :: proc(line: string, ok: bool, allocator: runtime.Allocator) -> (string, Lines_Error) {
if !ok { return "", .Addr2line_Unexpected_EOF }
if line == "" { return "", .Addr2line_Output_Error }
if line == "??" {
return "??", nil
}
ret, err := strings.clone(strings.trim_right_space(line), allocator)
return ret, err == nil ? nil : .Out_Of_Memory
}
}
foreign lib {
backtrace :: proc(buffer: [^]rawptr, size: c.int) -> c.int ---
backtrace_symbols :: proc(buffer: [^]rawptr, size: c.int) -> [^]cstring ---
backtrace_symbols_fd :: proc(buffer: [^]rawptr, size: c.int, fd: ^libc.FILE) ---
}
}