Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb: kgdboc,tty: Fix tty polling search to use name correctly kgdb, x86_64: fix PS CS SS registers in gdb serial kgdb, x86_64: gdb serial has BX and DX reversed kgdb, x86, arm, mips, powerpc: ignore user space single stepping kgdb: could not write to the last of valid memory with kgdb
This commit is contained in:
commit
929675d58c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,9 @@ static int gdb_x86vector = -1;
|
||||||
*/
|
*/
|
||||||
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
#ifndef CONFIG_X86_32
|
||||||
|
u32 *gdb_regs32 = (u32 *)gdb_regs;
|
||||||
|
#endif
|
||||||
gdb_regs[GDB_AX] = regs->ax;
|
gdb_regs[GDB_AX] = regs->ax;
|
||||||
gdb_regs[GDB_BX] = regs->bx;
|
gdb_regs[GDB_BX] = regs->bx;
|
||||||
gdb_regs[GDB_CX] = regs->cx;
|
gdb_regs[GDB_CX] = regs->cx;
|
||||||
|
@ -76,9 +79,9 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||||
gdb_regs[GDB_SI] = regs->si;
|
gdb_regs[GDB_SI] = regs->si;
|
||||||
gdb_regs[GDB_DI] = regs->di;
|
gdb_regs[GDB_DI] = regs->di;
|
||||||
gdb_regs[GDB_BP] = regs->bp;
|
gdb_regs[GDB_BP] = regs->bp;
|
||||||
gdb_regs[GDB_PS] = regs->flags;
|
|
||||||
gdb_regs[GDB_PC] = regs->ip;
|
gdb_regs[GDB_PC] = regs->ip;
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
|
gdb_regs[GDB_PS] = regs->flags;
|
||||||
gdb_regs[GDB_DS] = regs->ds;
|
gdb_regs[GDB_DS] = regs->ds;
|
||||||
gdb_regs[GDB_ES] = regs->es;
|
gdb_regs[GDB_ES] = regs->es;
|
||||||
gdb_regs[GDB_CS] = regs->cs;
|
gdb_regs[GDB_CS] = regs->cs;
|
||||||
|
@ -94,6 +97,9 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||||
gdb_regs[GDB_R13] = regs->r13;
|
gdb_regs[GDB_R13] = regs->r13;
|
||||||
gdb_regs[GDB_R14] = regs->r14;
|
gdb_regs[GDB_R14] = regs->r14;
|
||||||
gdb_regs[GDB_R15] = regs->r15;
|
gdb_regs[GDB_R15] = regs->r15;
|
||||||
|
gdb_regs32[GDB_PS] = regs->flags;
|
||||||
|
gdb_regs32[GDB_CS] = regs->cs;
|
||||||
|
gdb_regs32[GDB_SS] = regs->ss;
|
||||||
#endif
|
#endif
|
||||||
gdb_regs[GDB_SP] = regs->sp;
|
gdb_regs[GDB_SP] = regs->sp;
|
||||||
}
|
}
|
||||||
|
@ -112,6 +118,9 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||||
*/
|
*/
|
||||||
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
|
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
|
||||||
{
|
{
|
||||||
|
#ifndef CONFIG_X86_32
|
||||||
|
u32 *gdb_regs32 = (u32 *)gdb_regs;
|
||||||
|
#endif
|
||||||
gdb_regs[GDB_AX] = 0;
|
gdb_regs[GDB_AX] = 0;
|
||||||
gdb_regs[GDB_BX] = 0;
|
gdb_regs[GDB_BX] = 0;
|
||||||
gdb_regs[GDB_CX] = 0;
|
gdb_regs[GDB_CX] = 0;
|
||||||
|
@ -129,8 +138,10 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
|
||||||
gdb_regs[GDB_FS] = 0xFFFF;
|
gdb_regs[GDB_FS] = 0xFFFF;
|
||||||
gdb_regs[GDB_GS] = 0xFFFF;
|
gdb_regs[GDB_GS] = 0xFFFF;
|
||||||
#else
|
#else
|
||||||
gdb_regs[GDB_PS] = *(unsigned long *)(p->thread.sp + 8);
|
gdb_regs32[GDB_PS] = *(unsigned long *)(p->thread.sp + 8);
|
||||||
gdb_regs[GDB_PC] = 0;
|
gdb_regs32[GDB_CS] = __KERNEL_CS;
|
||||||
|
gdb_regs32[GDB_SS] = __KERNEL_DS;
|
||||||
|
gdb_regs[GDB_PC] = p->thread.ip;
|
||||||
gdb_regs[GDB_R8] = 0;
|
gdb_regs[GDB_R8] = 0;
|
||||||
gdb_regs[GDB_R9] = 0;
|
gdb_regs[GDB_R9] = 0;
|
||||||
gdb_regs[GDB_R10] = 0;
|
gdb_regs[GDB_R10] = 0;
|
||||||
|
@ -153,6 +164,9 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
|
||||||
*/
|
*/
|
||||||
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
#ifndef CONFIG_X86_32
|
||||||
|
u32 *gdb_regs32 = (u32 *)gdb_regs;
|
||||||
|
#endif
|
||||||
regs->ax = gdb_regs[GDB_AX];
|
regs->ax = gdb_regs[GDB_AX];
|
||||||
regs->bx = gdb_regs[GDB_BX];
|
regs->bx = gdb_regs[GDB_BX];
|
||||||
regs->cx = gdb_regs[GDB_CX];
|
regs->cx = gdb_regs[GDB_CX];
|
||||||
|
@ -160,9 +174,9 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||||
regs->si = gdb_regs[GDB_SI];
|
regs->si = gdb_regs[GDB_SI];
|
||||||
regs->di = gdb_regs[GDB_DI];
|
regs->di = gdb_regs[GDB_DI];
|
||||||
regs->bp = gdb_regs[GDB_BP];
|
regs->bp = gdb_regs[GDB_BP];
|
||||||
regs->flags = gdb_regs[GDB_PS];
|
|
||||||
regs->ip = gdb_regs[GDB_PC];
|
regs->ip = gdb_regs[GDB_PC];
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
|
regs->flags = gdb_regs[GDB_PS];
|
||||||
regs->ds = gdb_regs[GDB_DS];
|
regs->ds = gdb_regs[GDB_DS];
|
||||||
regs->es = gdb_regs[GDB_ES];
|
regs->es = gdb_regs[GDB_ES];
|
||||||
regs->cs = gdb_regs[GDB_CS];
|
regs->cs = gdb_regs[GDB_CS];
|
||||||
|
@ -175,6 +189,9 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||||
regs->r13 = gdb_regs[GDB_R13];
|
regs->r13 = gdb_regs[GDB_R13];
|
||||||
regs->r14 = gdb_regs[GDB_R14];
|
regs->r14 = gdb_regs[GDB_R14];
|
||||||
regs->r15 = gdb_regs[GDB_R15];
|
regs->r15 = gdb_regs[GDB_R15];
|
||||||
|
regs->flags = gdb_regs32[GDB_PS];
|
||||||
|
regs->cs = gdb_regs32[GDB_CS];
|
||||||
|
regs->ss = gdb_regs32[GDB_SS];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,10 +395,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 +481,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))
|
||||||
|
|
|
@ -695,13 +695,23 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
|
||||||
{
|
{
|
||||||
struct tty_driver *p, *res = NULL;
|
struct tty_driver *p, *res = NULL;
|
||||||
int tty_line = 0;
|
int tty_line = 0;
|
||||||
|
int len;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
|
for (str = name; *str; str++)
|
||||||
|
if ((*str >= '0' && *str <= '9') || *str == ',')
|
||||||
|
break;
|
||||||
|
if (!*str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
len = str - name;
|
||||||
|
tty_line = simple_strtoul(str, &str, 10);
|
||||||
|
|
||||||
mutex_lock(&tty_mutex);
|
mutex_lock(&tty_mutex);
|
||||||
/* Search through the tty devices to look for a match */
|
/* Search through the tty devices to look for a match */
|
||||||
list_for_each_entry(p, &tty_drivers, tty_drivers) {
|
list_for_each_entry(p, &tty_drivers, tty_drivers) {
|
||||||
str = name + strlen(p->name);
|
if (strncmp(name, p->name, len) != 0)
|
||||||
tty_line = simple_strtoul(str, &str, 10);
|
continue;
|
||||||
if (*str == ',')
|
if (*str == ',')
|
||||||
str++;
|
str++;
|
||||||
if (*str == '\0')
|
if (*str == '\0')
|
||||||
|
|
|
@ -39,12 +39,13 @@ enum regnames {
|
||||||
GDB_FS, /* 14 */
|
GDB_FS, /* 14 */
|
||||||
GDB_GS, /* 15 */
|
GDB_GS, /* 15 */
|
||||||
};
|
};
|
||||||
|
#define NUMREGBYTES ((GDB_GS+1)*4)
|
||||||
#else /* ! CONFIG_X86_32 */
|
#else /* ! CONFIG_X86_32 */
|
||||||
enum regnames {
|
enum regnames64 {
|
||||||
GDB_AX, /* 0 */
|
GDB_AX, /* 0 */
|
||||||
GDB_DX, /* 1 */
|
GDB_BX, /* 1 */
|
||||||
GDB_CX, /* 2 */
|
GDB_CX, /* 2 */
|
||||||
GDB_BX, /* 3 */
|
GDB_DX, /* 3 */
|
||||||
GDB_SI, /* 4 */
|
GDB_SI, /* 4 */
|
||||||
GDB_DI, /* 5 */
|
GDB_DI, /* 5 */
|
||||||
GDB_BP, /* 6 */
|
GDB_BP, /* 6 */
|
||||||
|
@ -58,18 +59,15 @@ enum regnames {
|
||||||
GDB_R14, /* 14 */
|
GDB_R14, /* 14 */
|
||||||
GDB_R15, /* 15 */
|
GDB_R15, /* 15 */
|
||||||
GDB_PC, /* 16 */
|
GDB_PC, /* 16 */
|
||||||
GDB_PS, /* 17 */
|
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_X86_32 */
|
|
||||||
|
|
||||||
/*
|
enum regnames32 {
|
||||||
* Number of bytes of registers:
|
GDB_PS = 34,
|
||||||
*/
|
GDB_CS,
|
||||||
#ifdef CONFIG_X86_32
|
GDB_SS,
|
||||||
# define NUMREGBYTES 64
|
};
|
||||||
#else
|
#define NUMREGBYTES ((GDB_SS+1)*4)
|
||||||
# define NUMREGBYTES ((GDB_PS+1)*8)
|
#endif /* CONFIG_X86_32 */
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline void arch_kgdb_breakpoint(void)
|
static inline void arch_kgdb_breakpoint(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -488,7 +488,7 @@ static int write_mem_msg(int binary)
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
if (CACHE_FLUSH_IS_SAFE)
|
if (CACHE_FLUSH_IS_SAFE)
|
||||||
flush_icache_range(addr, addr + length + 1);
|
flush_icache_range(addr, addr + length);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue