hitHuang opened a new pull request, #19528:
URL: https://github.com/apache/nuttx/pull/19528

   ## Summary
   
   risc-v's `up_backtrace()` currently has the following problems:
   
   1. Under `CONFIG_BUILD_KERNEL`, `dumpstack` on a user task only dumps its 
user stack, never its kernel stack.
   2. Under `CONFIG_BUILD_FLAT`/`CONFIG_BUILD_PROTECTED`, backtrace output 
contains duplicate frames.
   3. The existing implementation piles up branches, macros, and conditionals 
to handle the various combinations, which makes the code hard to follow and 
makes it increasingly difficult to keep fixing bugs or adding support for new 
scenarios on top of the existing structure.
   
   Problem 1 was already noted in https://github.com/apache/nuttx/pull/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`, `dumpstack` on a user task only shows frames on the user 
stack (tid 2/3/4 partially only show kernel-stack addresses `0xc0...`, missing 
the corresponding user-stack frames):
   
   ```
   NuttShell (NSH) NuttX-13.0.0
   nsh> dumpstack 0 10
   [3951369912320000.001000] sched_dumpstack: backtrace| 0: 0x8020cf92 
0x80608730 0x802011d6 0x8020004a
   [3977139716096000.001000] sched_dumpstack: backtrace| 1: 0x8020cafc 
0x80218ffa 0x80208cfc 0x80208d20 0x8020312c 0x80202a94
   [3990024617984000.001000] sched_dumpstack: backtrace| 3: 0xc000c478 
0xc000561e 0xc0002d4e 0xc0003cbc 0xc0003d5c 0xc0002722 0xc0002542 0xc0000b4a
   [4002909519872000.001000] sched_dumpstack: backtrace| 3: 0xc0000b08
   [4011499454464000.001000] sched_dumpstack: backtrace| 4: 0xc000289a 
0xc0000b44 0xc0000aca 0xc0000a8c
   ```
   
   ### Problem 2 repro
   
   `rv-virt:nsh`, `mb 0xdeadbeef 1` faults on an invalid address, and the 
