|
@@ -161,6 +161,16 @@ static void set_task_blockstep(struct task_struct *task, bool on)
|
|
{
|
|
{
|
|
unsigned long debugctl;
|
|
unsigned long debugctl;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Ensure irq/preemption can't change debugctl in between.
|
|
|
|
+ * Note also that both TIF_BLOCKSTEP and debugctl should
|
|
|
|
+ * be changed atomically wrt preemption.
|
|
|
|
+ * FIXME: this means that set/clear TIF_BLOCKSTEP is simply
|
|
|
|
+ * wrong if task != current, SIGKILL can wakeup the stopped
|
|
|
|
+ * tracee and set/clear can play with the running task, this
|
|
|
|
+ * can confuse the next __switch_to_xtra().
|
|
|
|
+ */
|
|
|
|
+ local_irq_disable();
|
|
debugctl = get_debugctlmsr();
|
|
debugctl = get_debugctlmsr();
|
|
if (on) {
|
|
if (on) {
|
|
debugctl |= DEBUGCTLMSR_BTF;
|
|
debugctl |= DEBUGCTLMSR_BTF;
|
|
@@ -169,7 +179,9 @@ static void set_task_blockstep(struct task_struct *task, bool on)
|
|
debugctl &= ~DEBUGCTLMSR_BTF;
|
|
debugctl &= ~DEBUGCTLMSR_BTF;
|
|
clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
|
|
clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
|
|
}
|
|
}
|
|
- update_debugctlmsr(debugctl);
|
|
|
|
|
|
+ if (task == current)
|
|
|
|
+ update_debugctlmsr(debugctl);
|
|
|
|
+ local_irq_enable();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|