diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2010-02-25 08:34:23 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-02-25 11:49:25 -0500 |
commit | 0f94eb634ef7af736dee5639aac1c2fe9635d089 (patch) | |
tree | 7194e60aaf439b7ad791b1cbf0fb89366fd5212a /arch/x86 | |
parent | b2be84df99ebc93599c69e931a3c4a5105abfabc (diff) |
kprobes/x86: Boost probes when reentering
Integrate prepare_singlestep() into setup_singlestep() to boost
up reenter probes, if possible.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Anders Kaseorg <andersk@ksplice.com>
Cc: Tim Abbott <tabbott@ksplice.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Jason Baron <jbaron@redhat.com>
Cc: Mathieu Desnoyers <compudj@krystal.dyndns.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
LKML-Reference: <20100225133423.6725.12071.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/kprobes.c | 48 |
1 files changed, 26 insertions, 22 deletions
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index 15177cdfdd00..c69bb65006f3 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c | |||
@@ -406,18 +406,6 @@ static void __kprobes restore_btf(void) | |||
406 | update_debugctlmsr(current->thread.debugctlmsr); | 406 | update_debugctlmsr(current->thread.debugctlmsr); |
407 | } | 407 | } |
408 | 408 | ||
409 | static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
410 | { | ||
411 | clear_btf(); | ||
412 | regs->flags |= X86_EFLAGS_TF; | ||
413 | regs->flags &= ~X86_EFLAGS_IF; | ||
414 | /* single step inline if the instruction is an int3 */ | ||
415 | if (p->opcode == BREAKPOINT_INSTRUCTION) | ||
416 | regs->ip = (unsigned long)p->addr; | ||
417 | else | ||
418 | regs->ip = (unsigned long)p->ainsn.insn; | ||
419 | } | ||
420 | |||
421 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, | 409 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, |
422 | struct pt_regs *regs) | 410 | struct pt_regs *regs) |
423 | { | 411 | { |
@@ -430,19 +418,38 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, | |||
430 | } | 418 | } |
431 | 419 | ||
432 | static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs, | 420 | static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs, |
433 | struct kprobe_ctlblk *kcb) | 421 | struct kprobe_ctlblk *kcb, int reenter) |
434 | { | 422 | { |
435 | #if !defined(CONFIG_PREEMPT) | 423 | #if !defined(CONFIG_PREEMPT) |
436 | if (p->ainsn.boostable == 1 && !p->post_handler) { | 424 | if (p->ainsn.boostable == 1 && !p->post_handler) { |
437 | /* Boost up -- we can execute copied instructions directly */ | 425 | /* Boost up -- we can execute copied instructions directly */ |
438 | reset_current_kprobe(); | 426 | if (!reenter) |
427 | reset_current_kprobe(); | ||
428 | /* | ||
429 | * Reentering boosted probe doesn't reset current_kprobe, | ||
430 | * nor set current_kprobe, because it doesn't use single | ||
431 | * stepping. | ||
432 | */ | ||
439 | regs->ip = (unsigned long)p->ainsn.insn; | 433 | regs->ip = (unsigned long)p->ainsn.insn; |
440 | preempt_enable_no_resched(); | 434 | preempt_enable_no_resched(); |
441 | return; | 435 | return; |
442 | } | 436 | } |
443 | #endif | 437 | #endif |
444 | prepare_singlestep(p, regs); | 438 | if (reenter) { |
445 | kcb->kprobe_status = KPROBE_HIT_SS; | 439 | save_previous_kprobe(kcb); |
440 | set_current_kprobe(p, regs, kcb); | ||
441 | kcb->kprobe_status = KPROBE_REENTER; | ||
442 | } else | ||
443 | kcb->kprobe_status = KPROBE_HIT_SS; | ||
444 | /* Prepare real single stepping */ | ||
445 | clear_btf(); | ||
446 | regs->flags |= X86_EFLAGS_TF; | ||
447 | regs->flags &= ~X86_EFLAGS_IF; | ||
448 | /* single step inline if the instruction is an int3 */ | ||
449 | if (p->opcode == BREAKPOINT_INSTRUCTION) | ||
450 | regs->ip = (unsigned long)p->addr; | ||
451 | else | ||
452 | regs->ip = (unsigned long)p->ainsn.insn; | ||
446 | } | 453 | } |
447 | 454 | ||
448 | /* | 455 | /* |
@@ -456,11 +463,8 @@ static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs, | |||
456 | switch (kcb->kprobe_status) { | 463 | switch (kcb->kprobe_status) { |
457 | case KPROBE_HIT_SSDONE: | 464 | case KPROBE_HIT_SSDONE: |
458 | case KPROBE_HIT_ACTIVE: | 465 | case KPROBE_HIT_ACTIVE: |
459 | save_previous_kprobe(kcb); | ||
460 | set_current_kprobe(p, regs, kcb); | ||
461 | kprobes_inc_nmissed_count(p); | 466 | kprobes_inc_nmissed_count(p); |
462 | prepare_singlestep(p, regs); | 467 | setup_singlestep(p, regs, kcb, 1); |
463 | kcb->kprobe_status = KPROBE_REENTER; | ||
464 | break; | 468 | break; |
465 | case KPROBE_HIT_SS: | 469 | case KPROBE_HIT_SS: |
466 | /* A probe has been hit in the codepath leading up to, or just | 470 | /* A probe has been hit in the codepath leading up to, or just |
@@ -535,13 +539,13 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
535 | * more here. | 539 | * more here. |
536 | */ | 540 | */ |
537 | if (!p->pre_handler || !p->pre_handler(p, regs)) | 541 | if (!p->pre_handler || !p->pre_handler(p, regs)) |
538 | setup_singlestep(p, regs, kcb); | 542 | setup_singlestep(p, regs, kcb, 0); |
539 | return 1; | 543 | return 1; |
540 | } | 544 | } |
541 | } else if (kprobe_running()) { | 545 | } else if (kprobe_running()) { |
542 | p = __get_cpu_var(current_kprobe); | 546 | p = __get_cpu_var(current_kprobe); |
543 | if (p->break_handler && p->break_handler(p, regs)) { | 547 | if (p->break_handler && p->break_handler(p, regs)) { |
544 | setup_singlestep(p, regs, kcb); | 548 | setup_singlestep(p, regs, kcb, 0); |
545 | return 1; | 549 | return 1; |
546 | } | 550 | } |
547 | } /* else: not a kprobe fault; let the kernel handle it */ | 551 | } /* else: not a kprobe fault; let the kernel handle it */ |