backtrace for nsh_main (tid 2) itself contains duplicate frames. This happens 
any time `up_backtrace()` tries to backtrace self from `up_interrupt_context()`.
   
   ```
   NuttShell (NSH) NuttX-13.0.0
   nsh> ps
     TID   PID  PPID PRI POLICY   TYPE    NPX STATE    EVENT     SIGMASK        
    STACK    USED FILLED COMMAND
       0     0     0   0 FIFO     Kthread   - Ready              
0000000000000000 0002016 0000668  33.1%  Idle_Task
       2     2     0 100 RR       Task      - Running            
0000000000000000 0001984 0001984 100.0%! nsh_main
   nsh> mb 0xdeadbeef 1
   riscv_exception: EXCEPTION: Load access fault. MCAUSE: 00000005, EPC: 
8000b450, MTVAL: deadbeef
   riscv_fault_handler: PANIC!!! Exception = 00000005
   dump_assert_info: Current Version: NuttX  13.0.0 2f73fe2267-dirty Jul 20 
2026 09:26:46 risc-v
   dump_assert_info: Assertion failed panic: at file: :0 task: nsh_main 
process: nsh_main 0x80008ce2
   up_dump_register: EPC: 8000b450
   ......
   stack_dump: 0x80039160: 00000000 00000000 80039180 80002288 00000000 
00000000 00000000 00000000
   stack_dump: 0x80039180: 00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
   sched_dumpstack: backtrace| 2: 0x80025234 0x80018dc8 0x80015590 0x80008566 
0x80001918 0x8000156a 0x8000150c 0x80000186
   sched_dumpstack: backtrace| 2: 0x8000b450 0x8000b3b6 0x8000973a 0x8000a490 
0x8000a530 0x80008f42 0x80008d62 0x80008d1e
   sched_dumpstack: backtrace| 2: 0x80006248 0x80002288 0x8000b450 0x8000b3b6 
0x8000973a 0x8000a490 0x8000a530 0x80008f42
   sched_dumpstack: backtrace| 2: 0x80008d62 0x80008d1e 0x80006248 0x80002288
   dump_tasks:    PID GROUP PRI POLICY   TYPE    NPX STATE   EVENT      SIGMASK 
         STACKBASE  STACKSIZE      USED   FILLED    COMMAND
   dump_tasks:   ----   --- --- -------- ------- --- ------- ---------- 
---------------- 0x80034380      2048      1100    53.7%    irq
   dump_task:       0     0   0 FIFO     Kthread -   Ready              
0000000000000000 0x80037180      2016       668    33.1%    Idle_Task
   dump_task:       2     2 100 RR       Task    -   Running            
0000000000000000 0x800389c0      1984      1984   100.0%!   nsh_main
   sched_dumpstack: backtrace| 0: 0x80008bc0 0x80037950 0x800014a0 0x80000048
   sched_dumpstack: backtrace| 2: 0x80025234 0x80018dc8 0x800151d8 0x80015960 
0x80015624 0x80008566 0x80001918 0x8000156a
   sched_dumpstack: backtrace| 2: 0x8000150c 0x80000186 0x8000b450 0x8000b3b6 
0x8000973a 0x8000a490 0x8000a530 0x80008f42
   sched_dumpstack: backtrace| 2: 0x80008d62 0x80008d1e 0x80006248 0x80002288 
0x8000b450 0x8000b3b6 0x8000973a 0x8000a490
   sched_dumpstack: backtrace| 2: 0x8000a530 0x80008f42 0x80008d62 0x80008d1e 
0x80006248 0x80002288
   ```
   
   The duplicated part (`0x8000b450 0x8000b3b6 0x8000973a 0x8000a490 0x8000a530 
0x80008f42 0x80008d62 0x80008d1e 0x80006248 0x80002288`) resolved via addr2line:
   
   ```
   huang@ubuntu:~/workspace/nuttx-fork/nuttx$ riscv64-unknown-elf-addr2line -f 
-i -e nuttx 0x8000b450 0x8000b3b6 0x8000973a 0x8000a490 0x8000a530 0x80008f42 
0x80008d62 0x80008d1e 0x80006248 0x80002288
   cmd_mb
   /home/huang/workspace/nuttx-fork/apps/nshlib/nsh_dbgcmds.c:150
   nsh_command
   /home/huang/workspace/nuttx-fork/apps/nshlib/nsh_command.c:1321
   nsh_execute
   /home/huang/workspace/nuttx-fork/apps/nshlib/nsh_parse.c:759
   nsh_parse_command
   /home/huang/workspace/nuttx-fork/apps/nshlib/nsh_parse.c:2911
   nsh_parse
   /home/huang/workspace/nuttx-fork/apps/nshlib/nsh_parse.c:3116
   nsh_session
   /home/huang/workspace/nuttx-fork/apps/nshlib/nsh_session.c:249
   nsh_consolemain
   /home/huang/workspace/nuttx-fork/apps/nshlib/nsh_consolemain.c:81
   nsh_main
   /home/huang/workspace/nuttx-fork/apps/system/nsh/nsh_main.c:82
   nxtask_startup
   /home/huang/workspace/nuttx-fork/nuttx/libs/libc/sched/task_startup.c:72 
(discriminator 1)
   nxtask_start
   /home/huang/workspace/nuttx-fork/nuttx/sched/task/task_start.c:72
   ```
   
   The same duplication reproduces under `rv-virt:pnsh` as well.
   
   Along the way, several related but independent issues were found and fixed 
and are tracked as separate PRs: https://github.com/apache/nuttx/pull/19439, 
https://github.com/apache/nuttx/pull/19468, 
https://github.com/apache/nuttx/pull/19471, 
https://github.com/apache/nuttx/pull/19479, 
https://github.com/apache/nuttx/pull/19487.
   
   This PR also picks up two small, related fixes/improvements along the way:
   
   1. `up_idle()` is a leaf function that doesn't spill `ra`, which produced 
