Skip to content

Commit 19f1bc3

Browse files
Abhishek Dubeympe
authored andcommitted
powerpc: Replace kretprobe code with rethook on powerpc
This is an adaptation of commit f3a112c ("x86,rethook,kprobes: Replace kretprobe with rethook on x86") to powerpc. Rethook follows the existing kretprobe implementation, but separates it from kprobes so that it can be used by fprobe (ftrace-based function entry/exit probes). As such, this patch also enables fprobe to work on powerpc. The only other change compared to the existing kretprobe implementation is doing the return address fixup in arch_rethook_fixup_return(). Reference to other archs: commit b57c2f1 ("riscv: add riscv rethook implementation") commit 7b0a096 ("LoongArch: Replace kretprobe with rethook") Note: ===== In future, rethook will be only for kretprobe, and kretprobe will be replaced by fprobe. https://lore.kernel.org/all/172000134410.63468.13742222887213469474.stgit@devnote2/ We will adapt the above implementation for powerpc once its upstream. Until then, we can have this implementation of rethook to serve current kretprobe usecases. Reviewed-by: Naveen Rao <naveen@kernel.org> Signed-off-by: Abhishek Dubey <adubey@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://msgid.link/20240830113131.7597-1-adubey@linux.ibm.com
1 parent 6f26832 commit 19f1bc3

6 files changed

Lines changed: 81 additions & 67 deletions

File tree

arch/powerpc/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ config PPC
269269
select HAVE_PERF_EVENTS_NMI if PPC64
270270
select HAVE_PERF_REGS
271271
select HAVE_PERF_USER_STACK_DUMP
272+
select HAVE_RETHOOK if KPROBES
272273
select HAVE_REGS_AND_STACK_ACCESS_API
273274
select HAVE_RELIABLE_STACKTRACE
274275
select HAVE_RSEQ

arch/powerpc/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o
139139
obj-$(CONFIG_OPTPROBES) += optprobes.o optprobes_head.o
140140
obj-$(CONFIG_KPROBES_ON_FTRACE) += kprobes-ftrace.o
141141
obj-$(CONFIG_UPROBES) += uprobes.o
142+
obj-$(CONFIG_RETHOOK) += rethook.o
142143
obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o
143144
obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o
144145
obj-$(CONFIG_ARCH_HAS_DMA_SET_MASK) += dma-mask.o

arch/powerpc/kernel/kprobes.c

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -228,16 +228,6 @@ static nokprobe_inline void set_current_kprobe(struct kprobe *p, struct pt_regs
228228
kcb->kprobe_saved_msr = regs->msr;
229229
}
230230

231-
void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
232-
{
233-
ri->ret_addr = (kprobe_opcode_t *)regs->link;
234-
ri->fp = NULL;
235-
236-
/* Replace the return addr with trampoline addr */
237-
regs->link = (unsigned long)__kretprobe_trampoline;
238-
}
239-
NOKPROBE_SYMBOL(arch_prepare_kretprobe);
240-
241231
static int try_to_emulate(struct kprobe *p, struct pt_regs *regs)
242232
{
243233
int ret;
@@ -394,49 +384,6 @@ int kprobe_handler(struct pt_regs *regs)
394384
}
395385
NOKPROBE_SYMBOL(kprobe_handler);
396386

397-
/*
398-
* Function return probe trampoline:
399-
* - init_kprobes() establishes a probepoint here
400-
* - When the probed function returns, this probe
401-
* causes the handlers to fire
402-
*/
403-
asm(".global __kretprobe_trampoline\n"
404-
".type __kretprobe_trampoline, @function\n"
405-
"__kretprobe_trampoline:\n"
406-
"nop\n"
407-
"blr\n"
408-
".size __kretprobe_trampoline, .-__kretprobe_trampoline\n");
409-
410-
/*
411-
* Called when the probe at kretprobe trampoline is hit
412-
*/
413-
static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
414-
{
415-
unsigned long orig_ret_address;
416-
417-
orig_ret_address = __kretprobe_trampoline_handler(regs, NULL);
418-
/*
419-
* We get here through one of two paths:
420-
* 1. by taking a trap -> kprobe_handler() -> here
421-
* 2. by optprobe branch -> optimized_callback() -> opt_pre_handler() -> here
422-
*
423-
* When going back through (1), we need regs->nip to be setup properly
424-
* as it is used to determine the return address from the trap.
425-
* For (2), since nip is not honoured with optprobes, we instead setup
426-
* the link register properly so that the subsequent 'blr' in
427-
* __kretprobe_trampoline jumps back to the right instruction.
428-
*
429-
* For nip, we should set the address to the previous instruction since
430-
* we end up emulating it in kprobe_handler(), which increments the nip
431-
* again.
432-
*/
433-
regs_set_return_ip(regs, orig_ret_address - 4);
434-
regs->link = orig_ret_address;
435-
436-
return 0;
437-
}
438-
NOKPROBE_SYMBOL(trampoline_probe_handler);
439-
440387
/*
441388
* Called after single-stepping. p->addr is the address of the
442389
* instruction whose first byte has been replaced by the "breakpoint"
@@ -539,19 +486,9 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
539486
}
540487
NOKPROBE_SYMBOL(kprobe_fault_handler);
541488

542-
static struct kprobe trampoline_p = {
543-
.addr = (kprobe_opcode_t *) &__kretprobe_trampoline,
544-
.pre_handler = trampoline_probe_handler
545-
};
546-
547-
int __init arch_init_kprobes(void)
548-
{
549-
return register_kprobe(&trampoline_p);
550-
}
551-
552489
int arch_trampoline_kprobe(struct kprobe *p)
553490
{
554-
if (p->addr == (kprobe_opcode_t *)&__kretprobe_trampoline)
491+
if (p->addr == (kprobe_opcode_t *)&arch_rethook_trampoline)
555492
return 1;
556493

557494
return 0;

arch/powerpc/kernel/optprobes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static unsigned long can_optimize(struct kprobe *p)
5656
* has a 'nop' instruction, which can be emulated.
5757
* So further checks can be skipped.
5858
*/
59-
if (p->addr == (kprobe_opcode_t *)&__kretprobe_trampoline)
59+
if (p->addr == (kprobe_opcode_t *)&arch_rethook_trampoline)
6060
return addr + sizeof(kprobe_opcode_t);
6161

