kgdb, x86, arm, mips, powerpc: ignore user space single stepping
On the x86 arch, user space single step exceptions should be ignored if they occur in the kernel space, such as ptrace stepping through a system call. First check if it is kgdb that is executing a single step, then ensure it is not an accidental traversal into the user space, while in kgdb, any other time the TIF_SINGLESTEP is set, kgdb should ignore the exception. On x86, arm, mips and powerpc, the kgdb_contthread usage was inconsistent with the way single stepping is implemented in the kgdb core. The arch specific stub should always set the kgdb_cpu_doing_single_step correctly if it is single stepping. This allows kgdb to correctly process an instruction steps if ptrace happens to be requesting an instruction step over a system call. Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
This commit is contained in:
@@ -111,8 +111,6 @@ int kgdb_arch_handle_exception(int exception_vector, int signo,
|
|||||||
case 'D':
|
case 'D':
|
||||||
case 'k':
|
case 'k':
|
||||||
case 'c':
|
case 'c':
|
||||||
kgdb_contthread = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to read optional parameter, pc unchanged if no parm.
|
* Try to read optional parameter, pc unchanged if no parm.
|
||||||
* If this was a compiled breakpoint, we need to move
|
* If this was a compiled breakpoint, we need to move
|
||||||
|
@@ -236,8 +236,7 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
|
|||||||
|
|
||||||
atomic_set(&kgdb_cpu_doing_single_step, -1);
|
atomic_set(&kgdb_cpu_doing_single_step, -1);
|
||||||
if (remcom_in_buffer[0] == 's')
|
if (remcom_in_buffer[0] == 's')
|
||||||
if (kgdb_contthread)
|
atomic_set(&kgdb_cpu_doing_single_step, cpu);
|
||||||
atomic_set(&kgdb_cpu_doing_single_step, cpu);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -347,9 +347,8 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
|
|||||||
linux_regs->msr |= MSR_SE;
|
linux_regs->msr |= MSR_SE;
|
||||||
#endif
|
#endif
|
||||||
kgdb_single_step = 1;
|
kgdb_single_step = 1;
|
||||||
if (kgdb_contthread)
|
atomic_set(&kgdb_cpu_doing_single_step,
|
||||||
atomic_set(&kgdb_cpu_doing_single_step,
|
raw_smp_processor_id());
|
||||||
raw_smp_processor_id());
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -378,10 +378,8 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
|
|||||||
if (remcomInBuffer[0] == 's') {
|
if (remcomInBuffer[0] == 's') {
|
||||||
linux_regs->flags |= X86_EFLAGS_TF;
|
linux_regs->flags |= X86_EFLAGS_TF;
|
||||||
kgdb_single_step = 1;
|
kgdb_single_step = 1;
|
||||||
if (kgdb_contthread) {
|
atomic_set(&kgdb_cpu_doing_single_step,
|
||||||
atomic_set(&kgdb_cpu_doing_single_step,
|
raw_smp_processor_id());
|
||||||
raw_smp_processor_id());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_debugreg(dr6, 6);
|
get_debugreg(dr6, 6);
|
||||||
@@ -466,9 +464,15 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd)
|
|||||||
|
|
||||||
case DIE_DEBUG:
|
case DIE_DEBUG:
|
||||||
if (atomic_read(&kgdb_cpu_doing_single_step) ==
|
if (atomic_read(&kgdb_cpu_doing_single_step) ==
|
||||||
raw_smp_processor_id() &&
|
raw_smp_processor_id()) {
|
||||||
user_mode(regs))
|
if (user_mode(regs))
|
||||||
return single_step_cont(regs, args);
|
return single_step_cont(regs, args);
|
||||||
|
break;
|
||||||
|
} else if (test_thread_flag(TIF_SINGLESTEP))
|
||||||
|
/* This means a user thread is single stepping
|
||||||
|
* a system call which should be ignored
|
||||||
|
*/
|
||||||
|
return NOTIFY_DONE;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
default:
|
default:
|
||||||
if (user_mode(regs))
|
if (user_mode(regs))
|
||||||
|
@@ -1462,7 +1462,7 @@ acquirelock:
|
|||||||
* Get the passive CPU lock which will hold all the non-primary
|
* Get the passive CPU lock which will hold all the non-primary
|
||||||
* CPU in a spin state while the debugger is active
|
* CPU in a spin state while the debugger is active
|
||||||
*/
|
*/
|
||||||
if (!kgdb_single_step || !kgdb_contthread) {
|
if (!kgdb_single_step) {
|
||||||
for (i = 0; i < NR_CPUS; i++)
|
for (i = 0; i < NR_CPUS; i++)
|
||||||
atomic_set(&passive_cpu_wait[i], 1);
|
atomic_set(&passive_cpu_wait[i], 1);
|
||||||
}
|
}
|
||||||
@@ -1475,7 +1475,7 @@ acquirelock:
|
|||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
/* Signal the other CPUs to enter kgdb_wait() */
|
/* Signal the other CPUs to enter kgdb_wait() */
|
||||||
if ((!kgdb_single_step || !kgdb_contthread) && kgdb_do_roundup)
|
if ((!kgdb_single_step) && kgdb_do_roundup)
|
||||||
kgdb_roundup_cpus(flags);
|
kgdb_roundup_cpus(flags);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1494,7 +1494,7 @@ acquirelock:
|
|||||||
kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code);
|
kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code);
|
||||||
kgdb_deactivate_sw_breakpoints();
|
kgdb_deactivate_sw_breakpoints();
|
||||||
kgdb_single_step = 0;
|
kgdb_single_step = 0;
|
||||||
kgdb_contthread = NULL;
|
kgdb_contthread = current;
|
||||||
exception_level = 0;
|
exception_level = 0;
|
||||||
|
|
||||||
/* Talk to debugger with gdbserial protocol */
|
/* Talk to debugger with gdbserial protocol */
|
||||||
@@ -1508,7 +1508,7 @@ acquirelock:
|
|||||||
kgdb_info[ks->cpu].task = NULL;
|
kgdb_info[ks->cpu].task = NULL;
|
||||||
atomic_set(&cpu_in_kgdb[ks->cpu], 0);
|
atomic_set(&cpu_in_kgdb[ks->cpu], 0);
|
||||||
|
|
||||||
if (!kgdb_single_step || !kgdb_contthread) {
|
if (!kgdb_single_step) {
|
||||||
for (i = NR_CPUS-1; i >= 0; i--)
|
for (i = NR_CPUS-1; i >= 0; i--)
|
||||||
atomic_set(&passive_cpu_wait[i], 0);
|
atomic_set(&passive_cpu_wait[i], 0);
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user