]> err.no Git - linux-2.6/commitdiff
x86: debugctlmsr kprobes
authorRoland McGrath <roland@redhat.com>
Wed, 30 Jan 2008 12:30:54 +0000 (13:30 +0100)
committerIngo Molnar <mingo@elte.hu>
Wed, 30 Jan 2008 12:30:54 +0000 (13:30 +0100)
This adjusts the x86 kprobes implementation to cope with per-thread
MSR_IA32_DEBUGCTLMSR being set for user mode.  I haven't delved deep
enough into the kprobes code to be really sure this covers all the
cases where the user-mode BTF setting needs to be cleared or restored.
It looks about right to me.

Signed-off-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
arch/x86/kernel/kprobes_32.c
arch/x86/kernel/kprobes_64.c

index 3a020f79f82b80195100adb8b431dc9502ed9780..bc4a68367cd04770cd9757239bc593eb650af252 100644 (file)
@@ -217,8 +217,21 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
                kcb->kprobe_saved_eflags &= ~IF_MASK;
 }
 
+static __always_inline void clear_btf(void)
+{
+       if (test_thread_flag(TIF_DEBUGCTLMSR))
+               wrmsr(MSR_IA32_DEBUGCTLMSR, 0, 0);
+}
+
+static __always_inline void restore_btf(void)
+{
+       if (test_thread_flag(TIF_DEBUGCTLMSR))
+               wrmsr(MSR_IA32_DEBUGCTLMSR, current->thread.debugctlmsr, 0);
+}
+
 static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 {
+       clear_btf();
        regs->eflags |= TF_MASK;
        regs->eflags &= ~IF_MASK;
        /*single step inline if the instruction is an int3*/
@@ -542,6 +555,8 @@ static void __kprobes resume_execution(struct kprobe *p,
        regs->eip = orig_eip + (regs->eip - copy_eip);
 
 no_change:
+       restore_btf();
+
        return;
 }
 
index 5df19a9f9239511536c2f994e1b35f539b723a63..10d66e323c7db780de8e2514f3dc7d40a81f4a10 100644 (file)
@@ -256,8 +256,21 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
                kcb->kprobe_saved_rflags &= ~IF_MASK;
 }
 
+static __always_inline void clear_btf(void)
+{
+       if (test_thread_flag(TIF_DEBUGCTLMSR))
+               wrmsrl(MSR_IA32_DEBUGCTLMSR, 0);
+}
+
+static __always_inline void restore_btf(void)
+{
+       if (test_thread_flag(TIF_DEBUGCTLMSR))
+               wrmsrl(MSR_IA32_DEBUGCTLMSR, current->thread.debugctlmsr);
+}
+
 static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 {
+       clear_btf();
        regs->eflags |= TF_MASK;
        regs->eflags &= ~IF_MASK;
        /*single step inline if the instruction is an int3*/
@@ -527,6 +540,7 @@ static void __kprobes resume_execution(struct kprobe *p,
 
        regs->rip = orig_rip + (regs->rip - copy_rip);
 no_change:
+       restore_btf();
 
        return;
 }