kernel_debugger_core: add interrupt-context debugger core
Brian Swetland [Wed, 9 Apr 2008 05:34:46 +0000 (22:34 -0700)]
This provides kernel_debugger() which can be called from an interrupt
context low level debugger wedge to execute commands that inspect
kernel state.  It doesn't do much on its own.

Signed-off-by: Brian Swetland <swetland@google.com>

kernel_debugger_core: Add sysrq command.

sysrq <c> will run the sysrq command <c> and dump what
was added to the kernel log while the command ran.

Signed-off-by: Brian Swetland <swetland@google.com>
Signed-off-by: Arve Hjønnevåg <arve@android.com>

drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/kernel_debugger.c [new file with mode: 0644]
include/linux/kernel_debugger.h [new file with mode: 0644]

index da986b0..d97dd9b 100644 (file)
@@ -234,6 +234,13 @@ config ENCLOSURE_SERVICES
          driver (SCSI/ATA) which supports enclosures
          or a SCSI enclosure device (SES) to use these services.
 
+config KERNEL_DEBUGGER_CORE
+       bool "Kernel Debugger Core"
+       default n
+       ---help---
+         Generic kernel debugging command processor used by low level
+         (interrupt context) platform-specific debuggers.
+
 config SGI_XP
        tristate "Support communication between SGI SSIs"
        depends on NET
index 3070e44..f657913 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_APDS990X)        += apds990x.o
 obj-$(CONFIG_ANDROID_PMEM)     += pmem.o
 obj-$(CONFIG_SGI_IOC4)         += ioc4.o
 obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
+obj-$(CONFIG_KERNEL_DEBUGGER_CORE)     += kernel_debugger.o
 obj-$(CONFIG_KGDB_TESTS)       += kgdbts.o
 obj-$(CONFIG_SGI_XP)           += sgi-xp/
 obj-$(CONFIG_SGI_GRU)          += sgi-gru/
diff --git a/drivers/misc/kernel_debugger.c b/drivers/misc/kernel_debugger.c
new file mode 100644 (file)
index 0000000..44c19fd
--- /dev/null
@@ -0,0 +1,79 @@
+/* drivers/android/kernel_debugger.c
+ *
+ * Guts of the kernel debugger.
+ * Needs something to actually push commands to it.
+ *
+ * Copyright (C) 2007-2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/kernel_debugger.h>
+
+#define dprintf(fmt...) (ctxt->printf(ctxt->cookie, fmt))
+
+static void do_ps(struct kdbg_ctxt *ctxt)
+{
+       struct task_struct *g, *p;
+       unsigned state;
+       static const char stat_nam[] = "RSDTtZX";
+
+       dprintf("pid   ppid  prio task            pc\n");
+       read_lock(&tasklist_lock);
+       do_each_thread(g, p) {
+               state = p->state ? __ffs(p->state) + 1 : 0;
+               dprintf("%5d %5d %4d ", p->pid, p->parent->pid, p->prio);
+               dprintf("%-13.13s %c", p->comm,
+                       state >= sizeof(stat_nam) ? '?' : stat_nam[state]);
+               if (state == TASK_RUNNING)
+                       dprintf(" running\n");
+               else
+                       dprintf(" %08lx\n", thread_saved_pc(p));
+       } while_each_thread(g, p);
+       read_unlock(&tasklist_lock);
+}
+
+int log_buf_copy(char *dest, int idx, int len);
+extern int do_syslog(int type, char __user *bug, int count);
+static void do_sysrq(struct kdbg_ctxt *ctxt, char rq)
+{
+       char buf[128];
+       int ret;
+       int idx = 0;
+       do_syslog(5 /* clear */, NULL, 0);
+       handle_sysrq(rq, NULL);
+       while (1) {
+               ret = log_buf_copy(buf, idx, sizeof(buf) - 1);
+               if (ret <= 0)
+                       break;
+               buf[ret] = 0;
+               dprintf("%s", buf);
+               idx += ret;
+       }
+}
+
+int kernel_debugger(struct kdbg_ctxt *ctxt, char *cmd)
+{
+       if (!strcmp(cmd, "ps"))
+               do_ps(ctxt);
+       if (!strcmp(cmd, "sysrq"))
+               do_sysrq(ctxt, 'h');
+       if (!strncmp(cmd, "sysrq ", 6))
+               do_sysrq(ctxt, cmd[6]);
+
+       return 0;
+}
+
diff --git a/include/linux/kernel_debugger.h b/include/linux/kernel_debugger.h
new file mode 100644 (file)
index 0000000..b4dbfe9
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * include/linux/kernel_debugger.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LINUX_KERNEL_DEBUGGER_H_
+#define _LINUX_KERNEL_DEBUGGER_H_
+
+struct kdbg_ctxt {
+       int (*printf)(void *cookie, const char *fmt, ...);
+       void *cookie;
+};
+
+/* kernel_debugger() is called from IRQ context and should
+ * use the kdbg_ctxt.printf to write output (do NOT call
+ * printk, do operations not safe from IRQ context, etc).
+ *
+ * kdbg_ctxt.printf will return -1 if there is not enough
+ * buffer space or if you are being aborted.  In this case
+ * you must return as soon as possible.
+ *
+ * Return non-zero if more data is available -- if buffer
+ * space ran and you had to stop, but could print more,
+ * for example.
+ *
+ * Additional calls where cmd is "more" will be made if
+ * the additional data is desired.
+ */
+int kernel_debugger(struct kdbg_ctxt *ctxt, char *cmd);
+
+#endif