Skip to content

Commit

Permalink
riscv: Add KPROBES_ON_FTRACE supported
Browse files Browse the repository at this point in the history
This patch adds support for kprobes on ftrace call sites to avoids
much of the overhead with regular kprobes. Try it with simple
steps:

 echo 'p:myprobe sys_clone a0=%a0 a1=%a1 stack_val=+4($stack)' > /sys/kernel/de
bug/tracing/kprobe_events
 echo 1 > /sys/kernel/debug/tracing/events/kprobes/enable
 cat /sys/kernel/debug/tracing/trace
 tracer: nop

 entries-in-buffer/entries-written: 1/1   #P:1

                                _-----=> irqs-off
                               / _----=> need-resched
                              | / _---=> hardirq/softirq
                              || / _--=> preempt-depth
                              ||| /     delay
           TASK-PID     CPU#  ||||   TIMESTAMP  FUNCTION
              | |         |   ||||      |         |
              sh-92      [000] ....   369.899962: myprobe: (sys_clone+0x0/0x28) a0=0x1200011 a1=0x0 stack_val=0x201c20ffffffe0
 cat /sys/kernel/debug/kprobes/list
ffffffe00020b584  k  sys_clone+0x0    [FTRACE]
                                       ^^^^^^

Signed-off-by: Guo Ren <[email protected]>
Reviewed-by: Masami Hiramatsu <[email protected]>
Signed-off-by: Palmer Dabbelt <[email protected]>
  • Loading branch information
guoren83 authored and palmer-dabbelt committed Jan 14, 2021
1 parent c22b0bc commit 829adda
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ config RISCV
select HAVE_GENERIC_VDSO if MMU && 64BIT
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_KPROBES
select HAVE_KPROBES_ON_FTRACE
select HAVE_KRETPROBES
select HAVE_PCI
select HAVE_PERF_EVENTS
Expand Down
1 change: 1 addition & 0 deletions arch/riscv/kernel/probes/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o simulate-insn.o
obj-$(CONFIG_KPROBES) += kprobes_trampoline.o
obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o
CFLAGS_REMOVE_simulate-insn.o = $(CC_FLAGS_FTRACE)
53 changes: 53 additions & 0 deletions arch/riscv/kernel/probes/ftrace.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0

#include <linux/kprobes.h>

/* Ftrace callback handler for kprobes -- called under preepmt disabed */
void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
struct ftrace_ops *ops, struct ftrace_regs *regs)
{
struct kprobe *p;
struct kprobe_ctlblk *kcb;

p = get_kprobe((kprobe_opcode_t *)ip);
if (unlikely(!p) || kprobe_disabled(p))
return;

kcb = get_kprobe_ctlblk();
if (kprobe_running()) {
kprobes_inc_nmissed_count(p);
} else {
unsigned long orig_ip = instruction_pointer(&(regs->regs));

instruction_pointer_set(&(regs->regs), ip);

__this_cpu_write(current_kprobe, p);
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
if (!p->pre_handler || !p->pre_handler(p, &(regs->regs))) {
/*
* Emulate singlestep (and also recover regs->pc)
* as if there is a nop
*/
instruction_pointer_set(&(regs->regs),
(unsigned long)p->addr + MCOUNT_INSN_SIZE);
if (unlikely(p->post_handler)) {
kcb->kprobe_status = KPROBE_HIT_SSDONE;
p->post_handler(p, &(regs->regs), 0);
}
instruction_pointer_set(&(regs->regs), orig_ip);
}

/*
* If pre_handler returns !0, it changes regs->pc. We have to
* skip emulating post_handler.
*/
__this_cpu_write(current_kprobe, NULL);
}
}
NOKPROBE_SYMBOL(kprobe_ftrace_handler);

int arch_prepare_kprobe_ftrace(struct kprobe *p)
{
p->ainsn.api.insn = NULL;
return 0;
}

0 comments on commit 829adda

Please sign in to comment.