[has_globals] module builtin #flag -I@VEXEROOT/thirdparty/libbacktrace #flag @VEXEROOT/thirdparty/libbacktrace/backtrace.o #include // NOTE: Don't mark this as a [typedef] or it may cause compiler errors! struct C.backtrace_state { // filename &char } type BacktraceErrorCallback = fn (data voidptr, msg &char, errnum int) voidptr type BacktraceFullCallback = fn (data voidptr, pc voidptr, filename &char, lineno int, func &char) &int fn C.backtrace_create_state(filename &char, threaded int, error_callback BacktraceErrorCallback, data voidptr) &C.backtrace_state fn C.backtrace_full(state &C.backtrace_state, skip int, cb BacktraceFullCallback, err_cb BacktraceErrorCallback, data voidptr) int __global bt_state = init_bt_state() fn init_bt_state() &C.backtrace_state { $if !tinyc { mut filename := &char(unsafe { nil }) $if windows { filename = unsafe { string_from_wide(&&u16(g_main_argv)[0]).str } } $else { filename = unsafe { &&char(g_main_argv)[0] } } return C.backtrace_create_state(filename, 1, bt_error_handler, 0) } return &C.backtrace_state(unsafe { nil }) } // for bt_error_callback struct BacktraceOptions { stdin bool = true } fn bt_print_callback(data &BacktraceOptions, pc voidptr, filename_ptr &char, line int, fn_name_ptr &char) int { filename := if filename_ptr == unsafe { nil } { '???' } else { unsafe { filename_ptr.vstring() } } fn_name := if fn_name_ptr == unsafe { nil } { '???' } else { (unsafe { fn_name_ptr.vstring() }).replace('__', '.') } // keep it for later // pc_64 := u64(pc) bt_str := '${filename}:${line}: by ${fn_name}' if data.stdin { println(bt_str) } else { eprintln(bt_str) } return 0 } fn bt_error_callback(data voidptr, msg_ptr &char, errnum int) { // if data != unsafe { nil } && data.state != unsafe { nil } && data.state.filename != unsafe { nil } { // filename := unsafe{ data.state.filename.vstring() } // eprint('$filename: ') // } msg := unsafe { msg_ptr.vstring() } eprint('libbacktrace: ${msg}') if errnum > 0 { eprint(': ${C.strerror(errnum)}') } eprintln('') } // for backtrace_create_state only fn bt_error_handler(data voidptr, msg &char, errnum int) { eprint('libbacktrace: ') eprint(unsafe { msg.vstring() }) if errnum > 0 { eprint(': ${C.strerror(errnum)}') } eprintln('') exit(1) } [noinline] fn print_libbacktrace(frames_to_skip int) { $if no_backtrace ? { return } data := &BacktraceOptions{} C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data) } [noinline] fn eprint_libbacktrace(frames_to_skip int) { $if no_backtrace ? { return } data := &BacktraceOptions{ stdin: false } C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data) }