diff --git a/base/stacktraces.jl b/base/stacktraces.jl index 8b5befa0eefee..e1577152571d7 100644 --- a/base/stacktraces.jl +++ b/base/stacktraces.jl @@ -109,8 +109,10 @@ Base.@constprop :none function lookup(pointer::Ptr{Cvoid}) infos = @ccall jl_lookup_code_address(pointer::Ptr{Cvoid}, false::Cint)::Core.SimpleVector pointer = convert(UInt64, pointer) isempty(infos) && return [StackFrame(empty_sym, empty_sym, -1, nothing, true, false, pointer)] # this is equal to UNKNOWN - res = Vector{StackFrame}(undef, length(infos)) - for i in 1:length(infos) + ninfos = length(infos) + res = Vector{StackFrame}(undef, ninfos) + local debuginfo = false + for i = ninfos:-1:1 info = infos[i]::Core.SimpleVector @assert(length(info) == 6) func = info[1]::Symbol @@ -118,7 +120,20 @@ Base.@constprop :none function lookup(pointer::Ptr{Cvoid}) linenum = info[3]::Int linfo = info[4] if linfo isa Core.CodeInstance + if debuginfo === false + debuginfo = linfo.debuginfo + else + debuginfo = true + end linfo = linfo.def + elseif debuginfo isa Core.DebugInfo + # TODO lookup a program counter `pc` at the parent frame and use `buildLineInfoNode(debuginfo, nothing, pc)` + if length(debuginfo.edges) == 1 # XXX + debuginfo = debuginfo.edges[1] + linfo = debuginfo.def + else + debuginfo = true + end end res[i] = StackFrame(func, file, linenum, linfo, info[5]::Bool, info[6]::Bool, pointer) end diff --git a/test/stacktraces.jl b/test/stacktraces.jl index 69b3b71d03167..907876a0f2fbf 100644 --- a/test/stacktraces.jl +++ b/test/stacktraces.jl @@ -92,9 +92,9 @@ can_inline = Bool(Base.JLOptions().can_inline) for (frame, func, inlined) in zip(trace, [g,h,f], (can_inline, can_inline, false)) @test frame.func === typeof(func).name.mt.name # broken until #50082 can be addressed - @test frame.linfo.def.module === which(func, (Any,)).module broken=inlined - @test frame.linfo.def === which(func, (Any,)) broken=inlined - @test frame.linfo.specTypes === Tuple{typeof(func), Int} broken=inlined + @test frame.linfo.def.module === which(func, (Any,)).module + @test frame.linfo.def === which(func, (Any,)) + @test frame.linfo.specTypes === Tuple{typeof(func), Int} # line @test frame.file === Symbol(@__FILE__) @test !frame.from_c @@ -266,3 +266,61 @@ end @testset "Base.StackTraces docstrings" begin @test isempty(Docs.undocumented_names(StackTraces)) end + +global f_parent1_line::Int, f_inner1_line::Int, f_innermost1_line::Int +function f_parent1(a) + x = a + return begin + @inline f_inner1(x) + end +end; f_parent1_line = (@__LINE__) - 2 +function f_inner1(a) + x = a + return @inline f_innermost1(x) +end; f_inner1_line = (@__LINE__) - 1 +f_innermost1(x) = x > 0 ? @noinline(sin(x)) : error("x is negative") +f_innermost1_line = (@__LINE__) - 1 +let st = try + f_parent1(-1) + catch err + stacktrace(catch_backtrace()) + end + @test any(st) do sf + sf.func === :f_parent1 && sf.line == f_parent1_line && sf.linfo isa Core.MethodInstance + end + @test any(st) do sf + sf.func === :f_inner1 && sf.line == f_inner1_line && sf.linfo isa Core.MethodInstance && sf.inlined + end + @test any(st) do sf + sf.func === :f_innermost1 && sf.line == f_innermost1_line && sf.linfo isa Core.MethodInstance && sf.inlined + end +end + +global f_parent2_line::Int, f_inner2_line::Int, f_innermost2_line::Int +function f_parent2(a) + x = identity(a) + return begin + @inline f_inner2(x) + end +end; f_parent2_line = (@__LINE__) - 2 +function f_inner2(a) + x = identity(a) + return @inline f_innermost1(x) +end; f_inner2_line = (@__LINE__) - 1 +f_innermost2(x) = x > 0 ? @noinline(sin(x)) : error("x is negative") +f_innermost2_line = (@__LINE__) - 1 +let st = try + f_parent2(-1) + catch err + stacktrace(catch_backtrace()) + end + @test any(st) do sf + sf.func === :f_parent2 && sf.line == f_parent2_line && sf.linfo isa Core.MethodInstance + end + @test_broken any(st) do sf + sf.func === :f_inner2 && sf.line == f_inner2_line && sf.linfo isa Core.MethodInstance && sf.inlined + end + @test_broken any(st) do sf + sf.func === :f_innermost2 && sf.line == f_innermost2_line && sf.linfo isa Core.MethodInstance && sf.inlined + end +end