1 | [has_globals] |
2 | module builtin |
3 | |
4 | #flag -I@VEXEROOT/thirdparty/libbacktrace |
5 | #flag @VEXEROOT/thirdparty/libbacktrace/backtrace.o |
6 | #include <backtrace.h> |
7 | |
8 | // NOTE: Don't mark this as a [typedef] or it may cause compiler errors! |
9 | struct C.backtrace_state { |
10 | // filename &char |
11 | } |
12 | |
13 | type BacktraceErrorCallback = fn (data voidptr, msg &char, errnum int) voidptr |
14 | |
15 | type BacktraceFullCallback = fn (data voidptr, pc voidptr, filename &char, lineno int, func &char) &int |
16 | |
17 | fn C.backtrace_create_state(filename &char, threaded int, error_callback BacktraceErrorCallback, data voidptr) &C.backtrace_state |
18 | fn C.backtrace_full(state &C.backtrace_state, skip int, cb BacktraceFullCallback, err_cb BacktraceErrorCallback, data voidptr) int |
19 | |
20 | __global bt_state = init_bt_state() |
21 | |
22 | fn init_bt_state() &C.backtrace_state { |
23 | $if !tinyc { |
24 | mut filename := &char(unsafe { nil }) |
25 | $if windows { |
26 | filename = unsafe { string_from_wide(&&u16(g_main_argv)[0]).str } |
27 | } $else { |
28 | filename = unsafe { &&char(g_main_argv)[0] } |
29 | } |
30 | return C.backtrace_create_state(filename, 1, bt_error_handler, 0) |
31 | } |
32 | return &C.backtrace_state(unsafe { nil }) |
33 | } |
34 | |
35 | // for bt_error_callback |
36 | struct BacktraceOptions { |
37 | stdin bool = true |
38 | } |
39 | |
40 | fn bt_print_callback(data &BacktraceOptions, pc voidptr, filename_ptr &char, line int, fn_name_ptr &char) int { |
41 | filename := if filename_ptr == unsafe { nil } { |
42 | '???' |
43 | } else { |
44 | unsafe { filename_ptr.vstring() } |
45 | } |
46 | fn_name := if fn_name_ptr == unsafe { nil } { |
47 | '???' |
48 | } else { |
49 | (unsafe { fn_name_ptr.vstring() }).replace('__', '.') |
50 | } |
51 | // keep it for later |
52 | // pc_64 := u64(pc) |
53 | bt_str := '${filename}:${line}: by ${fn_name}' |
54 | if data.stdin { |
55 | println(bt_str) |
56 | } else { |
57 | eprintln(bt_str) |
58 | } |
59 | return 0 |
60 | } |
61 | |
62 | fn bt_error_callback(data voidptr, msg_ptr &char, errnum int) { |
63 | // if data != unsafe { nil } && data.state != unsafe { nil } && data.state.filename != unsafe { nil } { |
64 | // filename := unsafe{ data.state.filename.vstring() } |
65 | // eprint('$filename: ') |
66 | // } |
67 | |
68 | msg := unsafe { msg_ptr.vstring() } |
69 | eprint('libbacktrace: ${msg}') |
70 | if errnum > 0 { |
71 | eprint(': ${C.strerror(errnum)}') |
72 | } |
73 | |
74 | eprintln('') |
75 | } |
76 | |
77 | // for backtrace_create_state only |
78 | fn bt_error_handler(data voidptr, msg &char, errnum int) { |
79 | eprint('libbacktrace: ') |
80 | eprint(unsafe { msg.vstring() }) |
81 | if errnum > 0 { |
82 | eprint(': ${C.strerror(errnum)}') |
83 | } |
84 | eprintln('') |
85 | exit(1) |
86 | } |
87 | |
88 | [noinline] |
89 | fn print_libbacktrace(frames_to_skip int) { |
90 | $if no_backtrace ? { |
91 | return |
92 | } |
93 | data := &BacktraceOptions{} |
94 | C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data) |
95 | } |
96 | |
97 | [noinline] |
98 | fn eprint_libbacktrace(frames_to_skip int) { |
99 | $if no_backtrace ? { |
100 | return |
101 | } |
102 | data := &BacktraceOptions{ |
103 | stdin: false |
104 | } |
105 | C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data) |
106 | } |