aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/kprobes.h1
-rw-r--r--arch/x86/kernel/kprobes.c48
-rw-r--r--include/linux/kprobes.h2
-rw-r--r--kernel/kprobes.c2
4 files changed, 51 insertions, 2 deletions
diff --git a/arch/x86/include/asm/kprobes.h b/arch/x86/include/asm/kprobes.h
index 547882539157..d3ddd17405d0 100644
--- a/arch/x86/include/asm/kprobes.h
+++ b/arch/x86/include/asm/kprobes.h
@@ -27,6 +27,7 @@
27#include <asm/insn.h> 27#include <asm/insn.h>
28 28
29#define __ARCH_WANT_KPROBES_INSN_SLOT 29#define __ARCH_WANT_KPROBES_INSN_SLOT
30#define ARCH_SUPPORTS_KPROBES_ON_FTRACE
30 31
31struct pt_regs; 32struct pt_regs;
32struct kprobe; 33struct kprobe;
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index e2f751efb7b1..47ae1023a93c 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -1052,6 +1052,54 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
1052 return 0; 1052 return 0;
1053} 1053}
1054 1054
1055#ifdef KPROBES_CAN_USE_FTRACE
1056/* Ftrace callback handler for kprobes */
1057void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
1058 struct ftrace_ops *ops, struct pt_regs *regs)
1059{
1060 struct kprobe *p;
1061 struct kprobe_ctlblk *kcb;
1062 unsigned long flags;
1063
1064 /* Disable irq for emulating a breakpoint and avoiding preempt */
1065 local_irq_save(flags);
1066
1067 p = get_kprobe((kprobe_opcode_t *)ip);
1068 if (unlikely(!p) || kprobe_disabled(p))
1069 goto end;
1070
1071 kcb = get_kprobe_ctlblk();
1072 if (kprobe_running()) {
1073 kprobes_inc_nmissed_count(p);
1074 } else {
1075 regs->ip += sizeof(kprobe_opcode_t);
1076
1077 __this_cpu_write(current_kprobe, p);
1078 kcb->kprobe_status = KPROBE_HIT_ACTIVE;
1079 if (p->pre_handler)
1080 p->pre_handler(p, regs);
1081
1082 if (unlikely(p->post_handler)) {
1083 /* Emulate singlestep as if there is a 5byte nop */
1084 regs->ip = ip + MCOUNT_INSN_SIZE;
1085 kcb->kprobe_status = KPROBE_HIT_SSDONE;
1086 p->post_handler(p, regs, 0);
1087 }
1088 __this_cpu_write(current_kprobe, NULL);
1089 regs->ip = ip; /* Recover for next callback */
1090 }
1091end:
1092 local_irq_restore(flags);
1093}
1094
1095int __kprobes arch_prepare_kprobe_ftrace(struct kprobe *p)
1096{
1097 p->ainsn.insn = NULL;
1098 p->ainsn.boostable = -1;
1099 return 0;
1100}
1101#endif
1102
1055int __init arch_init_kprobes(void) 1103int __init arch_init_kprobes(void)
1056{ 1104{
1057 return arch_init_optprobes(); 1105 return arch_init_optprobes();
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index aa0d05e852e3..23755ba42abc 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -318,7 +318,7 @@ extern int proc_kprobes_optimization_handler(struct ctl_table *table,
318#endif /* CONFIG_OPTPROBES */ 318#endif /* CONFIG_OPTPROBES */
319#ifdef KPROBES_CAN_USE_FTRACE 319#ifdef KPROBES_CAN_USE_FTRACE
320extern void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, 320extern void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
321 struct pt_regs *regs); 321 struct ftrace_ops *ops, struct pt_regs *regs);
322extern int arch_prepare_kprobe_ftrace(struct kprobe *p); 322extern int arch_prepare_kprobe_ftrace(struct kprobe *p);
323#endif 323#endif
324 324
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 69c16efc315b..35b4315d84f5 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -921,7 +921,7 @@ static __kprobes struct kprobe *alloc_aggr_kprobe(struct kprobe *p)
921 921
922#ifdef KPROBES_CAN_USE_FTRACE 922#ifdef KPROBES_CAN_USE_FTRACE
923static struct ftrace_ops kprobe_ftrace_ops __read_mostly = { 923static struct ftrace_ops kprobe_ftrace_ops __read_mostly = {
924 .regs_func = kprobe_ftrace_handler, 924 .func = kprobe_ftrace_handler,
925 .flags = FTRACE_OPS_FL_SAVE_REGS, 925 .flags = FTRACE_OPS_FL_SAVE_REGS,
926}; 926};
927static int kprobe_ftrace_enabled; 927static int kprobe_ftrace_enabled;