diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kernel/signal.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/uprobes.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/uprobes.c | 54 |
3 files changed, 26 insertions, 38 deletions
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index a2dc75793bd5..3b997118df50 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c | |||
@@ -158,10 +158,8 @@ static int do_signal(struct pt_regs *regs) | |||
158 | 158 | ||
159 | void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) | 159 | void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) |
160 | { | 160 | { |
161 | if (thread_info_flags & _TIF_UPROBE) { | 161 | if (thread_info_flags & _TIF_UPROBE) |
162 | clear_thread_flag(TIF_UPROBE); | ||
163 | uprobe_notify_resume(regs); | 162 | uprobe_notify_resume(regs); |
164 | } | ||
165 | 163 | ||
166 | if (thread_info_flags & _TIF_SIGPENDING) | 164 | if (thread_info_flags & _TIF_SIGPENDING) |
167 | do_signal(regs); | 165 | do_signal(regs); |
diff --git a/arch/powerpc/kernel/uprobes.c b/arch/powerpc/kernel/uprobes.c index d2d46d1014f8..bc77834dbf43 100644 --- a/arch/powerpc/kernel/uprobes.c +++ b/arch/powerpc/kernel/uprobes.c | |||
@@ -64,6 +64,8 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
64 | autask->saved_trap_nr = current->thread.trap_nr; | 64 | autask->saved_trap_nr = current->thread.trap_nr; |
65 | current->thread.trap_nr = UPROBE_TRAP_NR; | 65 | current->thread.trap_nr = UPROBE_TRAP_NR; |
66 | regs->nip = current->utask->xol_vaddr; | 66 | regs->nip = current->utask->xol_vaddr; |
67 | |||
68 | user_enable_single_step(current); | ||
67 | return 0; | 69 | return 0; |
68 | } | 70 | } |
69 | 71 | ||
@@ -119,6 +121,8 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
119 | * to be executed. | 121 | * to be executed. |
120 | */ | 122 | */ |
121 | regs->nip = utask->vaddr + MAX_UINSN_BYTES; | 123 | regs->nip = utask->vaddr + MAX_UINSN_BYTES; |
124 | |||
125 | user_disable_single_step(current); | ||
122 | return 0; | 126 | return 0; |
123 | } | 127 | } |
124 | 128 | ||
@@ -162,6 +166,8 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
162 | 166 | ||
163 | current->thread.trap_nr = utask->autask.saved_trap_nr; | 167 | current->thread.trap_nr = utask->autask.saved_trap_nr; |
164 | instruction_pointer_set(regs, utask->vaddr); | 168 | instruction_pointer_set(regs, utask->vaddr); |
169 | |||
170 | user_disable_single_step(current); | ||
165 | } | 171 | } |
166 | 172 | ||
167 | /* | 173 | /* |
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index aafa5557b396..c71025b67462 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
@@ -478,6 +478,11 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
478 | regs->ip = current->utask->xol_vaddr; | 478 | regs->ip = current->utask->xol_vaddr; |
479 | pre_xol_rip_insn(auprobe, regs, autask); | 479 | pre_xol_rip_insn(auprobe, regs, autask); |
480 | 480 | ||
481 | autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); | ||
482 | regs->flags |= X86_EFLAGS_TF; | ||
483 | if (test_tsk_thread_flag(current, TIF_BLOCKSTEP)) | ||
484 | set_task_blockstep(current, false); | ||
485 | |||
481 | return 0; | 486 | return 0; |
482 | } | 487 | } |
483 | 488 | ||
@@ -603,6 +608,16 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
603 | if (auprobe->fixups & UPROBE_FIX_CALL) | 608 | if (auprobe->fixups & UPROBE_FIX_CALL) |
604 | result = adjust_ret_addr(regs->sp, correction); | 609 | result = adjust_ret_addr(regs->sp, correction); |
605 | 610 | ||
611 | /* | ||
612 | * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP | ||
613 | * so we can get an extra SIGTRAP if we do not clear TF. We need | ||
614 | * to examine the opcode to make it right. | ||
615 | */ | ||
616 | if (utask->autask.saved_tf) | ||
617 | send_sig(SIGTRAP, current, 0); | ||
618 | else if (!(auprobe->fixups & UPROBE_FIX_SETF)) | ||
619 | regs->flags &= ~X86_EFLAGS_TF; | ||
620 | |||
606 | return result; | 621 | return result; |
607 | } | 622 | } |
608 | 623 | ||
@@ -647,6 +662,10 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
647 | current->thread.trap_nr = utask->autask.saved_trap_nr; | 662 | current->thread.trap_nr = utask->autask.saved_trap_nr; |
648 | handle_riprel_post_xol(auprobe, regs, NULL); | 663 | handle_riprel_post_xol(auprobe, regs, NULL); |
649 | instruction_pointer_set(regs, utask->vaddr); | 664 | instruction_pointer_set(regs, utask->vaddr); |
665 | |||
666 | /* clear TF if it was set by us in arch_uprobe_pre_xol() */ | ||
667 | if (!utask->autask.saved_tf) | ||
668 | regs->flags &= ~X86_EFLAGS_TF; | ||
650 | } | 669 | } |
651 | 670 | ||
652 | /* | 671 | /* |
@@ -676,38 +695,3 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
676 | send_sig(SIGTRAP, current, 0); | 695 | send_sig(SIGTRAP, current, 0); |
677 | return ret; | 696 | return ret; |
678 | } | 697 | } |
679 | |||
680 | void arch_uprobe_enable_step(struct arch_uprobe *auprobe) | ||
681 | { | ||
682 | struct task_struct *task = current; | ||
683 | struct arch_uprobe_task *autask = &task->utask->autask; | ||
684 | struct pt_regs *regs = task_pt_regs(task); | ||
685 | |||
686 | autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); | ||
687 | |||
688 | regs->flags |= X86_EFLAGS_TF; | ||
689 | if (test_tsk_thread_flag(task, TIF_BLOCKSTEP)) | ||
690 | set_task_blockstep(task, false); | ||
691 | } | ||
692 | |||
693 | void arch_uprobe_disable_step(struct arch_uprobe *auprobe) | ||
694 | { | ||
695 | struct task_struct *task = current; | ||
696 | struct arch_uprobe_task *autask = &task->utask->autask; | ||
697 | bool trapped = (task->utask->state == UTASK_SSTEP_TRAPPED); | ||
698 | struct pt_regs *regs = task_pt_regs(task); | ||
699 | /* | ||
700 | * The state of TIF_BLOCKSTEP was not saved so we can get an extra | ||
701 | * SIGTRAP if we do not clear TF. We need to examine the opcode to | ||
702 | * make it right. | ||
703 | */ | ||
704 | if (unlikely(trapped)) { | ||
705 | if (!autask->saved_tf) | ||
706 | regs->flags &= ~X86_EFLAGS_TF; | ||
707 | } else { | ||
708 | if (autask->saved_tf) | ||
709 | send_sig(SIGTRAP, task, 0); | ||
710 | else if (!(auprobe->fixups & UPROBE_FIX_SETF)) | ||
711 | regs->flags &= ~X86_EFLAGS_TF; | ||
712 | } | ||
713 | } | ||