vxx2 / vlib / builtin / builtin_d_use_libbacktrace.c.v
126 lines · 109 sloc · 3.4 KB · 099040eb391e8186e1bafd1906cb9dc01e20f07c
Raw
1@[has_globals]
2module builtin
3
4$if openbsd {
5 // OpenBSD lacks the sysctl path lookup that bundled libbacktrace needs,
6 // so `-d use_libbacktrace` falls back to the native BSD backtrace path.
7 fn print_libbacktrace(frames_to_skip int) {
8 }
9
10 @[noinline]
11 fn eprint_libbacktrace(frames_to_skip int) {
12 }
13} $else $if !tinyc {
14 // full libbacktrace implementation for gcc/clang (TCC can't compile libbacktrace's C code)
15 #flag -I@VEXEROOT/thirdparty/libbacktrace
16 #flag @VEXEROOT/thirdparty/libbacktrace/backtrace.o
17 #include <backtrace.h>
18
19 // NOTE: Don't mark this as a @[typedef] or it may cause compiler errors!
20 pub struct C.backtrace_state {
21 // filename &char
22 }
23
24 type BacktraceErrorCallback = fn (data voidptr, msg &char, errnum int)
25
26 type BacktraceFullCallback = fn (data voidptr, pc voidptr, filename &char, lineno int, func &char) int
27
28 fn C.backtrace_create_state(filename &char, threaded i32, error_callback BacktraceErrorCallback, data voidptr) &C.backtrace_state
29 fn C.backtrace_full(state &C.backtrace_state, skip i32, cb BacktraceFullCallback, err_cb BacktraceErrorCallback,
30 data voidptr) i32
31
32 __global bt_state = init_bt_state()
33
34 fn init_bt_state() &C.backtrace_state {
35 mut filename := &char(unsafe { nil })
36 $if windows {
37 filename = unsafe { string_from_wide(&&u16(g_main_argv)[0]).str }
38 } $else {
39 filename = unsafe { &&char(g_main_argv)[0] }
40 }
41 return C.backtrace_create_state(filename, 1, bt_error_handler, 0)
42 }
43
44 // for bt_error_callback
45 struct BacktraceOptions {
46 stdin bool = true
47 }
48
49 fn bt_print_callback(data_ptr voidptr, pc voidptr, filename_ptr &char, line int, fn_name_ptr &char) int {
50 data := unsafe { &BacktraceOptions(data_ptr) }
51 filename := if filename_ptr == unsafe { nil } {
52 '???'
53 } else {
54 unsafe { filename_ptr.vstring() }
55 }
56 fn_name := if fn_name_ptr == unsafe { nil } {
57 '???'
58 } else {
59 demangle_v_symbol(unsafe { fn_name_ptr.vstring() })
60 }
61 // keep it for later
62 // pc_64 := u64(pc)
63 bt_str := '${filename}:${line}: by ${fn_name}'
64 if data.stdin {
65 println(bt_str)
66 } else {
67 eprintln(bt_str)
68 }
69 return 0
70 }
71
72 fn bt_error_callback(data voidptr, msg_ptr &char, errnum int) {
73 // if data != unsafe { nil } && data.state != unsafe { nil } && data.state.filename != unsafe { nil } {
74 // filename := unsafe{ data.state.filename.vstring() }
75 // eprint('${filename}: ')
76 // }
77
78 msg := unsafe { msg_ptr.vstring() }
79 eprint('libbacktrace: ${msg}')
80 if errnum > 0 {
81 eprint(': ${C.strerror(errnum)}')
82 }
83
84 eprintln('')
85 }
86
87 // for backtrace_create_state only
88 fn bt_error_handler(data voidptr, msg &char, errnum int) {
89 eprint('libbacktrace: ')
90 eprint(unsafe { msg.vstring() })
91 if errnum > 0 {
92 eprint(': ${C.strerror(errnum)}')
93 }
94 eprintln('')
95 exit(1)
96 }
97
98 @[noinline]
99 fn print_libbacktrace(frames_to_skip int) {
100 $if no_backtrace ? {
101 return
102 }
103 data := &BacktraceOptions{}
104 C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data)
105 }
106
107 @[noinline]
108 fn eprint_libbacktrace(frames_to_skip int) {
109 $if no_backtrace ? {
110 return
111 }
112 data := &BacktraceOptions{
113 stdin: false
114 }
115 C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data)
116 }
117} $else {
118 // no-op stubs for TCC (TCC can't compile libbacktrace's C code, and
119 // it has its own built-in backtrace via tcc_backtrace instead)
120 fn print_libbacktrace(frames_to_skip int) {
121 }
122
123 @[noinline]
124 fn eprint_libbacktrace(frames_to_skip int) {
125 }
126}
127