garbage frames at the tail of a backtrace that unwound through it.
   2. Under `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()` in `arch/risc-v/src/common/riscv_backtrace.c`. 
Fixes the missing-kernel-stack-frames bug under `CONFIG_BUILD_KERNEL` and the 
duplicate-frame bug under `CONFIG_BUILD_FLAT`/`CONFIG_BUILD_PROTECTED` 
described 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:
   
   1. rv32 / rv64
   2. BUILD_FLAT / BUILD_PROTECTED / BUILD_KERNEL
   3. no-smp / smp
   4. CONFIG_ARCH_INTERRUPTSTACK > 15 / < 15
   
   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_INTERRUPTSTACK` toggled manually to cover the 
remaining combination. These configs cover the combinations of interest:
   
   | Config          | Arch | Build mode | SMP | INTERRUPTSTACK > 15 | 
KERNEL_STACK + ADDRENV | LIBC_SYSCALL |
   
|------------------|------|------------|-----|----------------------|------------------------|--------------|
   | nsh              | RV32 | FLAT       | N   | Y                    | N      
                | N            |
   | pnsh             | RV32 | PROTECTED  | N   | Y                    | N      
                | Y            |
   | knsh             | RV32 | KERNEL     | N   | Y                    | Y      
                | Y            |
   | smp              | RV64 | FLAT       | Y   | Y                    | N      
                | N            |
   | ksmp64           | RV64 | KERNEL     | Y   | Y                    | Y      
                | Y            |
   | nsh (no intstack)  | RV32 | FLAT       | N   | N                    | N    
                  | N            |
   | pnsh (no intstack) | RV32 | PROTECTED  | N   | N                    | N    
                  | Y            |
   | knsh (no intstack) | RV32 | KERNEL     | N   | N                    | Y    
                  | Y            |
   
   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):
   
   1. ostest
   2. dumpstack (application) on self / another task
   3. `mb` on an invalid address triggering a panic with backtrace output
   4. backtrace from an interrupt handler that preempted a kernel thread
   5. backtrace from an interrupt handler that preempted a user thread running 
in user mode
   6. backtrace from an interrupt handler that preempted a user thread that had 
trapped into the kernel via a syscall
   7. NULL pointer access inside an interrupt handler that preempted a kernel 
thread, triggering a panic with backtrace output
   8. NULL pointer access inside an interrupt handler that preempted a user 
thread running in user mode, triggering a panic with backtrace output
   9. NULL pointer access inside an interrupt handler that preempted a user 
thread that had trapped into the kernel via a syscall, triggering a panic with 
backtrace output
   10. a user thread trapping into the kernel and accessing a NULL pointer, 
triggering a panic with backtrace output
   
   Notes:
   
   - Under BUILD_FLAT/BUILD_PROTECTED, scenarios 4/5/6 are treated as a single 
case, since these build modes don't distinguish user stack from kernel stack; 
likewise for 7/8/9. Scenario 10 only applies to BUILD_KERNEL.
   - Under SMP, interrupt-handler scenarios only test backtracing self 
(cross-CPU backtracing from interrupt context isn't recommended).
   
   Test matrix and results (`-` means not applicable for that config):
   
   | Config             | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
   |--------------------|---|---|---|---|---|---|---|---|---|----|
   | nsh                | Y | Y | Y | Y |   |   | Y |   |   | -  |
   | pnsh               | Y | Y | Y | Y |   |   | Y |   |   | -  |
   | knsh               | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y  |
   | smp                | Y | Y | Y | Y |   |   | Y |   |   | -  |
   | ksmp64             | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y  |
   | nsh (no intstack)  | Y | Y | Y | Y |   |   | Y |   |   | -  |
   | pnsh (no intstack) | Y | Y | Y | Y |   |   | Y |   |   | -  |
   | knsh (no intstack) | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y  |
   
   All the above test cases have been covered, and the backtrace output matched 
expectations in every case.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to