diff options
author | Roland McGrath <roland@redhat.com> | 2008-01-30 07:30:54 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:30:54 -0500 |
commit | 1ecc798c67645e0ee6eb028cb988b71b3edf4b40 (patch) | |
tree | a0456da7328d9b07212b5845003e67c88185f1f3 /arch/x86/kernel | |
parent | 10faa81e102e2b7695f386812055cd2ef9e44b4c (diff) |
x86: debugctlmsr kprobes
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>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/kprobes_32.c | 15 | ||||
-rw-r--r-- | arch/x86/kernel/kprobes_64.c | 14 |
2 files changed, 29 insertions, 0 deletions
diff --git a/arch/x86/kernel/kprobes_32.c b/arch/x86/kernel/kprobes_32.c index 3a020f79f82b..bc4a68367cd0 100644 --- a/arch/x86/kernel/kprobes_32.c +++ b/arch/x86/kernel/kprobes_32.c | |||
@@ -217,8 +217,21 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, | |||
217 | kcb->kprobe_saved_eflags &= ~IF_MASK; | 217 | kcb->kprobe_saved_eflags &= ~IF_MASK; |
218 | } | 218 | } |
219 | 219 | ||
220 | static __always_inline void clear_btf(void) | ||
221 | { | ||
222 | if (test_thread_flag(TIF_DEBUGCTLMSR)) | ||
223 | wrmsr(MSR_IA32_DEBUGCTLMSR, 0, 0); | ||
224 | } | ||
225 | |||
226 | static __always_inline void restore_btf(void) | ||
227 | { | ||
228 | if (test_thread_flag(TIF_DEBUGCTLMSR)) | ||
229 | wrmsr(MSR_IA32_DEBUGCTLMSR, current->thread.debugctlmsr, 0); | ||
230 | } | ||
231 | |||
220 | static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | 232 | static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) |
221 | { | 233 | { |
234 | clear_btf(); | ||
222 | regs->eflags |= TF_MASK; | 235 | regs->eflags |= TF_MASK; |
223 | regs->eflags &= ~IF_MASK; | 236 | regs->eflags &= ~IF_MASK; |
224 | /*single step inline if the instruction is an int3*/ | 237 | /*single step inline if the instruction is an int3*/ |
@@ -542,6 +555,8 @@ static void __kprobes resume_execution(struct kprobe *p, | |||
542 | regs->eip = orig_eip + (regs->eip - copy_eip); | 555 | regs->eip = orig_eip + (regs->eip - copy_eip); |
543 | 556 | ||
544 | no_change: | 557 | no_change: |
558 | restore_btf(); | ||
559 | |||
545 | return; | 560 | return; |
546 | } | 561 | } |
547 | 562 | ||
diff --git a/arch/x86/kernel/kprobes_64.c b/arch/x86/kernel/kprobes_64.c index 5df19a9f9239..10d66e323c7d 100644 --- a/arch/x86/kernel/kprobes_64.c +++ b/arch/x86/kernel/kprobes_64.c | |||
@@ -256,8 +256,21 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, | |||
256 | kcb->kprobe_saved_rflags &= ~IF_MASK; | 256 | kcb->kprobe_saved_rflags &= ~IF_MASK; |
257 | } | 257 | } |
258 | 258 | ||
259 | static __always_inline void clear_btf(void) | ||
260 | { | ||
261 | if (test_thread_flag(TIF_DEBUGCTLMSR)) | ||
262 | wrmsrl(MSR_IA32_DEBUGCTLMSR, 0); | ||
263 | } | ||
264 | |||
265 | static __always_inline void restore_btf(void) | ||
266 | { | ||
267 | if (test_thread_flag(TIF_DEBUGCTLMSR)) | ||
268 | wrmsrl(MSR_IA32_DEBUGCTLMSR, current->thread.debugctlmsr); | ||
269 | } | ||
270 | |||
259 | static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | 271 | static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) |
260 | { | 272 | { |
273 | clear_btf(); | ||
261 | regs->eflags |= TF_MASK; | 274 | regs->eflags |= TF_MASK; |
262 | regs->eflags &= ~IF_MASK; | 275 | regs->eflags &= ~IF_MASK; |
263 | /*single step inline if the instruction is an int3*/ | 276 | /*single step inline if the instruction is an int3*/ |
@@ -527,6 +540,7 @@ static void __kprobes resume_execution(struct kprobe *p, | |||
527 | 540 | ||
528 | regs->rip = orig_rip + (regs->rip - copy_rip); | 541 | regs->rip = orig_rip + (regs->rip - copy_rip); |
529 | no_change: | 542 | no_change: |
543 | restore_btf(); | ||
530 | 544 | ||
531 | return; | 545 | return; |
532 | } | 546 | } |