in src/backward.h [1185:1330]
ResolvedTrace resolve(ResolvedTrace trace)
{
Dl_info symbol_info;
// trace.addr is a virtual address in memory pointing to some code.
// Let's try to find from which loaded object it comes from.
// The loaded object can be yourself btw.
if (!dladdr(trace.addr, &symbol_info)) {
return trace; // dat broken trace...
}
// Now we get in symbol_info:
// .dli_fname:
// pathname of the shared object that contains the address.
// .dli_fbase:
// where the object is loaded in memory.
// .dli_sname:
// the name of the nearest symbol to trace.addr, we expect a
// function name.
// .dli_saddr:
// the exact address corresponding to .dli_sname.
if (symbol_info.dli_sname) {
trace.object_function = demangle(symbol_info.dli_sname);
}
if (!symbol_info.dli_fname) {
return trace;
}
trace.object_filename = resolve_exec_path(symbol_info);
bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname);
if (!fobj.handle) {
return trace; // sad, we couldn't load the object :(
}
find_sym_result* details_selected; // to be filled.
// trace.addr is the next instruction to be executed after returning
// from the nested stack frame. In C++ this usually relate to the next
// statement right after the function call that leaded to a new stack
// frame. This is not usually what you want to see when printing out a
// stacktrace...
find_sym_result details_call_site = find_symbol_details(fobj, trace.addr, symbol_info.dli_fbase);
details_selected = &details_call_site;
# if BACKWARD_HAS_UNWIND == 0
// ...this is why we also try to resolve the symbol that is right
// before the return address. If we are lucky enough, we will get the
// line of the function that was called. But if the code is optimized,
// we might get something absolutely not related since the compiler
// can reschedule the return address with inline functions and
// tail-call optimisation (among other things that I don't even know
// or cannot even dream about with my tiny limited brain).
find_sym_result details_adjusted_call_site =
find_symbol_details(fobj, (void*)(uintptr_t(trace.addr) - 1), symbol_info.dli_fbase);
// In debug mode, we should always get the right thing(TM).
if (details_call_site.found && details_adjusted_call_site.found) {
// Ok, we assume that details_adjusted_call_site is a better estimation.
details_selected = &details_adjusted_call_site;
trace.addr = (void*)(uintptr_t(trace.addr) - 1);
}
if (details_selected == &details_call_site && details_call_site.found) {
// we have to re-resolve the symbol in order to reset some
// internal state in BFD... so we can call backtrace_inliners
// thereafter...
details_call_site = find_symbol_details(fobj, trace.addr, symbol_info.dli_fbase);
}
# endif // BACKWARD_HAS_UNWIND
if (details_selected->found) {
if (details_selected->filename) {
trace.source.filename = details_selected->filename;
}
trace.source.line = details_selected->line;
if (details_selected->funcname) {
// this time we get the name of the function where the code is
// located, instead of the function were the address is
// located. In short, if the code was inlined, we get the
// function correspoding to the code. Else we already got in
// trace.function.
trace.source.function = demangle(details_selected->funcname);
if (!symbol_info.dli_sname) {
// for the case dladdr failed to find the symbol name of
// the function, we might as well try to put something
// here.
trace.object_function = trace.source.function;
}
}
// Maybe the source of the trace got inlined inside the function
// (trace.source.function). Let's see if we can get all the inlined
// calls along the way up to the initial call site.
trace.inliners = backtrace_inliners(fobj, *details_selected);
# if 0
if (trace.inliners.size() == 0) {
// Maybe the trace was not inlined... or maybe it was and we
// are lacking the debug information. Let's try to make the
// world better and see if we can get the line number of the
// function (trace.source.function) now.
//
// We will get the location of where the function start (to be
// exact: the first instruction that really start the
// function), not where the name of the function is defined.
// This can be quite far away from the name of the function
// btw.
//
// If the source of the function is the same as the source of
// the trace, we cannot say if the trace was really inlined or
// not. However, if the filename of the source is different
// between the function and the trace... we can declare it as
// an inliner. This is not 100% accurate, but better than
// nothing.
if (symbol_info.dli_saddr) {
find_sym_result details = find_symbol_details(fobj,
symbol_info.dli_saddr,
symbol_info.dli_fbase);
if (details.found) {
ResolvedTrace::SourceLoc diy_inliner;
diy_inliner.line = details.line;
if (details.filename) {
diy_inliner.filename = details.filename;
}
if (details.funcname) {
diy_inliner.function = demangle(details.funcname);
} else {
diy_inliner.function = trace.source.function;
}
if (diy_inliner != trace.source) {
trace.inliners.push_back(diy_inliner);
}
}
}
}
# endif
}
return trace;
}