vxx2 / vlib / builtin / panicing.c.v
184 lines · 175 sloc · 5.09 KB · 099040eb391e8186e1bafd1906cb9dc01e20f07c
Raw
1module builtin
2
3// panic_debug private function that V uses for panics, -cg/-g is passed
4// recent versions of tcc print nicer backtraces automatically
5// Note: the duplication here is because tcc_backtrace should be called directly
6// inside the panic functions.
7@[noreturn]
8fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
9 // Note: the order here is important for a stabler test output
10 // module is less likely to change than function, etc...
11 // During edits, the line number will change most frequently,
12 // so it is last
13 $if freestanding {
14 bare_panic(s)
15 } $else $if v2_native_windows_pe_minimal ? {
16 flush_stdout()
17 eprintln('================ V panic ================')
18 eprint(' message: ')
19 eprintln(s)
20 eprintln('=========================================')
21 flush_stdout()
22 exit(1)
23 } $else {
24 // vfmt off
25 // Note: be carefull to not allocate here, avoid string interpolation
26 flush_stdout()
27 eprintln('================ V panic ================')
28 eprint(' module: '); eprintln(mod)
29 eprint(' function: '); eprint(fn_name); eprintln('()')
30 eprint(' message: '); eprintln(s)
31 eprint(' file: '); eprint(file); eprint(':');
32 C.fprintf(C.stderr, c'%d\n', line_no)
33 eprint(' v hash: '); eprintln(vcurrent_hash())
34 $if !vinix {
35 eprint(' pid: '); C.fprintf(C.stderr, c'%p\n', voidptr(v_getpid()))
36 eprint(' tid: '); C.fprintf(C.stderr, c'%p\n', voidptr(v_gettid()))
37 }
38 eprintln('=========================================')
39 flush_stdout()
40 // vfmt on
41 $if exit_after_panic_message ? {
42 C.exit(1)
43 } $else $if no_backtrace ? {
44 C.exit(1)
45 } $else $if tinyc && !glibc {
46 $if panics_break_into_debugger ? {
47 break_if_debugger_attached()
48 } $else {
49 C.tcc_backtrace(c'Backtrace')
50 }
51 C.exit(1)
52 } $else {
53 $if use_libbacktrace ? && !tinyc {
54 $if openbsd {
55 print_backtrace_skipping_top_frames(1)
56 } $else {
57 eprint_libbacktrace(1)
58 }
59 } $else {
60 print_backtrace_skipping_top_frames(1)
61 }
62 $if panics_break_into_debugger ? {
63 break_if_debugger_attached()
64 }
65 C.exit(1)
66 }
67 }
68 C.exit(1)
69 for {}
70}
71
72// panic_option_not_set is called by V, when you use option error propagation in your main function.
73// It ends the program with a panic.
74@[noreturn]
75pub fn panic_option_not_set(s string) {
76 panic('option not set (' + s + ')')
77}
78
79// panic_result_not_set is called by V, when you use result error propagation in your main function
80// It ends the program with a panic.
81@[noreturn]
82pub fn panic_result_not_set(s string) {
83 panic('result not set (' + s + ')')
84}
85
86// panic prints a nice error message, then exits the process with exit code of 1.
87// It also shows a backtrace on most platforms.
88@[noreturn]
89pub fn panic(s string) {
90 // Note: be careful to not use string interpolation here:
91 $if freestanding {
92 bare_panic(s)
93 } $else $if v2_native_windows_pe_minimal ? {
94 flush_stdout()
95 eprint('V panic: ')
96 eprintln(s)
97 flush_stdout()
98 exit(1)
99 } $else {
100 // vfmt off
101 flush_stdout()
102 eprint('V panic: ')
103 eprintln(s)
104 eprint(' v hash: ')
105 eprintln(vcurrent_hash())
106 $if !vinix {
107 eprint(' pid: '); C.fprintf(C.stderr, c'%p\n', voidptr(v_getpid()))
108 eprint(' tid: '); C.fprintf(C.stderr, c'%p\n', voidptr(v_gettid()))
109 }
110 flush_stdout()
111 // vfmt on
112 $if exit_after_panic_message ? {
113 C.exit(1)
114 } $else $if no_backtrace ? {
115 C.exit(1)
116 } $else $if tinyc && !glibc {
117 $if panics_break_into_debugger ? {
118 break_if_debugger_attached()
119 } $else {
120 C.tcc_backtrace(c'Backtrace')
121 }
122 C.exit(1)
123 } $else {
124 $if use_libbacktrace ? && !tinyc {
125 $if openbsd {
126 print_backtrace_skipping_top_frames(1)
127 } $else {
128 eprint_libbacktrace(1)
129 }
130 } $else {
131 print_backtrace_skipping_top_frames(1)
132 }
133 $if panics_break_into_debugger ? {
134 break_if_debugger_attached()
135 }
136 C.exit(1)
137 }
138 }
139 C.exit(1)
140 for {}
141}
142
143// return a C-API error message matching to `errnum`
144pub fn c_error_number_str(errnum int) string {
145 mut err_msg := ''
146 $if freestanding {
147 err_msg = 'error ' + errnum.str()
148 } $else {
149 $if !vinix {
150 c_msg := C.strerror(errnum)
151 err_msg = string{
152 str: &u8(c_msg)
153 len: int(unsafe { C.strlen(c_msg) })
154 is_lit: 1
155 }
156 }
157 }
158 return err_msg
159}
160
161// panic_n prints an error message, followed by the given number, then exits the process with exit code of 1.
162@[noreturn]
163pub fn panic_n(s string, number1 i64) {
164 panic(s + impl_i64_to_string(number1))
165}
166
167// panic_n2 prints an error message, followed by the given numbers, then exits the process with exit code of 1.
168@[noreturn]
169pub fn panic_n2(s string, number1 i64, number2 i64) {
170 panic(s + impl_i64_to_string(number1) + ', ' + impl_i64_to_string(number2))
171}
172
173// panic_n3 prints an error message, followed by the given numbers, then exits the process with exit code of 1.
174@[noreturn]
175fn panic_n3(s string, number1 i64, number2 i64, number3 i64) {
176 panic(s + impl_i64_to_string(number1) + ', ' + impl_i64_to_string(number2) + ', ' +
177 impl_i64_to_string(number3))
178}
179
180// panic with a C-API error message matching `errnum`
181@[noreturn]
182pub fn panic_error_number(basestr string, errnum int) {
183 panic(basestr + c_error_number_str(errnum))
184}
185