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 | |
| 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>
| -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 */ |
