aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/kprobes.c
diff options
context:
space:
mode:
authorAbhishek Sagar <sagar.abhishek@gmail.com>2008-01-30 07:32:50 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:32:50 -0500
commitf315decbd05fefbca09bd492ae54eaa334ba826b (patch)
tree635e16d872ed000faa4d4cf3c69b3727b60025e1 /arch/x86/kernel/kprobes.c
parent4c4915627f94a81a834a7a65dee83acdfb45788c (diff)
x86: kprobes change kprobe_handler flow
Signed-off-by: Abhishek Sagar <sagar.abhishek@gmail.com> Signed-off-by: Quentin Barnes <qbarnes@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/kprobes.c')
-rw-r--r--arch/x86/kernel/kprobes.c153
1 files changed, 86 insertions, 67 deletions
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index 711fec8f6379..53ba6a5b6550 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -442,6 +442,34 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
442 /* Replace the return addr with trampoline addr */ 442 /* Replace the return addr with trampoline addr */
443 *sara = (unsigned long) &kretprobe_trampoline; 443 *sara = (unsigned long) &kretprobe_trampoline;
444} 444}
445
446static void __kprobes recursive_singlestep(struct kprobe *p,
447 struct pt_regs *regs,
448 struct kprobe_ctlblk *kcb)
449{
450 save_previous_kprobe(kcb);
451 set_current_kprobe(p, regs, kcb);
452 kprobes_inc_nmissed_count(p);
453 prepare_singlestep(p, regs);
454 kcb->kprobe_status = KPROBE_REENTER;
455}
456
457static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs,
458 struct kprobe_ctlblk *kcb)
459{
460#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
461 if (p->ainsn.boostable == 1 && !p->post_handler) {
462 /* Boost up -- we can execute copied instructions directly */
463 reset_current_kprobe();
464 regs->ip = (unsigned long)p->ainsn.insn;
465 preempt_enable_no_resched();
466 return;
467 }
468#endif
469 prepare_singlestep(p, regs);
470 kcb->kprobe_status = KPROBE_HIT_SS;
471}
472
445/* 473/*
446 * We have reentered the kprobe_handler(), since another probe was hit while 474 * We have reentered the kprobe_handler(), since another probe was hit while
447 * within the handler. We save the original kprobes variables and just single 475 * within the handler. We save the original kprobes variables and just single
@@ -450,13 +478,9 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
450static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs, 478static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
451 struct kprobe_ctlblk *kcb) 479 struct kprobe_ctlblk *kcb)
452{ 480{
453 if (kcb->kprobe_status == KPROBE_HIT_SS && 481 switch (kcb->kprobe_status) {
454 *p->ainsn.insn == BREAKPOINT_INSTRUCTION) { 482 case KPROBE_HIT_SSDONE:
455 regs->flags &= ~X86_EFLAGS_TF;
456 regs->flags |= kcb->kprobe_saved_flags;
457 return 0;
458#ifdef CONFIG_X86_64 483#ifdef CONFIG_X86_64
459 } else if (kcb->kprobe_status == KPROBE_HIT_SSDONE) {
460 /* TODO: Provide re-entrancy from post_kprobes_handler() and 484 /* TODO: Provide re-entrancy from post_kprobes_handler() and
461 * avoid exception stack corruption while single-stepping on 485 * avoid exception stack corruption while single-stepping on
462 * the instruction of the new probe. 486 * the instruction of the new probe.
@@ -464,14 +488,26 @@ static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
464 arch_disarm_kprobe(p); 488 arch_disarm_kprobe(p);
465 regs->ip = (unsigned long)p->addr; 489 regs->ip = (unsigned long)p->addr;
466 reset_current_kprobe(); 490 reset_current_kprobe();
467 return 1; 491 preempt_enable_no_resched();
492 break;
468#endif 493#endif
494 case KPROBE_HIT_ACTIVE:
495 recursive_singlestep(p, regs, kcb);
496 break;
497 case KPROBE_HIT_SS:
498 if (*p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
499 regs->flags &= ~TF_MASK;
500 regs->flags |= kcb->kprobe_saved_flags;
501 return 0;
502 } else {
503 recursive_singlestep(p, regs, kcb);
504 }
505 break;
506 default:
507 /* impossible cases */
508 WARN_ON(1);
469 } 509 }
470 save_previous_kprobe(kcb); 510
471 set_current_kprobe(p, regs, kcb);
472 kprobes_inc_nmissed_count(p);
473 prepare_singlestep(p, regs);
474 kcb->kprobe_status = KPROBE_REENTER;
475 return 1; 511 return 1;
476} 512}
477 513
@@ -481,83 +517,66 @@ static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
481 */ 517 */
482static int __kprobes kprobe_handler(struct pt_regs *regs) 518static int __kprobes kprobe_handler(struct pt_regs *regs)
483{ 519{
484 struct kprobe *p;
485 int ret = 0;
486 kprobe_opcode_t *addr; 520 kprobe_opcode_t *addr;
521 struct kprobe *p;
487 struct kprobe_ctlblk *kcb; 522 struct kprobe_ctlblk *kcb;
488 523
489 addr = (kprobe_opcode_t *)(regs->ip - sizeof(kprobe_opcode_t)); 524 addr = (kprobe_opcode_t *)(regs->ip - sizeof(kprobe_opcode_t));
525 if (*addr != BREAKPOINT_INSTRUCTION) {
526 /*
527 * The breakpoint instruction was removed right
528 * after we hit it. Another cpu has removed
529 * either a probepoint or a debugger breakpoint
530 * at this address. In either case, no further
531 * handling of this interrupt is appropriate.
532 * Back up over the (now missing) int3 and run
533 * the original instruction.
534 */
535 regs->ip = (unsigned long)addr;
536 return 1;
537 }
490 538
491 /* 539 /*
492 * We don't want to be preempted for the entire 540 * We don't want to be preempted for the entire
493 * duration of kprobe processing 541 * duration of kprobe processing. We conditionally
542 * re-enable preemption at the end of this function,
543 * and also in reenter_kprobe() and setup_singlestep().
494 */ 544 */
495 preempt_disable(); 545 preempt_disable();
496 kcb = get_kprobe_ctlblk();
497 546
547 kcb = get_kprobe_ctlblk();
498 p = get_kprobe(addr); 548 p = get_kprobe(addr);
549
499 if (p) { 550 if (p) {
500 /* Check we're not actually recursing */
501 if (kprobe_running()) { 551 if (kprobe_running()) {
502 ret = reenter_kprobe(p, regs, kcb); 552 if (reenter_kprobe(p, regs, kcb))
503 if (kcb->kprobe_status == KPROBE_REENTER) 553 return 1;
504 {
505 ret = 1;
506 goto out;
507 }
508 goto preempt_out;
509 } else { 554 } else {
510 set_current_kprobe(p, regs, kcb); 555 set_current_kprobe(p, regs, kcb);
511 kcb->kprobe_status = KPROBE_HIT_ACTIVE; 556 kcb->kprobe_status = KPROBE_HIT_ACTIVE;
512 if (p->pre_handler && p->pre_handler(p, regs)) 557
513 {
514 /* handler set things up, skip ss setup */
515 ret = 1;
516 goto out;
517 }
518 }
519 } else {
520 if (*addr != BREAKPOINT_INSTRUCTION) {
521 /* 558 /*
522 * The breakpoint instruction was removed right 559 * If we have no pre-handler or it returned 0, we
523 * after we hit it. Another cpu has removed 560 * continue with normal processing. If we have a
524 * either a probepoint or a debugger breakpoint 561 * pre-handler and it returned non-zero, it prepped
525 * at this address. In either case, no further 562 * for calling the break_handler below on re-entry
526 * handling of this interrupt is appropriate. 563 * for jprobe processing, so get out doing nothing
527 * Back up over the (now missing) int3 and run 564 * more here.
528 * the original instruction.
529 */ 565 */
530 regs->ip = (unsigned long)addr; 566 if (!p->pre_handler || !p->pre_handler(p, regs))
531 ret = 1; 567 setup_singlestep(p, regs, kcb);
532 goto preempt_out; 568 return 1;
533 } 569 }
534 if (kprobe_running()) { 570 } else if (kprobe_running()) {
535 p = __get_cpu_var(current_kprobe); 571 p = __get_cpu_var(current_kprobe);
536 if (p->break_handler && p->break_handler(p, regs)) 572 if (p->break_handler && p->break_handler(p, regs)) {
537 goto ss_probe; 573 setup_singlestep(p, regs, kcb);
574 return 1;
538 } 575 }
539 /* Not one of ours: let kernel handle it */ 576 } /* else: not a kprobe fault; let the kernel handle it */
540 goto preempt_out;
541 }
542 577
543ss_probe:
544 ret = 1;
545#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
546 if (p->ainsn.boostable == 1 && !p->post_handler) {
547 /* Boost up -- we can execute copied instructions directly */
548 reset_current_kprobe();
549 regs->ip = (unsigned long)p->ainsn.insn;
550 goto preempt_out;
551 }
552#endif
553 prepare_singlestep(p, regs);
554 kcb->kprobe_status = KPROBE_HIT_SS;
555 goto out;
556
557preempt_out:
558 preempt_enable_no_resched(); 578 preempt_enable_no_resched();
559out: 579 return 0;
560 return ret;
561} 580}
562 581
563/* 582/*