aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2012-08-20 06:47:34 -0400
committerOleg Nesterov <oleg@redhat.com>2012-09-15 11:37:28 -0400
commitbdc1e47217315be14ba04881b0a4c8ecb3ff320c (patch)
tree12f3ad73096cffde4d560c44783d791c5333a797
parent9d778782266f95e5c6ec43ed8195ba331c821018 (diff)
uprobes/x86: Implement x86 specific arch_uprobe_*_step
The arch specific implementation behaves like user_enable_single_step() except that it does not disable single stepping if it was already enabled by ptrace. This allows the debugger to single step over an uprobe. The state of block stepping is not restored. It makes only sense together with TF and if that was enabled then the debugger is notified. Note: this is still not correct. For example, TIF_SINGLESTEP check is not right, the application itself can set X86_EFLAGS_TF. And otoh we leak TIF_SINGLESTEP (set by enable) if the probed insn is "popf". See the next patches, we need the changes in arch/x86/kernel/step.c first. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
-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}