Re: [PATCH] decode_stacktrace: Support heuristic caller address search
From: Google
Date: Thu Mar 05 2026 - 11:34:36 EST
On Thu, 5 Mar 2026 10:51:47 -0500
Sasha Levin <sashal@xxxxxxxxxx> wrote:
> On Thu, 5 Mar 2026 14:12:19 +0900, Masami Hiramatsu (Google) wrote:
> > Add -c option to search call address search to decode_stacktrace.
> > This tries to decode line info backwards, starting from 1byte before
> > the return address, and displays the first line info it founds as
> > the caller address.
> > If it tries up to 10bytes before (or the symbol address) and still
> > can not find it, it gives up and decodes the return address.
>
> The commit message says "up to 10bytes" but the code passes $offset
> (the function offset from the symbol) as the max iteration count to
> search_call_site(). There's no 10-byte cap anywhere in the code?
> $offset can easily be hundreds or thousands of bytes into a function.
Ah, sorry. I forgot to set maximum :(
>
> > +search_call_site() {
> > + # Instead of using the return address, use the nearest line info
> > + # address before given address.
> > + local return_addr=${2}
> > + local max=${3}
> > + local i
> > +
> > + for i in $(seq 1 ${max}); do
> > + local expr=$((0x$return_addr-$i))
> > + local address=$(printf "%x\n" "$expr")
> > +
> > + local code=$(${ADDR2LINE} -i -e "${1}" "$address" 2>/dev/null)
> > + local first=${code% *}
> > + if [[ "$code" != "" && "$code" != ${UNKNOWN_LINE} && "${first#*:}" != "?" ]]; then
>
> To also address Matthieu's question about performance: I think this
> whole iterative search could be replaced by simply subtracting 1 from
> the return address before passing it to addr2line.
>
> DWARF line tables map address *ranges* to source lines, so any address
> within the CALL instruction resolves to the correct source line.
> return_addr-1 is guaranteed to land inside the CALL instruction (it's
> the last byte of it), so a single addr2line call is sufficient.
Ah, got it, OK. I also confirmed "addr-1" works. But if there is no lineinfo
entry for the call instruction, shouldn't we check more instructions before
the call?
>
> This is exactly what the kernel itself does in sprint_backtrace()
> (kernel/kallsyms.c:570): it passes symbol_offset=-1 to
> __sprint_symbol(), which does `address += symbol_offset` before
> lookup. GDB, perf, and libunwind all use the same addr-1 trick for
> the same reason.
OK.
>
> That would make this both correct and free.
>
> > + if [[ "$code" != "" && "$code" != ${UNKNOWN_LINE} && "${first#*:}" != "?" ]]; then
>
> Minor: ${UNKNOWN_LINE} is "??:0" -- when unquoted on the RHS of != inside
> [[ ]], the ? characters are interpreted as glob wildcards (each matching
> any single character). It happens to work here because ? also matches '?'
> itself, but it should be quoted as "${UNKNOWN_LINE}" for correctness.
> Same issue on the other != ${UNKNOWN_LINE} below.
Ah, OK. Let me fix it.
Thanks,
>
> --
> Thanks,
> Sasha
--
Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>