diff options
author | Abhishek Sagar <sagar.abhishek@gmail.com> | 2008-01-30 07:32:50 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:32:50 -0500 |
commit | f315decbd05fefbca09bd492ae54eaa334ba826b (patch) | |
tree | 635e16d872ed000faa4d4cf3c69b3727b60025e1 /arch/x86/kernel/kprobes.c | |
parent | 4c4915627f94a81a834a7a65dee83acdfb45788c (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.c | 153 |
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 | |||
446 | static 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 | |||
457 | static 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, | |||
450 | static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs, | 478 | static 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 | */ |
482 | static int __kprobes kprobe_handler(struct pt_regs *regs) | 518 | static 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 | ||
543 | ss_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 | |||
557 | preempt_out: | ||
558 | preempt_enable_no_resched(); | 578 | preempt_enable_no_resched(); |
559 | out: | 579 | return 0; |
560 | return ret; | ||
561 | } | 580 | } |
562 | 581 | ||
563 | /* | 582 | /* |