@@ -8,12 +8,13 @@ easy to use programmatically.
8
8
The primary function used to obtain a stack trace is [ ` stacktrace ` ] ( @ref ) :
9
9
10
10
``` julia-repl
11
- julia> stacktrace()
12
- 4-element Array{StackFrame,1}:
13
- eval(::Module, ::Any) at boot.jl:236
14
- eval_user_input(::Any, ::Base.REPL.REPLBackend) at REPL.jl:66
15
- macro expansion at REPL.jl:97 [inlined]
16
- (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at event.jl:73
11
+ 6-element Array{Base.StackTraces.StackFrame,1}:
12
+ top-level scope
13
+ eval at boot.jl:317 [inlined]
14
+ eval(::Module, ::Expr) at REPL.jl:5
15
+ eval_user_input(::Any, ::REPL.REPLBackend) at REPL.jl:85
16
+ macro expansion at REPL.jl:116 [inlined]
17
+ (::getfield(REPL, Symbol("##28#29")){REPL.REPLBackend})() at event.jl:92
17
18
```
18
19
19
20
Calling [ ` stacktrace() ` ] ( @ref ) returns a vector of [ ` StackTraces.StackFrame ` ] ( @ref ) s. For ease of use, the
@@ -25,9 +26,10 @@ julia> example() = stacktrace()
25
26
example (generic function with 1 method)
26
27
27
28
julia> example()
28
- 5 -element Array{StackFrame,1}:
29
+ 7 -element Array{Base.StackTraces. StackFrame,1}:
29
30
example() at REPL[1]:1
30
- eval(::Module, ::Any) at boot.jl:236
31
+ top-level scope
32
+ eval at boot.jl:317 [inlined]
31
33
[...]
32
34
33
35
julia> @noinline child() = stacktrace()
@@ -40,14 +42,14 @@ julia> grandparent() = parent()
40
42
grandparent (generic function with 1 method)
41
43
42
44
julia> grandparent()
43
- 7 -element Array{StackFrame,1}:
45
+ 9 -element Array{Base.StackTraces. StackFrame,1}:
44
46
child() at REPL[3]:1
45
47
parent() at REPL[4]:1
46
48
grandparent() at REPL[5]:1
47
49
[...]
48
50
```
49
51
50
- Note that when calling [ ` stacktrace() ` ] ( @ref ) you'll typically see a frame with ` eval(...) at boot.jl ` .
52
+ Note that when calling [ ` stacktrace() ` ] ( @ref ) you'll typically see a frame with ` eval at boot.jl ` .
51
53
When calling [ ` stacktrace() ` ] ( @ref ) from the REPL you'll also have a few extra frames in the stack
52
54
from ` REPL.jl ` , usually looking something like this:
53
55
@@ -56,12 +58,14 @@ julia> example() = stacktrace()
56
58
example (generic function with 1 method)
57
59
58
60
julia> example()
59
- 5 -element Array{StackFrame,1}:
61
+ 7 -element Array{Base.StackTraces. StackFrame,1}:
60
62
example() at REPL[1]:1
61
- eval(::Module, ::Any) at boot.jl:236
62
- eval_user_input(::Any, ::Base.REPL.REPLBackend) at REPL.jl:66
63
- macro expansion at REPL.jl:97 [inlined]
64
- (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at event.jl:73
63
+ top-level scope
64
+ eval at boot.jl:317 [inlined]
65
+ eval(::Module, ::Expr) at REPL.jl:5
66
+ eval_user_input(::Any, ::REPL.REPLBackend) at REPL.jl:85
67
+ macro expansion at REPL.jl:116 [inlined]
68
+ (::getfield(REPL, Symbol("##28#29")){REPL.REPLBackend})() at event.jl:92
65
69
```
66
70
67
71
## Extracting useful information
@@ -72,17 +76,17 @@ default C functions do not appear in the stack trace), and an integer representa
72
76
returned by [ ` backtrace ` ] ( @ref ) :
73
77
74
78
``` julia-repl
75
- julia> top_frame = stacktrace()[1 ]
76
- eval(::Module, ::Expr) at REPL.jl:3
79
+ julia> frame = stacktrace()[3 ]
80
+ eval(::Module, ::Expr) at REPL.jl:5
77
81
78
- julia> top_frame .func
82
+ julia> frame .func
79
83
:eval
80
84
81
- julia> top_frame .file
82
- Symbol("./boot .jl")
85
+ julia> frame .file
86
+ Symbol("~/julia/usr/share/julia/stdlib/v0.7/REPL/src/REPL .jl")
83
87
84
- julia> top_frame .line
85
- 236
88
+ julia> frame .line
89
+ 5
86
90
87
91
julia> top_frame.linfo
88
92
MethodInstance for eval(::Module, ::Expr)
96
100
97
101
``` julia-repl
98
102
julia> top_frame.pointer
99
- 0x00007f390d152a59
103
+ 0x00007f92d6293171
100
104
```
101
105
102
106
This makes stack trace information available programmatically for logging, error handling, and
@@ -119,9 +123,10 @@ julia> @noinline example() = try
119
123
example (generic function with 1 method)
120
124
121
125
julia> example()
122
- 5 -element Array{StackFrame,1}:
126
+ 7 -element Array{Base.StackTraces. StackFrame,1}:
123
127
example() at REPL[2]:4
124
- eval(::Module, ::Any) at boot.jl:236
128
+ top-level scope
129
+ eval at boot.jl:317 [inlined]
125
130
[...]
126
131
```
127
132
@@ -147,7 +152,7 @@ julia> @noinline example() = try
147
152
example (generic function with 1 method)
148
153
149
154
julia> example()
150
- 6 -element Array{StackFrame,1}:
155
+ 8 -element Array{Base.StackTraces. StackFrame,1}:
151
156
bad_function() at REPL[1]:1
152
157
example() at REPL[2]:2
153
158
[...]
@@ -174,7 +179,8 @@ grandparent (generic function with 1 method)
174
179
175
180
julia> grandparent()
176
181
ERROR: Whoops!
177
- 7-element Array{StackFrame,1}:
182
+ 10-element Array{Base.StackTraces.StackFrame,1}:
183
+ error at error.jl:33 [inlined]
178
184
child() at REPL[1]:1
179
185
parent() at REPL[2]:1
180
186
grandparent() at REPL[3]:3
@@ -183,77 +189,63 @@ ERROR: Whoops!
183
189
184
190
## Comparison with [ ` backtrace ` ] ( @ref )
185
191
186
- A call to [ ` backtrace ` ] ( @ref ) returns a vector of ` Ptr{Cvoid } ` , which may then be passed into
192
+ A call to [ ` backtrace ` ] ( @ref ) returns a vector of ` Union{ Ptr{Nothing}, Base.InterpreterIP }` , which may then be passed into
187
193
[ ` stacktrace ` ] ( @ref ) for translation:
188
194
189
195
``` julia-repl
190
196
julia> trace = backtrace()
191
- 21-element Array{Ptr{Cvoid},1}:
192
- Ptr{Cvoid} @0x00007f10049d5b2f
193
- Ptr{Cvoid} @0x00007f0ffeb4d29c
194
- Ptr{Cvoid} @0x00007f0ffeb4d2a9
195
- Ptr{Cvoid} @0x00007f1004993fe7
196
- Ptr{Cvoid} @0x00007f10049a92be
197
- Ptr{Cvoid} @0x00007f10049a823a
198
- Ptr{Cvoid} @0x00007f10049a9fb0
199
- Ptr{Cvoid} @0x00007f10049aa718
200
- Ptr{Cvoid} @0x00007f10049c0d5e
201
- Ptr{Cvoid} @0x00007f10049a3286
202
- Ptr{Cvoid} @0x00007f0ffe9ba3ba
203
- Ptr{Cvoid} @0x00007f0ffe9ba3d0
204
- Ptr{Cvoid} @0x00007f1004993fe7
205
- Ptr{Cvoid} @0x00007f0ded34583d
206
- Ptr{Cvoid} @0x00007f0ded345a87
207
- Ptr{Cvoid} @0x00007f1004993fe7
208
- Ptr{Cvoid} @0x00007f0ded34308f
209
- Ptr{Cvoid} @0x00007f0ded343320
210
- Ptr{Cvoid} @0x00007f1004993fe7
211
- Ptr{Cvoid} @0x00007f10049aeb67
212
- Ptr{Cvoid} @0x0000000000000000
197
+ 18-element Array{Union{Ptr{Nothing}, Base.InterpreterIP},1}:
198
+ Ptr{Nothing} @0x00007fd8734c6209
199
+ Ptr{Nothing} @0x00007fd87362b342
200
+ Ptr{Nothing} @0x00007fd87362c136
201
+ Ptr{Nothing} @0x00007fd87362c986
202
+ Ptr{Nothing} @0x00007fd87362d089
203
+ Base.InterpreterIP(CodeInfo(:(begin
204
+ Core.SSAValue(0) = backtrace()
205
+ trace = Core.SSAValue(0)
206
+ return Core.SSAValue(0)
207
+ end)), 0x0000000000000000)
208
+ Ptr{Nothing} @0x00007fd87362e4cf
209
+ [...]
213
210
214
211
julia> stacktrace(trace)
215
- 5-element Array{StackFrame,1}:
216
- backtrace() at error.jl:46
217
- eval(::Module, ::Any) at boot.jl:236
218
- eval_user_input(::Any, ::Base.REPL.REPLBackend) at REPL.jl:66
219
- macro expansion at REPL.jl:97 [inlined]
220
- (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at event.jl:73
212
+ 6-element Array{Base.StackTraces.StackFrame,1}:
213
+ top-level scope
214
+ eval at boot.jl:317 [inlined]
215
+ eval(::Module, ::Expr) at REPL.jl:5
216
+ eval_user_input(::Any, ::REPL.REPLBackend) at REPL.jl:85
217
+ macro expansion at REPL.jl:116 [inlined]
218
+ (::getfield(REPL, Symbol("##28#29")){REPL.REPLBackend})() at event.jl:92
221
219
```
222
220
223
- Notice that the vector returned by [ ` backtrace ` ] ( @ref ) had 21 pointers , while the vector returned
224
- by [ ` stacktrace ` ] ( @ref ) only has 5 . This is because, by default, [ ` stacktrace ` ] ( @ref ) removes
221
+ Notice that the vector returned by [ ` backtrace ` ] ( @ref ) had 18 elements , while the vector returned
222
+ by [ ` stacktrace ` ] ( @ref ) only has 6 . This is because, by default, [ ` stacktrace ` ] ( @ref ) removes
225
223
any lower-level C functions from the stack. If you want to include stack frames from C calls,
226
224
you can do it like this:
227
225
228
226
``` julia-repl
229
227
julia> stacktrace(trace, true)
230
- 27-element Array{StackFrame,1}:
231
- jl_backtrace_from_here at stackwalk.c:103
232
- backtrace() at error.jl:46
233
- backtrace() at sys.so:?
234
- jl_call_method_internal at julia_internal.h:248 [inlined]
235
- jl_apply_generic at gf.c:2215
236
- do_call at interpreter.c:75
237
- eval at interpreter.c:215
238
- eval_body at interpreter.c:519
239
- jl_interpret_toplevel_thunk at interpreter.c:664
240
- jl_toplevel_eval_flex at toplevel.c:592
241
- jl_toplevel_eval_in at builtins.c:614
242
- eval(::Module, ::Any) at boot.jl:236
243
- eval(::Module, ::Any) at sys.so:?
244
- jl_call_method_internal at julia_internal.h:248 [inlined]
245
- jl_apply_generic at gf.c:2215
246
- eval_user_input(::Any, ::Base.REPL.REPLBackend) at REPL.jl:66
247
- ip:0x7f1c707f1846
248
- jl_call_method_internal at julia_internal.h:248 [inlined]
249
- jl_apply_generic at gf.c:2215
250
- macro expansion at REPL.jl:97 [inlined]
251
- (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at event.jl:73
252
- ip:0x7f1c707ea1ef
253
- jl_call_method_internal at julia_internal.h:248 [inlined]
254
- jl_apply_generic at gf.c:2215
255
- jl_apply at julia.h:1411 [inlined]
256
- start_task at task.c:261
228
+ 21-element Array{Base.StackTraces.StackFrame,1}:
229
+ jl_apply_generic at gf.c:2167
230
+ do_call at interpreter.c:324
231
+ eval_value at interpreter.c:416
232
+ eval_body at interpreter.c:559
233
+ jl_interpret_toplevel_thunk_callback at interpreter.c:798
234
+ top-level scope
235
+ jl_interpret_toplevel_thunk at interpreter.c:807
236
+ jl_toplevel_eval_flex at toplevel.c:856
237
+ jl_toplevel_eval_in at builtins.c:624
238
+ eval at boot.jl:317 [inlined]
239
+ eval(::Module, ::Expr) at REPL.jl:5
240
+ jl_apply_generic at gf.c:2167
241
+ eval_user_input(::Any, ::REPL.REPLBackend) at REPL.jl:85
242
+ jl_apply_generic at gf.c:2167
243
+ macro expansion at REPL.jl:116 [inlined]
244
+ (::getfield(REPL, Symbol("##28#29")){REPL.REPLBackend})() at event.jl:92
245
+ jl_fptr_trampoline at gf.c:1838
246
+ jl_apply_generic at gf.c:2167
247
+ jl_apply at julia.h:1540 [inlined]
248
+ start_task at task.c:268
257
249
ip:0xffffffffffffffff
258
250
```
259
251
@@ -264,9 +256,10 @@ s by passing them into [`StackTraces.lookup`](@ref):
264
256
julia> pointer = backtrace()[1];
265
257
266
258
julia> frame = StackTraces.lookup(pointer)
267
- 1-element Array{StackFrame,1}:
268
- jl_backtrace_from_here at stackwalk .c:103
259
+ 1-element Array{Base.StackTraces. StackFrame,1}:
260
+ jl_apply_generic at gf .c:2167
269
261
270
262
julia> println("The top frame is from $(frame[1].func)!")
271
- The top frame is from jl_backtrace_from_here !
263
+ The top frame is from jl_apply_generic !
272
264
```
265
+
0 commit comments