From 543305d020db10030ae3053a2db0181f2e4c590c Mon Sep 17 00:00:00 2001 From: Isaiah Norton Date: Mon, 10 Aug 2015 15:20:17 -0400 Subject: [PATCH 1/4] Include filename with every linenode --- src/julia-parser.scm | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/julia-parser.scm b/src/julia-parser.scm index c77ab37a4594b..dd594ca73dd44 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -590,9 +590,6 @@ (memv tok '(#\) #\] #\} else elseif catch finally =)))) (define (line-number-node s) - `(line ,(input-port-line (ts:port s)))) - -(define (line-number-filename-node s) `(line ,(input-port-line (ts:port s)) ,current-filename)) ;; insert line/file for short-form function defs, otherwise leave alone @@ -910,7 +907,7 @@ ((->) (take-token s) ;; -> is unusual: it binds tightly on the left and ;; loosely on the right. - (let ((lno (line-number-filename-node s))) + (let ((lno (line-number-node s))) `(-> ,ex (block ,lno ,(parse-eq* s))))) (else ex))))) @@ -1088,7 +1085,7 @@ (case word ((begin quote) (let ((loc (begin (skip-ws-and-comments (ts:port s)) - (line-number-filename-node s))) + (line-number-node s))) (blk (parse-block s))) (expect-end s) (let ((blk (if (and (length> blk 1) @@ -1176,7 +1173,7 @@ (loc (begin (if (not (eq? (peek-token s) 'end)) ;; if ends on same line, don't skip the following newline (skip-ws-and-comments (ts:port s))) - (line-number-filename-node s))) + (line-number-node s))) (body (parse-block s))) (expect-end s) (add-filename-to-block! body loc) @@ -1188,7 +1185,7 @@ (if (memq (peek-token s) reserved-words) (error (string "invalid type name \"" (take-token s) "\""))) (let ((sig (parse-subtype-spec s)) - (loc (line-number-filename-node s))) + (loc (line-number-node s))) (begin0 (list 'type (if (eq? word 'type) #t #f) sig (add-filename-to-block! (parse-block s) loc)) (expect-end s))))) @@ -1269,7 +1266,7 @@ `(const ,assgn)))) ((module baremodule) (let* ((name (parse-unary-prefix s)) - (loc (line-number-filename-node s)) + (loc (line-number-node s)) (body (parse-block s (lambda (s) (parse-docstring s parse-eq))))) (expect-end s) (list 'module (eq? word 'module) name @@ -1326,7 +1323,7 @@ (let* ((doargs (if (eqv? (peek-token s) #\newline) '() (parse-comma-separated s parse-range))) - (loc (line-number-filename-node s))) + (loc (line-number-node s))) `(-> (tuple ,@doargs) ,(begin0 (add-filename-to-block! (parse-block s) loc) (expect-end- s 'do))))))) From 7bf34490dd90aaa7329b56f5689ea1cf57a83500 Mon Sep 17 00:00:00 2001 From: Isaiah Norton Date: Mon, 10 Aug 2015 15:21:18 -0400 Subject: [PATCH 2/4] Emit debug info for inlined code to improve line #s Utilizes the DebugLoc "inlinedAt" parameter to remember inlining location in addition to source code origin. When available, we now print both the inlinee origin below the top-level call site. Mostly addresses #1334. (this does not handle nested inlines, which may require deeper changes) --- base/boot.jl | 3 +- base/cartesian.jl | 2 +- base/deprecated.jl | 2 +- base/docs/Docs.jl | 2 +- base/essentials.jl | 2 +- base/profile.jl | 8 +-- base/replutil.jl | 34 +++++++++---- base/show.jl | 10 +--- base/task.jl | 3 +- src/alloc.c | 6 +-- src/ast.c | 21 ++++++-- src/builtins.c | 2 +- src/codegen.cpp | 116 +++++++++++++++++++------------------------ src/debuginfo.cpp | 66 ++++++++++++++++++------ src/disasm.cpp | 7 ++- src/gf.c | 11 ++-- src/jltypes.c | 4 +- src/julia.h | 3 +- src/julia_internal.h | 5 +- src/task.c | 32 ++++++++---- test/backtrace.jl | 57 ++++++++++++++++++++- 21 files changed, 260 insertions(+), 136 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index ab6a6730e6762..e27d3e64c0e35 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -87,6 +87,7 @@ #end #immutable LineNumberNode +# file::Symbol # line::Int #end @@ -284,13 +285,13 @@ TypeConstructor(p::ANY, t::ANY) = ccall(:jl_new_type_constructor, Any, (Any, Any Expr(args::ANY...) = _expr(args...) _new(typ::Symbol, argty::Symbol) = eval(:(Core.call(::Type{$typ}, n::$argty) = $(Expr(:new, typ, :n)))) -_new(:LineNumberNode, :Int) _new(:LabelNode, :Int) _new(:GotoNode, :Int) _new(:TopNode, :Symbol) _new(:NewvarNode, :Symbol) _new(:QuoteNode, :ANY) _new(:GenSym, :Int) +eval(:(Core.call(::Type{LineNumberNode}, f::Symbol, l::Int) = $(Expr(:new, :LineNumberNode, :f, :l)))) eval(:(Core.call(::Type{GlobalRef}, m::Module, s::Symbol) = $(Expr(:new, :GlobalRef, :m, :s)))) Module(name::Symbol=:anonymous, std_imports::Bool=true) = ccall(:jl_f_new_module, Any, (Any, Bool), name, std_imports)::Module diff --git a/base/cartesian.jl b/base/cartesian.jl index 07e45e71c1703..f4e90fc83e533 100644 --- a/base/cartesian.jl +++ b/base/cartesian.jl @@ -222,7 +222,7 @@ function poplinenum(ex::Expr) if ex.head == :block if length(ex.args) == 1 return ex.args[1] - elseif length(ex.args) == 2 && ex.args[1].head == :line + elseif length(ex.args) == 2 && isa(ex.args[1], LineNumberNode) return ex.args[2] end end diff --git a/base/deprecated.jl b/base/deprecated.jl index c7aa7e4463c4a..6ea9b9b907cf7 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -80,7 +80,7 @@ function firstcaller(bt::Array{Ptr{Void},1}, funcsym::Symbol) if lkup === () continue end - fname, file, line, fromC = lkup + fname, file, line, inlined_file, inlined_line, fromC = lkup if fname == funcsym break end diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 4d9551f83762d..8f08a2f0e26da 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -288,7 +288,7 @@ isexpr(x, ts...) = any(T->isa(T, Type) && isa(x, T), ts) function unblock(ex) isexpr(ex, :block) || return ex - exs = filter(ex->!isexpr(ex, :line), ex.args) + exs = filter(ex -> !(isa(ex, LineNumberNode) || isexpr(ex, :line)), ex.args) length(exs) == 1 || return ex return unblock(exs[1]) end diff --git a/base/essentials.jl b/base/essentials.jl index f7da5dbd601a1..7af89e0ce1076 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -40,7 +40,7 @@ call(T::Type{UTF8String}, d::Array{UInt8,1}) = Core.call(T, d) call(T::Type{TypeVar}, args...) = Core.call(T, args...) call(T::Type{TypeConstructor}, args...) = Core.call(T, args...) call(T::Type{Expr}, args::ANY...) = _expr(args...) -call(T::Type{LineNumberNode}, n::Int) = Core.call(T, n) +call(T::Type{LineNumberNode}, f::Symbol, n::Int) = Core.call(T, f, n) call(T::Type{LabelNode}, n::Int) = Core.call(T, n) call(T::Type{GotoNode}, n::Int) = Core.call(T, n) call(T::Type{QuoteNode}, x::ANY) = Core.call(T, x) diff --git a/base/profile.jl b/base/profile.jl index b61a055f68772..caaf8be021617 100644 --- a/base/profile.jl +++ b/base/profile.jl @@ -99,11 +99,13 @@ immutable LineInfo func::ByteString file::ByteString line::Int + inlined_file::ByteString + inlined_line::Int fromC::Bool ip::Int64 # large enough that this struct can be losslessly read on any machine (32 or 64 bit) end -const UNKNOWN = LineInfo("?", "?", -1, true, 0) +const UNKNOWN = LineInfo("?", "?", -1, "?", -1, true, 0) # # If the LineInfo has function and line information, we consider two of them the same @@ -134,8 +136,8 @@ maxlen_data() = convert(Int, ccall(:jl_profile_maxlen_data, Csize_t, ())) function lookup(ip::Ptr{Void}) info = ccall(:jl_lookup_code_address, Any, (Ptr{Void},Cint), ip, false) - if length(info) == 5 - return LineInfo(string(info[1]), string(info[2]), Int(info[3]), info[4], Int64(info[5])) + if length(info) == 7 + return LineInfo(string(info[1]), string(info[2]), Int(info[3]), string(info[4]), Int(info[5]), info[6], Int64(info[7])) else return UNKNOWN end diff --git a/base/replutil.jl b/base/replutil.jl index 4b0ca4437cc01..3e444f91b770c 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -104,7 +104,7 @@ function showerror(io::IO, ex::DomainError, bt; backtrace=true) print(io, "DomainError:") for b in bt code = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), b-1, true) - if length(code) == 5 && !code[4] # code[4] == fromC + if length(code) == 7 && !code[6] # code[6] == fromC if code[1] in (:log, :log2, :log10, :sqrt) # TODO add :besselj, :besseli, :bessely, :besselk println(io,"\n$(code[1]) will only return a complex result if called with a complex argument.") print(io, "try $(code[1]) (complex(x))") @@ -339,9 +339,19 @@ function show_method_candidates(io::IO, ex::MethodError) end end -function show_trace_entry(io, fname, file, line, n) +function show_trace_entry(io, fname, file, line, inlinedfile, inlinedline, n) print(io, "\n") - print(io, " in ", fname, " at ", file) + print(io, " in ", fname) + + if (inlinedfile != symbol("")) + print(io, " at ", inlinedfile, ":", inlinedline) + print(io, " \n [ thrown by inlined function defined at ]\n ") + else + print(io, " at ") + end + + print(io, file) + if line >= 1 try print(io, ":", line) @@ -349,6 +359,7 @@ function show_trace_entry(io, fname, file, line, n) print(io, '?') #for when dec is not yet defined end end + if n > 1 print(io, " (repeats ", n, " times)") end @@ -367,14 +378,16 @@ function show_backtrace(io::IO, t, set=1:typemax(Int)) end function show_backtrace(io::IO, top_function::Symbol, t, set) - process_entry(lastname, lastfile, lastline, n) = show_trace_entry(io, lastname, lastfile, lastline, n) + process_entry(lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n) = + show_trace_entry(io, lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n) process_backtrace(process_entry, top_function, t, set) end # process the backtrace, up to (but not including) top_function function process_backtrace(process_func::Function, top_function::Symbol, t, set) n = 1 - lastfile = ""; lastline = -11; lastname = symbol("#") + lastfile = ""; lastline = -11; lastname = symbol("#"); + last_inlinedfile = ""; last_inlinedline = -1 local fname, file, line count = 0 for i = 1:length(t) @@ -382,23 +395,26 @@ function process_backtrace(process_func::Function, top_function::Symbol, t, set) if lkup === nothing continue end - fname, file, line, fromC = lkup + fname, file, line, inlinedfile, inlinedline, fromC = lkup + if fromC; continue; end if i == 1 && fname == :error; continue; end if fname == top_function; break; end count += 1 if !in(count, set); continue; end + if file != lastfile || line != lastline || fname != lastname if lastline != -11 - process_func(lastname, lastfile, lastline, n) + process_func(lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n) end n = 1 - lastfile = file; lastline = line; lastname = fname + lastfile = file; lastline = line; lastname = fname; + last_inlinedfile = inlinedfile; last_inlinedline = inlinedline; else n += 1 end end if n > 1 || lastline != -11 - process_func(lastname, lastfile, lastline, n) + process_func(lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n) end end diff --git a/base/show.jl b/base/show.jl index 5f7d6e70015f8..72538c5eeb67b 100644 --- a/base/show.jl +++ b/base/show.jl @@ -318,7 +318,6 @@ is_expr(ex, head::Symbol) = (isa(ex, Expr) && (ex.head == head)) is_expr(ex, head::Symbol, n::Int) = is_expr(ex, head) && length(ex.args) == n is_linenumber(ex::LineNumberNode) = true -is_linenumber(ex::Expr) = is(ex.head, :line) is_linenumber(ex) = false is_quoted(ex) = false @@ -351,8 +350,7 @@ end emphasize(io, str::AbstractString) = have_color ? print_with_color(:red, io, str) : print(io, uppercase(str)) -show_linenumber(io::IO, line) = print(io," # line ",line,':') -show_linenumber(io::IO, line, file) = print(io," # ",file,", line ",line,':') +show_linenumber(io::IO, file, line) = print(io," # ", file,", line ",line,':') # show a block, e g if/for/etc function show_block(io::IO, head, args::Vector, body, indent::Int) @@ -421,7 +419,7 @@ end ## AST printing ## show_unquoted(io::IO, sym::Symbol, ::Int, ::Int) = print(io, sym) -show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.line) +show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.file, ex.line) show_unquoted(io::IO, ex::LabelNode, ::Int, ::Int) = print(io, ex.label, ": ") show_unquoted(io::IO, ex::GotoNode, ::Int, ::Int) = print(io, "goto ", ex.label) show_unquoted(io::IO, ex::TopNode, ::Int, ::Int) = print(io,"top(",ex.name,')') @@ -652,10 +650,6 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) print(io, "typealias ") show_list(io, args, ' ', indent) - elseif is(head, :line) && 1 <= nargs <= 2 - show_type = false - show_linenumber(io, args...) - elseif is(head, :if) && nargs == 3 # if/else show_block(io, "if", args[1], args[2], indent) show_block(io, "else", args[3], indent) diff --git a/base/task.jl b/base/task.jl index bec12a1f7be0b..af4761912f959 100644 --- a/base/task.jl +++ b/base/task.jl @@ -24,7 +24,8 @@ type CapturedException # Process bt_raw so that it can be safely serialized bt_lines = Any[] - process_func(name, file, line, n) = push!(bt_lines, (name, file, line, n)) + process_func(name, file, line, inlined_file, inlined_line, n) = + push!(bt_lines, (name, file, line, inlined_file, inlined_line, n)) process_backtrace(process_func, :(:), bt_raw, 1:100) # Limiting this to 100 lines. new(ex, bt_lines) diff --git a/src/alloc.c b/src/alloc.c index 3b97319352fa4..9ed147011aa96 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -335,9 +335,9 @@ jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_svec_t *sparams, jl_mod li->line = 0; if (ast != NULL && jl_is_expr(ast)) { jl_value_t *body1 = skip_meta(jl_lam_body((jl_expr_t*)ast)->args); - if (jl_is_expr(body1) && ((jl_expr_t*)body1)->head == line_sym) { - li->file = (jl_sym_t*)jl_exprarg(body1, 1); - li->line = jl_unbox_long(jl_exprarg(body1, 0)); + if (jl_is_linenode(body1)) { + li->file = (jl_sym_t*)jl_fieldref(body1, 0); + li->line = jl_unbox_long(jl_fieldref(body1, 1)); } } li->module = ctx; diff --git a/src/ast.c b/src/ast.c index de15549174c47..df0feb616f745 100644 --- a/src/ast.c +++ b/src/ast.c @@ -326,9 +326,14 @@ static jl_value_t *scm_to_julia_(value_t e, int eo) e = cdr_(e); if (!eo) { - if (sym == line_sym && n==1) { - return jl_new_struct(jl_linenumbernode_type, - scm_to_julia_(car_(e),0)); + if (sym == line_sym && n==2) { + jl_value_t *filename = scm_to_julia_(car_(cdr_(e)),0); + jl_value_t *linenum = scm_to_julia_(car_(e),0); + JL_GC_PUSH2(&filename, &linenum); + jl_value_t *temp = jl_new_struct(jl_linenumbernode_type, + filename, linenum); + JL_GC_POP(); + return temp; } if (sym == label_sym) { return jl_new_struct(jl_labelnode_type, @@ -459,8 +464,14 @@ static value_t julia_to_scm_(jl_value_t *v) fl_free_gc_handles(1); return scmv; } - if (jl_typeis(v, jl_linenumbernode_type)) - return julia_to_list2((jl_value_t*)line_sym, jl_fieldref(v,0)); + if (jl_typeis(v, jl_linenumbernode_type)) { + value_t args = julia_to_list2(jl_fieldref(v,1), jl_fieldref(v,0)); + fl_gc_handle(&args); + value_t hd = julia_to_scm_((jl_value_t*)line_sym); + value_t scmv = fl_cons(hd, args); + fl_free_gc_handles(1); + return scmv; + } if (jl_typeis(v, jl_labelnode_type)) return julia_to_list2((jl_value_t*)label_sym, jl_fieldref(v,0)); if (jl_typeis(v, jl_gotonode_type)) diff --git a/src/builtins.c b/src/builtins.c index e05068db53d52..1c8d5f8c0f84f 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1516,7 +1516,7 @@ size_t jl_static_show_x(JL_STREAM *out, jl_value_t *v, int depth) n += jl_printf(out, ")"); } else if (jl_is_linenode(v)) { - n += jl_printf(out, "# line %" PRIuPTR, jl_linenode_line(v)); + n += jl_printf(out, "# line %"PRIuPTR" %s", jl_linenode_line(v), jl_linenode_file(v)->name); } else if (jl_is_expr(v)) { jl_expr_t *e = (jl_expr_t*)v; diff --git a/src/codegen.cpp b/src/codegen.cpp index d09a6fb25d94a..7aee3a8d05781 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4062,32 +4062,17 @@ static Function *emit_function(jl_lambda_info_t *lam) // look for initial (line num filename) node if (jl_is_linenode(stmt)) { lno = jl_linenode_line(stmt); - } - else if (jl_is_expr(stmt) && ((jl_expr_t*)stmt)->head == line_sym && - jl_array_dim0(((jl_expr_t*)stmt)->args) > 0) { - jl_value_t *a1 = jl_exprarg(stmt,0); - if (jl_is_long(a1)) - lno = jl_unbox_long(a1); - if (jl_array_dim0(((jl_expr_t*)stmt)->args) > 1) { - a1 = jl_exprarg(stmt,1); - if (jl_is_symbol(a1)) - filename = ((jl_sym_t*)a1)->name; - if (jl_array_dim0(((jl_expr_t*)stmt)->args) > 2) { - a1 = jl_exprarg(stmt,2); - if (jl_is_symbol(a1)) - dbgFuncName = ((jl_sym_t*)a1)->name; - } - } + filename = jl_linenode_file(stmt)->name; } ctx.lineno = lno; DIBuilder dbuilder(*m); ctx.dbuilder = &dbuilder; #ifdef LLVM37 - DIFile *fil = NULL; + DIFile *topfile = NULL; DISubprogram *SP; #else - DIFile fil; + DIFile topfile; DISubprogram SP; #endif @@ -4140,13 +4125,13 @@ static Function *emit_function(jl_lambda_info_t *lam) ditypes.push_back(julia_type_to_di(jl_tparam(lam->specTypes,i),ctx.dbuilder,false)); } #ifdef LLVM36 - subrty = ctx.dbuilder->createSubroutineType(fil,ctx.dbuilder->getOrCreateTypeArray(ditypes)); + subrty = ctx.dbuilder->createSubroutineType(topfile,ctx.dbuilder->getOrCreateTypeArray(ditypes)); #else - subrty = ctx.dbuilder->createSubroutineType(fil,ctx.dbuilder->getOrCreateArray(ditypes)); + subrty = ctx.dbuilder->createSubroutineType(topfile,ctx.dbuilder->getOrCreateArray(ditypes)); #endif } - fil = dbuilder.createFile(filename, "."); + topfile = dbuilder.createFile(filename, "."); #ifndef LLVM34 SP = dbuilder.createFunction((DIDescriptor)dbuilder.getCU(), #else @@ -4154,7 +4139,7 @@ static Function *emit_function(jl_lambda_info_t *lam) #endif dbgFuncName, // Name f->getName(), // LinkageName - fil, // File + topfile, // File 0, // LineNo subrty, // Ty false, // isLocalToUnit @@ -4189,7 +4174,7 @@ static Function *emit_function(jl_lambda_info_t *lam) llvm::dwarf::DW_TAG_arg_variable, // Tag SP, // Scope (current function will be fill in later) argname->name, // Variable name - fil, // File + topfile, // File ctx.lineno == -1 ? 0 : ctx.lineno, // Line (for now, use lineno of the function) julia_type_to_di(varinfo.declType,ctx.dbuilder,specsig), // Variable type false, // May be optimized out @@ -4203,16 +4188,15 @@ static Function *emit_function(jl_lambda_info_t *lam) SP, // Scope (current function will be fill in later) ctx.vaName->name, // Variable name nreq + 1, // Argument number (1-based) - fil, // File + topfile, // File ctx.lineno == -1 ? 0 : ctx.lineno, // Line (for now, use lineno of the function) julia_type_to_di(ctx.vars[ctx.vaName].declType,ctx.dbuilder,false)); #else - ctx.vars[ctx.vaName].dinfo = ctx.dbuilder->createLocalVariable( llvm::dwarf::DW_TAG_arg_variable, // Tag SP, // Scope (current function will be fill in later) ctx.vaName->name, // Variable name - fil, // File + topfile, // File ctx.lineno == -1 ? 0 : ctx.lineno, // Line (for now, use lineno of the function) julia_type_to_di(ctx.vars[ctx.vaName].declType,ctx.dbuilder,false), // Variable type false, // May be optimized out @@ -4233,7 +4217,7 @@ static Function *emit_function(jl_lambda_info_t *lam) #endif SP, // Scope (current function will be fill in later) s->name, // Variable name - fil, // File + topfile, // File ctx.lineno == -1 ? 0 : ctx.lineno, // Line (for now, use lineno of the function) julia_type_to_di(varinfo.declType,ctx.dbuilder,specsig), // Variable type false, // May be optimized out @@ -4257,7 +4241,7 @@ static Function *emit_function(jl_lambda_info_t *lam) #endif SP, // Scope (current function will be filled in later) vname->name, // Variable name - fil, // File + topfile, // File ctx.lineno == -1 ? 0 : ctx.lineno, // Line (for now, use lineno of the function) julia_type_to_di(varinfo.declType,ctx.dbuilder,specsig), // Variable type false, // May be optimized out @@ -4581,59 +4565,59 @@ static Function *emit_function(jl_lambda_info_t *lam) jl_value_t *stmt = jl_cellref(stmts,i); if (jl_is_linenode(stmt)) { lno = jl_linenode_line(stmt); - if (ctx.debug_enabled) - builder.SetCurrentDebugLocation(DebugLoc::get(lno, 1, (MDNode*)SP, NULL)); - if (do_coverage) - coverageVisitLine(filename, lno); - ctx.lineno = lno; - } - else if (jl_is_expr(stmt) && ((jl_expr_t*)stmt)->head == line_sym) { - lno = jl_unbox_long(jl_exprarg(stmt, 0)); - #ifdef LLVM37 + jl_sym_t *file = jl_linenode_file(stmt); + +# ifdef LLVM37 DIFile *dfil = NULL; - #else +# else MDNode *dfil = NULL; - #endif - if (jl_array_dim0(((jl_expr_t*)stmt)->args) > 1) { - jl_value_t *a1 = jl_exprarg(stmt,1); - if (jl_is_symbol(a1)) { - jl_sym_t *file = (jl_sym_t*)a1; - // If the string is not empty - if (*file->name != '\0') { - #ifdef LLVM37 - std::map::iterator it = filescopes.find(file); - #else - std::map::iterator it = filescopes.find(file); - #endif - if (it != filescopes.end()) { - dfil = it->second; - } - else { - #ifdef LLVM37 - dfil = filescopes[file] = (DIFile*)dbuilder.createFile(file->name, "."); - #else - dfil = filescopes[file] = (MDNode*)dbuilder.createFile(file->name, "."); - #endif - } - } +# endif + + // If the string is not empty + if (*file->name != '\0') { +# ifdef LLVM37 + std::map::iterator it = filescopes.find(file); +# else + std::map::iterator it = filescopes.find(file); +# endif + if (it != filescopes.end()) { + dfil = it->second; + } else { +# ifdef LLVM37 + dfil = (DIFile*)dbuilder.createFile(file->name, "."); +# else + dfil = (MDNode*)dbuilder.createFile(file->name, "."); +# endif } } + DebugLoc loc; + MDNode *funcscope = (MDNode*)dbuilder.createLexicalBlockFile(SP,topfile); if (ctx.debug_enabled) { MDNode *scope; - if (dfil == NULL) - scope = SP; - else { + if ((dfil == topfile || dfil == NULL) && + lno >= ctx.lineno) // if we are in the top-level file + // and the current lineno is less than + // the last, must be same-file inline + // TODO: improve this heuristic... + { + // set location to the current top-level line + loc = DebugLoc::get(lno, 1, SP, NULL); + } else { + // otherwise, we are compiling code from another file, + // so create a location for the top-level line, and + // set the DebugLoc "inlinedAt" parameter. #ifdef LLVM37 scope = (MDNode*)dbuilder.createLexicalBlockFile(SP,dfil); #else scope = (MDNode*)dbuilder.createLexicalBlockFile(SP,DIFile(dfil)); #endif + MDNode *inlineLocMd = DebugLoc::get(ctx.lineno, 1, funcscope, NULL).getAsMDNode(jl_LLVMContext); + loc = DebugLoc::get(lno, 1, scope, inlineLocMd); } - builder.SetCurrentDebugLocation(DebugLoc::get(lno, 1, scope, NULL)); + builder.SetCurrentDebugLocation(loc); } if (do_coverage) coverageVisitLine(filename, lno); - ctx.lineno = lno; } if (jl_is_labelnode(stmt)) { if (prevlabel) continue; diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 9136097ffb948..93268a2ffe563 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -463,10 +463,12 @@ void RegisterJuliaJITEventListener() // *name and *filename are either NULL or malloc'd pointers void lookup_pointer(DIContext *context, char **name, size_t *line, - char **filename, size_t pointer, int demangle, - int *fromC) + char **filename, size_t *inlined_line, + char **inlined_file, size_t pointer, + int demangle, int *fromC) { - DILineInfo info; + DILineInfo info, topinfo; + DIInliningInfo inlineinfo; if (demangle && *name != NULL) { char *oldname = *name; *name = jl_demangle(*name); @@ -475,13 +477,21 @@ void lookup_pointer(DIContext *context, char **name, size_t *line, #ifdef LLVM35 DILineInfoSpecifier infoSpec(DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, DILineInfoSpecifier::FunctionNameKind::ShortName); + DILineInfoSpecifier inlineSpec(DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, + DILineInfoSpecifier::FunctionNameKind::ShortName); #else int infoSpec = DILineInfoSpecifier::FileLineInfo | DILineInfoSpecifier::AbsoluteFilePath | DILineInfoSpecifier::FunctionName; + int inlineSpec = DILineInfoSpecifier::FileLineInfo | + DILineInfoSpecifier::AbsoluteFilePath | + DILineInfoSpecifier::FunctionName; #endif + if (context == NULL) goto done; info = context->getLineInfoForAddress(pointer, infoSpec); + inlineinfo = context->getInliningInfoForAddress(pointer, inlineSpec); + #ifndef LLVM35 // LLVM <= 3.4 if (strcmp(info.getFunctionName(), "") == 0) goto done; if (demangle) { @@ -493,12 +503,25 @@ void lookup_pointer(DIContext *context, char **name, size_t *line, } *line = info.getLine(); jl_copy_str(filename, info.getFileName()); + + if (inlineinfo.getNumberOfFrames() > 1) { + topinfo = inlineinfo.getFrame(inlineinfo.getNumberOfFrames() - 1); + jl_copy_str(inlined_file, topinfo.getFileName()); + *inlined_line = topinfo.getLine(); + } #else if (strcmp(info.FunctionName.c_str(), "") == 0) goto done; jl_copy_str(name, info.FunctionName.c_str()); *line = info.Line; jl_copy_str(filename, info.FileName.c_str()); + + if (inlineinfo.getNumberOfFrames() > 1) { + topinfo = inlineinfo.getFrame(inlineinfo.getNumberOfFrames() - 1); + jl_copy_str(inlined_file, topinfo.FileName.c_str()); + *inlined_line = topinfo.getLine(); + } #endif + done: // If this is a jlcall wrapper, set fromC to match JIT behavior if (*name == NULL || memcmp(*name, "jlcall_",7) == 0) { @@ -561,8 +584,9 @@ bool getObjUUID(llvm::object::MachOObjectFile *obj, uint8_t uuid[16]) extern "C" uint64_t jl_sysimage_base; // *name and *filename should be either NULL or malloc'd pointer -void jl_getDylibFunctionInfo(char **name, size_t *line, char **filename, - size_t pointer, int *fromC, int skipC) +void jl_getDylibFunctionInfo(char **name, char **filename, size_t *line, + char** inlined_file, size_t *inlined_line, + size_t pointer, int *fromC, int skipC, int skipInline) { #ifdef _OS_WINDOWS_ IMAGEHLP_MODULE64 ModuleInfo; @@ -759,7 +783,7 @@ void jl_getDylibFunctionInfo(char **name, size_t *line, char **filename, #ifdef _OS_DARWIN_ lookup: #endif - lookup_pointer(context, name, line, filename, pointer+slide, + lookup_pointer(context, name, line, filename, inlined_line, inlined_file, pointer+slide, fbase == jl_sysimage_base, fromC); } else { @@ -768,12 +792,15 @@ void jl_getDylibFunctionInfo(char **name, size_t *line, char **filename, } // Set *name and *filename to either NULL or malloc'd string -void jl_getFunctionInfo(char **name, size_t *line, char **filename, - size_t pointer, int *fromC, int skipC) +void jl_getFunctionInfo(char **name, char **filename, size_t *line, + char **inlined_file, size_t *inlined_line, + size_t pointer, int *fromC, int skipC, int skipInline) { *name = NULL; *line = -1; *filename = NULL; + *inlined_file = NULL; + *inlined_line = -1; *fromC = 0; #ifdef USE_MCJIT @@ -803,7 +830,7 @@ void jl_getFunctionInfo(char **name, size_t *line, char **filename, DIContext *context = DIContext::getDWARFContext(const_cast(it->second.object)); #endif #endif - lookup_pointer(context, name, line, filename, pointer, 1, fromC); + lookup_pointer(context, name, line, filename, inlined_line, inlined_file, pointer, 1, fromC); delete context; return; } @@ -837,14 +864,13 @@ void jl_getFunctionInfo(char **name, size_t *line, char **filename, if ((*it).second.func) { DISubprogram debugscope = DISubprogram(prev.Loc.getScope((*it).second.func->getContext())); - jl_copy_str(filename, debugscope.getFilename().data()); + jl_copy_str(filename, debugscope.getFilename().str().c_str()); // the DISubprogram has the un-mangled name, so use that if // available. However, if the scope need not be the current // subprogram. if (debugscope.getName().data() != NULL) { - jl_copy_str(name, debugscope.getName().data()); - } - else { + jl_copy_str(name, debugscope.getName().str().c_str()); + } else { char *oldname = *name; *name = jl_demangle(*name); free(oldname); @@ -864,10 +890,22 @@ void jl_getFunctionInfo(char **name, size_t *line, char **filename, if (*line == (size_t) -1) { *line = prev.Loc.getLine(); } + + DILexicalBlockFile locscope = DILexicalBlockFile(prev.Loc.getScope((*it).second.func->getContext())); + jl_copy_str(filename, locscope.getFilename().str().c_str()); + + MDNode *inlinedAt = skipInline ? NULL : prev.Loc.getInlinedAt((*it).second.func->getContext()); + if ((!skipInline) && (inlinedAt != NULL)) { + DebugLoc inlineloc = DebugLoc::getFromDILocation(inlinedAt); + DILexicalBlockFile inlinescope = DILexicalBlockFile(inlineloc.getScope((*it).second.func->getContext())); + jl_copy_str(inlined_file, inlinescope.getFilename().str().c_str()); + *inlined_line = inlineloc.getLine(); + } + return; } #endif // USE_MCJIT - jl_getDylibFunctionInfo(name, line, filename, pointer, fromC, skipC); + jl_getDylibFunctionInfo(name, filename, line, inlined_file, inlined_line, pointer, fromC, skipC, skipInline); } int jl_get_llvmf_info(uint64_t fptr, uint64_t *symsize, uint64_t *slide, diff --git a/src/disasm.cpp b/src/disasm.cpp index 70dc6991feed1..f6b7ca43ebdd4 100644 --- a/src/disasm.cpp +++ b/src/disasm.cpp @@ -228,11 +228,14 @@ int OpInfoLookup(void *DisInfo, uint64_t PC, } int skipC = 0; char *name; - size_t line; char *filename; + size_t line; + char *inlined_file; + size_t inlined_line; int fromC; - jl_getFunctionInfo(&name, &line, &filename, pointer, &fromC, skipC); + jl_getFunctionInfo(&name, &filename, &line, &inlined_file, &inlined_line, pointer, &fromC, skipC, 1); free(filename); + free(inlined_file); if (!name) return 0; // Did not find symbolic information // Describe the symbol diff --git a/src/gf.c b/src/gf.c index a388e15d08742..72aa7e14c9f3d 100644 --- a/src/gf.c +++ b/src/gf.c @@ -902,7 +902,8 @@ DLLEXPORT jl_function_t *jl_instantiate_staged(jl_methlist_t *m, jl_tupletype_t jl_expr_t *ex = NULL; jl_expr_t *oldast = NULL; jl_function_t *func = NULL; - JL_GC_PUSH3(&ex, &oldast, &func); + jl_value_t *linenum = NULL; + JL_GC_PUSH4(&ex, &oldast, &func, &linenum); if (jl_is_expr(m->func->linfo->ast)) oldast = (jl_expr_t*)m->func->linfo->ast; else @@ -930,10 +931,12 @@ DLLEXPORT jl_function_t *jl_instantiate_staged(jl_methlist_t *m, jl_tupletype_t func = with_appended_env(m->func, env); jl_expr_t *body = jl_exprn(jl_symbol("block"), 2); jl_cellset(ex->args, 1, body); - jl_expr_t *linenode = jl_exprn(line_sym, 2); + linenum = jl_box_long(m->func->linfo->line); + jl_value_t *linenode = jl_new_struct(jl_linenumbernode_type, + m->func->linfo->file, + linenum + ); jl_cellset(body->args, 0, linenode); - jl_cellset(linenode->args, 0, jl_box_long(m->func->linfo->line)); - jl_cellset(linenode->args, 1, m->func->linfo->file); jl_cellset(body->args, 1, jl_apply(func, jl_svec_data(tt->parameters), jl_nparams(tt))); if (m->tvars != jl_emptysvec) { // mark this function as having the same static parameters as the generator diff --git a/src/jltypes.c b/src/jltypes.c index 736d721eae7c6..98411941946e3 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3345,8 +3345,8 @@ void jl_init_types(void) jl_linenumbernode_type = jl_new_datatype(jl_symbol("LineNumberNode"), jl_any_type, jl_emptysvec, - jl_svec(1, jl_symbol("line")), - jl_svec(1, jl_long_type), 0, 0, 1); + jl_svec(2, jl_symbol("file"), jl_symbol("line")), + jl_svec(2, jl_symbol_type, jl_long_type), 0, 0, 2); jl_labelnode_type = jl_new_datatype(jl_symbol("LabelNode"), jl_any_type, jl_emptysvec, diff --git a/src/julia.h b/src/julia.h index 0812e44ae3587..ee1d40c371e3b 100644 --- a/src/julia.h +++ b/src/julia.h @@ -666,7 +666,8 @@ STATIC_INLINE jl_value_t *jl_cellset(void *a, size_t i, void *x) #define jl_symbolnode_sym(s) ((jl_sym_t*)jl_fieldref(s,0)) #define jl_symbolnode_type(s) (jl_fieldref(s,1)) -#define jl_linenode_line(x) (((ptrint_t*)x)[0]) +#define jl_linenode_file(x) ((jl_sym_t*)jl_fieldref(x,0)) +#define jl_linenode_line(x) (((ptrint_t*)jl_fieldref(x,1))[0]) #define jl_labelnode_label(x) (((ptrint_t*)x)[0]) #define jl_gotonode_label(x) (((ptrint_t*)x)[0]) #define jl_globalref_mod(s) ((jl_module_t*)jl_fieldref(s,0)) diff --git a/src/julia_internal.h b/src/julia_internal.h index bee4145480e7b..6058078079d79 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -177,8 +177,9 @@ DLLEXPORT void jl_raise_debugger(void); DLLEXPORT void attach_exception_port(void); #endif // Set *name and *filename to either NULL or malloc'd string -void jl_getFunctionInfo(char **name, size_t *line, char **filename, - uintptr_t pointer, int *fromC, int skipC); +void jl_getFunctionInfo(char **name, char **filename, size_t *line, + char **inlined_file, size_t *inlined_line, + uintptr_t pointer, int *fromC, int skipC, int skipInline); // *to is NULL or malloc'd pointer, from is allowed to be NULL static inline char *jl_copy_str(char **to, const char *from) diff --git a/src/task.c b/src/task.c index 02beb5a1d168c..6921707d722bf 100644 --- a/src/task.c +++ b/src/task.c @@ -468,13 +468,16 @@ ptrint_t bt_data[MAX_BT_SIZE+1]; size_t bt_size = 0; // Always Set *func_name and *file_name to malloc'd pointers (non-NULL) -static int frame_info_from_ip(char **func_name, size_t *line_num, - char **file_name, size_t ip, int skipC) +static int frame_info_from_ip(char **func_name, + char **file_name, size_t *line_num, + char **inlined_file, size_t *inlined_line, + size_t ip, int skipC, int skipInline) { static const char *name_unknown = "???"; int fromC = 0; - jl_getFunctionInfo(func_name, line_num, file_name, ip, &fromC, skipC); + jl_getFunctionInfo(func_name, file_name, line_num, inlined_file, inlined_line, ip, &fromC, + skipC, skipInline); if (!*func_name) { *func_name = strdup(name_unknown); *line_num = ip; @@ -707,17 +710,22 @@ DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC) char *func_name; size_t line_num; char *file_name; - int fromC = frame_info_from_ip(&func_name, &line_num, &file_name, - (size_t)ip, skipC); - jl_value_t *r = (jl_value_t*)jl_alloc_svec(5); + size_t inlined_line; + char *inlined_file; + int fromC = frame_info_from_ip(&func_name, &file_name, &line_num, + &inlined_file, &inlined_line, (size_t)ip, skipC, 0); + jl_value_t *r = (jl_value_t*)jl_alloc_svec(7); JL_GC_PUSH1(&r); jl_svecset(r, 0, jl_symbol(func_name)); jl_svecset(r, 1, jl_symbol(file_name)); jl_svecset(r, 2, jl_box_long(line_num)); - jl_svecset(r, 3, jl_box_bool(fromC)); - jl_svecset(r, 4, jl_box_long((intptr_t)ip)); + jl_svecset(r, 3, jl_symbol(inlined_file ? inlined_file : "")); + jl_svecset(r, 4, jl_box_long(inlined_file ? inlined_line : -1)); + jl_svecset(r, 5, jl_box_bool(fromC)); + jl_svecset(r, 6, jl_box_long((intptr_t)ip)); free(func_name); free(file_name); + free(inlined_file); JL_GC_POP(); return r; } @@ -743,7 +751,10 @@ DLLEXPORT void gdblookup(ptrint_t ip) char *func_name; size_t line_num; char *file_name; - frame_info_from_ip(&func_name, &line_num, &file_name, ip, 0); + size_t inlined_line; + char *inlined_file; + frame_info_from_ip(&func_name, &file_name, &line_num, &inlined_file, &inlined_line, ip, + /* skipC */ 0, /* skipInline */ 1); if (line_num == ip) { jl_safe_printf("unknown function (ip: %p)\n", (void*)ip); } @@ -754,6 +765,9 @@ DLLEXPORT void gdblookup(ptrint_t ip) jl_safe_printf("%s at %s:%" PRIuPTR "\n", func_name, file_name, (uintptr_t)line_num); } + free(func_name); + free(file_name); + free(inlined_file); } DLLEXPORT void jlbacktrace() diff --git a/test/backtrace.jl b/test/backtrace.jl index d4e27235210d4..ee8af816770bf 100644 --- a/test/backtrace.jl +++ b/test/backtrace.jl @@ -1,14 +1,69 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license +# note: when modifying this file, update TESTLINE below or the inline test will fail! + bt = backtrace() have_backtrace = false for l in bt lkup = ccall(:jl_lookup_code_address, Any, (Ptr{Void},), l) if lkup[1] == :backtrace - @test lkup[4] == false # fromC + @test lkup[6] == false # fromC have_backtrace = true break end end @test have_backtrace + +# Test location information for inlined code (ref issues #1334 #12544) +module test_inline_bt +using Base.Test + +function get_bt_frame(functionname, bt) + for i = 1:length(bt) + lkup = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), bt[i], true) + # find the function frame + lkup[1] == functionname && (return lkup) + end +end + +# same-file inline +eval(Expr(:function, Expr(:call, :test_inline_1), + Expr(:block, LineNumberNode(symbol("backtrace.jl"), 42), + LineNumberNode(symbol("backtrace.jl"), 37), + Expr(:call, :throw, "foo")))) + +# different-file inline +eval(Expr(:function, Expr(:call, :test_inline_2), + Expr(:block, LineNumberNode(symbol("backtrace.jl"), 99), + LineNumberNode(symbol("/foo/bar/baz.jl"), 111), + Expr(:call, :throw, "foo")))) + +try + eval(:(test_inline_1())) +catch err + lkup = get_bt_frame(:test_inline_1, catch_backtrace()) + if is(lkup, nothing) + throw(Test.Failure("Missing backtrace in inlining test")) + end + + fname, file, line, inlinedfile, inlinedline, fromC = lkup + @test endswith(string(inlinedfile), "backtrace.jl") + @test inlinedline == 42 +end +try + eval(:(test_inline_2())) +catch err + lkup = get_bt_frame(:test_inline_2, catch_backtrace()) + if is(lkup, nothing) + throw(Test.Failure("Missing backtrace in inlining test")) + end + + fname, file, line, inlinedfile, inlinedline, fromC = lkup + @test string(file) == "/foo/bar/baz.jl" + @test line == 111 + @test endswith(string(inlinedfile), "backtrace.jl") + @test inlinedline == 99 +end + +end # module From eb867a95a07084553520803c70fa4894d276c37c Mon Sep 17 00:00:00 2001 From: Isaiah Norton Date: Sat, 22 Aug 2015 10:50:38 -0400 Subject: [PATCH 3/4] Add missing GC roots in ast.c --- src/ast.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/ast.c b/src/ast.c index df0feb616f745..101b32a023592 100644 --- a/src/ast.c +++ b/src/ast.c @@ -327,34 +327,48 @@ static jl_value_t *scm_to_julia_(value_t e, int eo) e = cdr_(e); if (!eo) { if (sym == line_sym && n==2) { - jl_value_t *filename = scm_to_julia_(car_(cdr_(e)),0); - jl_value_t *linenum = scm_to_julia_(car_(e),0); + jl_value_t *filename = NULL, *linenum = NULL; JL_GC_PUSH2(&filename, &linenum); + filename = scm_to_julia_(car_(cdr_(e)),0); + linenum = scm_to_julia_(car_(e),0); jl_value_t *temp = jl_new_struct(jl_linenumbernode_type, filename, linenum); JL_GC_POP(); return temp; } + jl_value_t *scmv = NULL, *temp = NULL; + JL_GC_PUSH(&scmv); if (sym == label_sym) { - return jl_new_struct(jl_labelnode_type, - scm_to_julia_(car_(e),0)); + scmv = scm_to_julia_(car_(e),0); + temp = jl_new_struct(jl_labelnode_type, scmv); + JL_GC_POP(); + return temp; } if (sym == goto_sym) { - return jl_new_struct(jl_gotonode_type, - scm_to_julia_(car_(e),0)); + scmv = scm_to_julia_(car_(e),0); + temp = jl_new_struct(jl_gotonode_type, scmv); + JL_GC_POP(); + return temp; } if (sym == inert_sym || (sym == quote_sym && (!iscons(car_(e))))) { - return jl_new_struct(jl_quotenode_type, - scm_to_julia_(car_(e),0)); + scmv = scm_to_julia_(car_(e),0); + temp = jl_new_struct(jl_quotenode_type, scmv); + JL_GC_POP(); + return temp; } if (sym == top_sym) { - return jl_new_struct(jl_topnode_type, - scm_to_julia_(car_(e),0)); + scmv = scm_to_julia_(car_(e),0); + temp = jl_new_struct(jl_topnode_type, scmv); + JL_GC_POP(); + return temp; } if (sym == newvar_sym) { - return jl_new_struct(jl_newvarnode_type, - scm_to_julia_(car_(e),0)); + scmv = scm_to_julia_(car_(e),0); + temp = jl_new_struct(jl_newvarnode_type, scmv); + JL_GC_POP(); + return temp; } + JL_GC_POP(); } else if (sym == inert_sym && !iscons(car_(e))) { sym = quote_sym; From 19e765e926536902d43fda0762fb6f48924fed11 Mon Sep 17 00:00:00 2001 From: Isaiah Norton Date: Thu, 27 Aug 2015 00:32:36 -0400 Subject: [PATCH 4/4] Address review comments - renamed inlinedfile/line -> inlinedat_file/line - update inlining message - fix poplinenum. --- base/cartesian.jl | 2 ++ base/deprecated.jl | 2 +- base/replutil.jl | 36 +++++++++++++++++++++--------------- src/debuginfo.cpp | 30 +++++++++++++++--------------- src/disasm.cpp | 8 ++++---- src/julia_internal.h | 2 +- src/task.c | 24 ++++++++++++------------ 7 files changed, 56 insertions(+), 48 deletions(-) diff --git a/base/cartesian.jl b/base/cartesian.jl index f4e90fc83e533..b765cded4b95e 100644 --- a/base/cartesian.jl +++ b/base/cartesian.jl @@ -224,6 +224,8 @@ function poplinenum(ex::Expr) return ex.args[1] elseif length(ex.args) == 2 && isa(ex.args[1], LineNumberNode) return ex.args[2] + elseif (length(ex.args) == 2 && isa(ex.args[1], Expr) && ex.args[1].head == :line) + return ex.args[2] end end ex diff --git a/base/deprecated.jl b/base/deprecated.jl index 6ea9b9b907cf7..d931dcee17f30 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -80,7 +80,7 @@ function firstcaller(bt::Array{Ptr{Void},1}, funcsym::Symbol) if lkup === () continue end - fname, file, line, inlined_file, inlined_line, fromC = lkup + fname, file, line, inlinedat_file, inlinedat_line, fromC = lkup if fname == funcsym break end diff --git a/base/replutil.jl b/base/replutil.jl index 3e444f91b770c..b6d246d9c04d8 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -339,15 +339,16 @@ function show_method_candidates(io::IO, ex::MethodError) end end -function show_trace_entry(io, fname, file, line, inlinedfile, inlinedline, n) - print(io, "\n") - print(io, " in ", fname) - - if (inlinedfile != symbol("")) - print(io, " at ", inlinedfile, ":", inlinedline) - print(io, " \n [ thrown by inlined function defined at ]\n ") +function show_trace_entry(io, fname, file, line, inlinedat_file, inlinedat_line, n) + # if we have inlining information, we print the `file`:`line` first, + # then show the inlining info, because the inlining location + # corresponds to `fname`. + if (inlinedat_file != symbol("")) + # align the location text + print(io, "\n") + print(io, " [inlined code] from ") else - print(io, " at ") + print(io, " in ", fname, " at ") end print(io, file) @@ -363,6 +364,11 @@ function show_trace_entry(io, fname, file, line, inlinedfile, inlinedline, n) if n > 1 print(io, " (repeats ", n, " times)") end + + if (inlinedat_file != symbol("")) + print(io, "\n in ", fname, " at ") + print(io, inlinedat_file, ":", inlinedat_line, "\n") + end end function show_backtrace(io::IO, t, set=1:typemax(Int)) @@ -378,8 +384,8 @@ function show_backtrace(io::IO, t, set=1:typemax(Int)) end function show_backtrace(io::IO, top_function::Symbol, t, set) - process_entry(lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n) = - show_trace_entry(io, lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n) + process_entry(lastname, lastfile, lastline, last_inlinedat_file, last_inlinedat_line, n) = + show_trace_entry(io, lastname, lastfile, lastline, last_inlinedat_file, last_inlinedat_line, n) process_backtrace(process_entry, top_function, t, set) end @@ -387,7 +393,7 @@ end function process_backtrace(process_func::Function, top_function::Symbol, t, set) n = 1 lastfile = ""; lastline = -11; lastname = symbol("#"); - last_inlinedfile = ""; last_inlinedline = -1 + last_inlinedat_file = ""; last_inlinedat_line = -1 local fname, file, line count = 0 for i = 1:length(t) @@ -395,7 +401,7 @@ function process_backtrace(process_func::Function, top_function::Symbol, t, set) if lkup === nothing continue end - fname, file, line, inlinedfile, inlinedline, fromC = lkup + fname, file, line, inlinedat_file, inlinedat_line, fromC = lkup if fromC; continue; end if i == 1 && fname == :error; continue; end @@ -405,16 +411,16 @@ function process_backtrace(process_func::Function, top_function::Symbol, t, set) if file != lastfile || line != lastline || fname != lastname if lastline != -11 - process_func(lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n) + process_func(lastname, lastfile, lastline, last_inlinedat_file, last_inlinedat_line, n) end n = 1 lastfile = file; lastline = line; lastname = fname; - last_inlinedfile = inlinedfile; last_inlinedline = inlinedline; + last_inlinedat_file = inlinedat_file; last_inlinedat_line = inlinedat_line; else n += 1 end end if n > 1 || lastline != -11 - process_func(lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n) + process_func(lastname, lastfile, lastline, last_inlinedat_file, last_inlinedat_line, n) end end diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 93268a2ffe563..fa734827edb33 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -463,8 +463,8 @@ void RegisterJuliaJITEventListener() // *name and *filename are either NULL or malloc'd pointers void lookup_pointer(DIContext *context, char **name, size_t *line, - char **filename, size_t *inlined_line, - char **inlined_file, size_t pointer, + char **filename, size_t *inlinedat_line, + char **inlinedat_file, size_t pointer, int demangle, int *fromC) { DILineInfo info, topinfo; @@ -506,8 +506,8 @@ void lookup_pointer(DIContext *context, char **name, size_t *line, if (inlineinfo.getNumberOfFrames() > 1) { topinfo = inlineinfo.getFrame(inlineinfo.getNumberOfFrames() - 1); - jl_copy_str(inlined_file, topinfo.getFileName()); - *inlined_line = topinfo.getLine(); + jl_copy_str(inlinedat_file, topinfo.getFileName()); + *inlinedat_line = topinfo.getLine(); } #else if (strcmp(info.FunctionName.c_str(), "") == 0) goto done; @@ -517,8 +517,8 @@ void lookup_pointer(DIContext *context, char **name, size_t *line, if (inlineinfo.getNumberOfFrames() > 1) { topinfo = inlineinfo.getFrame(inlineinfo.getNumberOfFrames() - 1); - jl_copy_str(inlined_file, topinfo.FileName.c_str()); - *inlined_line = topinfo.getLine(); + jl_copy_str(inlinedat_file, topinfo.FileName.c_str()); + *inlinedat_line = topinfo.getLine(); } #endif @@ -585,7 +585,7 @@ extern "C" uint64_t jl_sysimage_base; // *name and *filename should be either NULL or malloc'd pointer void jl_getDylibFunctionInfo(char **name, char **filename, size_t *line, - char** inlined_file, size_t *inlined_line, + char** inlinedat_file, size_t *inlinedat_line, size_t pointer, int *fromC, int skipC, int skipInline) { #ifdef _OS_WINDOWS_ @@ -783,7 +783,7 @@ void jl_getDylibFunctionInfo(char **name, char **filename, size_t *line, #ifdef _OS_DARWIN_ lookup: #endif - lookup_pointer(context, name, line, filename, inlined_line, inlined_file, pointer+slide, + lookup_pointer(context, name, line, filename, inlinedat_line, inlinedat_file, pointer+slide, fbase == jl_sysimage_base, fromC); } else { @@ -793,14 +793,14 @@ void jl_getDylibFunctionInfo(char **name, char **filename, size_t *line, // Set *name and *filename to either NULL or malloc'd string void jl_getFunctionInfo(char **name, char **filename, size_t *line, - char **inlined_file, size_t *inlined_line, + char **inlinedat_file, size_t *inlinedat_line, size_t pointer, int *fromC, int skipC, int skipInline) { *name = NULL; *line = -1; *filename = NULL; - *inlined_file = NULL; - *inlined_line = -1; + *inlinedat_file = NULL; + *inlinedat_line = -1; *fromC = 0; #ifdef USE_MCJIT @@ -830,7 +830,7 @@ void jl_getFunctionInfo(char **name, char **filename, size_t *line, DIContext *context = DIContext::getDWARFContext(const_cast(it->second.object)); #endif #endif - lookup_pointer(context, name, line, filename, inlined_line, inlined_file, pointer, 1, fromC); + lookup_pointer(context, name, line, filename, inlinedat_line, inlinedat_file, pointer, 1, fromC); delete context; return; } @@ -898,14 +898,14 @@ void jl_getFunctionInfo(char **name, char **filename, size_t *line, if ((!skipInline) && (inlinedAt != NULL)) { DebugLoc inlineloc = DebugLoc::getFromDILocation(inlinedAt); DILexicalBlockFile inlinescope = DILexicalBlockFile(inlineloc.getScope((*it).second.func->getContext())); - jl_copy_str(inlined_file, inlinescope.getFilename().str().c_str()); - *inlined_line = inlineloc.getLine(); + jl_copy_str(inlinedat_file, inlinescope.getFilename().str().c_str()); + *inlinedat_line = inlineloc.getLine(); } return; } #endif // USE_MCJIT - jl_getDylibFunctionInfo(name, filename, line, inlined_file, inlined_line, pointer, fromC, skipC, skipInline); + jl_getDylibFunctionInfo(name, filename, line, inlinedat_file, inlinedat_line, pointer, fromC, skipC, skipInline); } int jl_get_llvmf_info(uint64_t fptr, uint64_t *symsize, uint64_t *slide, diff --git a/src/disasm.cpp b/src/disasm.cpp index f6b7ca43ebdd4..bfc3d41ff7bf4 100644 --- a/src/disasm.cpp +++ b/src/disasm.cpp @@ -230,12 +230,12 @@ int OpInfoLookup(void *DisInfo, uint64_t PC, char *name; char *filename; size_t line; - char *inlined_file; - size_t inlined_line; + char *inlinedat_file; + size_t inlinedat_line; int fromC; - jl_getFunctionInfo(&name, &filename, &line, &inlined_file, &inlined_line, pointer, &fromC, skipC, 1); + jl_getFunctionInfo(&name, &filename, &line, &inlinedat_file, &inlinedat_line, pointer, &fromC, skipC, 1); free(filename); - free(inlined_file); + free(inlinedat_file); if (!name) return 0; // Did not find symbolic information // Describe the symbol diff --git a/src/julia_internal.h b/src/julia_internal.h index 6058078079d79..230bcd9f6de5a 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -178,7 +178,7 @@ DLLEXPORT void attach_exception_port(void); #endif // Set *name and *filename to either NULL or malloc'd string void jl_getFunctionInfo(char **name, char **filename, size_t *line, - char **inlined_file, size_t *inlined_line, + char **inlinedat_file, size_t *inlinedat_line, uintptr_t pointer, int *fromC, int skipC, int skipInline); // *to is NULL or malloc'd pointer, from is allowed to be NULL diff --git a/src/task.c b/src/task.c index 6921707d722bf..4fc7b28a003d6 100644 --- a/src/task.c +++ b/src/task.c @@ -470,13 +470,13 @@ size_t bt_size = 0; // Always Set *func_name and *file_name to malloc'd pointers (non-NULL) static int frame_info_from_ip(char **func_name, char **file_name, size_t *line_num, - char **inlined_file, size_t *inlined_line, + char **inlinedat_file, size_t *inlinedat_line, size_t ip, int skipC, int skipInline) { static const char *name_unknown = "???"; int fromC = 0; - jl_getFunctionInfo(func_name, file_name, line_num, inlined_file, inlined_line, ip, &fromC, + jl_getFunctionInfo(func_name, file_name, line_num, inlinedat_file, inlinedat_line, ip, &fromC, skipC, skipInline); if (!*func_name) { *func_name = strdup(name_unknown); @@ -710,22 +710,22 @@ DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC) char *func_name; size_t line_num; char *file_name; - size_t inlined_line; - char *inlined_file; + size_t inlinedat_line; + char *inlinedat_file; int fromC = frame_info_from_ip(&func_name, &file_name, &line_num, - &inlined_file, &inlined_line, (size_t)ip, skipC, 0); + &inlinedat_file, &inlinedat_line, (size_t)ip, skipC, 0); jl_value_t *r = (jl_value_t*)jl_alloc_svec(7); JL_GC_PUSH1(&r); jl_svecset(r, 0, jl_symbol(func_name)); jl_svecset(r, 1, jl_symbol(file_name)); jl_svecset(r, 2, jl_box_long(line_num)); - jl_svecset(r, 3, jl_symbol(inlined_file ? inlined_file : "")); - jl_svecset(r, 4, jl_box_long(inlined_file ? inlined_line : -1)); + jl_svecset(r, 3, jl_symbol(inlinedat_file ? inlinedat_file : "")); + jl_svecset(r, 4, jl_box_long(inlinedat_file ? inlinedat_line : -1)); jl_svecset(r, 5, jl_box_bool(fromC)); jl_svecset(r, 6, jl_box_long((intptr_t)ip)); free(func_name); free(file_name); - free(inlined_file); + free(inlinedat_file); JL_GC_POP(); return r; } @@ -751,9 +751,9 @@ DLLEXPORT void gdblookup(ptrint_t ip) char *func_name; size_t line_num; char *file_name; - size_t inlined_line; - char *inlined_file; - frame_info_from_ip(&func_name, &file_name, &line_num, &inlined_file, &inlined_line, ip, + size_t inlinedat_line; + char *inlinedat_file; + frame_info_from_ip(&func_name, &file_name, &line_num, &inlinedat_file, &inlinedat_line, ip, /* skipC */ 0, /* skipInline */ 1); if (line_num == ip) { jl_safe_printf("unknown function (ip: %p)\n", (void*)ip); @@ -767,7 +767,7 @@ DLLEXPORT void gdblookup(ptrint_t ip) } free(func_name); free(file_name); - free(inlined_file); + free(inlinedat_file); } DLLEXPORT void jlbacktrace()