ResolvedTrace resolve()

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;
    }