[PW_SID:1117959] riscv: Add reliable stack unwinding for livepatch#2158
[PW_SID:1117959] riscv: Add reliable stack unwinding for livepatch#2158linux-riscv-bot wants to merge 8 commits into
Conversation
Reliable frame-pointer unwinding needs an explicit way to identify
exception boundaries and the final entry frame. The existing unwinder
infers those boundaries from return addresses, which is too loose for a
future reliable unwinder.
Add a small metadata frame record to pt_regs and initialize it on
exception entry, kernel stack overflow, kernel thread fork, user fork,
and early idle task setup. The record uses a zero {fp, ra} sentinel plus
a type field so a later unwinder can distinguish a final user-to-kernel
boundary from a nested kernel pt_regs boundary.
This follows the arm64 metadata frame-record model, adapted to the
RISC-V {fp, ra} frame record convention.
The metadata is established at the RISC-V entry boundaries that need an
explicit unwind marker:
* exception entry clears the metadata {fp, ra} pair and uses SPP
(or MPP in M-mode) to record whether the pt_regs frame is the final
user-to-kernel boundary or a nested kernel boundary;
* the kernel stack overflow path builds a nested pt_regs metadata
record on the overflow stack so an unwinder can resume from the
pre-overflow s0 saved in PT_S0;
* _start_kernel builds the init task's final metadata record, while
the secondary CPU path sets up s0 before smp_callin() so idle-task
unwinding does not inherit an undefined caller frame;
* copy_thread creates matching final metadata records for new kernel
and user tasks, and keeps s0 available for the frame-pointer chain.
Keep the embedded metadata-record field offsets distinct from the
s0-relative STACKFRAME_* offsets used by call_on_irq_stack(), because
the latter describe a frame record relative to s0 rather than to the
record base.
These changes keep s0 reserved for the frame-pointer chain at task and
exception boundaries.
Signed-off-by: Wang Han <wanghan@linux.alibaba.com>
Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
…ace.o KASAN records stack traces for every alloc/free, which means it walks the unwinder very frequently. Instrumenting the stack trace collection code itself adds substantial overhead and makes the traces themselves noisier. KCOV instruments every basic-block edge. The unwinder is a hot path, especially with KASAN enabled, so KCOV instrumentation has the same kind of cost and noise problem here. Mark stacktrace.o as not KASAN- or KCOV-instrumented, matching the x86 treatment of its stack unwinding code. RISC-V keeps the relevant unwinder code in stacktrace.o, so a single translation-unit annotation covers the equivalent scope. This is a prerequisite preference for the upcoming reliable unwinder, but the change is valid on its own. Signed-off-by: Wang Han <wanghan@linux.alibaba.com> Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
struct __arch_ftrace_regs declares s0 unconditionally, and both ftrace_regs_get_frame_pointer() and ftrace_partial_regs() read it unconditionally. But the SAVE_ABI_REGS / RESTORE_ABI_REGS macros in mcount-dyn.S only stored s0 under HAVE_FUNCTION_GRAPH_FP_TEST (CONFIG_FUNCTION_GRAPH_TRACER && CONFIG_FRAME_POINTER). With CONFIG_FRAME_POINTER=n the slot held whatever was on the stack before, so any callback going through ftrace_partial_regs() saw a garbage regs->s0. RISC-V kernels default to FRAME_POINTER=y, which is why this has not bitten in practice. Save and restore s0 unconditionally in the dynamic ftrace ABI register frame. This fixes the latent garbage-s0 case, brings the dynamic ftrace path in line with the static _mcount path (mcount.S SAVE_ABI_STATE already saves s0 unconditionally), and matches the frame layout already documented in the comment above SAVE_ABI_REGS. It is also a prerequisite for the upcoming reliable unwinder, which reads ftrace_regs_get_frame_pointer(fregs) directly. The cost is one extra REG_S/REG_L pair per traced call, negligible compared to the overall ftrace cost; the existing FREGS_SIZE_ON_STACK already reserved the slot, so no extra stack space is used. Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com> Signed-off-by: Wang Han <wanghan@linux.alibaba.com> Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
A reliable unwinder needs to validate that every frame record it reads
is fully contained in a known kernel stack, and it needs to refuse to
walk back into a stack it has already left. Add the building blocks
for that:
* struct stack_info / struct unwind_state in a new
asm/stacktrace/common.h, modelled on the arm64 reference
implementation.
* stackinfo_get_irq() / stackinfo_get_task() / stackinfo_get_overflow()
plus the corresponding on_*_stack() predicates in asm/stacktrace.h,
so callers can ask "is this object on stack X?" by stack kind
rather than open-coded address arithmetic.
* unwind_init_common(), unwind_find_stack() and
unwind_consume_stack() helpers that enforce the
forward-progress-only invariant required for reliability.
No existing user is wired up to these helpers in this commit; the
unwinder switch comes in a follow-up. The header changes leave
on_thread_stack() with the same semantics as before, just expressed in
terms of the new helpers.
Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
Signed-off-by: Wang Han <wanghan@linux.alibaba.com>
Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
Replace the open-coded frame-pointer walker in arch_stack_walk() with a
robust kunwind state machine, modelled on arch/arm64/kernel/stacktrace.c
and retargeted to the RISC-V {fp, ra} frame record convention. The new
walker tracks stack bounds, consumes frame records monotonically,
understands the metadata pt_regs records added in the previous frame
record metadata patch, and recovers return addresses replaced by
function graph tracing and kretprobes.
This commit introduces arch_stack_walk_reliable() but does not yet
select HAVE_RELIABLE_STACKTRACE; that is done in a follow-up Kconfig
patch so this commit can be reviewed and bisected as a pure unwinder
replacement. Until that Kconfig change lands, livepatch is not yet
enabled and arch_stack_walk_reliable() has no in-tree caller.
Three related callers are updated to keep the same frame-record
assumptions everywhere:
* Function graph tracing: the old RISC-V unwinder matched function
graph return-stack entries by the saved return-address slot. That
was consistent with the static mcount path, but not with the dynamic
ftrace path where the parent slot is ftrace_regs::ra. Use the
architectural frame pointer as the function graph return-address
cookie, matching the kunwind walker.
* Perf callchains: route kernel callchain collection through
arch_stack_walk() so perf sees the same frame-pointer unwind
behaviour as dump_stack() and the upcoming livepatch path.
* dump_backtrace() / __get_wchan() / show_stack(): these now go
through arch_stack_walk(); the explicit "Call Trace:" header is
moved into dump_backtrace() to preserve the original output.
The non-frame-pointer fallback walker is kept untouched for
!CONFIG_FRAME_POINTER builds.
Signed-off-by: Wang Han <wanghan@linux.alibaba.com>
Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
Now that the metadata frame records, the kunwind state machine and
arch_stack_walk_reliable() are all in place, advertise the capability
to the rest of the kernel:
* select HAVE_RELIABLE_STACKTRACE under FRAME_POINTER && 64BIT, so
only the configurations with the tested metadata records and
FP-based reliable walker enable it.
* select HAVE_LIVEPATCH under the same condition and source
kernel/livepatch/Kconfig so the livepatch menu is reachable from
the RISC-V configuration.
The 64BIT dependency is conservative scoping rather than a hard
technical requirement: the metadata frame record, kunwind state machine
and arch_stack_walk_reliable() also build on RV32, and the IRQ-stack
frame-record adjustment fixes a latent RV32 issue. However, the syscall
livepatch selftest and module relocation path have only been exercised
on RV64 QEMU virt so far. The 64BIT gate can be relaxed in a follow-up
once RV32 has equivalent coverage.
This is split out from the unwinder change so the policy decision and
the implementation can be reviewed and reverted independently.
Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
Signed-off-by: Wang Han <wanghan@linux.alibaba.com>
Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
The syscall livepatch selftest resolves and patches a syscall wrapper symbol. To use that test for RISC-V livepatch validation, add the RISC-V FN_PREFIX definition for ARCH_HAS_SYSCALL_WRAPPER. Without this macro, the syscall livepatch selftest cannot resolve the RISC-V target symbol, and the syscall-related livepatch test fails on RISC-V. Reviewed-by: Marcos Paulo de Souza <mpdesouza@suse.com> Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com> Signed-off-by: Wang Han <wanghan@linux.alibaba.com> Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 1: "[v4,RESEND,1/7] riscv: stacktrace: Add frame record metadata" |
|
Patch 2: "[v4,RESEND,2/7] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o" |
|
Patch 2: "[v4,RESEND,2/7] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o" |
|
Patch 2: "[v4,RESEND,2/7] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o" |
|
Patch 2: "[v4,RESEND,2/7] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o" |
|
Patch 2: "[v4,RESEND,2/7] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o" |
|
Patch 2: "[v4,RESEND,2/7] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o" |
|
Patch 2: "[v4,RESEND,2/7] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o" |
|
Patch 2: "[v4,RESEND,2/7] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o" |
|
Patch 2: "[v4,RESEND,2/7] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o" |
|
Patch 2: "[v4,RESEND,2/7] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o" |
|
Patch 5: "[v4,RESEND,5/7] riscv: stacktrace: switch to frame-pointer based unwinder" |
|
Patch 5: "[v4,RESEND,5/7] riscv: stacktrace: switch to frame-pointer based unwinder" |
|
Patch 5: "[v4,RESEND,5/7] riscv: stacktrace: switch to frame-pointer based unwinder" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 6: "[v4,RESEND,6/7] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
|
Patch 7: "[v4,RESEND,7/7] selftests/livepatch: Add RISC-V syscall wrapper prefix" |
4d827ba to
89be0ce
Compare
PR for series 1117959 applied to workflow__riscv__fixes
Name: riscv: Add reliable stack unwinding for livepatch
URL: https://patchwork.kernel.org/project/linux-riscv/list/?series=1117959
Version: 4