aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/kprobes.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-02-25 08:34:23 -0500
committerIngo Molnar <mingo@elte.hu>2010-02-25 11:49:25 -0500
commit0f94eb634ef7af736dee5639aac1c2fe9635d089 (patch)
tree7194e60aaf439b7ad791b1cbf0fb89366fd5212a /arch/x86/kernel/kprobes.c
parentb2be84df99ebc93599c69e931a3c4a5105abfabc (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/kernel/kprobes.c')
-rw-r--r--arch/x86/kernel/kprobes.c48
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
409static 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
421void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, 409void __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
432static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs, 420static 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 */