6262
/*

arch/powerpc/kernel/rethook.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* PowerPC implementation of rethook. This depends on kprobes.
4+
*/
5+
6+
#include <linux/kprobes.h>
7+
#include <linux/rethook.h>
8+
9+
/*
10+
* Function return trampoline:
11+
* - init_kprobes() establishes a probepoint here
12+
* - When the probed function returns, this probe
13+
* causes the handlers to fire
14+
*/
15+
asm(".global arch_rethook_trampoline\n"
16+
".type arch_rethook_trampoline, @function\n"
17+
"arch_rethook_trampoline:\n"
18+
"nop\n"
19+
"blr\n"
20+
".size arch_rethook_trampoline, .-arch_rethook_trampoline\n");
21+
22+
/*
23+
* Called when the probe at kretprobe trampoline is hit
24+
*/
25+
static int trampoline_rethook_handler(struct kprobe *p, struct pt_regs *regs)
26+
{
27+
return !rethook_trampoline_handler(regs, regs->gpr[1]);
28+
}
29+
NOKPROBE_SYMBOL(trampoline_rethook_handler);
30+
31+
void arch_rethook_prepare(struct rethook_node *rh, struct pt_regs *regs, bool mcount)
32+
{
33+
rh->ret_addr = regs->link;
34+
rh->frame = regs->gpr[1];
35+
36+
/* Replace the return addr with trampoline addr */
37+
regs->link = (unsigned long)arch_rethook_trampoline;
38+
}
39+
NOKPROBE_SYMBOL(arch_rethook_prepare);
40+
41+
/* This is called from rethook_trampoline_handler(). */
42+
void arch_rethook_fixup_return(struct pt_regs *regs, unsigned long orig_ret_address)
43+
{
44+
/*
45+
* We get here through one of two paths:
46+
* 1. by taking a trap -> kprobe_handler() -> here
47+
* 2. by optprobe branch -> optimized_callback() -> opt_pre_handler() -> here
48+
*
49+
* When going back through (1), we need regs->nip to be setup properly
50+
* as it is used to determine the return address from the trap.
51+
* For (2), since nip is not honoured with optprobes, we instead setup
52+
* the link register properly so that the subsequent 'blr' in
53+
* arch_rethook_trampoline jumps back to the right instruction.
54+
*
55+
* For nip, we should set the address to the previous instruction since
56+
* we end up emulating it in kprobe_handler(), which increments the nip
57+
* again.
58+
*/
59+
regs_set_return_ip(regs, orig_ret_address - 4);
60+
regs->link = orig_ret_address;
61+
}
62+
NOKPROBE_SYMBOL(arch_rethook_fixup_return);
63+
64+
static struct kprobe trampoline_p = {
65+
.addr = (kprobe_opcode_t *) &arch_rethook_trampoline,
66+
.pre_handler = trampoline_rethook_handler
67+
};
68+
69+
/* rethook initializer */
70+
int __init arch_init_kprobes(void)
71+
{
72+
return register_kprobe(&trampoline_p);
73+
}

arch/powerpc/kernel/stacktrace.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <asm/processor.h>
2222
#include <linux/ftrace.h>
2323
#include <asm/kprobes.h>
24+
#include <linux/rethook.h>
2425

2526
#include <asm/paca.h>
2627

@@ -133,12 +134,13 @@ int __no_sanitize_address arch_stack_walk_reliable(stack_trace_consume_fn consum
133134
* arch-dependent code, they are generic.
134135
*/
135136
ip = ftrace_graph_ret_addr(task, &graph_idx, ip, stack);
136-
#ifdef CONFIG_KPROBES
137+
137138
/*
138139
* Mark stacktraces with kretprobed functions on them
139140
* as unreliable.
140141
*/
141-
if (ip == (unsigned long)__kretprobe_trampoline)
142+
#ifdef CONFIG_RETHOOK
143+
if (ip == (unsigned long)arch_rethook_trampoline)
142144
return -EINVAL;
143145
#endif
144146

0 commit comments

Comments
 (0)