|
6 | 6 | # sites of the containing function. if there's only one, repeat the process from that call.
|
7 | 7 | # finally, the debug information is converted to a Julia stack trace.
|
8 | 8 | function backtrace(inst::LLVM.Instruction, bt = StackTraces.StackFrame[])
|
9 |
| - # look up the debug information from the current instruction |
10 |
| - if haskey(metadata(inst), LLVM.MD_dbg) |
11 |
| - loc = metadata(inst)[LLVM.MD_dbg] |
12 |
| - while loc !== nothing |
13 |
| - scope = LLVM.scope(loc) |
14 |
| - if scope !== nothing |
15 |
| - name = replace(LLVM.name(scope), r";$"=>"") |
16 |
| - file = LLVM.file(scope) |
17 |
| - path = joinpath(LLVM.directory(file), LLVM.filename(file)) |
18 |
| - line = LLVM.line(loc) |
19 |
| - push!(bt, StackTraces.StackFrame(name, path, line)) |
| 9 | + done = Set{LLVM.Instruction}() |
| 10 | + while true |
| 11 | + if in(inst, done) |
| 12 | + break |
| 13 | + end |
| 14 | + push!(done, inst) |
| 15 | + |
| 16 | + # look up the debug information from the current instruction |
| 17 | + if haskey(metadata(inst), LLVM.MD_dbg) |
| 18 | + loc = metadata(inst)[LLVM.MD_dbg] |
| 19 | + while loc !== nothing |
| 20 | + scope = LLVM.scope(loc) |
| 21 | + if scope !== nothing |
| 22 | + name = replace(LLVM.name(scope), r";$"=>"") |
| 23 | + file = LLVM.file(scope) |
| 24 | + path = joinpath(LLVM.directory(file), LLVM.filename(file)) |
| 25 | + line = LLVM.line(loc) |
| 26 | + push!(bt, StackTraces.StackFrame(name, path, line)) |
| 27 | + end |
| 28 | + loc = LLVM.inlined_at(loc) |
20 | 29 | end
|
21 |
| - loc = LLVM.inlined_at(loc) |
22 | 30 | end
|
23 |
| - end |
24 | 31 |
|
25 |
| - # move up the call chain |
26 |
| - f = LLVM.parent(LLVM.parent(inst)) |
27 |
| - ## functions can be used as a *value* in eg. constant expressions, so filter those out |
28 |
| - callers = filter(val -> isa(user(val), LLVM.CallInst), collect(uses(f))) |
29 |
| - ## get rid of calls without debug info |
30 |
| - filter!(callers) do call |
31 |
| - md = metadata(user(call)) |
32 |
| - haskey(md, LLVM.MD_dbg) |
33 |
| - end |
34 |
| - if !isempty(callers) |
35 |
| - # figure out the call sites of this instruction |
36 |
| - call_sites = unique(callers) do call |
37 |
| - # there could be multiple calls, originating from the same source location |
| 32 | + # move up the call chain |
| 33 | + f = LLVM.parent(LLVM.parent(inst)) |
| 34 | + ## functions can be used as a *value* in eg. constant expressions, so filter those out |
| 35 | + callers = filter(val -> isa(user(val), LLVM.CallInst), collect(uses(f))) |
| 36 | + ## get rid of calls without debug info |
| 37 | + filter!(callers) do call |
38 | 38 | md = metadata(user(call))
|
39 |
| - md[LLVM.MD_dbg] |
| 39 | + haskey(md, LLVM.MD_dbg) |
40 | 40 | end
|
| 41 | + if !isempty(callers) |
| 42 | + # figure out the call sites of this instruction |
| 43 | + call_sites = unique(callers) do call |
| 44 | + # there could be multiple calls, originating from the same source location |
| 45 | + md = metadata(user(call)) |
| 46 | + md[LLVM.MD_dbg] |
| 47 | + end |
41 | 48 |
|
42 |
| - if length(call_sites) > 1 |
43 |
| - frame = StackTraces.StackFrame("multiple call sites", "unknown", 0) |
44 |
| - push!(bt, frame) |
45 |
| - elseif length(call_sites) == 1 |
46 |
| - backtrace(user(first(call_sites)), bt) |
| 49 | + if length(call_sites) > 1 |
| 50 | + frame = StackTraces.StackFrame("multiple call sites", "unknown", 0) |
| 51 | + push!(bt, frame) |
| 52 | + elseif length(call_sites) == 1 |
| 53 | + inst = user(first(call_sites)) |
| 54 | + continue |
| 55 | + end |
47 | 56 | end
|
| 57 | + break |
48 | 58 | end
|
49 | 59 |
|
50 | 60 | return bt
|
|
0 commit comments