diff options
Diffstat (limited to 'arch/x86/kernel/step.c')
| -rw-r--r-- | arch/x86/kernel/step.c | 53 | 
1 files changed, 33 insertions, 20 deletions
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index c346d116148..cd3b2438a98 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c @@ -157,6 +157,33 @@ static int enable_single_step(struct task_struct *child)  	return 1;  } +void set_task_blockstep(struct task_struct *task, bool on) +{ +	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(); +	if (on) { +		debugctl |= DEBUGCTLMSR_BTF; +		set_tsk_thread_flag(task, TIF_BLOCKSTEP); +	} else { +		debugctl &= ~DEBUGCTLMSR_BTF; +		clear_tsk_thread_flag(task, TIF_BLOCKSTEP); +	} +	if (task == current) +		update_debugctlmsr(debugctl); +	local_irq_enable(); +} +  /*   * Enable single or block step.   */ @@ -169,19 +196,10 @@ static void enable_step(struct task_struct *child, bool block)  	 * So no one should try to use debugger block stepping in a program  	 * that uses user-mode single stepping itself.  	 */ -	if (enable_single_step(child) && block) { -		unsigned long debugctl = get_debugctlmsr(); - -		debugctl |= DEBUGCTLMSR_BTF; -		update_debugctlmsr(debugctl); -		set_tsk_thread_flag(child, TIF_BLOCKSTEP); -	} else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { -		unsigned long debugctl = get_debugctlmsr(); - -		debugctl &= ~DEBUGCTLMSR_BTF; -		update_debugctlmsr(debugctl); -		clear_tsk_thread_flag(child, TIF_BLOCKSTEP); -	} +	if (enable_single_step(child) && block) +		set_task_blockstep(child, true); +	else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) +		set_task_blockstep(child, false);  }  void user_enable_single_step(struct task_struct *child) @@ -199,13 +217,8 @@ void user_disable_single_step(struct task_struct *child)  	/*  	 * Make sure block stepping (BTF) is disabled.  	 */ -	if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { -		unsigned long debugctl = get_debugctlmsr(); - -		debugctl &= ~DEBUGCTLMSR_BTF; -		update_debugctlmsr(debugctl); -		clear_tsk_thread_flag(child, TIF_BLOCKSTEP); -	} +	if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) +		set_task_blockstep(child, false);  	/* Always clear TIF_SINGLESTEP... */  	clear_tsk_thread_flag(child, TIF_SINGLESTEP);  |