kgdb: Add the ability to schedule a breakpoint via a tasklet
[sfrench/cifs-2.6.git] / kernel / debug / debug_core.c
index 7e03969330bcdbb6039bf5525bbadcf60737194a..fff59019cca014cb58284120471a9c2cd4c36ed2 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/sysrq.h>
 #include <linux/init.h>
 #include <linux/kgdb.h>
+#include <linux/kdb.h>
 #include <linux/pid.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
@@ -65,7 +66,7 @@ int                           kgdb_connected;
 EXPORT_SYMBOL_GPL(kgdb_connected);
 
 /* All the KGDB handlers are installed */
-static int                     kgdb_io_module_registered;
+int                    kgdb_io_module_registered;
 
 /* Guard for recursive entry */
 static int                     exception_level;
@@ -77,6 +78,11 @@ static DEFINE_SPINLOCK(kgdb_registration_lock);
 static int kgdb_con_registered;
 /* determine if kgdb console output should be used */
 static int kgdb_use_con;
+/* Next cpu to become the master debug core */
+int dbg_switch_cpu;
+
+/* Use kdb or gdbserver mode */
+int dbg_kdb_mode = 1;
 
 static int __init opt_kgdb_con(char *str)
 {
@@ -100,6 +106,7 @@ static struct kgdb_bkpt             kgdb_break[KGDB_MAX_BREAKPOINTS] = {
  * The CPU# of the active CPU, or -1 if none:
  */
 atomic_t                       kgdb_active = ATOMIC_INIT(-1);
+EXPORT_SYMBOL_GPL(kgdb_active);
 
 /*
  * We use NR_CPUs not PERCPU, in case kgdb is used to debug early
@@ -107,6 +114,7 @@ atomic_t                    kgdb_active = ATOMIC_INIT(-1);
  */
 static atomic_t                        passive_cpu_wait[NR_CPUS];
 static atomic_t                        cpu_in_kgdb[NR_CPUS];
+static atomic_t                        kgdb_break_tasklet_var;
 atomic_t                       kgdb_setting_breakpoint;
 
 struct task_struct             *kgdb_usethread;
@@ -196,12 +204,6 @@ int __weak kgdb_skipexception(int exception, struct pt_regs *regs)
        return 0;
 }
 
-void __weak
-kgdb_post_primary_code(struct pt_regs *regs, int e_vector, int err_code)
-{
-       return;
-}
-
 /**
  *     kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb.
  *     @regs: Current &struct pt_regs.
@@ -301,7 +303,7 @@ int dbg_set_sw_break(unsigned long addr)
        return 0;
 }
 
-static int kgdb_deactivate_sw_breakpoints(void)
+int dbg_deactivate_sw_breakpoints(void)
 {
        unsigned long addr;
        int error;
@@ -395,8 +397,14 @@ static int kgdb_io_ready(int print_wait)
                return 1;
        if (atomic_read(&kgdb_setting_breakpoint))
                return 1;
-       if (print_wait)
+       if (print_wait) {
+#ifdef CONFIG_KGDB_KDB
+               if (!dbg_kdb_mode)
+                       printk(KERN_CRIT "KGDB: waiting... or $3#33 for KDB\n");
+#else
                printk(KERN_CRIT "KGDB: Waiting for remote debugger\n");
+#endif
+       }
        return 1;
 }
 
@@ -410,7 +418,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks)
        /* Panic on recursive debugger calls: */
        exception_level++;
        addr = kgdb_arch_pc(ks->ex_vector, ks->linux_regs);
-       kgdb_deactivate_sw_breakpoints();
+       dbg_deactivate_sw_breakpoints();
 
        /*
         * If the break point removed ok at the place exception
@@ -443,11 +451,24 @@ static int kgdb_reenter_check(struct kgdb_state *ks)
        return 1;
 }
 
+static void dbg_cpu_switch(int cpu, int next_cpu)
+{
+       /* Mark the cpu we are switching away from as a slave when it
+        * holds the kgdb_active token.  This must be done so that the
+        * that all the cpus wait in for the debug core will not enter
+        * again as the master. */
+       if (cpu == atomic_read(&kgdb_active)) {
+               kgdb_info[cpu].exception_state |= DCPU_IS_SLAVE;
+               kgdb_info[cpu].exception_state &= ~DCPU_WANT_MASTER;
+       }
+       kgdb_info[next_cpu].exception_state |= DCPU_NEXT_MASTER;
+}
+
 static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs)
 {
        unsigned long flags;
        int sstep_tries = 100;
-       int error = 0;
+       int error;
        int i, cpu;
        int trace_on = 0;
 acquirelock:
@@ -460,6 +481,8 @@ acquirelock:
        cpu = ks->cpu;
        kgdb_info[cpu].debuggerinfo = regs;
        kgdb_info[cpu].task = current;
+       kgdb_info[cpu].ret_state = 0;
+       kgdb_info[cpu].irq_depth = hardirq_count() >> HARDIRQ_SHIFT;
        /*
         * Make sure the above info reaches the primary CPU before
         * our cpu_in_kgdb[] flag setting does:
@@ -471,7 +494,11 @@ acquirelock:
         * master cpu and acquire the kgdb_active lock:
         */
        while (1) {
-               if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) {
+cpu_loop:
+               if (kgdb_info[cpu].exception_state & DCPU_NEXT_MASTER) {
+                       kgdb_info[cpu].exception_state &= ~DCPU_NEXT_MASTER;
+                       goto cpu_master_loop;
+               } else if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) {
                        if (atomic_cmpxchg(&kgdb_active, -1, cpu) == cpu)
                                break;
                } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) {
@@ -513,7 +540,7 @@ return_normal:
        }
 
        if (!kgdb_io_ready(1)) {
-               error = 1;
+               kgdb_info[cpu].ret_state = 1;
                goto kgdb_restore; /* No I/O connection, resume the system */
        }
 
