Skip to content

Commit

Permalink
Use inlining info to improve line #s
Browse files Browse the repository at this point in the history
Utilizes the DebugLoc "inlinedAt" information added in the previous commit to
provide line information for inlined code. For functions where this information
is available, we now print both the inlinee origin and the top-level call site.

Mostly addresses #1334. (this does not handle nested inlines, which may require
deeper changes)
  • Loading branch information
ihnorton committed Aug 10, 2015

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 0123967 commit 9e71ba4
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 34 deletions.
33 changes: 25 additions & 8 deletions base/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -321,19 +321,34 @@ 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, context, n)
print(io, "\n")
print(io, " in ", fname, " at ", file)
print(io, " in ", fname)

if (context != symbol(""))
print(io, " at ", context)
print(io, " \n [ with inlined function from ")
else
print(io, " at ")
end

print(io, file)

if line >= 1
try
print(io, ":", line)
catch
print(io, '?') #for when dec is not yet defined
end
end

if n > 1
print(io, " (repeats ", n, " times)")
end

if (context != symbol(""))
print(io, " ]")
end
end

function show_backtrace(io::IO, t, set=1:typemax(Int))
Expand All @@ -349,38 +364,40 @@ 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, context, n) = show_trace_entry(io, lastname, lastfile, lastline, context, 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("#"); lastcontext = ""
local fname, file, line
count = 0
for i = 1:length(t)
lkup = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), t[i]-1, true)
if lkup === nothing
continue
end
fname, file, line, fromC = lkup
fname, file, context, line, 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, lastcontext, n)
end
n = 1
lastfile = file; lastline = line; lastname = fname
lastfile = file; lastline = line; lastname = fname; lastcontext = context
else
n += 1
end
end
if n > 1 || lastline != -11
process_func(lastname, lastfile, lastline, n)
process_func(lastname, lastfile, lastline, lastcontext, n)
end
end
43 changes: 28 additions & 15 deletions src/debuginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,10 +458,11 @@ 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, char **inlineloc,
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);
Expand All @@ -470,13 +471,19 @@ 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(), "<invalid>") == 0) goto done;
if (demangle) {
Expand All @@ -487,6 +494,12 @@ 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);
if (strcmp(topinfo.getFunctionName(), "<invalid>") == 0) goto done;
asprintf(inlineloc, "%s:%d", topinfo.getFileName(), topinfo.getLine());
}
#else
if (strcmp(info.FunctionName.c_str(), "<invalid>") == 0) goto done;
jl_copy_str(name, info.FunctionName.c_str());
Expand Down Expand Up @@ -555,8 +568,8 @@ 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, size_t *line, char **filename, char** inlineinfo,
size_t pointer, int *fromC, int skipC, int skipInline)
{
#ifdef _OS_WINDOWS_
IMAGEHLP_MODULE64 ModuleInfo;
Expand Down Expand Up @@ -753,7 +766,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, inlineinfo, pointer+slide,
fbase == jl_sysimage_base, fromC);
}
else {
Expand All @@ -762,12 +775,13 @@ 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, size_t *line, char **filename, char **inlineinfo,
size_t pointer, int *fromC, int skipC, int skipInline)
{
*name = NULL;
*line = -1;
*filename = NULL;
*inlineinfo = NULL;
*fromC = 0;

#ifdef USE_MCJIT
Expand Down Expand Up @@ -797,7 +811,7 @@ void jl_getFunctionInfo(char **name, size_t *line, char **filename,
DIContext *context = DIContext::getDWARFContext(const_cast<object::ObjectFile*>(it->second.object));
#endif
#endif
lookup_pointer(context, name, line, filename, pointer, 1, fromC);
lookup_pointer(context, name, line, filename, inlineinfo, pointer, 1, fromC);
delete context;
return;
}
Expand Down Expand Up @@ -859,20 +873,19 @@ void jl_getFunctionInfo(char **name, size_t *line, char **filename,
}

DILexicalBlockFile locscope = DILexicalBlockFile(prev.Loc.getScope((*it).second.func->getContext()));
*filename = locscope.getFilename().data();
jl_copy_str(filename, (char*)(uintptr_t)locscope.getFilename().data());

MDNode *inlinedAt = prev.Loc.getInlinedAt((*it).second.func->getContext());
if (inlinedAt) {
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_printf(JL_STDERR, "inlined at: %s : %d\n", inlinescope.getFilename().data(), inlineloc.getLine());
asprintf(inlineinfo, "%s:%d", inlinescope.getFilename().data(), inlineloc.getLine());
}

return;
}
#endif // USE_MCJIT
jl_getDylibFunctionInfo(name, line, filename, pointer, fromC, skipC);
jl_getDylibFunctionInfo(name, line, filename, inlineinfo, pointer, fromC, skipC, skipInline);
}

int jl_get_llvmf_info(uint64_t fptr, uint64_t *symsize, uint64_t *slide,
Expand Down
3 changes: 2 additions & 1 deletion src/disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,9 @@ int OpInfoLookup(void *DisInfo, uint64_t PC,
char *name;
size_t line;
char *filename;
char *inlineinfo;
int fromC;
jl_getFunctionInfo(&name, &line, &filename, pointer, &fromC, skipC);
jl_getFunctionInfo(&name, &line, &filename, &inlineinfo, pointer, &fromC, skipC, 1);
free(filename);
if (!name)
return 0; // Did not find symbolic information
Expand Down
4 changes: 2 additions & 2 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ 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, size_t *line, char **filename, char **inlineinfo,
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)
Expand Down
23 changes: 15 additions & 8 deletions src/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,12 +463,14 @@ 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)
char **file_name, char** inline_info,
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, line_num, file_name, inline_info, ip, &fromC,
skipC, skipInline);
if (!*func_name) {
*func_name = strdup(name_unknown);
*line_num = ip;
Expand Down Expand Up @@ -701,17 +703,20 @@ DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC)
char *func_name;
size_t line_num;
char *file_name;
char *inline_info;
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);
&inline_info, (size_t)ip, skipC, 0);
jl_value_t *r = (jl_value_t*)jl_alloc_svec(6);
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, 2, jl_symbol(inline_info ? inline_info : "")); // TODO don't use symbol here?
jl_svecset(r, 3, jl_box_long(line_num));
jl_svecset(r, 4, jl_box_bool(fromC));
jl_svecset(r, 5, jl_box_long((intptr_t)ip));
free(func_name);
free(file_name);
free(inline_info);
JL_GC_POP();
return r;
}
Expand All @@ -737,7 +742,9 @@ 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);
char *inline_info;
frame_info_from_ip(&func_name, &line_num, &file_name, &inline_info, ip,
/* skipC */ 0, /* skipInline */ 1);
if (line_num == ip) {
jl_safe_printf("unknown function (ip: %p)\n", (void*)ip);
} else if (line_num == -1) {
Expand Down

0 comments on commit 9e71ba4

Please sign in to comment.