* [PATCH] uprobes: Restore original return address in uretprobe context
@ 2026-07-17 8:23 daichengrong
2026-07-23 0:31 ` Masami Hiramatsu
0 siblings, 1 reply; 2+ messages in thread
From: daichengrong @ 2026-07-17 8:23 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou
Cc: linux-riscv, linux-kernel, linux-trace-kernel, daichengrong
uretprobe replaces the original return address of a probed function with
a trampoline address to capture function return events.
After the trampoline is entered and the uretprobe handler completes, the
original return address needs to be restored in the user register context
to keep the register state consistent with the state before probing.
Add an architecture-specific hook for restoring the original return
address during uretprobe handling.
The initial implementation adds support for RISC-V. Other architectures
keep the default empty implementation until their corresponding restore
logic is implemented.
Signed-off-by: daichengrong <daichengrong@iscas.ac.cn>
---
arch/riscv/kernel/probes/uprobes.c | 7 +++++++
include/linux/uprobes.h | 1 +
kernel/events/uprobes.c | 5 +++++
3 files changed, 13 insertions(+)
diff --git a/arch/riscv/kernel/probes/uprobes.c b/arch/riscv/kernel/probes/uprobes.c
index eb177d0ce8ab..0b1b94d9683e 100644
--- a/arch/riscv/kernel/probes/uprobes.c
+++ b/arch/riscv/kernel/probes/uprobes.c
@@ -139,6 +139,13 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
return ra;
}
+void
+arch_uretprobe_hijack_set_addr(unsigned long orig_ret_vaddr,
+ struct pt_regs *regs)
+{
+ regs->ra = orig_ret_vaddr;
+}
+
int arch_uprobe_exception_notify(struct notifier_block *self,
unsigned long val, void *data)
{
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index f548fea2adec..2d0dc919845d 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -230,6 +230,7 @@ extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs);
+extern void arch_uretprobe_hijack_set_addr(unsigned long orig_ret_vaddr, struct pt_regs *regs);
extern bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx, struct pt_regs *regs);
extern bool arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs);
extern void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 4084e926e284..deecaae01ab7 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1748,6 +1748,10 @@ void * __weak arch_uretprobe_trampoline(unsigned long *psize)
return &insn;
}
+void __weak arch_uretprobe_hijack_set_addr(unsigned long orig_ret_vaddr, struct pt_regs *regs)
+{
+}
+
static struct xol_area *__create_xol_area(unsigned long vaddr)
{
struct mm_struct *mm = current->mm;
@@ -2659,6 +2663,7 @@ void uprobe_handle_trampoline(struct pt_regs *regs)
valid = !next_chain || arch_uretprobe_is_alive(next_chain, RP_CHECK_RET, regs);
instruction_pointer_set(regs, ri->orig_ret_vaddr);
+ arch_uretprobe_hijack_set_addr(ri->orig_ret_vaddr, regs);
do {
/* pop current instance from the stack of pending return instances,
* as it's not pending anymore: we just fixed up original
--
2.25.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] uprobes: Restore original return address in uretprobe context
2026-07-17 8:23 [PATCH] uprobes: Restore original return address in uretprobe context daichengrong
@ 2026-07-23 0:31 ` Masami Hiramatsu
0 siblings, 0 replies; 2+ messages in thread
From: Masami Hiramatsu @ 2026-07-23 0:31 UTC (permalink / raw)
To: daichengrong
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, linux-riscv,
linux-kernel, linux-trace-kernel
On Fri, 17 Jul 2026 16:23:31 +0800
daichengrong <daichengrong@iscas.ac.cn> wrote:
> uretprobe replaces the original return address of a probed function with
> a trampoline address to capture function return events.
>
> After the trampoline is entered and the uretprobe handler completes, the
> original return address needs to be restored in the user register context
> to keep the register state consistent with the state before probing.
>
> Add an architecture-specific hook for restoring the original return
> address during uretprobe handling.
>
> The initial implementation adds support for RISC-V. Other architectures
> keep the default empty implementation until their corresponding restore
> logic is implemented.
>
> Signed-off-by: daichengrong <daichengrong@iscas.ac.cn>
> ---
> arch/riscv/kernel/probes/uprobes.c | 7 +++++++
> include/linux/uprobes.h | 1 +
> kernel/events/uprobes.c | 5 +++++
> 3 files changed, 13 insertions(+)
>
> diff --git a/arch/riscv/kernel/probes/uprobes.c b/arch/riscv/kernel/probes/uprobes.c
> index eb177d0ce8ab..0b1b94d9683e 100644
> --- a/arch/riscv/kernel/probes/uprobes.c
> +++ b/arch/riscv/kernel/probes/uprobes.c
> @@ -139,6 +139,13 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
> return ra;
> }
>
> +void
> +arch_uretprobe_hijack_set_addr(unsigned long orig_ret_vaddr,
> + struct pt_regs *regs)
OK, but hijack may not be a good naming, what about
"arch_uretprobe_restore_return_address()"?
And I need RISC-V maintainer's review.
Thank you,
> +{
> + regs->ra = orig_ret_vaddr;
> +}
> +
> int arch_uprobe_exception_notify(struct notifier_block *self,
> unsigned long val, void *data)
> {
> diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
> index f548fea2adec..2d0dc919845d 100644
> --- a/include/linux/uprobes.h
> +++ b/include/linux/uprobes.h
> @@ -230,6 +230,7 @@ extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
> extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
> extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
> extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs);
> +extern void arch_uretprobe_hijack_set_addr(unsigned long orig_ret_vaddr, struct pt_regs *regs);
> extern bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx, struct pt_regs *regs);
> extern bool arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs);
> extern void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index 4084e926e284..deecaae01ab7 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -1748,6 +1748,10 @@ void * __weak arch_uretprobe_trampoline(unsigned long *psize)
> return &insn;
> }
>
> +void __weak arch_uretprobe_hijack_set_addr(unsigned long orig_ret_vaddr, struct pt_regs *regs)
> +{
> +}
> +
> static struct xol_area *__create_xol_area(unsigned long vaddr)
> {
> struct mm_struct *mm = current->mm;
> @@ -2659,6 +2663,7 @@ void uprobe_handle_trampoline(struct pt_regs *regs)
> valid = !next_chain || arch_uretprobe_is_alive(next_chain, RP_CHECK_RET, regs);
>
> instruction_pointer_set(regs, ri->orig_ret_vaddr);
> + arch_uretprobe_hijack_set_addr(ri->orig_ret_vaddr, regs);
> do {
> /* pop current instance from the stack of pending return instances,
> * as it's not pending anymore: we just fixed up original
> --
> 2.25.1
>
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-23 0:31 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-17 8:23 [PATCH] uprobes: Restore original return address in uretprobe context daichengrong
2026-07-23 0:31 ` Masami Hiramatsu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox