v2 / vlib / builtin / builtin_d_use_libbacktrace.c.v
119 lines · 103 sloc · 3.12 KB · da76f5588e022410b2c6e32749b54b9ce3a4ae91
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 {
14 #flag -I@VEXEROOT/thirdparty/libbacktrace
15 #flag @VEXEROOT/thirdparty/libbacktrace/backtrace.o
16 #include <backtrace.h>
17
18 // NOTE: Don't mark this as a @[typedef] or it may cause compiler errors!
19 pub struct C.backtrace_state {
20 // filename &char
21 }
22
23 type BacktraceErrorCallback = fn (data voidptr, msg &char, errnum int)
24
25 type BacktraceFullCallback = fn (data voidptr, pc voidptr, filename &char, lineno int, func &char) int
26
27 fn C.backtrace_create_state(filename &char, threaded i32, error_callback BacktraceErrorCallback, data voidptr) &C.backtrace_state
28 fn C.backtrace_full(state &C.backtrace_state, skip i32, cb BacktraceFullCallback, err_cb BacktraceErrorCallback,
29 data voidptr) i32
30
31 __global bt_state = init_bt_state()
32
33 fn init_bt_state() &C.backtrace_state {
34 $if !tinyc {
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 return &C.backtrace_state(unsafe { nil })
44 }
45
46 // for bt_error_callback
47 struct BacktraceOptions {
48 stdin bool = true
49 }
50
51 fn bt_print_callback(data_ptr voidptr, pc voidptr, filename_ptr &char, line int, fn_name_ptr &char) int {
52 data := unsafe { &BacktraceOptions(data_ptr) }
53 filename := if filename_ptr == unsafe { nil } {
54 '???'
55 } else {
56 unsafe { filename_ptr.vstring() }
57 }
58 fn_name := if fn_name_ptr == unsafe { nil } {
59 '???'
60 } else {
61 demangle_v_symbol(unsafe { fn_name_ptr.vstring() })
62 }
63 // keep it for later
64 // pc_64 := u64(pc)
65 bt_str := '${filename}:${line}: by ${fn_name}'
66 if data.stdin {
67 println(bt_str)
68 } else {
69 eprintln(bt_str)
70 }
71 return 0
72 }
73
74 fn bt_error_callback(data voidptr, msg_ptr &char, errnum int) {
75 // if data != unsafe { nil } && data.state != unsafe { nil } && data.state.filename != unsafe { nil } {
76 // filename := unsafe{ data.state.filename.vstring() }
77 // eprint('${filename}: ')
78 // }
79
80 msg := unsafe { msg_ptr.vstring() }
81 eprint('libbacktrace: ${msg}')
82 if errnum > 0 {
83 eprint(': ${C.strerror(errnum)}')
84 }
85
86 eprintln('')
87 }
88
89 // for backtrace_create_state only
90 fn bt_error_handler(data voidptr, msg &char, errnum int) {
91 eprint('libbacktrace: ')
92 eprint(unsafe { msg.vstring() })
93 if errnum > 0 {
94 eprint(': ${C.strerror(errnum)}')
95 }
96 eprintln('')
97 exit(1)
98 }
99
100 @[noinline]
101 fn print_libbacktrace(frames_to_skip int) {
102 $if no_backtrace ? {
103 return
104 }
105 data := &BacktraceOptions{}
106 C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data)
107 }
108
109 @[noinline]
110 fn eprint_libbacktrace(frames_to_skip int) {
111 $if no_backtrace ? {
112 return
113 }
114 data := &BacktraceOptions{
115 stdin: false
116 }
117 C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data)
118 }
119}
120