Skip to content

Commit 09e679c

Browse files
seehearfeelchenhuacai
authored andcommitted
LoongArch: Add kprobes on ftrace support
Add kprobe_ftrace_handler() and arch_prepare_kprobe_ftrace() to support kprobes on ftrace, the code is similar with x86 and riscv. Here is a simple example: # echo 'p:myprobe kernel_clone' > /sys/kernel/debug/tracing/kprobe_events # echo 'r:myretprobe kernel_clone $retval' >> /sys/kernel/debug/tracing/kprobe_events # echo 1 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enable # echo 1 > /sys/kernel/debug/tracing/events/kprobes/myretprobe/enable # echo 1 > /sys/kernel/debug/tracing/tracing_on # cat /sys/kernel/debug/tracing/trace # tracer: nop # # entries-in-buffer/entries-written: 2/2 #P:4 # # _-----=> irqs-off/BH-disabled # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / _-=> migrate-disable # |||| / delay # TASK-PID CPU# ||||| TIMESTAMP FUNCTION # | | | ||||| | | bash-488 [002] ..... 2041.190681: myprobe: (kernel_clone+0x0/0x40c) bash-488 [002] ..... 2041.190788: myretprobe: (__do_sys_clone+0x84/0xb8 <- kernel_clone) arg1=0x200 Tested-by: Jeff Xie <[email protected]> Signed-off-by: Tiezhu Yang <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent 3f55368 commit 09e679c

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

arch/loongarch/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ config LOONGARCH
107107
select HAVE_IRQ_EXIT_ON_IRQ_STACK
108108
select HAVE_IRQ_TIME_ACCOUNTING
109109
select HAVE_KPROBES
110+
select HAVE_KPROBES_ON_FTRACE
110111
select HAVE_KRETPROBES
111112
select HAVE_MOD_ARCH_SPECIFIC
112113
select HAVE_NMI

arch/loongarch/kernel/ftrace_dyn.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
#include <linux/ftrace.h>
9+
#include <linux/kprobes.h>
910
#include <linux/uaccess.h>
1011

1112
#include <asm/inst.h>
@@ -271,3 +272,66 @@ int ftrace_disable_ftrace_graph_caller(void)
271272
}
272273
#endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */
273274
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
275+
276+
#ifdef CONFIG_KPROBES_ON_FTRACE
277+
/* Ftrace callback handler for kprobes -- called under preepmt disabled */
278+
void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
279+
struct ftrace_ops *ops, struct ftrace_regs *fregs)
280+
{
281+
int bit;
282+
struct pt_regs *regs;
283+
struct kprobe *p;
284+
struct kprobe_ctlblk *kcb;
285+
286+
bit = ftrace_test_recursion_trylock(ip, parent_ip);
287+
if (bit < 0)
288+
return;
289+
290+
p = get_kprobe((kprobe_opcode_t *)ip);
291+
if (unlikely(!p) || kprobe_disabled(p))
292+
goto out;
293+
294+
regs = ftrace_get_regs(fregs);
295+
if (!regs)
296+
goto out;
297+
298+
kcb = get_kprobe_ctlblk();
299+
if (kprobe_running()) {
300+
kprobes_inc_nmissed_count(p);
301+
} else {
302+
unsigned long orig_ip = instruction_pointer(regs);
303+
304+
instruction_pointer_set(regs, ip);
305+
306+
__this_cpu_write(current_kprobe, p);
307+
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
308+
if (!p->pre_handler || !p->pre_handler(p, regs)) {
309+
/*
310+
* Emulate singlestep (and also recover regs->csr_era)
311+
* as if there is a nop
312+
*/
313+
instruction_pointer_set(regs, (unsigned long)p->addr + MCOUNT_INSN_SIZE);
314+
if (unlikely(p->post_handler)) {
315+
kcb->kprobe_status = KPROBE_HIT_SSDONE;
316+
p->post_handler(p, regs, 0);
317+
}
318+
instruction_pointer_set(regs, orig_ip);
319+
}
320+
321+
/*
322+
* If pre_handler returns !0, it changes regs->csr_era. We have to
323+
* skip emulating post_handler.
324+
*/
325+
__this_cpu_write(current_kprobe, NULL);
326+
}
327+
out:
328+
ftrace_test_recursion_unlock(bit);
329+
}
330+
NOKPROBE_SYMBOL(kprobe_ftrace_handler);
331+
332+
int arch_prepare_kprobe_ftrace(struct kprobe *p)
333+
{
334+
p->ainsn.insn = NULL;
335+
return 0;
336+
}
337+
#endif /* CONFIG_KPROBES_ON_FTRACE */

0 commit comments

Comments
 (0)