Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Dec 2009 23:19:56 +0000 (15:19 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Dec 2009 23:19:56 +0000 (15:19 -0800)
* '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

arch/x86/kernel/kgdb.c
drivers/misc/kgdbts.c
kernel/kgdb.c

index 20a5b3689463c6df5d26b98fcfcb2f43fca5b851..dd74fe7273b120643bf2f4a7563295afde009233 100644 (file)
@@ -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_ES]        = regs->es;
        gdb_regs[GDB_CS]        = regs->cs;
-       gdb_regs[GDB_SS]        = __KERNEL_DS;
        gdb_regs[GDB_FS]        = 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
        gdb_regs[GDB_R8]        = regs->r8;
        gdb_regs[GDB_R9]        = regs->r9;
@@ -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_CS]      = regs->cs;
        gdb_regs32[GDB_SS]      = regs->ss;
-#endif
        gdb_regs[GDB_SP]        = kernel_stack_pointer(regs);
+#endif
 }
 
 /**
@@ -220,8 +226,7 @@ static void kgdb_correct_hw_break(void)
                        dr7 |= ((breakinfo[breakno].len << 2) |
                                 breakinfo[breakno].type) <<
                               ((breakno << 2) + 16);
-                       if (breakno >= 0 && breakno <= 3)
-                               set_debugreg(breakinfo[breakno].addr, breakno);
+                       set_debugreg(breakinfo[breakno].addr, breakno);
 
                } else {
                        if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
@@ -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 */
                if (remcomInBuffer[0] == 's') {
                        linux_regs->flags |= X86_EFLAGS_TF;
-                       kgdb_single_step = 1;
                        atomic_set(&kgdb_cpu_doing_single_step,
                                   raw_smp_processor_id());
                }
index e4ff50b95a5ee8c5f834ab17f4834795108eaa8f..fcb6ec1af173dfe22e3130ef6016f348c3f24858 100644 (file)
@@ -712,6 +712,12 @@ static int run_simple_test(int is_get_char, int chr)
 
        /* End of packet == #XX so look for the '#' */
        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';
                v2printk("put%i: %s\n", ts.idx, put_buf);
                /* Trigger check here */
@@ -885,16 +891,16 @@ static void kgdbts_run_tests(void)
        int nmi_sleep = 0;
        int i;
 
-       ptr = strstr(config, "F");
+       ptr = strchr(config, 'F');
        if (ptr)
                fork_test = simple_strtol(ptr + 1, NULL, 10);
-       ptr = strstr(config, "S");
+       ptr = strchr(config, 'S');
        if (ptr)
                do_sys_open_test = simple_strtol(ptr + 1, NULL, 10);
-       ptr = strstr(config, "N");
+       ptr = strchr(config, 'N');
        if (ptr)
                nmi_sleep = simple_strtol(ptr+1, NULL, 10);
-       ptr = strstr(config, "I");
+       ptr = strchr(config, 'I');
        if (ptr)
                sstep_test = simple_strtol(ptr+1, NULL, 10);
 
index 7d70146340224b501c2c77dec5fdc0a40bb1820a..2eb517e2351462bd263d8976cf3d2108ecfeebc2 100644 (file)
@@ -129,6 +129,7 @@ struct task_struct          *kgdb_usethread;
 struct task_struct             *kgdb_contthread;
 
 int                            kgdb_single_step;
+pid_t                          kgdb_sstep_pid;
 
 /* Our I/O buffers. */
 static char                    remcom_in_buffer[BUFMAX];
@@ -541,12 +542,17 @@ static struct task_struct *getthread(struct pt_regs *regs, int tid)
         */
        if (tid == 0 || tid == -1)
                tid = -atomic_read(&kgdb_active) - 2;
-       if (tid < 0) {
+       if (tid < -1 && tid > -NR_CPUS - 2) {
                if (kgdb_info[-tid - 2].task)
                        return kgdb_info[-tid - 2].task;
                else
                        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
@@ -619,7 +625,8 @@ static void kgdb_flush_swbreak_addr(unsigned long addr)
 static int kgdb_activate_sw_breakpoints(void)
 {
        unsigned long addr;
-       int error = 0;
+       int error;
+       int ret = 0;
        int i;
 
        for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
@@ -629,13 +636,16 @@ static int kgdb_activate_sw_breakpoints(void)
                addr = kgdb_break[i].bpt_addr;
                error = kgdb_arch_set_breakpoint(addr,
                                kgdb_break[i].saved_instr);
-               if (error)
-                       return error;
+               if (error) {
+                       ret = error;
+                       printk(KERN_INFO "KGDB: BP install failed: %lx", addr);
+                       continue;
+               }
 
                kgdb_flush_swbreak_addr(addr);
                kgdb_break[i].state = BP_ACTIVE;
        }
-       return 0;
+       return ret;
 }
 
 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)
 {
        unsigned long addr;
-       int error = 0;
+       int error;
+       int ret = 0;
        int i;
 
        for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
@@ -691,13 +702,15 @@ static int kgdb_deactivate_sw_breakpoints(void)
                addr = kgdb_break[i].bpt_addr;
                error = kgdb_arch_remove_breakpoint(addr,
                                        kgdb_break[i].saved_instr);
-               if (error)
-                       return error;
+               if (error) {
+                       printk(KERN_INFO "KGDB: BP remove failed: %lx\n", addr);
+                       ret = error;
+               }
 
                kgdb_flush_swbreak_addr(addr);
                kgdb_break[i].state = BP_SET;
        }
-       return 0;
+       return ret;
 }
 
 static int kgdb_remove_sw_break(unsigned long addr)
@@ -1204,8 +1217,10 @@ static int gdb_cmd_exception_pass(struct kgdb_state *ks)
                return 1;
 
        } else {
-               error_packet(remcom_out_buffer, -EINVAL);
-               return 0;
+               kgdb_msg_write("KGDB only knows signal 9 (pass)"
+                       " and 15 (pass and disconnect)\n"
+                       "Executing a continue without signal passing\n", 0);
+               remcom_in_buffer[0] = 'c';
        }
 
        /* Indicate fall through */
@@ -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 *ks = &kgdb_var;
        unsigned long flags;
+       int sstep_tries = 100;
        int error = 0;
        int i, cpu;
 
@@ -1425,13 +1441,14 @@ acquirelock:
                cpu_relax();
 
        /*
-        * Do not start the debugger connection on this CPU if the last
-        * instance of the exception handler wanted to come into the
-        * debugger on a different CPU via a single step
+        * For single stepping, try to only enter on the processor
+        * that was single stepping.  To gaurd against a deadlock, the
+        * 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 &&
-           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);
                touch_softlockup_watchdog();
                clocksource_touch_watchdog();
@@ -1524,6 +1541,13 @@ acquirelock:
        }
 
 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 */
        atomic_set(&kgdb_active, -1);
        touch_softlockup_watchdog();