mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
backtraces: add source line numbers too on linux
* Add source line numbers to backtraces on linux. * Fix -g (broken after token caching). * reset the #line directives after all the v code is compiled * cleanup p.cgen.line setting inside p.next() . * Support windows filepaths like "C:\Users\travis\build\vlang\v\v.exe.tmp.c" inside generated #line directives. * Try to diagnose better windows-gcc failing. * Revert "Try to diagnose better windows-gcc failing." * implement and use cescaped_path/1 . * Use cescaped_path/1 consistently throughout compiler/ .
This commit is contained in:
parent
c254c9842b
commit
2b087dbf95
@ -63,7 +63,9 @@ fn (g mut CGen) genln(s string) {
|
||||
g.cur_line = '$g.cur_line $s'
|
||||
if g.cur_line != '' {
|
||||
if g.line_directives && g.cur_line.trim_space() != '' {
|
||||
g.lines << '\n#line $g.line "$g.file"'
|
||||
if g.file.len > 0 && g.line > 0 {
|
||||
g.lines << '\n#line $g.line "$g.file"'
|
||||
}
|
||||
}
|
||||
g.lines << g.cur_line
|
||||
g.prev_line = g.cur_line
|
||||
|
@ -809,7 +809,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
|
||||
if p.v.pref.is_debug && f.name == 'panic' && !p.is_js {
|
||||
mod_name := p.mod.replace('_dot_', '.')
|
||||
fn_name := p.cur_fn.name.replace('${p.mod}__', '')
|
||||
file_path := p.file_path.replace('\\', '\\\\') // escape \
|
||||
file_path := cescaped_path(p.file_path)
|
||||
p.cgen.resetln(p.cgen.cur_line.replace(
|
||||
'v_panic (',
|
||||
'panic_debug ($p.scanner.line_nr, tos3("$file_path"), tos3("$mod_name"), tos2((byte *)"$fn_name"), '
|
||||
|
@ -73,8 +73,8 @@ fn (v &V) generate_hot_reload_code() {
|
||||
mut vexe := os.args[0]
|
||||
|
||||
if os.user_os() == 'windows' {
|
||||
vexe = vexe.replace('\\', '\\\\')
|
||||
file = file.replace('\\', '\\\\')
|
||||
vexe = cescaped_path(vexe)
|
||||
file = cescaped_path(file)
|
||||
}
|
||||
|
||||
mut msvc := ''
|
||||
|
@ -338,6 +338,7 @@ fn (v mut V) compile() {
|
||||
if v.pref.build_mode == .build_module {
|
||||
v.generate_vh()
|
||||
}
|
||||
|
||||
// parse generated V code (str() methods etc)
|
||||
mut vgen_parser := v.new_parser_from_string(v.vgen_buf.str(), 'vgen')
|
||||
// free the string builder which held the generated methods
|
||||
@ -383,6 +384,15 @@ fn (v mut V) generate_main() {
|
||||
mut cgen := v.cgen
|
||||
$if js { return }
|
||||
|
||||
///// After this point, the v files are compiled.
|
||||
///// The rest is auto generated code, which will not have
|
||||
///// different .v source file/line numbers.
|
||||
lines_so_far := cgen.lines.join('\n').count('\n') + 5
|
||||
cgen.genln('')
|
||||
cgen.genln('////////////////// Reset the file/line numbers //////////')
|
||||
cgen.lines << '#line $lines_so_far "${cescaped_path(os.realpath(cgen.out_path))}"'
|
||||
cgen.genln('')
|
||||
|
||||
if v.pref.build_mode == .default_mode {
|
||||
mut consts_init_body := cgen.consts_init.join_lines()
|
||||
// vlib can't have `init_consts()`
|
||||
@ -1042,3 +1052,7 @@ fn vhash() string {
|
||||
C.snprintf(*char(buf), 50, '%s', C.V_COMMIT_HASH )
|
||||
return tos_clone(buf)
|
||||
}
|
||||
|
||||
fn cescaped_path(s string) string {
|
||||
return s.replace('\\','\\\\')
|
||||
}
|
||||
|
@ -100,7 +100,14 @@ fn (v mut V) new_parser_from_string(text string, id string) Parser {
|
||||
return p
|
||||
}
|
||||
|
||||
fn (v mut V) reset_cgen_file_line_parameters(){
|
||||
v.cgen.line = 0
|
||||
v.cgen.file = ''
|
||||
v.cgen.line_directives = v.pref.is_debuggable
|
||||
}
|
||||
|
||||
fn (v mut V) new_parser_from_file(path string) Parser {
|
||||
v.reset_cgen_file_line_parameters()
|
||||
//println('new_parser("$path")')
|
||||
mut path_pcguard := ''
|
||||
mut path_platform := '.v'
|
||||
@ -124,7 +131,6 @@ fn (v mut V) new_parser_from_file(path string) Parser {
|
||||
if p.pref.building_v {
|
||||
p.scanner.should_print_relative_paths_on_error = true
|
||||
}
|
||||
v.cgen.file = path
|
||||
p.scan_tokens()
|
||||
//p.scanner.debug_tokens()
|
||||
return p
|
||||
@ -133,6 +139,7 @@ fn (v mut V) new_parser_from_file(path string) Parser {
|
||||
// creates a new parser. most likely you will want to use
|
||||
// `new_parser_file` or `new_parser_string` instead.
|
||||
fn (v mut V) new_parser(scanner &Scanner, id string) Parser {
|
||||
v.reset_cgen_file_line_parameters()
|
||||
mut p := Parser {
|
||||
id: id
|
||||
scanner: scanner
|
||||
@ -155,8 +162,6 @@ fn (v mut V) new_parser(scanner &Scanner, id string) Parser {
|
||||
p.scanner.should_print_errors_in_color = false
|
||||
p.scanner.should_print_relative_paths_on_error = true
|
||||
}
|
||||
v.cgen.line_directives = v.pref.is_debuggable
|
||||
// v.cgen.file = path
|
||||
return p
|
||||
}
|
||||
|
||||
@ -195,6 +200,7 @@ fn (p mut Parser) next() {
|
||||
p.tok = res.tok
|
||||
p.lit = res.lit
|
||||
p.scanner.line_nr = res.line_nr
|
||||
p.cgen.line = res.line_nr
|
||||
}
|
||||
|
||||
fn (p & Parser) peek() TokenKind {
|
||||
@ -229,7 +235,10 @@ fn (p &Parser) log(s string) {
|
||||
*/
|
||||
}
|
||||
|
||||
fn (p mut Parser) parse(pass Pass) {
|
||||
fn (p mut Parser) parse(pass Pass) {
|
||||
p.cgen.line = 0
|
||||
p.cgen.file = cescaped_path(os.realpath(p.file_path))
|
||||
/////////////////////////////////////
|
||||
p.pass = pass
|
||||
p.token_idx = 0
|
||||
p.next()
|
||||
@ -2807,7 +2816,7 @@ fn (p mut Parser) string_expr() {
|
||||
// No ${}, just return a simple string
|
||||
if p.peek() != .dollar || is_raw {
|
||||
p.fgen("'$str'")
|
||||
f := if is_raw { str.replace('\\', '\\\\') } else { format_str(str) }
|
||||
f := if is_raw { cescaped_path(str) } else { format_str(str) }
|
||||
// `C.puts('hi')` => `puts("hi");`
|
||||
/*
|
||||
Calling a C function sometimes requires a call to a string method
|
||||
@ -3849,7 +3858,7 @@ fn (p mut Parser) assert_statement() {
|
||||
p.gen('bool $tmp = ')
|
||||
p.check_types(p.bool_expression(), 'bool')
|
||||
// TODO print "expected: got" for failed tests
|
||||
filename := p.file_path.replace('\\', '\\\\')
|
||||
filename := cescaped_path(p.file_path)
|
||||
p.genln(';
|
||||
\n
|
||||
|
||||
|
@ -410,7 +410,7 @@ fn (s mut Scanner) scan() ScanRes {
|
||||
// println( 'file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @FN)
|
||||
// ... which is useful while debugging/tracing
|
||||
if name == 'FN' { return scan_res(.str, s.fn_name) }
|
||||
if name == 'FILE' { return scan_res(.str, os.realpath(s.file_path).replace('\\', '\\\\')) } // escape \
|
||||
if name == 'FILE' { return scan_res(.str, cescaped_path(os.realpath(s.file_path))) }
|
||||
if name == 'LINE' { return scan_res(.str, (s.line_nr+1).str()) }
|
||||
if name == 'COLUMN' { return scan_res(.str, (s.current_column()).str()) }
|
||||
if name == 'VHASH' { return scan_res(.str, vhash()) }
|
||||
|
@ -55,7 +55,32 @@ pub fn print_backtrace_skipping_top_frames(skipframes int) {
|
||||
if C.backtrace_symbols_fd != 0 {
|
||||
buffer := [100]byteptr
|
||||
nr_ptrs := C.backtrace(*voidptr(buffer), 100)
|
||||
C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_ptrs-skipframes, 1)
|
||||
nr_actual_frames := nr_ptrs-skipframes
|
||||
mut sframes := []string
|
||||
csymbols := *byteptr(C.backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames))
|
||||
for i in 0..nr_actual_frames { sframes << tos2(csymbols[i]) }
|
||||
for sframe in sframes {
|
||||
executable := sframe.all_before('(')
|
||||
addr := sframe.all_after('[').all_before(']')
|
||||
cmd := 'addr2line -e $executable $addr'
|
||||
|
||||
// taken from os, to avoid depending on the os module inside builtin.v
|
||||
f := byteptr(C.popen(cmd.str, 'r'))
|
||||
if isnil(f) {
|
||||
println(sframe) continue
|
||||
}
|
||||
buf := [1000]byte
|
||||
mut output := ''
|
||||
for C.fgets(buf, 1000, f) != 0 {
|
||||
output += tos(buf, vstrlen(buf))
|
||||
}
|
||||
output = output.trim_space()+':'
|
||||
if 0 != int(C.pclose(f)) {
|
||||
println(sframe) continue
|
||||
}
|
||||
println( '${output:-45s} | $sframe')
|
||||
}
|
||||
//C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_actual_frames, 1)
|
||||
return
|
||||
}else{
|
||||
C.printf('backtrace_symbols_fd is missing, so printing backtraces is not available.\n')
|
||||
|
Loading…
Reference in New Issue
Block a user