Skip to content

Commit

Permalink
Refactored, doctests, show_stacktrace is now show.
Browse files Browse the repository at this point in the history
Added doctests to the manual.
Removed show_stacktrace in favour of show(x::StackFrame).
Removed format_stacktrace and format_stackframe.
Additional test cases (which currently fail due to difficult to track
down line number issues)
  • Loading branch information
spurll committed Jan 13, 2016
1 parent c26f4e2 commit be2dfff
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 418 deletions.
1 change: 0 additions & 1 deletion base/docs/helpdb.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ include("helpdb/Libdl.jl")
include("helpdb/Libc.jl")
include("helpdb/Collections.jl")
include("helpdb/Profile.jl")
include("helpdb/StackTraces.jl")
include("helpdb/Base.jl")
include("helpdb/Dates.jl")
104 changes: 0 additions & 104 deletions base/docs/helpdb/StackTraces.jl

This file was deleted.

5 changes: 2 additions & 3 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1050,11 +1050,10 @@ export
systemerror,

# stack traces
StackTrace,
StackFrame,
stacktrace,
catch_stacktrace,
format_stacktrace,
format_stackframe,
show_stacktrace,

# types
convert,
Expand Down
5 changes: 4 additions & 1 deletion base/profile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module Profile

import Base.StackTraces: StackFrame, UNKNOWN, lookup
import Base.StackTraces: StackFrame, lookup

export @profile

Expand All @@ -23,6 +23,7 @@ end
####
#### User-level functions
####

function init(; n::Union{Void,Integer} = nothing, delay::Union{Void,Float64} = nothing)
n_cur = ccall(:jl_profile_maxlen_data, Csize_t, ())
delay_cur = ccall(:jl_profile_delay_nsec, UInt64, ())/10^9
Expand Down Expand Up @@ -127,6 +128,8 @@ end
#@windows_only const btskip = 0
const btskip = 0

const UNKNOWN = StackFrame(symbol("???"), symbol("???"), 0, symbol(""), -1, true, 0)

## Print as a flat list
# Counts the number of times each line appears, at any nesting level
function count_flat{T<:Unsigned}(data::Vector{T})
Expand Down
95 changes: 52 additions & 43 deletions base/stacktraces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,40 @@
module StackTraces


import Base: hash, ==
import Base: hash, ==, show

export stacktrace, catch_stacktrace, format_stacktrace, format_stackframe, show_stacktrace
export StackTrace, StackFrame, stacktrace, catch_stacktrace

"""
StackFrame
Stack information representing execution context.
"""
immutable StackFrame
"the name of the function containing the execution context"
func::Symbol
"the path to the file containing the execution context"
file::Symbol
"the line number in the file containing the execution context"
line::Int
"the path to the file containing the context for inlined code"
inlined_file::Symbol
"the line number in the file containing the context for inlined code"
inlined_line::Int
"true if the code is from C"
from_c::Bool
"representation of the pointer to the execution context as returned by `backtrace`"
pointer::Int64 # Large enough to be read losslessly on 32- and 64-bit machines.
end

typealias StackTrace Vector{StackFrame}
"""
StackTrace
An alias for `Vector{StackFrame}` provided for convenience; returned by calls to
`stacktrace` and `catch_stacktrace`.
"""
typealias StackTrace Vector{StackFrame}

# Placeholder for unknown execution context.
const UNKNOWN = StackFrame(:?, :?, -1, :?, -1, true, 0)

#=
If the StackFrame has function and line information, we consider two of them the same if
Expand All @@ -40,15 +55,27 @@ function hash(frame::StackFrame, h::UInt)
end


"""
lookup(pointer::Union{Ptr{Void}, UInt}) -> StackFrame
Given a pointer to an execution context (usually generated by a call to `backtrace`), looks
up stack frame context information.
"""
function lookup(pointer::Ptr{Void})
frame_info = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), pointer, 0)
return (length(frame_info) == 7) ? StackFrame(frame_info...) : UNKNOWN
return StackFrame(ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), pointer, 0)...)
end

lookup(pointer::UInt) = lookup(convert(Ptr{Void}, pointer))

"""
stacktrace([trace::Vector{Ptr{Void}},] [c_funcs::Bool=false]) -> StackTrace
Returns a stack trace in the form of a vector of `StackFrame`s. (By default stacktrace
doesn't return C functions, but this can be enabled.) When called without specifying a
trace, `stacktrace` first calls `backtrace`.
"""
function stacktrace(trace::Vector{Ptr{Void}}, c_funcs::Bool=false)
stack = map(lookup, trace)
stack = map(lookup, trace)::StackTrace

# Remove frames that come from C calls.
if !c_funcs
Expand All @@ -61,19 +88,33 @@ end

stacktrace(c_funcs::Bool=false) = stacktrace(backtrace(), c_funcs)

"""
catch_stacktrace([c_funcs::Bool=false]) -> StackTrace
Returns the stack trace for the most recent error thrown, rather than the current execution
context.
"""
catch_stacktrace(c_funcs::Bool=false) = stacktrace(catch_backtrace(), c_funcs)

"""
remove_frames!(stack::StackTrace, name::Symbol)
Takes a `StackTrace` (a vector of `StackFrames`) and a function name (a `Symbol`) and
removes the `StackFrame` specified by the function name from the `StackTrace` (also removing
all frames above the specified function). Primarily used to remove `StackTraces` functions
from the `StackTrace` prior to returning it.
"""
function remove_frames!(stack::StackTrace, name::Symbol)
splice!(stack, 1:findlast(frame -> frame.func == name, stack))
return stack
end

function remove_frames!(stack::StackTrace, names::Vector{Symbol})
splice!(stack, 1:findlast(frame -> in(frame.func, names), stack))
splice!(stack, 1:findlast(frame -> frame.func in names, stack))
return stack
end

function format_stackframe(frame::StackFrame; full_path::Bool=false)
function show(io::IO, frame::StackFrame; full_path::Bool=false)
file_info = "$(full_path ? frame.file : basename(string(frame.file))):$(frame.line)"

if frame.inlined_file != Symbol("")
Expand All @@ -86,39 +127,7 @@ function format_stackframe(frame::StackFrame; full_path::Bool=false)
inline_info = ""
end

return string(inline_info, frame.func != "" ? frame.func : "?", " at ", file_info)
end

function format_stacktrace(
stack::StackTrace, separator::AbstractString, start::AbstractString="",
finish::AbstractString=""; full_path::Bool=false
)
if isempty(stack)
return ""
end

string(
start,
join(map(f -> format_stackframe(f, full_path=full_path), stack), separator),
finish
)
end

function show_stacktrace(io::IO, stack::StackTrace; full_path::Bool=false)
println(
io, "StackTrace with $(length(stack)) StackFrames$(isempty(stack) ? "" : ":")",
format_stacktrace(stack, "\n ", "\n "; full_path=full_path)
)
end

show_stacktrace(; full_path::Bool=false) = show_stacktrace(STDOUT; full_path=full_path)

function show_stacktrace(io::IO; full_path::Bool=false)
show_stacktrace(io, remove_frames!(stacktrace(), :show_stacktrace); full_path=full_path)
end

function show_stacktrace(stack::StackTrace; full_path::Bool=false)
show_stacktrace(STDOUT, stack; full_path=full_path)
print(io, string(inline_info, frame.func != "" ? frame.func : "?", " at ", file_info))
end


Expand Down
Loading

0 comments on commit be2dfff

Please sign in to comment.