[PATCH v1 1/2] riscv: stacktrace: Remove bogus -0x4 offset in non-FP walk_stackframe
From: Rui Qi
Date: Wed Jun 03 2026 - 08:01:26 EST
In the non-frame-pointer version of walk_stackframe, each value read
from the stack is treated as a potential return address and has 0x4
subtracted before being used as the program counter. This was intended
to convert the return address (the instruction after a call) back to
the call site, but it is incorrect:
1. RISC-V has variable-length instructions due to the RVC (compressed
instruction) extension. A call instruction can be either 4 bytes
(regular) or 2 bytes (compressed, e.g. c.jal). Subtracting a fixed
0x4 assumes all call instructions are 4 bytes, which is wrong for
compressed instructions.
2. Stack traces conventionally report return addresses, not call sites.
Other architectures (ARM64, x86, ARM) do not subtract instruction
size from return addresses in their stack unwinding code.
3. The frame-pointer version of walk_stackframe already dropped the
-0x4 offset. Commit b785ec129bd9 ("riscv/ftrace: Add
HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support") replaced "pc =
frame->ra - 0x4" with ftrace_graph_ret_addr(), and the commit
message explicitly noted that "the original calculation, pc =
frame->ra - 4, is buggy when the instruction at the return address
happened to be a compressed inst." The non-FP version was simply
overlooked.
Remove the bogus -0x4 offset to match the FP version and the
conventions used by other architectures.
Fixes: 5d8544e2d007 ("RISC-V: Generic library routines and assembly")
Signed-off-by: Rui Qi <qirui.001@xxxxxxxxxxxxx>
---
arch/riscv/kernel/stacktrace.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
index 2692d3a06afa..c7555447149b 100644
--- a/arch/riscv/kernel/stacktrace.c
+++ b/arch/riscv/kernel/stacktrace.c
@@ -129,7 +129,7 @@ void notrace walk_stackframe(struct task_struct *task,
while (!kstack_end(ksp)) {
if (__kernel_text_address(pc) && unlikely(!fn(arg, pc)))
break;
- pc = READ_ONCE_NOCHECK(*ksp++) - 0x4;
+ pc = READ_ONCE_NOCHECK(*ksp++);
}
}
--
2.20.1