diff options
-rw-r--r-- | arch/x86/include/asm/kprobes.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/kprobes.c | 48 | ||||
-rw-r--r-- | include/linux/kprobes.h | 2 | ||||
-rw-r--r-- | kernel/kprobes.c | 2 |
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 | ||
31 | struct pt_regs; | 32 | struct pt_regs; |
32 | struct kprobe; | 33 | struct 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 */ | ||
1057 | void __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 | } | ||
1091 | end: | ||
1092 | local_irq_restore(flags); | ||
1093 | } | ||
1094 | |||
1095 | int __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 | |||
1055 | int __init arch_init_kprobes(void) | 1103 | int __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 |
320 | extern void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, | 320 | extern 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); |
322 | extern int arch_prepare_kprobe_ftrace(struct kprobe *p); | 322 | extern 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 |
923 | static struct ftrace_ops kprobe_ftrace_ops __read_mostly = { | 923 | static 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 | }; |
927 | static int kprobe_ftrace_enabled; | 927 | static int kprobe_ftrace_enabled; |