trace: stop all recording to ring buffer on ftrace_dump
[safe/jmp/linux-2.6] / kernel / kgdb.c
index 14787de..e4dcfb2 100644 (file)
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
+#include <asm/unaligned.h>
 
 static int kgdb_break_asap;
 
+#define KGDB_MAX_THREAD_QUERY 17
 struct kgdb_state {
        int                     ex_vector;
        int                     signo;
        int                     err_code;
        int                     cpu;
        int                     pass_exception;
+       unsigned long           thr_query;
        unsigned long           threadid;
        long                    kgdb_usethreadid;
        struct pt_regs          *linux_regs;
@@ -165,13 +168,6 @@ early_param("nokgdbroundup", opt_nokgdbroundup);
  * Weak aliases for breakpoint management,
  * can be overriden by architectures when needed:
  */
-int __weak kgdb_validate_break_address(unsigned long addr)
-{
-       char tmp_variable[BREAK_INSTR_SIZE];
-
-       return probe_kernel_read(tmp_variable, (char *)addr, BREAK_INSTR_SIZE);
-}
-
 int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
 {
        int err;
@@ -190,6 +186,25 @@ int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
                                  (char *)bundle, BREAK_INSTR_SIZE);
 }
 
+int __weak kgdb_validate_break_address(unsigned long addr)
+{
+       char tmp_variable[BREAK_INSTR_SIZE];
+       int err;
+       /* Validate setting the breakpoint and then removing it.  In the
+        * remove fails, the kernel needs to emit a bad message because we
+        * are deep trouble not being able to put things back the way we
+        * found them.
+        */
+       err = kgdb_arch_set_breakpoint(addr, tmp_variable);
+       if (err)
+               return err;
+       err = kgdb_arch_remove_breakpoint(addr, tmp_variable);
+       if (err)
+               printk(KERN_ERR "KGDB: Critical breakpoint error, kernel "
+                  "memory destroyed at: %lx", addr);
+       return err;
+}
+
 unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs)
 {
        return instruction_pointer(regs);
@@ -227,8 +242,6 @@ void __weak kgdb_disable_hw_debug(struct pt_regs *regs)
  * GDB remote protocol parser:
  */
 
-static const char      hexchars[] = "0123456789abcdef";
-
 static int hex(char ch)
 {
        if ((ch >= 'a') && (ch <= 'f'))
@@ -316,8 +329,8 @@ static void put_packet(char *buffer)
                }
 
                kgdb_io_ops->write_char('#');
-               kgdb_io_ops->write_char(hexchars[checksum >> 4]);
-               kgdb_io_ops->write_char(hexchars[checksum & 0xf]);
+               kgdb_io_ops->write_char(hex_asc_hi(checksum));
+               kgdb_io_ops->write_char(hex_asc_lo(checksum));
                if (kgdb_io_ops->flush)
                        kgdb_io_ops->flush();
 
@@ -434,9 +447,14 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val)
 {
        int hex_val;
        int num = 0;
+       int negate = 0;
 
        *long_val = 0;
 
+       if (**ptr == '-') {
+               negate = 1;
+               (*ptr)++;
+       }
        while (**ptr) {
                hex_val = hex(**ptr);
                if (hex_val < 0)
@@ -447,6 +465,9 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val)
                (*ptr)++;
        }
 
+       if (negate)
+               *long_val = -*long_val;
+
        return num;
 }
 
@@ -467,7 +488,7 @@ static int write_mem_msg(int binary)
                if (err)
                        return err;
                if (CACHE_FLUSH_IS_SAFE)
-                       flush_icache_range(addr, addr + length + 1);
+                       flush_icache_range(addr, addr + length);
                return 0;
        }
 
@@ -478,8 +499,8 @@ static void error_packet(char *pkt, int error)
 {
        error = -error;
        pkt[0] = 'E';
-       pkt[1] = hexchars[(error / 10)];
-       pkt[2] = hexchars[(error % 10)];
+       pkt[1] = hex_asc[(error / 10)];
+       pkt[2] = hex_asc[(error % 10)];
        pkt[3] = '\0';
 }
 
@@ -510,19 +531,22 @@ static void int_to_threadref(unsigned char *id, int value)
        scan = (unsigned char *)id;
        while (i--)
                *scan++ = 0;
-       *scan++ = (value >> 24) & 0xff;
-       *scan++ = (value >> 16) & 0xff;
-       *scan++ = (value >> 8) & 0xff;
-       *scan++ = (value & 0xff);
+       put_unaligned_be32(value, scan);
 }
 
 static struct task_struct *getthread(struct pt_regs *regs, int tid)
 {
        /*
-        * Non-positive TIDs are remapped idle tasks:
+        * Non-positive TIDs are remapped to the cpu shadow information
         */
-       if (tid <= 0)
-               return idle_task(-tid);
+       if (tid == 0 || tid == -1)
+               tid = -atomic_read(&kgdb_active) - 2;
+       if (tid < 0) {
+               if (kgdb_info[-tid - 2].task)
+                       return kgdb_info[-tid - 2].task;
+               else
+                       return idle_task(-tid - 2);
+       }
 
        /*
         * find_task_by_pid_ns() does not take the tasklist lock anymore
@@ -566,6 +590,7 @@ static void kgdb_wait(struct pt_regs *regs)
 
        /* Signal the primary CPU that we are done: */
        atomic_set(&cpu_in_kgdb[cpu], 0);
+       touch_softlockup_watchdog();
        clocksource_touch_watchdog();
        local_irq_restore(flags);
 }
