/
backtraces_nix.c.v
111 lines (108 loc) · 3.3 KB
/
backtraces_nix.c.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
module builtin
// print_backtrace_skipping_top_frames prints the backtrace skipping N top frames
pub fn print_backtrace_skipping_top_frames(xskipframes int) bool {
$if no_backtrace ? {
return false
} $else {
skipframes := xskipframes + 2
$if macos || freebsd || openbsd || netbsd {
return print_backtrace_skipping_top_frames_bsd(skipframes)
} $else $if linux {
return print_backtrace_skipping_top_frames_linux(skipframes)
} $else {
println('print_backtrace_skipping_top_frames is not implemented. skipframes: ${skipframes}')
}
}
return false
}
// the functions below are not called outside this file,
// so there is no need to have their twins in builtin_windows.v
fn print_backtrace_skipping_top_frames_bsd(skipframes int) bool {
$if no_backtrace ? {
return false
} $else {
$if macos || freebsd || netbsd {
buffer := [100]voidptr{}
nr_ptrs := C.backtrace(&buffer[0], 100)
if nr_ptrs < 2 {
eprintln('C.backtrace returned less than 2 frames')
return false
}
C.backtrace_symbols_fd(&buffer[skipframes], nr_ptrs - skipframes, 2)
}
return true
}
}
fn C.tcc_backtrace(fmt &char) int
fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
$if android {
eprintln('On Android no backtrace is available.')
return false
}
$if !glibc {
eprintln('backtrace_symbols is missing => printing backtraces is not available.')
eprintln('Some libc implementations like musl simply do not provide it.')
return false
}
$if native {
eprintln('native backend does not support backtraces yet.')
return false
} $else $if no_backtrace ? {
return false
} $else {
$if linux && !freestanding {
$if tinyc {
C.tcc_backtrace(c'Backtrace')
return false
} $else {
buffer := [100]voidptr{}
nr_ptrs := C.backtrace(&buffer[0], 100)
if nr_ptrs < 2 {
eprintln('C.backtrace returned less than 2 frames')
return false
}
nr_actual_frames := nr_ptrs - skipframes
mut sframes := []string{}
//////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames)
csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames)
for i in 0 .. nr_actual_frames {
sframes << unsafe { tos2(&u8(csymbols[i])) }
}
for sframe in sframes {
executable := sframe.all_before('(')
addr := sframe.all_after('[').all_before(']')
beforeaddr := sframe.all_before('[')
cmd := 'addr2line -e ${executable} ${addr}'
// taken from os, to avoid depending on the os module inside builtin.v
f := C.popen(&char(cmd.str), c'r')
if f == unsafe { nil } {
eprintln(sframe)
continue
}
buf := [1000]u8{}
mut output := ''
unsafe {
bp := &buf[0]
for C.fgets(&char(bp), 1000, f) != 0 {
output += tos(bp, vstrlen(bp))
}
}
output = output.trim_space() + ':'
if C.pclose(f) != 0 {
eprintln(sframe)
continue
}
if output in ['??:0:', '??:?:'] {
output = ''
}
// See http://wiki.dwarfstd.org/index.php?title=Path_Discriminators
// Note: it is shortened here to just d. , just so that it fits, and so
// that the common error file:lineno: line format is enforced.
output = output.replace(' (discriminator', ': (d.')
eprintln('${output:-55s} | ${addr:14s} | ${beforeaddr}')
}
}
}
}
return true
}