aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/uprobes.h2
-rw-r--r--arch/x86/kernel/uprobes.c33
2 files changed, 35 insertions, 0 deletions
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
index f3971bbcd1de..cee58624cb30 100644
--- a/arch/x86/include/asm/uprobes.h
+++ b/arch/x86/include/asm/uprobes.h
@@ -46,6 +46,8 @@ struct arch_uprobe_task {
46#ifdef CONFIG_X86_64 46#ifdef CONFIG_X86_64
47 unsigned long saved_scratch_register; 47 unsigned long saved_scratch_register;
48#endif 48#endif
49#define UPROBE_CLEAR_TF (1 << 0)
50 unsigned int restore_flags;
49}; 51};
50 52
51extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); 53extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr);
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 36fd42091fa7..309a0e02b124 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -41,6 +41,9 @@
41/* Adjust the return address of a call insn */ 41/* Adjust the return address of a call insn */
42#define UPROBE_FIX_CALL 0x2 42#define UPROBE_FIX_CALL 0x2
43 43
44/* Instruction will modify TF, don't change it */
45#define UPROBE_FIX_SETF 0x4
46
44#define UPROBE_FIX_RIP_AX 0x8000 47#define UPROBE_FIX_RIP_AX 0x8000
45#define UPROBE_FIX_RIP_CX 0x4000 48#define UPROBE_FIX_RIP_CX 0x4000
46 49
@@ -239,6 +242,10 @@ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn)
239 insn_get_opcode(insn); /* should be a nop */ 242 insn_get_opcode(insn); /* should be a nop */
240 243
241 switch (OPCODE1(insn)) { 244 switch (OPCODE1(insn)) {
245 case 0x9d:
246 /* popf */
247 auprobe->fixups |= UPROBE_FIX_SETF;
248 break;
242 case 0xc3: /* ret/lret */ 249 case 0xc3: /* ret/lret */
243 case 0xcb: 250 case 0xcb:
244 case 0xc2: 251 case 0xc2:
@@ -673,3 +680,29 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
673 } 680 }
674 return false; 681 return false;
675} 682}
683
684void arch_uprobe_enable_step(struct arch_uprobe *auprobe)
685{
686 struct uprobe_task *utask = current->utask;
687 struct arch_uprobe_task *autask = &utask->autask;
688
689 autask->restore_flags = 0;
690 if (!test_tsk_thread_flag(current, TIF_SINGLESTEP) &&
691 !(auprobe->fixups & UPROBE_FIX_SETF))
692 autask->restore_flags |= UPROBE_CLEAR_TF;
693 /*
694 * The state of TIF_BLOCKSTEP is not saved. With the TF flag set we
695 * would to examine the opcode and the flags to make it right. Without
696 * TF block stepping makes no sense.
697 */
698 user_enable_single_step(current);
699}
700
701void arch_uprobe_disable_step(struct arch_uprobe *auprobe)
702{
703 struct uprobe_task *utask = current->utask;
704 struct arch_uprobe_task *autask = &utask->autask;
705
706 if (autask->restore_flags & UPROBE_CLEAR_TF)
707 user_disable_single_step(current);
708}