From 7aae4da91eebf75da1785fc771690ac4a96e53f2 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 30 Dec 2018 04:36:33 -0600 Subject: [PATCH 1/7] Update Rebugger to Revise.pkgdatas --- src/debug.jl | 81 ++++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/src/debug.jl b/src/debug.jl index 7a2d013..434d3bf 100644 --- a/src/debug.jl +++ b/src/debug.jl @@ -89,31 +89,15 @@ function pregenerated_stacktrace(trace; topname = :capture_stacktrace) usrtrace, defs = Method[], RelocatableExpr[] methodsused = Set{Method}() - function load_file(file, mod=Base) - ret = Revise.find_file(file, mod) - ret == nothing && return nothing - file, recipemod = ret - if !haskey(Revise.fileinfos, file) - try - @info "tracking $recipemod" - Revise.track(recipemod) - catch err - err isa Revise.GitRepoException && return nothing - rethrow(err) - end - end - return file - end - # When the method can't be found directly in the tables, # look it up by fie and line number - function add_by_file_line(defmap, sf) + function add_by_file_line(defmap, line) for (def, info) in defmap info == nothing && continue sigts, offset = info r = linerange(def, offset) r == nothing && continue - if sf.line ∈ r + if line ∈ r mths = Base._methods_by_ftype(last(sigts), -1, typemax(UInt)) m = mths[end][3] # the last method is the least specific that matches the signature (which would be more specific if it were used) if m ∉ methodsused @@ -126,6 +110,16 @@ function pregenerated_stacktrace(trace; topname = :capture_stacktrace) end return false end + function add_by_file_line(pkgdata, file, line) + fi = get(pkgdata.fileinfos, file, nothing) + if fi !== nothing + Revise.maybe_parse_from_cache!(pkgdata, file) + for (mod, fmm) in fi.fm + add_by_file_line(fmm.defmap, line) && return true + end + end + return false + end for (i, sf) in enumerate(trace) sf.func == topname && break # truncate at the chosen spot @@ -134,36 +128,47 @@ function pregenerated_stacktrace(trace; topname = :capture_stacktrace) file = String(sf.file) if mi isa Core.MethodInstance method = mi.def - # Set up tracking, if necessary - if !haskey(Revise.fileinfos, file) - file = load_file(file, method.module) + def = nothing + if String(method.name)[1] != '#' # if not a keyword/default arg method + def = Revise.get_def(method) end - haskey(Revise.fileinfos, file) || continue - fi = Revise.fileinfos[file] - Revise.maybe_parse_from_cache!(fi, file) - funcname = String(sf.func) - if startswith(funcname, '#') - # This is a generated method, perhaps it's a keyword function handler + if def === nothing + # This may be a generated method, perhaps it's a keyword function handler # Look for it by line number - defmap = fi.fm[method.module].defmap - add_by_file_line(defmap, sf) + id = Revise.get_tracked_id(method.module) + id === nothing && continue + pkgdata = Revise.pkgdatas[id] + rpath = relpath(file, pkgdata) + fi = get(pkgdata.fileinfos, rpath, nothing) + if fi !== nothing + add_by_file_line(fi.fm[method.module].defmap, sf) + end else method ∈ methodsused && continue - def = Revise.get_def(method; modified_files=String[]) def isa ExLike || continue push!(defs, def) push!(usrtrace, method) end else # This method was inlined and hence linfo was not available - if !haskey(Revise.fileinfos, file) - file = load_file(file) + # Try to find it + if startswith(file, "./") + # This is a file in Base or Core + file = relpath(file, "./") + id = Revise.get_tracked_id(Base) + pkgdata = Revise.pkgdatas[id] + if haskey(pkgdata.fileinfos, file) + add_by_file_line(pkgdata, file, sf.line) && continue + elseif startswith(file, "compiler") + id = Revise.get_tracked_id(Core.Compiler) + pkgdata = Revise.pkgdatas[id] + add_by_file_line(pkgdata, relpath(file, pkgdata), sf.line) && continue + end end - haskey(Revise.fileinfos, file) || continue - fi = Revise.fileinfos[file] - Revise.maybe_parse_from_cache!(fi, file) - for (mod, fmm) in fi.fm - add_by_file_line(fmm.defmap, sf) && break + # Try all loaded packages + for (id, pkgdata) in Revise.pkgdatas + rpath = relpath(file, pkgdata) + add_by_file_line(pkgdata, rpath, sf.line) && break end end end @@ -449,7 +454,7 @@ function method_capture_from_callee(method; kwargs...) # Could use a default arg above but this generates a more understandable error message local def try - def = get_def(method; modified_files=String[]) + def = get_def(method; modified_files=typeof(Revise.revision_queue)()) catch err throw(DefMissing(method, err)) end From e039d85b505a9865150c21ff9fff9aa6b0b2726c Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 30 Dec 2018 14:38:56 -0600 Subject: [PATCH 2/7] Reduce startup latency --- src/Rebugger.jl | 30 ++++++++++++++++++------------ src/precompile.jl | 5 +++++ 2 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 src/precompile.jl diff --git a/src/Rebugger.jl b/src/Rebugger.jl index ce78465..0e0ddc1 100644 --- a/src/Rebugger.jl +++ b/src/Rebugger.jl @@ -23,21 +23,27 @@ function repl_init(repl) repl.interface = REPL.setup_interface(repl; extra_repl_keymap = get_rebugger_modeswitch_dict()) end -function __init__() +function rebugrepl_init() # Set up the Rebugger REPL mode with all of its key bindings repl_inited = isdefined(Base, :active_repl) - @async begin - while !isdefined(Base, :active_repl) - sleep(0.05) - end - sleep(0.1) # for extra safety - # Set up the custom "rebug" REPL - main_repl = Base.active_repl - repl = HeaderREPL(main_repl, RebugHeader()) - interface = REPL.setup_interface(repl; extra_repl_keymap=[get_rebugger_modeswitch_dict(), rebugger_keys]) - rebug_prompt_ref[] = interface.modes[end] - add_keybindings(; override=repl_inited, deprecated_keybindings..., keybindings...) + while !isdefined(Base, :active_repl) + sleep(0.05) end + sleep(0.1) # for extra safety + # Set up the custom "rebug" REPL + main_repl = Base.active_repl + repl = HeaderREPL(main_repl, RebugHeader()) + interface = REPL.setup_interface(repl; extra_repl_keymap=[get_rebugger_modeswitch_dict(), rebugger_keys]) + rebug_prompt_ref[] = interface.modes[end] + add_keybindings(; override=repl_inited, deprecated_keybindings..., keybindings...) +end + + +function __init__() + schedule(Task(rebugrepl_init)) end +include("precompile.jl") +_precompile_() + end # module diff --git a/src/precompile.jl b/src/precompile.jl new file mode 100644 index 0000000..a2a1da1 --- /dev/null +++ b/src/precompile.jl @@ -0,0 +1,5 @@ +function _precompile_() + ccall(:jl_generating_output, Cint, ()) == 1 || return nothing + precompile(Tuple{typeof(get_rebugger_modeswitch_dict)}) + precompile(Tuple{typeof(rebugrepl_init)}) +end From 0185986e46993aa5a6c769a9d21bba2d247afb41 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Tue, 1 Jan 2019 13:41:01 -0600 Subject: [PATCH 3/7] Fix "NoPkg" demo --- src/debug.jl | 4 +++- test/runtests.jl | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/debug.jl b/src/debug.jl index 434d3bf..f44f565 100644 --- a/src/debug.jl +++ b/src/debug.jl @@ -138,7 +138,9 @@ function pregenerated_stacktrace(trace; topname = :capture_stacktrace) id = Revise.get_tracked_id(method.module) id === nothing && continue pkgdata = Revise.pkgdatas[id] - rpath = relpath(file, pkgdata) + cfile = get(Revise.src_file_key, file, file) + rpath = relpath(cfile, pkgdata) + Revise.maybe_parse_from_cache!(pkgdata, rpath) fi = get(pkgdata.fileinfos, rpath, nothing) if fi !== nothing add_by_file_line(fi.fm[method.module].defmap, sf) diff --git a/test/runtests.jl b/test/runtests.jl index cf2bd6e..19efe03 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,6 @@ using Rebugger using Rebugger: StopException -using Test, UUIDs, InteractiveUtils, REPL, HeaderREPLs +using Test, UUIDs, InteractiveUtils, REPL, Pkg, HeaderREPLs using REPL.LineEdit using Revise, Colors @@ -429,6 +429,14 @@ Base.show(io::IO, ::ErrorsOnShow) = throw(ArgumentError("no show")) @test occursin("error", hist.history[idx[end]]) end + @testset "Pkg demo" begin + updated = Pkg.UPDATED_REGISTRY_THIS_SESSION[] + Pkg.UPDATED_REGISTRY_THIS_SESSION[] = true + uuids = Rebugger.capture_stacktrace(Pkg, :(add("NoPkg"))) + @test length(uuids) >= 2 + Pkg.UPDATED_REGISTRY_THIS_SESSION[] = updated + end + @testset "Empty stacktraces" begin cmd = "ccall(:jl_throw, Nothing, (Any,), ArgumentError(\"oops\"))" mktemp() do path, io From bf284704a77ca5a0bf357b09067bbf1c439c57ba Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 2 Jan 2019 04:44:31 -0600 Subject: [PATCH 4/7] Switch to the new Documenter --- .travis.yml | 21 ++++++++++++--------- README.md | 2 +- docs/Project.toml | 5 +++++ docs/make.jl | 9 +-------- 4 files changed, 19 insertions(+), 18 deletions(-) create mode 100644 docs/Project.toml diff --git a/.travis.yml b/.travis.yml index fcbf111..f7573e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,14 +13,17 @@ notifications: git: depth: 99999999 -# TODO: remove this once HeaderREPLs is registered -before_script: - - julia -e 'using Pkg; - Pkg.clone("https://github.com/timholy/HeaderREPLs.jl")' - -after_script: # TODO: change to after_success once https://github.com/JuliaLang/julia/issues/28306 is fixed +after_success: # push coverage results to Codecov - julia -e 'using Pkg, Rebugger; cd(joinpath(dirname(pathof(Rebugger)), "..")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())' - # Update the documentation - - julia -e 'using Pkg; ps=Pkg.PackageSpec(name="Documenter", version="0.19"); Pkg.add(ps); Pkg.pin(ps)' - - julia -e 'using Rebugger; ENV["DOCUMENTER_DEBUG"] = "true"; include(joinpath(dirname(pathof(Rebugger)), "..", "docs", "make.jl"))' + +jobs: + include: + - stage: "Documentation" + julia: 1.0 + os: linux + script: + - julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); + Pkg.instantiate()' + - julia --project=docs/ docs/make.jl +after_success: skip diff --git a/README.md b/README.md index afb3fe4..f63e8ab 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The name "Rebugger" has 3 meanings: **See the documentation**: [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://timholy.github.io/Rebugger.jl/stable) -[![](https://img.shields.io/badge/docs-latest-blue.svg)](https://timholy.github.io/Rebugger.jl/latest) +[![](https://img.shields.io/badge/docs-latest-blue.svg)](https://timholy.github.io/Rebugger.jl/dev) Note that Rebugger may benefit from custom configuration, as described in the documentation. diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 0000000..ce87d15 --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,5 @@ +[deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" + +[compat] +Documenter = "~0.21" diff --git a/docs/make.jl b/docs/make.jl index 83cdb9b..c25915f 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -3,7 +3,7 @@ using Documenter, Rebugger makedocs( modules = [Rebugger], clean = false, - format = :html, + format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"), sitename = "Rebugger.jl", authors = "Tim Holy", linkcheck = !("skiplinks" in ARGS), @@ -15,15 +15,8 @@ makedocs( "internals.md", "reference.md", ], - # # Use clean URLs, unless built as a "local" build - # html_prettyurls = !("local" in ARGS), -# html_canonical = "https://juliadocs.github.io/Rebugger.jl/stable/", ) deploydocs( repo = "github.com/timholy/Rebugger.jl.git", - target = "build", - julia = "1.0", - deps = nothing, - make = nothing, ) From 17f8ebd09de2f7e78f87effd2eede31ffeb54e28 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 2 Jan 2019 04:47:52 -0600 Subject: [PATCH 5/7] Update the documentation and requirements This provides significantly more guidance on the REPL, since some users (esp Windows and Mac users) may not have familiarity with the more advanced REPL features that enhance usage of Rebugger. --- .travis.yml | 1 - README.md | 2 +- REQUIRE | 4 +- appveyor.yml | 1 - docs/src/images/stepin4.png | Bin 0 -> 67946 bytes docs/src/index.md | 2 +- docs/src/usage.md | 101 +++++++++++++++++++++++++----------- 7 files changed, 74 insertions(+), 37 deletions(-) create mode 100644 docs/src/images/stepin4.png diff --git a/.travis.yml b/.travis.yml index f7573e2..9327cf4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ os: - linux - osx julia: - - 0.7 - 1.0 - nightly notifications: diff --git a/README.md b/README.md index f63e8ab..858b7e2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![codecov.io](http://codecov.io/github/timholy/Rebugger.jl/coverage.svg?branch=master)](http://codecov.io/github/timholy/Rebugger.jl?branch=master) Rebugger is an expression-level debugger for Julia. -It has no ability to interact with or manipulate call stacks (see [ASTInterpreter2](https://github.com/Keno/ASTInterpreter2.jl)), +It has no ability to interact with or manipulate call stacks (see [Gallium](https://github.com/Keno/Gallium.jl)), but it can trace execution via the manipulation of Julia expressions. The name "Rebugger" has 3 meanings: diff --git a/REQUIRE b/REQUIRE index 88fe3a7..69c3ef0 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,3 +1,3 @@ -julia 0.7 -Revise 0.7.15 +julia 1.0 +Revise 1.0 HeaderREPLs 0.2 diff --git a/appveyor.yml b/appveyor.yml index f06875d..55c58b6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,5 @@ environment: matrix: - - julia_version: 0.7 - julia_version: 1 - julia_version: nightly diff --git a/docs/src/images/stepin4.png b/docs/src/images/stepin4.png new file mode 100644 index 0000000000000000000000000000000000000000..9d107e237b1eff42f8a578499127bc5554e57b08 GIT binary patch literal 67946 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 literal 0 HcmV?d00001 diff --git a/docs/src/index.md b/docs/src/index.md index f57ceab..6f9f4df 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,7 +1,7 @@ # Introduction to Rebugger Rebugger is an expression-level debugger for Julia. -It has no ability to interact with or manipulate call stacks (see [ASTInterpreter2](https://github.com/Keno/ASTInterpreter2.jl)), +It has no ability to interact with or manipulate call stacks (see [Gallium](https://github.com/Keno/Gallium.jl)), but it can trace execution via the manipulation of Julia expressions. The name "Rebugger" has 3 meanings: diff --git a/docs/src/usage.md b/docs/src/usage.md index 4297c27..04d652f 100644 --- a/docs/src/usage.md +++ b/docs/src/usage.md @@ -19,15 +19,21 @@ Select the expression you want to step into by positioning "point" (your cursor) at the desired location in the command line: ```@raw html - + ``` It's essential that point is at the very first character of the expression, in this case on the `s` in `show`. + +!!! note + Don't confuse the REPL's cursor with your mouse pointer. + Your mouse is essentially irrelevant on the REPL; use arrow keys or the other + [navigation features of Julia's REPL](https://docs.julialang.org/en/latest/stdlib/REPL/). + Now if you hit Meta-e, you should see something like this: ```@raw html - + ``` (If not, check [Keyboard shortcuts](@ref) and [Customize keybindings](@ref).) @@ -42,12 +48,12 @@ Indented blue line(s) show the value(s) of any input arguments or type parameter If you're following along, move your cursor to the next `show` call as illustrated above. Hit Meta-e again. You should see a new `show` method, this time with two input arguments. -Now let's demonstrate another important display item: position your cursor at the +Now let's demonstrate another important display item: position point at the beginning of the `_show_empty` call and hit Meta-e. The display should now look like this: ```@raw html - + ``` This time, note the yellow/orange line: this is a warning message, and you should pay attention to these. @@ -55,9 +61,23 @@ This time, note the yellow/orange line: this is a warning message, and you shoul In this case execution never reached `_show_empty`, because it enters `show_vector` instead; if you moved your cursor there, you could trace execution more completely. +You can edit these expressions to insert code to display variables or test +changes to the code. +As an experiment, try stepping into the `show_vector` call from the example above +and adding `@show limited` to display a local variable's value: + +```@raw html + +``` + +!!! note + When editing expressions, you can insert a blank line with Meta-Enter (i.e., Esc-Enter, Alt-Enter, or Option-Enter). + See the many [advanced features of Julia's REPL](https://docs.julialang.org/en/latest/stdlib/REPL/#Key-bindings-1) that allow you to efficiently edit these `let`-blocks. + Having illustrated the importance of "point" and the various colors used for messages from Rebugger, to ensure readability the remaining examples will be rendered as text. + ## Capturing stacktraces For a quick demo, we'll use the `Colors` package (`add` it if you don't have it) @@ -81,19 +101,21 @@ in expression starting at REPL[3]:1 ``` To capture the stacktrace, type the last line again or hit the up arrow, but instead of -pressing enter type Meta-s. +pressing Enter, type Meta-s. After a short delay, you should see something like this: + ```julia julia> colorant"hsl(80%, 20%, 15%)" ┌ Warning: Tuple{getfield(Colors, Symbol("#@colorant_str")),LineNumberNode,Module,Any} was not found, perhaps it was generated by code -└ @ Revise ~/.julia/dev/Revise/src/Revise.jl:614 +└ @ Revise ~/.julia/dev/Revise/src/Revise.jl:659 Captured elements of stacktrace: -[1] parse_hsl_hue(num::AbstractString) in Colors at /home/tim/.julia/dev/Colors/src/parse.jl:25 -[2] _parse_colorant(desc::AbstractString) in Colors at /home/tim/.julia/dev/Colors/src/parse.jl:51 -[3] parse(::Type{C}, desc::AbstractString) where C<:Colorant in Colors at /home/tim/.julia/dev/Colors/src/parse.jl:140 -parse_hsl_hue(num::AbstractString) in Colors at /home/tim/.julia/dev/Colors/src/parse.jl:25 +[1] parse_hsl_hue(num::AbstractString) in Colors at /home/tim/.julia/packages/Colors/4hvzi/src/parse.jl:25 +[2] _parse_colorant(desc::AbstractString) in Colors at /home/tim/.julia/packages/Colors/4hvzi/src/parse.jl:51 +[3] _parse_colorant(::Type{C}, ::Type{SUP}, desc::AbstractString) where {C<:Colorant, SUP} in Colors at /home/tim/.julia/packages/Colors/4hvzi/src/parse.jl:112 +[4] parse(::Type{C}, desc::AbstractString) where C<:Colorant in Colors at /home/tim/.julia/packages/Colors/4hvzi/src/parse.jl:140 +parse_hsl_hue(num::AbstractString) in Colors at /home/tim/.julia/packages/Colors/4hvzi/src/parse.jl:25 num = 80% -rebug> @eval Colors let (num,) = Main.Rebugger.getstored("c592f0a4-a226-11e8-1002-fd2731558606") +rebug> @eval Colors let (num,) = Main.Rebugger.getstored("57dbc76a-0def-11e9-1dbf-ef97d29d2e25") begin if num[end] == '%' error("hue cannot end in %") @@ -105,13 +127,41 @@ rebug> @eval Colors let (num,) = Main.Rebugger.getstored("c592f0a4-a226-11e8-100 ``` (Again, if this doesn't happen check [Keyboard shortcuts](@ref) and [Customize keybindings](@ref).) +You are in the method corresponding to `[1]` in the stacktrace. Now you can navigate with your up and down arrows to browse the captured stacktrace. -You can pick any of these expressions to execute (hit Enter) or edit before execution. -For example you could add `@show` commands to examine intermediate variables or test -out different ways to fix a bug. +For example, if you hit the up arrow twice, you will be in the method corresponding to `[3]`: + +```julia +julia> colorant"hsl(80%, 20%, 15%)" +┌ Warning: Tuple{getfield(Colors, Symbol("#@colorant_str")),LineNumberNode,Module,Any} was not found, perhaps it was generated by code +└ @ Revise ~/.julia/dev/Revise/src/Revise.jl:659 +Captured elements of stacktrace: +[1] parse_hsl_hue(num::AbstractString) in Colors at /home/tim/.julia/packages/Colors/4hvzi/src/parse.jl:25 +[2] _parse_colorant(desc::AbstractString) in Colors at /home/tim/.julia/packages/Colors/4hvzi/src/parse.jl:51 +[3] _parse_colorant(::Type{C}, ::Type{SUP}, desc::AbstractString) where {C<:Colorant, SUP} in Colors at /home/tim/.julia/packages/Colors/4hvzi/src/parse.jl:112 +[4] parse(::Type{C}, desc::AbstractString) where C<:Colorant in Colors at /home/tim/.julia/packages/Colors/4hvzi/src/parse.jl:140 +_parse_colorant(::Type{C}, ::Type{SUP}, desc::AbstractString) where {C<:Colorant, SUP} in Colors at /home/tim/.julia/packages/Colors/4hvzi/src/parse.jl:112 + C = Colorant + SUP = Any + desc = hsl(80%, 20%, 15%) +rebug> @eval Colors let (C, SUP, desc) = Main.Rebugger.getstored("57d9ebc0-0def-11e9-2ab0-e5d1e4c6e82d") + begin + _parse_colorant(desc) + end + end +``` + +You can hit the down arrow and go back to earlier entries in the trace. +Alternatively, you can pick any of these expressions to execute (hit Enter) or edit before execution. You can use the REPL history to test the results of many different changes to the same "method"; the "method" will be run with the same inputs each time. +!!! note + When point is at the end of the input, the up and down arrows step through the history. + But if you move point into the method body (e.g., by using left-arrow), + the up and down arrows move within the method body. + If you've entered edit mode, you can go back to history mode using PgUp and PgDn. + ## Important notes ### "Missing" methods from stacktraces @@ -119,9 +169,6 @@ the "method" will be run with the same inputs each time. In the example above, you may have noticed the warning about the `@colorant_str` macro being omitted from the "captured" (interactive) expressions comprising the stacktrace. Macros are not traced. -Also notice that the inlined method does not appear in the captured stacktrace. -However, you can enter an inlined method using "step in," starting from the method -above it in the stacktrace. When many methods use keyword arguments, the apparent difference between the "real" stacktrace and the "captured" stacktrace can be quite dramatic: @@ -154,29 +201,21 @@ Stacktrace: julia> Pkg.add("NoPkg") # hit Meta-s here Captured elements of stacktrace: [1] pkgerror(msg::String...) in Pkg.Types at /home/tim/src/julia-1.0/usr/share/julia/stdlib/v1.0/Pkg/src/Types.jl:120 -[2] ensure_resolved(env::Pkg.Types.EnvCache, pkgs::AbstractArray{Pkg.Types.PackageSpec,1}) in Pkg.Types at /home/tim/src/julia-1.0/usr/share/julia/stdlib/v1.0/Pkg/src/Types.jl:860 -[3] add_or_develop(ctx::Pkg.Types.Context, pkgs::Array{Pkg.Types.PackageSpec,1}) in Pkg.API at /home/tim/src/julia-1.0/usr/share/julia/stdlib/v1.0/Pkg/src/API.jl:32 -[4] add_or_develop(pkgs::Array{String,1}) in Pkg.API at /home/tim/src/julia-1.0/usr/share/julia/stdlib/v1.0/Pkg/src/API.jl:28 -[5] add(args...) in Pkg.API at /home/tim/src/julia-1.0/usr/share/julia/stdlib/v1.0/Pkg/src/API.jl:69 +[2] add(args...) in Pkg.API at /home/tim/src/julia-1.0/usr/share/julia/stdlib/v1.0/Pkg/src/API.jl:69 pkgerror(msg::String...) in Pkg.Types at /home/tim/src/julia-1.0/usr/share/julia/stdlib/v1.0/Pkg/src/Types.jl:120 msg = ("The following package names could not be resolved:\n * NoPkg (not found in project, manifest or registry)\nPlease specify by known `name=uuid`.",) -rebug> @eval Pkg.Types let (msg,) = Main.Rebugger.getstored("b5c899c2-a228-11e8-0877-d102334a9f65") +rebug> @eval Pkg.Types let (msg,) = Main.Rebugger.getstored("161c53ba-0dfe-11e9-0f8f-59f468aec692") begin throw(PkgError(join(msg))) end end ``` -Note that only five methods got captured but the stacktrace is much longer. +Note that only two methods got captured but the stacktrace is much longer. Most of these methods, however, start with `#`, an indication that they are -generated methods rather than ones that appear in the source code. -The interactive stacktrace visits only those methods that appear in the original source code. - -!!! note - `Pkg` is one of Julia's standard libraries, and to step into or trace Julia's stdlibs - you must build Julia from source. - - +generated (keyword-handling) methods rather than ones that appear directly in the source code. +For now, Rebugger omits these entries. +However, you can enter (i.e., Meta-e) such methods from one that is higher in the stack trace. ### Modified "signatures" From 8da95d13a82c28d2bfaf09b46756391bb02eada1 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 2 Jan 2019 10:25:09 -0600 Subject: [PATCH 6/7] Fix Windows path problems --- src/debug.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/debug.jl b/src/debug.jl index f44f565..b58b793 100644 --- a/src/debug.jl +++ b/src/debug.jl @@ -35,6 +35,7 @@ struct EvalException <: Exception exception end +const base_prefix = '.' * Base.Filesystem.path_separator """ Rebugger.clear() @@ -154,9 +155,9 @@ function pregenerated_stacktrace(trace; topname = :capture_stacktrace) else # This method was inlined and hence linfo was not available # Try to find it - if startswith(file, "./") + if startswith(file, base_prefix) # This is a file in Base or Core - file = relpath(file, "./") + file = relpath(file, base_prefix) id = Revise.get_tracked_id(Base) pkgdata = Revise.pkgdatas[id] if haskey(pkgdata.fileinfos, file) From 84fe340ec705917b2c422d97abf814f1c928c4ca Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 2 Jan 2019 10:53:33 -0600 Subject: [PATCH 7/7] Fix stacktrace capture for methods from Core --- src/debug.jl | 22 +++++++++++++++++++--- test/runtests.jl | 12 +++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/debug.jl b/src/debug.jl index b58b793..f1053ad 100644 --- a/src/debug.jl +++ b/src/debug.jl @@ -131,16 +131,27 @@ function pregenerated_stacktrace(trace; topname = :capture_stacktrace) method = mi.def def = nothing if String(method.name)[1] != '#' # if not a keyword/default arg method - def = Revise.get_def(method) + try + def = Revise.get_def(method) + catch + continue + end end if def === nothing # This may be a generated method, perhaps it's a keyword function handler # Look for it by line number - id = Revise.get_tracked_id(method.module) + local id + try + id = Revise.get_tracked_id(method.module) + catch + # Methods from Core.Compiler cause errors on Julia binaries + continue + end id === nothing && continue pkgdata = Revise.pkgdatas[id] cfile = get(Revise.src_file_key, file, file) rpath = relpath(cfile, pkgdata) + haskey(pkgdata.fileinfos, rpath) || continue Revise.maybe_parse_from_cache!(pkgdata, rpath) fi = get(pkgdata.fileinfos, rpath, nothing) if fi !== nothing @@ -163,7 +174,12 @@ function pregenerated_stacktrace(trace; topname = :capture_stacktrace) if haskey(pkgdata.fileinfos, file) add_by_file_line(pkgdata, file, sf.line) && continue elseif startswith(file, "compiler") - id = Revise.get_tracked_id(Core.Compiler) + try + id = Revise.get_tracked_id(Core.Compiler) + catch + # On Julia binaries Core.Compiler is not available + continue + end pkgdata = Revise.pkgdatas[id] add_by_file_line(pkgdata, relpath(file, pkgdata), sf.line) && continue end diff --git a/test/runtests.jl b/test/runtests.jl index 19efe03..1cdb65d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -315,7 +315,8 @@ Base.show(io::IO, ::ErrorsOnShow) = throw(ArgumentError("no show")) # A case that tests inlining and several other aspects of argument capture ex = :([1, 2, 3] .* [1, 2]) - # Capture the actual stack trace, trimming it to avoid anything involving the `eval` itself + # Capture the actual stack trace, trimming it to avoid + # anything involving the `eval` itself trace = try Core.eval(Main, ex) catch @@ -339,6 +340,15 @@ Base.show(io::IO, ::ErrorsOnShow) = throw(ArgumentError("no show")) for (uuid, t) in zip(reverse(uuids), trace) @test Rebugger.stored[uuid].method.name == t.func end + + # Try capturing a method from Core. On binaries this would throw + # if we didn't catch it. + # Because the first entry is "top-level scope", and that terminates + # processing in Rebugger.pregenerated_stacktrace, we have to intervene a bit. + mod, ex = Main, :(Core.throw(ArgumentError("oops"))) + trace = try Core.eval(mod, command) catch err stacktrace(catch_backtrace()) end + usrtrace, defs = Rebugger.pregenerated_stacktrace(trace[2:3]) + @test usrtrace isa Vector end end