@@ -729,14 +754,15 @@ setundefined:
 }
 
 /*
- * Remap normal tasks to their real PID, idle tasks to -1 ... -NR_CPUs:
+ * Remap normal tasks to their real PID,
+ * CPU shadow threads are mapped to -CPU - 2
  */
 static inline int shadow_pid(int realpid)
 {
        if (realpid)
                return realpid;
 
-       return -1-raw_smp_processor_id();
+       return -raw_smp_processor_id() - 2;
 }
 
 static char gdbmsgbuf[BUFMAX + 1];
@@ -830,7 +856,7 @@ static void gdb_cmd_getregs(struct kgdb_state *ks)
                local_debuggerinfo = kgdb_info[ks->cpu].debuggerinfo;
        } else {
                local_debuggerinfo = NULL;
-               for (i = 0; i < NR_CPUS; i++) {
+               for_each_online_cpu(i) {
                        /*
                         * Try to find the task on some other
                         * or possibly this node if we do not
@@ -964,10 +990,13 @@ static int gdb_cmd_reboot(struct kgdb_state *ks)
 /* Handle the 'q' query packets */
 static void gdb_cmd_query(struct kgdb_state *ks)
 {
-       struct task_struct *thread;
+       struct task_struct *g;
+       struct task_struct *p;
        unsigned char thref[8];
        char *ptr;
        int i;
+       int cpu;
+       int finished = 0;
 
        switch (remcom_in_buffer[1]) {
        case 's':
@@ -977,22 +1006,34 @@ static void gdb_cmd_query(struct kgdb_state *ks)
                        break;
                }
 
-               if (remcom_in_buffer[1] == 'f')
-                       ks->threadid = 1;
-
+               i = 0;
                remcom_out_buffer[0] = 'm';
                ptr = remcom_out_buffer + 1;
-
-               for (i = 0; i < 17; ks->threadid++) {
-                       thread = getthread(ks->linux_regs, ks->threadid);
-                       if (thread) {
-                               int_to_threadref(thref, ks->threadid);
+               if (remcom_in_buffer[1] == 'f') {
+                       /* Each cpu is a shadow thread */
+                       for_each_online_cpu(cpu) {
+                               ks->thr_query = 0;
+                               int_to_threadref(thref, -cpu - 2);
                                pack_threadid(ptr, thref);
                                ptr += BUF_THREAD_ID_SIZE;
                                *(ptr++) = ',';
                                i++;
                        }
                }
+
+               do_each_thread(g, p) {
+                       if (i >= ks->thr_query && !finished) {
+                               int_to_threadref(thref, p->pid);
+                               pack_threadid(ptr, thref);
+                               ptr += BUF_THREAD_ID_SIZE;
+                               *(ptr++) = ',';
+                               ks->thr_query++;
+                               if (ks->thr_query % KGDB_MAX_THREAD_QUERY == 0)
+                                       finished = 1;
+                       }
+                       i++;
+               } while_each_thread(g, p);
+
                *(--ptr) = '\0';
                break;
 
@@ -1015,15 +1056,15 @@ static void gdb_cmd_query(struct kgdb_state *ks)
                        error_packet(remcom_out_buffer, -EINVAL);
                        break;
                }
-               if (ks->threadid > 0) {
+               if ((int)ks->threadid > 0) {
                        kgdb_mem2hex(getthread(ks->linux_regs,
                                        ks->threadid)->comm,
                                        remcom_out_buffer, 16);
                } else {
                        static char tmpstr[23 + BUF_THREAD_ID_SIZE];
 
-                       sprintf(tmpstr, "Shadow task %d for pid 0",
-                                       (int)(-ks->threadid-1));
+                       sprintf(tmpstr, "shadowCPU%d",
+                                       (int)(-ks->threadid - 2));
                        kgdb_mem2hex(tmpstr, remcom_out_buffer, strlen(tmpstr));
                }
                break;
@@ -1392,6 +1433,7 @@ acquirelock:
            atomic_read(&kgdb_cpu_doing_single_step) != cpu) {
 
                atomic_set(&kgdb_active, -1);
+               touch_softlockup_watchdog();
                clocksource_touch_watchdog();
                local_irq_restore(flags);
 
@@ -1422,7 +1464,7 @@ acquirelock:
         * Get the passive CPU lock which will hold all the non-primary
         * 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++)
                        atomic_set(&passive_cpu_wait[i], 1);
        }
@@ -1435,7 +1477,7 @@ acquirelock:
 
 #ifdef CONFIG_SMP
        /* 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);
 #endif
 
@@ -1454,7 +1496,7 @@ acquirelock:
        kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code);
        kgdb_deactivate_sw_breakpoints();
        kgdb_single_step = 0;
-       kgdb_contthread = NULL;
+       kgdb_contthread = current;
        exception_level = 0;
 
        /* Talk to debugger with gdbserial protocol */
@@ -1468,7 +1510,7 @@ acquirelock:
        kgdb_info[ks->cpu].task = NULL;
        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--)
                        atomic_set(&passive_cpu_wait[i], 0);
                /*
@@ -1484,6 +1526,7 @@ acquirelock:
 kgdb_restore:
        /* Free kgdb_active */
        atomic_set(&kgdb_active, -1);
+       touch_softlockup_watchdog();
        clocksource_touch_watchdog();
        local_irq_restore(flags);
 
@@ -1503,7 +1546,8 @@ int kgdb_nmicallback(int cpu, void *regs)
        return 1;
 }
 
-void kgdb_console_write(struct console *co, const char *s, unsigned count)
+static void kgdb_console_write(struct console *co, const char *s,
+   unsigned count)
 {
        unsigned long flags;