Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,244 @@
|
||||
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
|
||||
@[direct_array_access]
|
||||
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
|
||||
}
|
||||
$if detailed_backtraces ? {
|
||||
nr_actual_frames := nr_ptrs - skipframes
|
||||
csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames)
|
||||
atos_lines := bsd_backtrace_resolve_atos(&buffer[skipframes], nr_actual_frames)
|
||||
for i in 0 .. nr_actual_frames {
|
||||
sframe := unsafe { tos2(&u8(csymbols[i])) }
|
||||
mut file_line := ''
|
||||
if i < atos_lines.len {
|
||||
file_line = atos_lines[i]
|
||||
}
|
||||
// macOS format: `0 main 0x00000001047232f8 veb__run_T_main__App_main__Context + 356`
|
||||
symbol_start := sframe.index('0x') or { -1 }
|
||||
if symbol_start < 0 {
|
||||
continue
|
||||
}
|
||||
rest := sframe[symbol_start..]
|
||||
space_after_addr := rest.index(' ') or { -1 }
|
||||
if space_after_addr < 0 {
|
||||
continue
|
||||
}
|
||||
symbol_and_offset := rest[space_after_addr + 1..]
|
||||
plus_pos := symbol_and_offset.index(' + ') or { -1 }
|
||||
mut raw_symbol := symbol_and_offset
|
||||
if plus_pos >= 0 {
|
||||
raw_symbol = symbol_and_offset[..plus_pos]
|
||||
}
|
||||
// Skip C runtime frames that are not V functions:
|
||||
if raw_symbol in ['main', 'start', '_main'] {
|
||||
continue
|
||||
}
|
||||
mut demangled := ''
|
||||
if plus_pos >= 0 {
|
||||
demangled = demangle_v_symbol(raw_symbol) + symbol_and_offset[plus_pos..]
|
||||
} else {
|
||||
demangled = demangle_v_symbol(raw_symbol)
|
||||
}
|
||||
if file_line.len > 0 {
|
||||
eprint(file_line)
|
||||
eprint_space_padding(file_line, 45)
|
||||
eprint(' | ')
|
||||
eprintln(demangled)
|
||||
} else {
|
||||
eprintln(demangled)
|
||||
}
|
||||
}
|
||||
if nr_actual_frames > 0 {
|
||||
unsafe { C.free(csymbols) }
|
||||
}
|
||||
} $else {
|
||||
C.backtrace_symbols_fd(&buffer[skipframes], nr_ptrs - skipframes, 2)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// bsd_backtrace_resolve_atos uses macOS `atos` to resolve addresses to file:line info.
|
||||
// Returns an array of file:line strings (one per frame). Empty string if unresolved.
|
||||
@[direct_array_access]
|
||||
fn bsd_backtrace_resolve_atos(buffer &voidptr, nr_frames int) []string {
|
||||
$if macos {
|
||||
exe_name := backtrace_current_executable_name()
|
||||
if exe_name.len == 0 {
|
||||
return []string{}
|
||||
}
|
||||
base_addr := voidptr(C._dyld_get_image_header(0))
|
||||
if base_addr == unsafe { nil } {
|
||||
return []string{}
|
||||
}
|
||||
// Build single atos command with all addresses for efficiency:
|
||||
mut cmd := 'atos --fullPath -o "' + exe_name + '" -l ' + ptr_str(base_addr)
|
||||
for i in 0 .. nr_frames {
|
||||
cmd += ' ' + ptr_str(unsafe { buffer[i] })
|
||||
}
|
||||
f := C.popen(&char(cmd.str), c'r')
|
||||
if f == unsafe { nil } {
|
||||
return []string{}
|
||||
}
|
||||
buf := [4096]u8{}
|
||||
mut lines := []string{cap: nr_frames}
|
||||
unsafe {
|
||||
bp := &u8(&buf[0])
|
||||
for C.fgets(&char(bp), 4096, f) != 0 {
|
||||
line := tos(bp, vstrlen(bp)).trim_chars(' \t\n\r', .trim_both)
|
||||
// atos output format: `func_name (in binary) (file.v:42)`
|
||||
// Extract the last parenthesized (file:line) part:
|
||||
paren_pos := line.index_last_('(')
|
||||
if paren_pos >= 0 {
|
||||
file_part := line[paren_pos + 1..]
|
||||
end_paren := file_part.index_last_(')')
|
||||
if end_paren >= 0 {
|
||||
file_line := file_part[..end_paren]
|
||||
if file_line.contains(':') && !file_line.starts_with('in ')
|
||||
&& !file_line.contains('.tmp.c:') {
|
||||
lines << file_line
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
lines << ''
|
||||
}
|
||||
}
|
||||
C.pclose(f)
|
||||
return lines
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
fn C.tcc_backtrace(fmt &char) i32
|
||||
|
||||
fn backtrace_current_executable_name() string {
|
||||
args := arguments()
|
||||
if args.len == 0 {
|
||||
return ''
|
||||
}
|
||||
return args[0]
|
||||
}
|
||||
|
||||
fn backtrace_addr2line_executable(executable string, current_executable_name string) string {
|
||||
if executable.len == 0 {
|
||||
return '/proc/self/exe'
|
||||
}
|
||||
if executable.contains('/') {
|
||||
return executable
|
||||
}
|
||||
if current_executable_name.len > 0
|
||||
&& executable.all_after_last('/') == current_executable_name.all_after_last('/') {
|
||||
return '/proc/self/exe'
|
||||
}
|
||||
return executable
|
||||
}
|
||||
|
||||
@[direct_array_access]
|
||||
fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
|
||||
$if android {
|
||||
eprintln('On Android no backtrace is available.')
|
||||
return false
|
||||
}
|
||||
$if no_backtrace ? {
|
||||
return false
|
||||
} $else {
|
||||
$if linux && !freestanding {
|
||||
$if tinyc {
|
||||
C.tcc_backtrace(c'Backtrace')
|
||||
return false
|
||||
} $else {
|
||||
$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
|
||||
} $else {
|
||||
current_executable_name := backtrace_current_executable_name()
|
||||
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
|
||||
//////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 {
|
||||
sframe := unsafe { tos2(&u8(csymbols[i])) }
|
||||
executable := sframe.all_before('(')
|
||||
addr2line_executable := backtrace_addr2line_executable(executable,
|
||||
current_executable_name)
|
||||
addr := sframe.all_after('[').all_before(']')
|
||||
beforeaddr := sframe.all_before('[')
|
||||
cmd := 'addr2line -e ' + addr2line_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 := &u8(&buf[0])
|
||||
for C.fgets(&char(bp), 1000, f) != 0 {
|
||||
output += tos(bp, vstrlen(bp))
|
||||
}
|
||||
}
|
||||
output = output.trim_chars(' \t\n', .trim_both) + ':'
|
||||
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.')
|
||||
eprint(output)
|
||||
eprint_space_padding(output, 55)
|
||||
eprint(' | ')
|
||||
eprint(addr)
|
||||
eprint(' | ')
|
||||
eprintln(demangle_backtrace_sym(beforeaddr))
|
||||
}
|
||||
if nr_actual_frames > 0 {
|
||||
unsafe { C.free(csymbols) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in new issue
Block a user