diff options
Diffstat (limited to 'arch/x86/kernel/kprobes/core.c')
| -rw-r--r-- | arch/x86/kernel/kprobes/core.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index f7e3cd50ece0..98f654d466e5 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c | |||
| @@ -1020,6 +1020,15 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 1020 | regs->flags &= ~X86_EFLAGS_IF; | 1020 | regs->flags &= ~X86_EFLAGS_IF; |
| 1021 | trace_hardirqs_off(); | 1021 | trace_hardirqs_off(); |
| 1022 | regs->ip = (unsigned long)(jp->entry); | 1022 | regs->ip = (unsigned long)(jp->entry); |
| 1023 | |||
| 1024 | /* | ||
| 1025 | * jprobes use jprobe_return() which skips the normal return | ||
| 1026 | * path of the function, and this messes up the accounting of the | ||
| 1027 | * function graph tracer to get messed up. | ||
| 1028 | * | ||
| 1029 | * Pause function graph tracing while performing the jprobe function. | ||
| 1030 | */ | ||
| 1031 | pause_graph_tracing(); | ||
| 1023 | return 1; | 1032 | return 1; |
| 1024 | } | 1033 | } |
| 1025 | NOKPROBE_SYMBOL(setjmp_pre_handler); | 1034 | NOKPROBE_SYMBOL(setjmp_pre_handler); |
| @@ -1048,24 +1057,25 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 1048 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 1057 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
| 1049 | u8 *addr = (u8 *) (regs->ip - 1); | 1058 | u8 *addr = (u8 *) (regs->ip - 1); |
| 1050 | struct jprobe *jp = container_of(p, struct jprobe, kp); | 1059 | struct jprobe *jp = container_of(p, struct jprobe, kp); |
| 1060 | void *saved_sp = kcb->jprobe_saved_sp; | ||
| 1051 | 1061 | ||
| 1052 | if ((addr > (u8 *) jprobe_return) && | 1062 | if ((addr > (u8 *) jprobe_return) && |
| 1053 | (addr < (u8 *) jprobe_return_end)) { | 1063 | (addr < (u8 *) jprobe_return_end)) { |
| 1054 | if (stack_addr(regs) != kcb->jprobe_saved_sp) { | 1064 | if (stack_addr(regs) != saved_sp) { |
| 1055 | struct pt_regs *saved_regs = &kcb->jprobe_saved_regs; | 1065 | struct pt_regs *saved_regs = &kcb->jprobe_saved_regs; |
| 1056 | printk(KERN_ERR | 1066 | printk(KERN_ERR |
| 1057 | "current sp %p does not match saved sp %p\n", | 1067 | "current sp %p does not match saved sp %p\n", |
| 1058 | stack_addr(regs), kcb->jprobe_saved_sp); | 1068 | stack_addr(regs), saved_sp); |
| 1059 | printk(KERN_ERR "Saved registers for jprobe %p\n", jp); | 1069 | printk(KERN_ERR "Saved registers for jprobe %p\n", jp); |
| 1060 | show_regs(saved_regs); | 1070 | show_regs(saved_regs); |
| 1061 | printk(KERN_ERR "Current registers\n"); | 1071 | printk(KERN_ERR "Current registers\n"); |
| 1062 | show_regs(regs); | 1072 | show_regs(regs); |
| 1063 | BUG(); | 1073 | BUG(); |
| 1064 | } | 1074 | } |
| 1075 | /* It's OK to start function graph tracing again */ | ||
| 1076 | unpause_graph_tracing(); | ||
| 1065 | *regs = kcb->jprobe_saved_regs; | 1077 | *regs = kcb->jprobe_saved_regs; |
| 1066 | memcpy((kprobe_opcode_t *)(kcb->jprobe_saved_sp), | 1078 | memcpy(saved_sp, kcb->jprobes_stack, MIN_STACK_SIZE(saved_sp)); |
| 1067 | kcb->jprobes_stack, | ||
| 1068 | MIN_STACK_SIZE(kcb->jprobe_saved_sp)); | ||
| 1069 | preempt_enable_no_resched(); | 1079 | preempt_enable_no_resched(); |
| 1070 | return 1; | 1080 | return 1; |
| 1071 | } | 1081 | } |
