Commit 880188b2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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:
  kgdb: Always process the whole breakpoint list on activate or deactivate
  kgdb: continue and warn on signal passing from gdb
  kgdb,x86: do not set kgdb_single_step on x86
  kgdb: allow for cpu switch when single stepping
  kgdb,i386: Fix corner case access to ss with NMI watch dog exception
  kgdb: Replace strstr() by strchr() for single-character needles
  kgdbts: Read buffer overflow
  kgdb: Read buffer overflow
  kgdb,x86: remove redundant test
parents 97647579 7f8b7ed6
...@@ -86,9 +86,15 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) ...@@ -86,9 +86,15 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
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;
gdb_regs[GDB_SS] = __KERNEL_DS;
gdb_regs[GDB_FS] = 0xFFFF; gdb_regs[GDB_FS] = 0xFFFF;
gdb_regs[GDB_GS] = 0xFFFF; gdb_regs[GDB_GS] = 0xFFFF;
if (user_mode_vm(regs)) {
gdb_regs[GDB_SS] = regs->ss;
gdb_regs[GDB_SP] = regs->sp;
} else {
gdb_regs[GDB_SS] = __KERNEL_DS;
gdb_regs[GDB_SP] = kernel_stack_pointer(regs);
}
#else #else
gdb_regs[GDB_R8] = regs->r8; gdb_regs[GDB_R8] = regs->r8;
gdb_regs[GDB_R9] = regs->r9; gdb_regs[GDB_R9] = regs->r9;
...@@ -101,8 +107,8 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) ...@@ -101,8 +107,8 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
gdb_regs32[GDB_PS] = regs->flags; gdb_regs32[GDB_PS] = regs->flags;
gdb_regs32[GDB_CS] = regs->cs; gdb_regs32[GDB_CS] = regs->cs;
gdb_regs32[GDB_SS] = regs->ss; gdb_regs32[GDB_SS] = regs->ss;
#endif
gdb_regs[GDB_SP] = kernel_stack_pointer(regs); gdb_regs[GDB_SP] = kernel_stack_pointer(regs);
#endif
} }
/** /**
...@@ -220,8 +226,7 @@ static void kgdb_correct_hw_break(void) ...@@ -220,8 +226,7 @@ static void kgdb_correct_hw_break(void)
dr7 |= ((breakinfo[breakno].len << 2) | dr7 |= ((breakinfo[breakno].len << 2) |
breakinfo[breakno].type) << breakinfo[breakno].type) <<
((breakno << 2) + 16); ((breakno << 2) + 16);
if (breakno >= 0 && breakno <= 3) set_debugreg(breakinfo[breakno].addr, breakno);
set_debugreg(breakinfo[breakno].addr, breakno);
} else { } else {
if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
...@@ -395,7 +400,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, ...@@ -395,7 +400,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
/* set the trace bit if we're stepping */ /* set the trace bit if we're stepping */
if (remcomInBuffer[0] == 's') { if (remcomInBuffer[0] == 's') {
linux_regs->flags |= X86_EFLAGS_TF; linux_regs->flags |= X86_EFLAGS_TF;
kgdb_single_step = 1;
atomic_set(&kgdb_cpu_doing_single_step, atomic_set(&kgdb_cpu_doing_single_step,
raw_smp_processor_id()); raw_smp_processor_id());
} }
......
...@@ -712,6 +712,12 @@ static int run_simple_test(int is_get_char, int chr) ...@@ -712,6 +712,12 @@ static int run_simple_test(int is_get_char, int chr)
/* End of packet == #XX so look for the '#' */ /* End of packet == #XX so look for the '#' */
if (put_buf_cnt > 3 && put_buf[put_buf_cnt - 3] == '#') { if (put_buf_cnt > 3 && put_buf[put_buf_cnt - 3] == '#') {
if (put_buf_cnt >= BUFMAX) {
eprintk("kgdbts: ERROR: put buffer overflow on"
" '%s' line %i\n", ts.name, ts.idx);
put_buf_cnt = 0;
return 0;
}
put_buf[put_buf_cnt] = '\0'; put_buf[put_buf_cnt] = '\0';
v2printk("put%i: %s\n", ts.idx, put_buf); v2printk("put%i: %s\n", ts.idx, put_buf);
/* Trigger check here */ /* Trigger check here */
...@@ -885,16 +891,16 @@ static void kgdbts_run_tests(void) ...@@ -885,16 +891,16 @@ static void kgdbts_run_tests(void)
int nmi_sleep = 0; int nmi_sleep = 0;
int i; int i;
ptr = strstr(config, "F"); ptr = strchr(config, 'F');
if (ptr) if (ptr)
fork_test = simple_strtol(ptr + 1, NULL, 10); fork_test = simple_strtol(ptr + 1, NULL, 10);
ptr = strstr(config, "S"); ptr = strchr(config, 'S');
if (ptr) if (ptr)
do_sys_open_test = simple_strtol(ptr + 1, NULL, 10); do_sys_open_test = simple_strtol(ptr + 1, NULL, 10);
ptr = strstr(config, "N"); ptr = strchr(config, 'N');
if (ptr) if (ptr)
nmi_sleep = simple_strtol(ptr+1, NULL, 10); nmi_sleep = simple_strtol(ptr+1, NULL, 10);
ptr = strstr(config, "I"); ptr = strchr(config, 'I');
if (ptr) if (ptr)
sstep_test = simple_strtol(ptr+1, NULL, 10); sstep_test = simple_strtol(ptr+1, NULL, 10);
......
...@@ -129,6 +129,7 @@ struct task_struct *kgdb_usethread; ...@@ -129,6 +129,7 @@ struct task_struct *kgdb_usethread;
struct task_struct *kgdb_contthread; struct task_struct *kgdb_contthread;
int kgdb_single_step; int kgdb_single_step;
pid_t kgdb_sstep_pid;
/* Our I/O buffers. */ /* Our I/O buffers. */
static char remcom_in_buffer[BUFMAX]; static char remcom_in_buffer[BUFMAX];
...@@ -541,12 +542,17 @@ static struct task_struct *getthread(struct pt_regs *regs, int tid) ...@@ -541,12 +542,17 @@ static struct task_struct *getthread(struct pt_regs *regs, int tid)
*/ */
if (tid == 0 || tid == -1) if (tid == 0 || tid == -1)
tid = -atomic_read(&kgdb_active) - 2; tid = -atomic_read(&kgdb_active) - 2;
if (tid < 0) { if (tid < -1 && tid > -NR_CPUS - 2) {
if (kgdb_info[-tid - 2].task) if (kgdb_info[-tid - 2].task)
return kgdb_info[-tid - 2].task; return kgdb_info[-tid - 2].task;
else else
return idle_task(-tid - 2); return idle_task(-tid - 2);
} }
if (tid <= 0) {
printk(KERN_ERR "KGDB: Internal thread select error\n");
dump_stack();
return NULL;
}
/* /*
* find_task_by_pid_ns() does not take the tasklist lock anymore * find_task_by_pid_ns() does not take the tasklist lock anymore
...@@ -619,7 +625,8 @@ static void kgdb_flush_swbreak_addr(unsigned long addr) ...@@ -619,7 +625,8 @@ static void kgdb_flush_swbreak_addr(unsigned long addr)
static int kgdb_activate_sw_breakpoints(void) static int kgdb_activate_sw_breakpoints(void)
{ {
unsigned long addr; unsigned long addr;
int error = 0; int error;
int ret = 0;
int i; int i;
for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
...@@ -629,13 +636,16 @@ static int kgdb_activate_sw_breakpoints(void) ...@@ -629,13 +636,16 @@ static int kgdb_activate_sw_breakpoints(void)
addr = kgdb_break[i].bpt_addr; addr = kgdb_break[i].bpt_addr;
error = kgdb_arch_set_breakpoint(addr, error = kgdb_arch_set_breakpoint(addr,
kgdb_break[i].saved_instr); kgdb_break[i].saved_instr);
if (error) if (error) {
return error; ret = error;
printk(KERN_INFO "KGDB: BP install failed: %lx", addr);
continue;
}
kgdb_flush_swbreak_addr(addr); kgdb_flush_swbreak_addr(addr);
kgdb_break[i].state = BP_ACTIVE; kgdb_break[i].state = BP_ACTIVE;
} }
return 0; return ret;
} }
static int kgdb_set_sw_break(unsigned long addr) static int kgdb_set_sw_break(unsigned long addr)
...@@ -682,7 +692,8 @@ static int kgdb_set_sw_break(unsigned long addr) ...@@ -682,7 +692,8 @@ static int kgdb_set_sw_break(unsigned long addr)
static int kgdb_deactivate_sw_breakpoints(void) static int kgdb_deactivate_sw_breakpoints(void)
{ {
unsigned long addr; unsigned long addr;
int error = 0; int error;
int ret = 0;
int i; int i;
for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
...@@ -691,13 +702,15 @@ static int kgdb_deactivate_sw_breakpoints(void) ...@@ -691,13 +702,15 @@ static int kgdb_deactivate_sw_breakpoints(void)
addr = kgdb_break[i].bpt_addr; addr = kgdb_break[i].bpt_addr;
error = kgdb_arch_remove_breakpoint(addr, error = kgdb_arch_remove_breakpoint(addr,
kgdb_break[i].saved_instr); kgdb_break[i].saved_instr);
if (error) if (error) {
return error; printk(KERN_INFO "KGDB: BP remove failed: %lx\n", addr);
ret = error;
}
kgdb_flush_swbreak_addr(addr); kgdb_flush_swbreak_addr(addr);
kgdb_break[i].state = BP_SET; kgdb_break[i].state = BP_SET;
} }
return 0; return ret;
} }
static int kgdb_remove_sw_break(unsigned long addr) static int kgdb_remove_sw_break(unsigned long addr)
...@@ -1204,8 +1217,10 @@ static int gdb_cmd_exception_pass(struct kgdb_state *ks) ...@@ -1204,8 +1217,10 @@ static int gdb_cmd_exception_pass(struct kgdb_state *ks)
return 1; return 1;
} else { } else {
error_packet(remcom_out_buffer, -EINVAL); kgdb_msg_write("KGDB only knows signal 9 (pass)"
return 0; " and 15 (pass and disconnect)\n"
"Executing a continue without signal passing\n", 0);
remcom_in_buffer[0] = 'c';
} }
/* Indicate fall through */ /* Indicate fall through */
...@@ -1395,6 +1410,7 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) ...@@ -1395,6 +1410,7 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
struct kgdb_state kgdb_var; struct kgdb_state kgdb_var;
struct kgdb_state *ks = &kgdb_var; struct kgdb_state *ks = &kgdb_var;
unsigned long flags; unsigned long flags;
int sstep_tries = 100;
int error = 0; int error = 0;
int i, cpu; int i, cpu;
...@@ -1425,13 +1441,14 @@ acquirelock: ...@@ -1425,13 +1441,14 @@ acquirelock:
cpu_relax(); cpu_relax();
/* /*
* Do not start the debugger connection on this CPU if the last * For single stepping, try to only enter on the processor
* instance of the exception handler wanted to come into the * that was single stepping. To gaurd against a deadlock, the
* debugger on a different CPU via a single step * kernel will only try for the value of sstep_tries before
* giving up and continuing on.
*/ */
if (atomic_read(&kgdb_cpu_doing_single_step) != -1 && if (atomic_read(&kgdb_cpu_doing_single_step) != -1 &&
atomic_read(&kgdb_cpu_doing_single_step) != cpu) { (kgdb_info[cpu].task &&
kgdb_info[cpu].task->pid != kgdb_sstep_pid) && --sstep_tries) {
atomic_set(&kgdb_active, -1); atomic_set(&kgdb_active, -1);
touch_softlockup_watchdog(); touch_softlockup_watchdog();
clocksource_touch_watchdog(); clocksource_touch_watchdog();
...@@ -1524,6 +1541,13 @@ acquirelock: ...@@ -1524,6 +1541,13 @@ acquirelock:
} }
kgdb_restore: kgdb_restore:
if (atomic_read(&kgdb_cpu_doing_single_step) != -1) {
int sstep_cpu = atomic_read(&kgdb_cpu_doing_single_step);
if (kgdb_info[sstep_cpu].task)
kgdb_sstep_pid = kgdb_info[sstep_cpu].task->pid;
else
kgdb_sstep_pid = 0;
}
/* Free kgdb_active */ /* Free kgdb_active */
atomic_set(&kgdb_active, -1); atomic_set(&kgdb_active, -1);
touch_softlockup_watchdog(); touch_softlockup_watchdog();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment