diff options
author | Harvey Harrison <harvey.harrison@gmail.com> | 2008-01-30 07:32:19 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:32:19 -0500 |
commit | b97601563704751162b122c652d7f390b8f480d2 (patch) | |
tree | 81b0e2a22fb19ddb27bcb3c0bba769feafdc26e4 /arch/x86/kernel/kprobes.c | |
parent | 33cb52438341d6e2d7e06e3b64ed776bc54a2ca4 (diff) |
x86: kprobes change kprobe_handler flow
Make the control flow of kprobe_handler more obvious.
Collapse the separate if blocks/gotos with if/else blocks
this unifies the duplication of the check for a breakpoint
instruction race with another cpu.
Create two jump targets:
preempt_out: re-enables preemption before returning ret
out: only returns ret
Signed-off-by: Harvey Harrison <harvey.harrison@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 | 60 |
1 files changed, 28 insertions, 32 deletions
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index 80bcb7635465..a72e02bf1135 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c | |||
@@ -494,32 +494,28 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
494 | preempt_disable(); | 494 | preempt_disable(); |
495 | kcb = get_kprobe_ctlblk(); | 495 | kcb = get_kprobe_ctlblk(); |
496 | 496 | ||
497 | /* Check we're not actually recursing */ | 497 | p = get_kprobe(addr); |
498 | if (kprobe_running()) { | 498 | if (p) { |
499 | p = get_kprobe(addr); | 499 | /* Check we're not actually recursing */ |
500 | if (p) { | 500 | if (kprobe_running()) { |
501 | ret = reenter_kprobe(p, regs, kcb); | 501 | ret = reenter_kprobe(p, regs, kcb); |
502 | if (kcb->kprobe_status == KPROBE_REENTER) | 502 | if (kcb->kprobe_status == KPROBE_REENTER) |
503 | return 1; | 503 | { |
504 | ret = 1; | ||
505 | goto out; | ||
506 | } | ||
507 | goto preempt_out; | ||
504 | } else { | 508 | } else { |
505 | if (*addr != BREAKPOINT_INSTRUCTION) { | 509 | set_current_kprobe(p, regs, kcb); |
506 | /* The breakpoint instruction was removed by | 510 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; |
507 | * another cpu right after we hit, no further | 511 | if (p->pre_handler && p->pre_handler(p, regs)) |
508 | * handling of this interrupt is appropriate | 512 | { |
509 | */ | 513 | /* handler set things up, skip ss setup */ |
510 | regs->ip = (unsigned long)addr; | ||
511 | ret = 1; | 514 | ret = 1; |
512 | goto no_kprobe; | 515 | goto out; |
513 | } | 516 | } |
514 | p = __get_cpu_var(current_kprobe); | ||
515 | if (p->break_handler && p->break_handler(p, regs)) | ||
516 | goto ss_probe; | ||
517 | } | 517 | } |
518 | goto no_kprobe; | 518 | } else { |
519 | } | ||
520 | |||
521 | p = get_kprobe(addr); | ||
522 | if (!p) { | ||
523 | if (*addr != BREAKPOINT_INSTRUCTION) { | 519 | if (*addr != BREAKPOINT_INSTRUCTION) { |
524 | /* | 520 | /* |
525 | * The breakpoint instruction was removed right | 521 | * The breakpoint instruction was removed right |
@@ -532,34 +528,34 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
532 | */ | 528 | */ |
533 | regs->ip = (unsigned long)addr; | 529 | regs->ip = (unsigned long)addr; |
534 | ret = 1; | 530 | ret = 1; |
531 | goto preempt_out; | ||
532 | } | ||
533 | if (kprobe_running()) { | ||
534 | p = __get_cpu_var(current_kprobe); | ||
535 | if (p->break_handler && p->break_handler(p, regs)) | ||
536 | goto ss_probe; | ||
535 | } | 537 | } |
536 | /* Not one of ours: let kernel handle it */ | 538 | /* Not one of ours: let kernel handle it */ |
537 | goto no_kprobe; | 539 | goto preempt_out; |
538 | } | 540 | } |
539 | 541 | ||
540 | set_current_kprobe(p, regs, kcb); | ||
541 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; | ||
542 | |||
543 | if (p->pre_handler && p->pre_handler(p, regs)) | ||
544 | /* handler has already set things up, so skip ss setup */ | ||
545 | return 1; | ||
546 | |||
547 | ss_probe: | 542 | ss_probe: |
543 | ret = 1; | ||
548 | #if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM) | 544 | #if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM) |
549 | if (p->ainsn.boostable == 1 && !p->post_handler) { | 545 | if (p->ainsn.boostable == 1 && !p->post_handler) { |
550 | /* Boost up -- we can execute copied instructions directly */ | 546 | /* Boost up -- we can execute copied instructions directly */ |
551 | reset_current_kprobe(); | 547 | reset_current_kprobe(); |
552 | regs->ip = (unsigned long)p->ainsn.insn; | 548 | regs->ip = (unsigned long)p->ainsn.insn; |
553 | preempt_enable_no_resched(); | 549 | goto preempt_out; |
554 | return 1; | ||
555 | } | 550 | } |
556 | #endif | 551 | #endif |
557 | prepare_singlestep(p, regs); | 552 | prepare_singlestep(p, regs); |
558 | kcb->kprobe_status = KPROBE_HIT_SS; | 553 | kcb->kprobe_status = KPROBE_HIT_SS; |
559 | return 1; | 554 | goto out; |
560 | 555 | ||
561 | no_kprobe: | 556 | preempt_out: |
562 | preempt_enable_no_resched(); | 557 | preempt_enable_no_resched(); |
558 | out: | ||
563 | return ret; | 559 | return ret; |
564 | } | 560 | } |
565 | 561 | ||