|
35 | 35 | #include <asm/cacheflush.h>
|
36 | 36 | #include <asm/kdebug.h>
|
37 | 37 | #include <asm/desc.h>
|
| 38 | +#include <asm/uaccess.h> |
38 | 39 |
|
39 | 40 | void jprobe_return_end(void);
|
40 | 41 |
|
@@ -547,15 +548,57 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
547 | 548 | struct kprobe *cur = kprobe_running();
|
548 | 549 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
549 | 550 |
|
550 |
| - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) |
551 |
| - return 1; |
552 |
| - |
553 |
| - if (kcb->kprobe_status & KPROBE_HIT_SS) { |
554 |
| - resume_execution(cur, regs, kcb); |
| 551 | + switch(kcb->kprobe_status) { |
| 552 | + case KPROBE_HIT_SS: |
| 553 | + case KPROBE_REENTER: |
| 554 | + /* |
| 555 | + * We are here because the instruction being single |
| 556 | + * stepped caused a page fault. We reset the current |
| 557 | + * kprobe and the eip points back to the probe address |
| 558 | + * and allow the page fault handler to continue as a |
| 559 | + * normal page fault. |
| 560 | + */ |
| 561 | + regs->eip = (unsigned long)cur->addr; |
555 | 562 | regs->eflags |= kcb->kprobe_old_eflags;
|
556 |
| - |
557 |
| - reset_current_kprobe(); |
| 563 | + if (kcb->kprobe_status == KPROBE_REENTER) |
| 564 | + restore_previous_kprobe(kcb); |
| 565 | + else |
| 566 | + reset_current_kprobe(); |
558 | 567 | preempt_enable_no_resched();
|
| 568 | + break; |
| 569 | + case KPROBE_HIT_ACTIVE: |
| 570 | + case KPROBE_HIT_SSDONE: |
| 571 | + /* |
| 572 | + * We increment the nmissed count for accounting, |
| 573 | + * we can also use npre/npostfault count for accouting |
| 574 | + * these specific fault cases. |
| 575 | + */ |
| 576 | + kprobes_inc_nmissed_count(cur); |
| 577 | + |
| 578 | + /* |
| 579 | + * We come here because instructions in the pre/post |
| 580 | + * handler caused the page_fault, this could happen |
| 581 | + * if handler tries to access user space by |
| 582 | + * copy_from_user(), get_user() etc. Let the |
| 583 | + * user-specified handler try to fix it first. |
| 584 | + */ |
| 585 | + if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) |
| 586 | + return 1; |
| 587 | + |
| 588 | + /* |
| 589 | + * In case the user-specified fault handler returned |
| 590 | + * zero, try to fix up. |
| 591 | + */ |
| 592 | + if (fixup_exception(regs)) |
| 593 | + return 1; |
| 594 | + |
| 595 | + /* |
| 596 | + * fixup_exception() could not handle it, |
| 597 | + * Let do_page_fault() fix it. |
| 598 | + */ |
| 599 | + break; |
| 600 | + default: |
| 601 | + break; |
559 | 602 | }
|
560 | 603 | return 0;
|
561 | 604 | }
|
|
0 commit comments