v / vlib / builtin
Raw file | 106 loc (91 sloc) | 2.68 KB | Latest commit hash 017ace6ea
1[has_globals]
2module 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!
9struct C.backtrace_state {
10 // filename &char
11}
12
13type BacktraceErrorCallback = fn (data voidptr, msg &char, errnum int) voidptr
14
15type BacktraceFullCallback = fn (data voidptr, pc voidptr, filename &char, lineno int, func &char) &int
16
17fn C.backtrace_create_state(filename &char, threaded int, error_callback BacktraceErrorCallback, data voidptr) &C.backtrace_state
18fn 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
22fn 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
36struct BacktraceOptions {
37 stdin bool = true
38}
39
40fn 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
62fn 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
78fn 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]
89fn 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]
98fn 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}