@@ -548,7 +575,7 @@ return_normal:
         * Wait for the other CPUs to be notified and be waiting for us:
         */
        for_each_online_cpu(i) {
-               while (!atomic_read(&cpu_in_kgdb[i]))
+               while (kgdb_do_roundup && !atomic_read(&cpu_in_kgdb[i]))
                        cpu_relax();
        }
 
@@ -556,8 +583,7 @@ return_normal:
         * At this point the primary processor is completely
         * in the debugger and all secondary CPUs are quiescent
         */
-       kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code);
-       kgdb_deactivate_sw_breakpoints();
+       dbg_deactivate_sw_breakpoints();
        kgdb_single_step = 0;
        kgdb_contthread = current;
        exception_level = 0;
@@ -565,8 +591,26 @@ return_normal:
        if (trace_on)
                tracing_off();
 
-       /* Talk to debugger with gdbserial protocol */
-       error = gdb_serial_stub(ks);
+       while (1) {
+cpu_master_loop:
+               if (dbg_kdb_mode) {
+                       kgdb_connected = 1;
+                       error = kdb_stub(ks);
+               } else {
+                       error = gdb_serial_stub(ks);
+               }
+
+               if (error == DBG_PASS_EVENT) {
+                       dbg_kdb_mode = !dbg_kdb_mode;
+                       kgdb_connected = 0;
+               } else if (error == DBG_SWITCH_CPU_EVENT) {
+                       dbg_cpu_switch(cpu, dbg_switch_cpu);
+                       goto cpu_loop;
+               } else {
+                       kgdb_info[cpu].ret_state = error;
+                       break;
+               }
+       }
 
        /* Call the I/O driver's post_exception routine */
        if (dbg_io_ops->post_exception)
@@ -578,11 +622,16 @@ return_normal:
                for (i = NR_CPUS-1; i >= 0; i--)
                        atomic_dec(&passive_cpu_wait[i]);
                /*
-                * Wait till all the CPUs have quit
-                * from the debugger.
+                * Wait till all the CPUs have quit from the debugger,
+                * but allow a CPU that hit an exception and is
+                * waiting to become the master to remain in the debug
+                * core.
                 */
                for_each_online_cpu(i) {
-                       while (atomic_read(&cpu_in_kgdb[i]))
+                       while (kgdb_do_roundup &&
+                              atomic_read(&cpu_in_kgdb[i]) &&
+                              !(kgdb_info[i].exception_state &
+                                DCPU_WANT_MASTER))
                                cpu_relax();
                }
        }
