arch/risc-v: optimize riscv backtrace#19528
Open
hitHuang wants to merge 3 commits into
Open
Conversation
hitHuang
requested review from
Ouss4,
gustavonihei,
jerpelea,
tmedicci,
xiaoxiang781216 and
yf13
as code owners
July 25, 2026 02:02
Contributor
|
@hitHuang please add: Assisted-by: in the commit message to indicate which AI model you used to create this code |
hitHuang
force-pushed
the
optimize/riscv_backtrace
branch
from
July 25, 2026 14:15
6c11cb7 to
a97eac8
Compare
Contributor
|
@hitHuang you need to add in all commits |
up_idle() is a leaf function; with frame pointers enabled the compiler skips spilling ra, corrupting the fp chain. Clobber "ra" in the WFI inline asm so backtrace can walk past the idle frame correctly. Assisted-by: Claude Code:claude-sonnet-5 Signed-off-by: liang.huang <liang.huang@houmo.ai>
When riscv_fault_handler() kills a user task with SIGSEGV, it previously produced no stack trace, making the crash hard to diagnose. Call sched_dumpstack() on the killed task when SCHED_BACKTRACE is enabled. Assisted-by: Claude Code:claude-sonnet-5 Signed-off-by: liang.huang <liang.huang@houmo.ai>
Bugs fixed: 1. BUILD_FLAT/BUILD_PROTECTED: the interrupt-context self backtrace printed the same frames twice. 2. BUILD_KERNEL: a cross-tcb backtrace never included the target task's kernel stack, so frames on it were missing. Also reworked the implementation around a list of independent starting points, each carrying every stack range its fp chain may cross into, splicing them into one backtrace. Assisted-by: Claude Code:claude-sonnet-5 Signed-off-by: liang.huang <liang.huang@houmo.ai>
hitHuang
force-pushed
the
optimize/riscv_backtrace
branch
from
July 26, 2026 09:11
a97eac8 to
47298a5
Compare
| #include "riscv_internal.h" | ||
|
|
||
| /**************************************************************************** | ||
| * Private Types |
| ****************************************************************************/ | ||
|
|
||
| static inline uintptr_t getfp(void) | ||
| always_inline_function static uintptr_t getfp(void) |
Contributor
There was a problem hiding this comment.
static always_inline_function...
| tcb->adj_stack_size); | ||
|
|
||
| #ifdef CONFIG_LIB_SYSCALL | ||
| bool insyscall = (tcb->flags & TCB_FLAG_SYSCALL) != 0; |
Contributor
There was a problem hiding this comment.
move to the beginning
|
|
||
| /* One candidate stack range a segment's fp chain may be walking. */ | ||
|
|
||
| struct bt_range_s |
Contributor
There was a problem hiding this comment.
let change bt_/BT_ to backtrace_/BACKTRACE_
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
risc-v's
up_backtrace()currently has the following problems:CONFIG_BUILD_KERNEL,dumpstackon a user task only dumps its user stack, never its kernel stack.CONFIG_BUILD_FLAT/CONFIG_BUILD_PROTECTED, backtrace output contains duplicate frames.Problem 1 was already noted in #19439, but never actually fixed in code. Problem 2 is caused by an implementation bug that dumps the same range of the user stack twice.
This change reworks
up_backtrace()around a table of stack ranges (interrupt stack / kernel stack / user stack) that a given fp chain may legitimately cross into, walked by one shared procedure that switches ranges as needed, instead of hand-writing a separate branch with one or two hardcoded ranges per scenario.Problem 1 repro
rv-virt:knsh,dumpstackon a user task only shows frames on the user stack (tid 2/3/4 partially only show kernel-stack addresses0xc0..., missing the corresponding user-stack frames):Problem 2 repro
rv-virt:nsh,mb 0xdeadbeef 1faults on an invalid address, and the backtrace for nsh_main (tid 2) itself contains duplicate frames. This happens any timeup_backtrace()tries to backtrace self fromup_interrupt_context().The duplicated part (
0x8000b450 0x8000b3b6 0x8000973a 0x8000a490 0x8000a530 0x80008f42 0x80008d62 0x80008d1e 0x80006248 0x80002288) resolved via addr2line:The same duplication reproduces under
rv-virt:pnshas well.Along the way, several related but independent issues were found and fixed and are tracked as separate PRs: #19439, #19468, #19471, #19479, #19487.
This PR also picks up two small, related fixes/improvements along the way:
up_idle()is a leaf function that doesn't spillra, which produced garbage frames at the tail of a backtrace that unwound through it.CONFIG_BUILD_KERNEL, when a user app is killed due to a fault, its backtrace is now dumped proactively to help with debugging.Since these two are small in scope, the rest of this description focuses on the
up_backtrace()fix/rework described above.Impact
Only affects
up_backtrace()inarch/risc-v/src/common/riscv_backtrace.c. Fixes the missing-kernel-stack-frames bug underCONFIG_BUILD_KERNELand the duplicate-frame bug underCONFIG_BUILD_FLAT/CONFIG_BUILD_PROTECTEDdescribed above, and replaces the previous scenario-specific hardcoded branches with a general multi-range registration + relay walk. Behavior for already-covered scenarios should stay equivalent or become more complete (recovering previously missing frames); no new Kconfig options or API changes.Testing
Only one SiFive U74 risc-v SoC is available as real hardware, so most of the verification below is on QEMU.
Config dimensions covered:
The full cross product is 2 * 3 * 2 * 2 = 24 combinations, too many to cover individually. Testing mainly relied on the existing nsh/pnsh/knsh/smp/ksmp64 configs, with
CONFIG_ARCH_INTERRUPTSTACKtoggled manually to cover the remaining combination. These configs cover the combinations of interest:Scenarios covered (the most complex case involves interrupt stack + kernel stack + user stack together; there's also an independent dimension of backtracing self vs. a different task, where cross-task backtracing under BUILD_KERNEL additionally has to cross address spaces):
mbon an invalid address triggering a panic with backtrace outputNotes:
Test matrix and results (
-means not applicable for that config):All the above test cases have been covered, and the backtrace output matched expectations in every case.