@@ -603,7 +652,7 @@ kgdb_restore:
        clocksource_touch_watchdog();
        local_irq_restore(flags);
 
-       return error;
+       return kgdb_info[cpu].ret_state;
 }
 
 /*
@@ -623,7 +672,6 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
        ks->cpu                 = raw_smp_processor_id();
        ks->ex_vector           = evector;
        ks->signo               = signo;
-       ks->ex_vector           = evector;
        ks->err_code            = ecode;
        ks->kgdb_usethreadid    = 0;
        ks->linux_regs          = regs;
@@ -632,7 +680,8 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
                return 0; /* Ouch, double exception ! */
        kgdb_info[ks->cpu].exception_state |= DCPU_WANT_MASTER;
        ret = kgdb_cpu_enter(ks, regs);
-       kgdb_info[ks->cpu].exception_state &= ~DCPU_WANT_MASTER;
+       kgdb_info[ks->cpu].exception_state &= ~(DCPU_WANT_MASTER |
+                                               DCPU_IS_SLAVE);
        return ret;
 }
 
@@ -665,7 +714,7 @@ static void kgdb_console_write(struct console *co, const char *s,
 
        /* If we're debugging, or KGDB has not connected, don't try
         * and print. */
-       if (!kgdb_connected || atomic_read(&kgdb_active) != -1)
+       if (!kgdb_connected || atomic_read(&kgdb_active) != -1 || dbg_kdb_mode)
                return;
 
        local_irq_save(flags);
@@ -687,8 +736,14 @@ static void sysrq_handle_dbg(int key, struct tty_struct *tty)
                printk(KERN_CRIT "ERROR: No KGDB I/O module available\n");
                return;
        }
-       if (!kgdb_connected)
+       if (!kgdb_connected) {
+#ifdef CONFIG_KGDB_KDB
+               if (!dbg_kdb_mode)
+                       printk(KERN_CRIT "KGDB or $3#33 for KDB\n");
+#else
                printk(KERN_CRIT "Entering KGDB\n");
+#endif
+       }
 
        kgdb_breakpoint();
 }
@@ -735,6 +790,31 @@ static void kgdb_unregister_callbacks(void)
        }
 }
 
+/*
+ * There are times a tasklet needs to be used vs a compiled in
+ * break point so as to cause an exception outside a kgdb I/O module,
+ * such as is the case with kgdboe, where calling a breakpoint in the
+ * I/O driver itself would be fatal.
+ */
+static void kgdb_tasklet_bpt(unsigned long ing)
+{
+       kgdb_breakpoint();
+       atomic_set(&kgdb_break_tasklet_var, 0);
+}
+
+static DECLARE_TASKLET(kgdb_tasklet_breakpoint, kgdb_tasklet_bpt, 0);
+
+void kgdb_schedule_breakpoint(void)
+{
+       if (atomic_read(&kgdb_break_tasklet_var) ||
+               atomic_read(&kgdb_active) != -1 ||
+               atomic_read(&kgdb_setting_breakpoint))
+               return;
+       atomic_inc(&kgdb_break_tasklet_var);
+       tasklet_schedule(&kgdb_tasklet_breakpoint);
+}
+EXPORT_SYMBOL_GPL(kgdb_schedule_breakpoint);
+
 static void kgdb_initial_breakpoint(void)
 {
        kgdb_break_asap = 0;
@@ -817,6 +897,18 @@ void kgdb_unregister_io_module(struct kgdb_io *old_dbg_io_ops)
 }
 EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
 
+int dbg_io_get_char(void)
+{
+       int ret = dbg_io_ops->read_char();
+       if (ret == NO_POLL_CHAR)
+               return -1;
+       if (!dbg_kdb_mode)
+               return ret;
+       if (ret == 127)
+               return 8;
+       return ret;
+}
+
 /**
  * kgdb_breakpoint - generate breakpoint exception
  *
@@ -839,6 +931,7 @@ static int __init opt_kgdb_wait(char *str)
 {
        kgdb_break_asap = 1;
 
+       kdb_init(KDB_INIT_EARLY);
        if (kgdb_io_module_registered)
                kgdb_initial_breakpoint();