Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / kernel / debug / kdb / kdb_main.c
diff --git a/kernel/kernel/debug/kdb/kdb_main.c b/kernel/kernel/debug/kdb/kdb_main.c
new file mode 100644 (file)
index 0000000..4121345
--- /dev/null
@@ -0,0 +1,2954 @@
+/*
+ * Kernel Debugger Architecture Independent Main Code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
+ * Xscale (R) modifications copyright (C) 2003 Intel Corporation.
+ * Copyright (c) 2009 Wind River Systems, Inc.  All Rights Reserved.
+ */
+
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/kmsg_dump.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/sysrq.h>
+#include <linux/smp.h>
+#include <linux/utsname.h>
+#include <linux/vmalloc.h>
+#include <linux/atomic.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/kallsyms.h>
+#include <linux/kgdb.h>
+#include <linux/kdb.h>
+#include <linux/notifier.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/nmi.h>
+#include <linux/time.h>
+#include <linux/ptrace.h>
+#include <linux/sysctl.h>
+#include <linux/cpu.h>
+#include <linux/kdebug.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include "kdb_private.h"
+
+#undef MODULE_PARAM_PREFIX
+#define        MODULE_PARAM_PREFIX "kdb."
+
+static int kdb_cmd_enabled = CONFIG_KDB_DEFAULT_ENABLE;
+module_param_named(cmd_enable, kdb_cmd_enabled, int, 0600);
+
+char kdb_grep_string[KDB_GREP_STRLEN];
+int kdb_grepping_flag;
+EXPORT_SYMBOL(kdb_grepping_flag);
+int kdb_grep_leading;
+int kdb_grep_trailing;
+
+/*
+ * Kernel debugger state flags
+ */
+int kdb_flags;
+atomic_t kdb_event;
+
+/*
+ * kdb_lock protects updates to kdb_initial_cpu.  Used to
+ * single thread processors through the kernel debugger.
+ */
+int kdb_initial_cpu = -1;      /* cpu number that owns kdb */
+int kdb_nextline = 1;
+int kdb_state;                 /* General KDB state */
+
+struct task_struct *kdb_current_task;
+EXPORT_SYMBOL(kdb_current_task);
+struct pt_regs *kdb_current_regs;
+
+const char *kdb_diemsg;
+static int kdb_go_count;
+#ifdef CONFIG_KDB_CONTINUE_CATASTROPHIC
+static unsigned int kdb_continue_catastrophic =
+       CONFIG_KDB_CONTINUE_CATASTROPHIC;
+#else
+static unsigned int kdb_continue_catastrophic;
+#endif
+
+/* kdb_commands describes the available commands. */
+static kdbtab_t *kdb_commands;
+#define KDB_BASE_CMD_MAX 50
+static int kdb_max_commands = KDB_BASE_CMD_MAX;
+static kdbtab_t kdb_base_commands[KDB_BASE_CMD_MAX];
+#define for_each_kdbcmd(cmd, num)                                      \
+       for ((cmd) = kdb_base_commands, (num) = 0;                      \
+            num < kdb_max_commands;                                    \
+            num++, num == KDB_BASE_CMD_MAX ? cmd = kdb_commands : cmd++)
+
+typedef struct _kdbmsg {
+       int     km_diag;        /* kdb diagnostic */
+       char    *km_msg;        /* Corresponding message text */
+} kdbmsg_t;
+
+#define KDBMSG(msgnum, text) \
+       { KDB_##msgnum, text }
+
+static kdbmsg_t kdbmsgs[] = {
+       KDBMSG(NOTFOUND, "Command Not Found"),
+       KDBMSG(ARGCOUNT, "Improper argument count, see usage."),
+       KDBMSG(BADWIDTH, "Illegal value for BYTESPERWORD use 1, 2, 4 or 8, "
+              "8 is only allowed on 64 bit systems"),
+       KDBMSG(BADRADIX, "Illegal value for RADIX use 8, 10 or 16"),
+       KDBMSG(NOTENV, "Cannot find environment variable"),
+       KDBMSG(NOENVVALUE, "Environment variable should have value"),
+       KDBMSG(NOTIMP, "Command not implemented"),
+       KDBMSG(ENVFULL, "Environment full"),
+       KDBMSG(ENVBUFFULL, "Environment buffer full"),
+       KDBMSG(TOOMANYBPT, "Too many breakpoints defined"),
+#ifdef CONFIG_CPU_XSCALE
+       KDBMSG(TOOMANYDBREGS, "More breakpoints than ibcr registers defined"),
+#else
+       KDBMSG(TOOMANYDBREGS, "More breakpoints than db registers defined"),
+#endif
+       KDBMSG(DUPBPT, "Duplicate breakpoint address"),
+       KDBMSG(BPTNOTFOUND, "Breakpoint not found"),
+       KDBMSG(BADMODE, "Invalid IDMODE"),
+       KDBMSG(BADINT, "Illegal numeric value"),
+       KDBMSG(INVADDRFMT, "Invalid symbolic address format"),
+       KDBMSG(BADREG, "Invalid register name"),
+       KDBMSG(BADCPUNUM, "Invalid cpu number"),
+       KDBMSG(BADLENGTH, "Invalid length field"),
+       KDBMSG(NOBP, "No Breakpoint exists"),
+       KDBMSG(BADADDR, "Invalid address"),
+       KDBMSG(NOPERM, "Permission denied"),
+};
+#undef KDBMSG
+
+static const int __nkdb_err = ARRAY_SIZE(kdbmsgs);
+
+
+/*
+ * Initial environment.   This is all kept static and local to
+ * this file.   We don't want to rely on the memory allocation
+ * mechanisms in the kernel, so we use a very limited allocate-only
+ * heap for new and altered environment variables.  The entire
+ * environment is limited to a fixed number of entries (add more
+ * to __env[] if required) and a fixed amount of heap (add more to
+ * KDB_ENVBUFSIZE if required).
+ */
+
+static char *__env[] = {
+#if defined(CONFIG_SMP)
+ "PROMPT=[%d]kdb> ",
+#else
+ "PROMPT=kdb> ",
+#endif
+ "MOREPROMPT=more> ",
+ "RADIX=16",
+ "MDCOUNT=8",                  /* lines of md output */
+ KDB_PLATFORM_ENV,
+ "DTABCOUNT=30",
+ "NOSECT=1",
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+ (char *)0,
+};
+
+static const int __nenv = ARRAY_SIZE(__env);
+
+struct task_struct *kdb_curr_task(int cpu)
+{
+       struct task_struct *p = curr_task(cpu);
+#ifdef _TIF_MCA_INIT
+       if ((task_thread_info(p)->flags & _TIF_MCA_INIT) && KDB_TSK(cpu))
+               p = krp->p;
+#endif
+       return p;
+}
+
+/*
+ * Check whether the flags of the current command and the permissions
+ * of the kdb console has allow a command to be run.
+ */
+static inline bool kdb_check_flags(kdb_cmdflags_t flags, int permissions,
+                                  bool no_args)
+{
+       /* permissions comes from userspace so needs massaging slightly */
+       permissions &= KDB_ENABLE_MASK;
+       permissions |= KDB_ENABLE_ALWAYS_SAFE;
+
+       /* some commands change group when launched with no arguments */
+       if (no_args)
+               permissions |= permissions << KDB_ENABLE_NO_ARGS_SHIFT;
+
+       flags |= KDB_ENABLE_ALL;
+
+       return permissions & flags;
+}
+
+/*
+ * kdbgetenv - This function will return the character string value of
+ *     an environment variable.
+ * Parameters:
+ *     match   A character string representing an environment variable.
+ * Returns:
+ *     NULL    No environment variable matches 'match'
+ *     char*   Pointer to string value of environment variable.
+ */
+char *kdbgetenv(const char *match)
+{
+       char **ep = __env;
+       int matchlen = strlen(match);
+       int i;
+
+       for (i = 0; i < __nenv; i++) {
+               char *e = *ep++;
+
+               if (!e)
+                       continue;
+
+               if ((strncmp(match, e, matchlen) == 0)
+                && ((e[matchlen] == '\0')
+                  || (e[matchlen] == '='))) {
+                       char *cp = strchr(e, '=');
+                       return cp ? ++cp : "";
+               }
+       }
+       return NULL;
+}
+
+/*
+ * kdballocenv - This function is used to allocate bytes for
+ *     environment entries.
+ * Parameters:
+ *     match   A character string representing a numeric value
+ * Outputs:
+ *     *value  the unsigned long representation of the env variable 'match'
+ * Returns:
+ *     Zero on success, a kdb diagnostic on failure.
+ * Remarks:
+ *     We use a static environment buffer (envbuffer) to hold the values
+ *     of dynamically generated environment variables (see kdb_set).  Buffer
+ *     space once allocated is never free'd, so over time, the amount of space
+ *     (currently 512 bytes) will be exhausted if env variables are changed
+ *     frequently.
+ */
+static char *kdballocenv(size_t bytes)
+{
+#define        KDB_ENVBUFSIZE  512
+       static char envbuffer[KDB_ENVBUFSIZE];
+       static int envbufsize;
+       char *ep = NULL;
+
+       if ((KDB_ENVBUFSIZE - envbufsize) >= bytes) {
+               ep = &envbuffer[envbufsize];
+               envbufsize += bytes;
+       }
+       return ep;
+}
+
+/*
+ * kdbgetulenv - This function will return the value of an unsigned
+ *     long-valued environment variable.
+ * Parameters:
+ *     match   A character string representing a numeric value
+ * Outputs:
+ *     *value  the unsigned long represntation of the env variable 'match'
+ * Returns:
+ *     Zero on success, a kdb diagnostic on failure.
+ */
+static int kdbgetulenv(const char *match, unsigned long *value)
+{
+       char *ep;
+
+       ep = kdbgetenv(match);
+       if (!ep)
+               return KDB_NOTENV;
+       if (strlen(ep) == 0)
+               return KDB_NOENVVALUE;
+
+       *value = simple_strtoul(ep, NULL, 0);
+
+       return 0;
+}
+
+/*
+ * kdbgetintenv - This function will return the value of an
+ *     integer-valued environment variable.
+ * Parameters:
+ *     match   A character string representing an integer-valued env variable
+ * Outputs:
+ *     *value  the integer representation of the environment variable 'match'
+ * Returns:
+ *     Zero on success, a kdb diagnostic on failure.
+ */
+int kdbgetintenv(const char *match, int *value)
+{
+       unsigned long val;
+       int diag;
+
+       diag = kdbgetulenv(match, &val);
+       if (!diag)
+               *value = (int) val;
+       return diag;
+}
+
+/*
+ * kdbgetularg - This function will convert a numeric string into an
+ *     unsigned long value.
+ * Parameters:
+ *     arg     A character string representing a numeric value
+ * Outputs:
+ *     *value  the unsigned long represntation of arg.
+ * Returns:
+ *     Zero on success, a kdb diagnostic on failure.
+ */
+int kdbgetularg(const char *arg, unsigned long *value)
+{
+       char *endp;
+       unsigned long val;
+
+       val = simple_strtoul(arg, &endp, 0);
+
+       if (endp == arg) {
+               /*
+                * Also try base 16, for us folks too lazy to type the
+                * leading 0x...
+                */
+               val = simple_strtoul(arg, &endp, 16);
+               if (endp == arg)
+                       return KDB_BADINT;
+       }
+
+       *value = val;
+
+       return 0;
+}
+
+int kdbgetu64arg(const char *arg, u64 *value)
+{
+       char *endp;
+       u64 val;
+
+       val = simple_strtoull(arg, &endp, 0);
+
+       if (endp == arg) {
+
+               val = simple_strtoull(arg, &endp, 16);
+               if (endp == arg)
+                       return KDB_BADINT;
+       }
+
+       *value = val;
+
+       return 0;
+}
+
+/*
+ * kdb_set - This function implements the 'set' command.  Alter an
+ *     existing environment variable or create a new one.
+ */
+int kdb_set(int argc, const char **argv)
+{
+       int i;
+       char *ep;
+       size_t varlen, vallen;
+
+       /*
+        * we can be invoked two ways:
+        *   set var=value    argv[1]="var", argv[2]="value"
+        *   set var = value  argv[1]="var", argv[2]="=", argv[3]="value"
+        * - if the latter, shift 'em down.
+        */
+       if (argc == 3) {
+               argv[2] = argv[3];
+               argc--;
+       }
+
+       if (argc != 2)
+               return KDB_ARGCOUNT;
+
+       /*
+        * Check for internal variables
+        */
+       if (strcmp(argv[1], "KDBDEBUG") == 0) {
+               unsigned int debugflags;
+               char *cp;
+
+               debugflags = simple_strtoul(argv[2], &cp, 0);
+               if (cp == argv[2] || debugflags & ~KDB_DEBUG_FLAG_MASK) {
+                       kdb_printf("kdb: illegal debug flags '%s'\n",
+                                   argv[2]);
+                       return 0;
+               }
+               kdb_flags = (kdb_flags &
+                            ~(KDB_DEBUG_FLAG_MASK << KDB_DEBUG_FLAG_SHIFT))
+                       | (debugflags << KDB_DEBUG_FLAG_SHIFT);
+
+               return 0;
+       }
+
+       /*
+        * Tokenizer squashed the '=' sign.  argv[1] is variable
+        * name, argv[2] = value.
+        */
+       varlen = strlen(argv[1]);
+       vallen = strlen(argv[2]);
+       ep = kdballocenv(varlen + vallen + 2);
+       if (ep == (char *)0)
+               return KDB_ENVBUFFULL;
+
+       sprintf(ep, "%s=%s", argv[1], argv[2]);
+
+       ep[varlen+vallen+1] = '\0';
+
+       for (i = 0; i < __nenv; i++) {
+               if (__env[i]
+                && ((strncmp(__env[i], argv[1], varlen) == 0)
+                  && ((__env[i][varlen] == '\0')
+                   || (__env[i][varlen] == '=')))) {
+                       __env[i] = ep;
+                       return 0;
+               }
+       }
+
+       /*
+        * Wasn't existing variable.  Fit into slot.
+        */
+       for (i = 0; i < __nenv-1; i++) {
+               if (__env[i] == (char *)0) {
+                       __env[i] = ep;
+                       return 0;
+               }
+       }
+
+       return KDB_ENVFULL;
+}
+
+static int kdb_check_regs(void)
+{
+       if (!kdb_current_regs) {
+               kdb_printf("No current kdb registers."
+                          "  You may need to select another task\n");
+               return KDB_BADREG;
+       }
+       return 0;
+}
+
+/*
+ * kdbgetaddrarg - This function is responsible for parsing an
+ *     address-expression and returning the value of the expression,
+ *     symbol name, and offset to the caller.
+ *
+ *     The argument may consist of a numeric value (decimal or
+ *     hexidecimal), a symbol name, a register name (preceded by the
+ *     percent sign), an environment variable with a numeric value
+ *     (preceded by a dollar sign) or a simple arithmetic expression
+ *     consisting of a symbol name, +/-, and a numeric constant value
+ *     (offset).
+ * Parameters:
+ *     argc    - count of arguments in argv
+ *     argv    - argument vector
+ *     *nextarg - index to next unparsed argument in argv[]
+ *     regs    - Register state at time of KDB entry
+ * Outputs:
+ *     *value  - receives the value of the address-expression
+ *     *offset - receives the offset specified, if any
+ *     *name   - receives the symbol name, if any
+ *     *nextarg - index to next unparsed argument in argv[]
+ * Returns:
+ *     zero is returned on success, a kdb diagnostic code is
+ *      returned on error.
+ */
+int kdbgetaddrarg(int argc, const char **argv, int *nextarg,
+                 unsigned long *value,  long *offset,
+                 char **name)
+{
+       unsigned long addr;
+       unsigned long off = 0;
+       int positive;
+       int diag;
+       int found = 0;
+       char *symname;
+       char symbol = '\0';
+       char *cp;
+       kdb_symtab_t symtab;
+
+       /*
+        * If the enable flags prohibit both arbitrary memory access
+        * and flow control then there are no reasonable grounds to
+        * provide symbol lookup.
+        */
+       if (!kdb_check_flags(KDB_ENABLE_MEM_READ | KDB_ENABLE_FLOW_CTRL,
+                            kdb_cmd_enabled, false))
+               return KDB_NOPERM;
+
+       /*
+        * Process arguments which follow the following syntax:
+        *
+        *  symbol | numeric-address [+/- numeric-offset]
+        *  %register
+        *  $environment-variable
+        */
+
+       if (*nextarg > argc)
+               return KDB_ARGCOUNT;
+
+       symname = (char *)argv[*nextarg];
+
+       /*
+        * If there is no whitespace between the symbol
+        * or address and the '+' or '-' symbols, we
+        * remember the character and replace it with a
+        * null so the symbol/value can be properly parsed
+        */
+       cp = strpbrk(symname, "+-");
+       if (cp != NULL) {
+               symbol = *cp;
+               *cp++ = '\0';
+       }
+
+       if (symname[0] == '$') {
+               diag = kdbgetulenv(&symname[1], &addr);
+               if (diag)
+                       return diag;
+       } else if (symname[0] == '%') {
+               diag = kdb_check_regs();
+               if (diag)
+                       return diag;
+               /* Implement register values with % at a later time as it is
+                * arch optional.
+                */
+               return KDB_NOTIMP;
+       } else {
+               found = kdbgetsymval(symname, &symtab);
+               if (found) {
+                       addr = symtab.sym_start;
+               } else {
+                       diag = kdbgetularg(argv[*nextarg], &addr);
+                       if (diag)
+                               return diag;
+               }
+       }
+
+       if (!found)
+               found = kdbnearsym(addr, &symtab);
+
+       (*nextarg)++;
+
+       if (name)
+               *name = symname;
+       if (value)
+               *value = addr;
+       if (offset && name && *name)
+               *offset = addr - symtab.sym_start;
+
+       if ((*nextarg > argc)
+        && (symbol == '\0'))
+               return 0;
+
+       /*
+        * check for +/- and offset
+        */
+
+       if (symbol == '\0') {
+               if ((argv[*nextarg][0] != '+')
+                && (argv[*nextarg][0] != '-')) {
+                       /*
+                        * Not our argument.  Return.
+                        */
+                       return 0;
+               } else {
+                       positive = (argv[*nextarg][0] == '+');
+                       (*nextarg)++;
+               }
+       } else
+               positive = (symbol == '+');
+
+       /*
+        * Now there must be an offset!
+        */
+       if ((*nextarg > argc)
+        && (symbol == '\0')) {
+               return KDB_INVADDRFMT;
+       }
+
+       if (!symbol) {
+               cp = (char *)argv[*nextarg];
+               (*nextarg)++;
+       }
+
+       diag = kdbgetularg(cp, &off);
+       if (diag)
+               return diag;
+
+       if (!positive)
+               off = -off;
+
+       if (offset)
+               *offset += off;
+
+       if (value)
+               *value += off;
+
+       return 0;
+}
+
+static void kdb_cmderror(int diag)
+{
+       int i;
+
+       if (diag >= 0) {
+               kdb_printf("no error detected (diagnostic is %d)\n", diag);
+               return;
+       }
+
+       for (i = 0; i < __nkdb_err; i++) {
+               if (kdbmsgs[i].km_diag == diag) {
+                       kdb_printf("diag: %d: %s\n", diag, kdbmsgs[i].km_msg);
+                       return;
+               }
+       }
+
+       kdb_printf("Unknown diag %d\n", -diag);
+}
+
+/*
+ * kdb_defcmd, kdb_defcmd2 - This function implements the 'defcmd'
+ *     command which defines one command as a set of other commands,
+ *     terminated by endefcmd.  kdb_defcmd processes the initial
+ *     'defcmd' command, kdb_defcmd2 is invoked from kdb_parse for
+ *     the following commands until 'endefcmd'.
+ * Inputs:
+ *     argc    argument count
+ *     argv    argument vector
+ * Returns:
+ *     zero for success, a kdb diagnostic if error
+ */
+struct defcmd_set {
+       int count;
+       int usable;
+       char *name;
+       char *usage;
+       char *help;
+       char **command;
+};
+static struct defcmd_set *defcmd_set;
+static int defcmd_set_count;
+static int defcmd_in_progress;
+
+/* Forward references */
+static int kdb_exec_defcmd(int argc, const char **argv);
+
+static int kdb_defcmd2(const char *cmdstr, const char *argv0)
+{
+       struct defcmd_set *s = defcmd_set + defcmd_set_count - 1;
+       char **save_command = s->command;
+       if (strcmp(argv0, "endefcmd") == 0) {
+               defcmd_in_progress = 0;
+               if (!s->count)
+                       s->usable = 0;
+               if (s->usable)
+                       /* macros are always safe because when executed each
+                        * internal command re-enters kdb_parse() and is
+                        * safety checked individually.
+                        */
+                       kdb_register_flags(s->name, kdb_exec_defcmd, s->usage,
+                                          s->help, 0,
+                                          KDB_ENABLE_ALWAYS_SAFE);
+               return 0;
+       }
+       if (!s->usable)
+               return KDB_NOTIMP;
+       s->command = kzalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB);
+       if (!s->command) {
+               kdb_printf("Could not allocate new kdb_defcmd table for %s\n",
+                          cmdstr);
+               s->usable = 0;
+               return KDB_NOTIMP;
+       }
+       memcpy(s->command, save_command, s->count * sizeof(*(s->command)));
+       s->command[s->count++] = kdb_strdup(cmdstr, GFP_KDB);
+       kfree(save_command);
+       return 0;
+}
+
+static int kdb_defcmd(int argc, const char **argv)
+{
+       struct defcmd_set *save_defcmd_set = defcmd_set, *s;
+       if (defcmd_in_progress) {
+               kdb_printf("kdb: nested defcmd detected, assuming missing "
+                          "endefcmd\n");
+               kdb_defcmd2("endefcmd", "endefcmd");
+       }
+       if (argc == 0) {
+               int i;
+               for (s = defcmd_set; s < defcmd_set + defcmd_set_count; ++s) {
+                       kdb_printf("defcmd %s \"%s\" \"%s\"\n", s->name,
+                                  s->usage, s->help);
+                       for (i = 0; i < s->count; ++i)
+                               kdb_printf("%s", s->command[i]);
+                       kdb_printf("endefcmd\n");
+               }
+               return 0;
+       }
+       if (argc != 3)
+               return KDB_ARGCOUNT;
+       if (in_dbg_master()) {
+               kdb_printf("Command only available during kdb_init()\n");
+               return KDB_NOTIMP;
+       }
+       defcmd_set = kmalloc((defcmd_set_count + 1) * sizeof(*defcmd_set),
+                            GFP_KDB);
+       if (!defcmd_set)
+               goto fail_defcmd;
+       memcpy(defcmd_set, save_defcmd_set,
+              defcmd_set_count * sizeof(*defcmd_set));
+       s = defcmd_set + defcmd_set_count;
+       memset(s, 0, sizeof(*s));
+       s->usable = 1;
+       s->name = kdb_strdup(argv[1], GFP_KDB);
+       if (!s->name)
+               goto fail_name;
+       s->usage = kdb_strdup(argv[2], GFP_KDB);
+       if (!s->usage)
+               goto fail_usage;
+       s->help = kdb_strdup(argv[3], GFP_KDB);
+       if (!s->help)
+               goto fail_help;
+       if (s->usage[0] == '"') {
+               strcpy(s->usage, argv[2]+1);
+               s->usage[strlen(s->usage)-1] = '\0';
+       }
+       if (s->help[0] == '"') {
+               strcpy(s->help, argv[3]+1);
+               s->help[strlen(s->help)-1] = '\0';
+       }
+       ++defcmd_set_count;
+       defcmd_in_progress = 1;
+       kfree(save_defcmd_set);
+       return 0;
+fail_help:
+       kfree(s->usage);
+fail_usage:
+       kfree(s->name);
+fail_name:
+       kfree(defcmd_set);
+fail_defcmd:
+       kdb_printf("Could not allocate new defcmd_set entry for %s\n", argv[1]);
+       defcmd_set = save_defcmd_set;
+       return KDB_NOTIMP;
+}
+
+/*
+ * kdb_exec_defcmd - Execute the set of commands associated with this
+ *     defcmd name.
+ * Inputs:
+ *     argc    argument count
+ *     argv    argument vector
+ * Returns:
+ *     zero for success, a kdb diagnostic if error
+ */
+static int kdb_exec_defcmd(int argc, const char **argv)
+{
+       int i, ret;
+       struct defcmd_set *s;
+       if (argc != 0)
+               return KDB_ARGCOUNT;
+       for (s = defcmd_set, i = 0; i < defcmd_set_count; ++i, ++s) {
+               if (strcmp(s->name, argv[0]) == 0)
+                       break;
+       }
+       if (i == defcmd_set_count) {
+               kdb_printf("kdb_exec_defcmd: could not find commands for %s\n",
+                          argv[0]);
+               return KDB_NOTIMP;
+       }
+       for (i = 0; i < s->count; ++i) {
+               /* Recursive use of kdb_parse, do not use argv after
+                * this point */
+               argv = NULL;
+               kdb_printf("[%s]kdb> %s\n", s->name, s->command[i]);
+               ret = kdb_parse(s->command[i]);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+/* Command history */
+#define KDB_CMD_HISTORY_COUNT  32
+#define CMD_BUFLEN             200     /* kdb_printf: max printline
+                                        * size == 256 */
+static unsigned int cmd_head, cmd_tail;
+static unsigned int cmdptr;
+static char cmd_hist[KDB_CMD_HISTORY_COUNT][CMD_BUFLEN];
+static char cmd_cur[CMD_BUFLEN];
+
+/*
+ * The "str" argument may point to something like  | grep xyz
+ */
+static void parse_grep(const char *str)
+{
+       int     len;
+       char    *cp = (char *)str, *cp2;
+
+       /* sanity check: we should have been called with the \ first */
+       if (*cp != '|')
+               return;
+       cp++;
+       while (isspace(*cp))
+               cp++;
+       if (strncmp(cp, "grep ", 5)) {
+               kdb_printf("invalid 'pipe', see grephelp\n");
+               return;
+       }
+       cp += 5;
+       while (isspace(*cp))
+               cp++;
+       cp2 = strchr(cp, '\n');
+       if (cp2)
+               *cp2 = '\0'; /* remove the trailing newline */
+       len = strlen(cp);
+       if (len == 0) {
+               kdb_printf("invalid 'pipe', see grephelp\n");
+               return;
+       }
+       /* now cp points to a nonzero length search string */
+       if (*cp == '"') {
+               /* allow it be "x y z" by removing the "'s - there must
+                  be two of them */
+               cp++;
+               cp2 = strchr(cp, '"');
+               if (!cp2) {
+                       kdb_printf("invalid quoted string, see grephelp\n");
+                       return;
+               }
+               *cp2 = '\0'; /* end the string where the 2nd " was */
+       }
+       kdb_grep_leading = 0;
+       if (*cp == '^') {
+               kdb_grep_leading = 1;
+               cp++;
+       }
+       len = strlen(cp);
+       kdb_grep_trailing = 0;
+       if (*(cp+len-1) == '$') {
+               kdb_grep_trailing = 1;
+               *(cp+len-1) = '\0';
+       }
+       len = strlen(cp);
+       if (!len)
+               return;
+       if (len >= KDB_GREP_STRLEN) {
+               kdb_printf("search string too long\n");
+               return;
+       }
+       strcpy(kdb_grep_string, cp);
+       kdb_grepping_flag++;
+       return;
+}
+
+/*
+ * kdb_parse - Parse the command line, search the command table for a
+ *     matching command and invoke the command function.  This
+ *     function may be called recursively, if it is, the second call
+ *     will overwrite argv and cbuf.  It is the caller's
+ *     responsibility to save their argv if they recursively call
+ *     kdb_parse().
+ * Parameters:
+ *      cmdstr The input command line to be parsed.
+ *     regs    The registers at the time kdb was entered.
+ * Returns:
+ *     Zero for success, a kdb diagnostic if failure.
+ * Remarks:
+ *     Limited to 20 tokens.
+ *
+ *     Real rudimentary tokenization. Basically only whitespace
+ *     is considered a token delimeter (but special consideration
+ *     is taken of the '=' sign as used by the 'set' command).
+ *
+ *     The algorithm used to tokenize the input string relies on
+ *     there being at least one whitespace (or otherwise useless)
+ *     character between tokens as the character immediately following
+ *     the token is altered in-place to a null-byte to terminate the
+ *     token string.
+ */
+
+#define MAXARGC        20
+
+int kdb_parse(const char *cmdstr)
+{
+       static char *argv[MAXARGC];
+       static int argc;
+       static char cbuf[CMD_BUFLEN+2];
+       char *cp;
+       char *cpp, quoted;
+       kdbtab_t *tp;
+       int i, escaped, ignore_errors = 0, check_grep = 0;
+
+       /*
+        * First tokenize the command string.
+        */
+       cp = (char *)cmdstr;
+
+       if (KDB_FLAG(CMD_INTERRUPT)) {
+               /* Previous command was interrupted, newline must not
+                * repeat the command */
+               KDB_FLAG_CLEAR(CMD_INTERRUPT);
+               KDB_STATE_SET(PAGER);
+               argc = 0;       /* no repeat */
+       }
+
+       if (*cp != '\n' && *cp != '\0') {
+               argc = 0;
+               cpp = cbuf;
+               while (*cp) {
+                       /* skip whitespace */
+                       while (isspace(*cp))
+                               cp++;
+                       if ((*cp == '\0') || (*cp == '\n') ||
+                           (*cp == '#' && !defcmd_in_progress))
+                               break;
+                       /* special case: check for | grep pattern */
+                       if (*cp == '|') {
+                               check_grep++;
+                               break;
+                       }
+                       if (cpp >= cbuf + CMD_BUFLEN) {
+                               kdb_printf("kdb_parse: command buffer "
+                                          "overflow, command ignored\n%s\n",
+                                          cmdstr);
+                               return KDB_NOTFOUND;
+                       }
+                       if (argc >= MAXARGC - 1) {
+                               kdb_printf("kdb_parse: too many arguments, "
+                                          "command ignored\n%s\n", cmdstr);
+                               return KDB_NOTFOUND;
+                       }
+                       argv[argc++] = cpp;
+                       escaped = 0;
+                       quoted = '\0';
+                       /* Copy to next unquoted and unescaped
+                        * whitespace or '=' */
+                       while (*cp && *cp != '\n' &&
+                              (escaped || quoted || !isspace(*cp))) {
+                               if (cpp >= cbuf + CMD_BUFLEN)
+                                       break;
+                               if (escaped) {
+                                       escaped = 0;
+                                       *cpp++ = *cp++;
+                                       continue;
+                               }
+                               if (*cp == '\\') {
+                                       escaped = 1;
+                                       ++cp;
+                                       continue;
+                               }
+                               if (*cp == quoted)
+                                       quoted = '\0';
+                               else if (*cp == '\'' || *cp == '"')
+                                       quoted = *cp;
+                               *cpp = *cp++;
+                               if (*cpp == '=' && !quoted)
+                                       break;
+                               ++cpp;
+                       }
+                       *cpp++ = '\0';  /* Squash a ws or '=' character */
+               }
+       }
+       if (!argc)
+               return 0;
+       if (check_grep)
+               parse_grep(cp);
+       if (defcmd_in_progress) {
+               int result = kdb_defcmd2(cmdstr, argv[0]);
+               if (!defcmd_in_progress) {
+                       argc = 0;       /* avoid repeat on endefcmd */
+                       *(argv[0]) = '\0';
+               }
+               return result;
+       }
+       if (argv[0][0] == '-' && argv[0][1] &&
+           (argv[0][1] < '0' || argv[0][1] > '9')) {
+               ignore_errors = 1;
+               ++argv[0];
+       }
+
+       for_each_kdbcmd(tp, i) {
+               if (tp->cmd_name) {
+                       /*
+                        * If this command is allowed to be abbreviated,
+                        * check to see if this is it.
+                        */
+
+                       if (tp->cmd_minlen
+                        && (strlen(argv[0]) <= tp->cmd_minlen)) {
+                               if (strncmp(argv[0],
+                                           tp->cmd_name,
+                                           tp->cmd_minlen) == 0) {
+                                       break;
+                               }
+                       }
+
+                       if (strcmp(argv[0], tp->cmd_name) == 0)
+                               break;
+               }
+       }
+
+       /*
+        * If we don't find a command by this name, see if the first
+        * few characters of this match any of the known commands.
+        * e.g., md1c20 should match md.
+        */
+       if (i == kdb_max_commands) {
+               for_each_kdbcmd(tp, i) {
+                       if (tp->cmd_name) {
+                               if (strncmp(argv[0],
+                                           tp->cmd_name,
+                                           strlen(tp->cmd_name)) == 0) {
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       if (i < kdb_max_commands) {
+               int result;
+
+               if (!kdb_check_flags(tp->cmd_flags, kdb_cmd_enabled, argc <= 1))
+                       return KDB_NOPERM;
+
+               KDB_STATE_SET(CMD);
+               result = (*tp->cmd_func)(argc-1, (const char **)argv);
+               if (result && ignore_errors && result > KDB_CMD_GO)
+                       result = 0;
+               KDB_STATE_CLEAR(CMD);
+
+               if (tp->cmd_flags & KDB_REPEAT_WITH_ARGS)
+                       return result;
+
+               argc = tp->cmd_flags & KDB_REPEAT_NO_ARGS ? 1 : 0;
+               if (argv[argc])
+                       *(argv[argc]) = '\0';
+               return result;
+       }
+
+       /*
+        * If the input with which we were presented does not
+        * map to an existing command, attempt to parse it as an
+        * address argument and display the result.   Useful for
+        * obtaining the address of a variable, or the nearest symbol
+        * to an address contained in a register.
+        */
+       {
+               unsigned long value;
+               char *name = NULL;
+               long offset;
+               int nextarg = 0;
+
+               if (kdbgetaddrarg(0, (const char **)argv, &nextarg,
+                                 &value, &offset, &name)) {
+                       return KDB_NOTFOUND;
+               }
+
+               kdb_printf("%s = ", argv[0]);
+               kdb_symbol_print(value, NULL, KDB_SP_DEFAULT);
+               kdb_printf("\n");
+               return 0;
+       }
+}
+
+
+static int handle_ctrl_cmd(char *cmd)
+{
+#define CTRL_P 16
+#define CTRL_N 14
+
+       /* initial situation */
+       if (cmd_head == cmd_tail)
+               return 0;
+       switch (*cmd) {
+       case CTRL_P:
+               if (cmdptr != cmd_tail)
+                       cmdptr = (cmdptr-1) % KDB_CMD_HISTORY_COUNT;
+               strncpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN);
+               return 1;
+       case CTRL_N:
+               if (cmdptr != cmd_head)
+                       cmdptr = (cmdptr+1) % KDB_CMD_HISTORY_COUNT;
+               strncpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * kdb_reboot - This function implements the 'reboot' command.  Reboot
+ *     the system immediately, or loop for ever on failure.
+ */
+static int kdb_reboot(int argc, const char **argv)
+{
+       emergency_restart();
+       kdb_printf("Hmm, kdb_reboot did not reboot, spinning here\n");
+       while (1)
+               cpu_relax();
+       /* NOTREACHED */
+       return 0;
+}
+
+static void kdb_dumpregs(struct pt_regs *regs)
+{
+       int old_lvl = console_loglevel;
+       console_loglevel = CONSOLE_LOGLEVEL_MOTORMOUTH;
+       kdb_trap_printk++;
+       show_regs(regs);
+       kdb_trap_printk--;
+       kdb_printf("\n");
+       console_loglevel = old_lvl;
+}
+
+void kdb_set_current_task(struct task_struct *p)
+{
+       kdb_current_task = p;
+
+       if (kdb_task_has_cpu(p)) {
+               kdb_current_regs = KDB_TSKREGS(kdb_process_cpu(p));
+               return;
+       }
+       kdb_current_regs = NULL;
+}
+
+/*
+ * kdb_local - The main code for kdb.  This routine is invoked on a
+ *     specific processor, it is not global.  The main kdb() routine
+ *     ensures that only one processor at a time is in this routine.
+ *     This code is called with the real reason code on the first
+ *     entry to a kdb session, thereafter it is called with reason
+ *     SWITCH, even if the user goes back to the original cpu.
+ * Inputs:
+ *     reason          The reason KDB was invoked
+ *     error           The hardware-defined error code
+ *     regs            The exception frame at time of fault/breakpoint.
+ *     db_result       Result code from the break or debug point.
+ * Returns:
+ *     0       KDB was invoked for an event which it wasn't responsible
+ *     1       KDB handled the event for which it was invoked.
+ *     KDB_CMD_GO      User typed 'go'.
+ *     KDB_CMD_CPU     User switched to another cpu.
+ *     KDB_CMD_SS      Single step.
+ */
+static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
+                    kdb_dbtrap_t db_result)
+{
+       char *cmdbuf;
+       int diag;
+       struct task_struct *kdb_current =
+               kdb_curr_task(raw_smp_processor_id());
+
+       KDB_DEBUG_STATE("kdb_local 1", reason);
+       kdb_go_count = 0;
+       if (reason == KDB_REASON_DEBUG) {
+               /* special case below */
+       } else {
+               kdb_printf("\nEntering kdb (current=0x%p, pid %d) ",
+                          kdb_current, kdb_current ? kdb_current->pid : 0);
+#if defined(CONFIG_SMP)
+               kdb_printf("on processor %d ", raw_smp_processor_id());
+#endif
+       }
+
+       switch (reason) {
+       case KDB_REASON_DEBUG:
+       {
+               /*
+                * If re-entering kdb after a single step
+                * command, don't print the message.
+                */
+               switch (db_result) {
+               case KDB_DB_BPT:
+                       kdb_printf("\nEntering kdb (0x%p, pid %d) ",
+                                  kdb_current, kdb_current->pid);
+#if defined(CONFIG_SMP)
+                       kdb_printf("on processor %d ", raw_smp_processor_id());
+#endif
+                       kdb_printf("due to Debug @ " kdb_machreg_fmt "\n",
+                                  instruction_pointer(regs));
+                       break;
+               case KDB_DB_SS:
+                       break;
+               case KDB_DB_SSBPT:
+                       KDB_DEBUG_STATE("kdb_local 4", reason);
+                       return 1;       /* kdba_db_trap did the work */
+               default:
+                       kdb_printf("kdb: Bad result from kdba_db_trap: %d\n",
+                                  db_result);
+                       break;
+               }
+
+       }
+               break;
+       case KDB_REASON_ENTER:
+               if (KDB_STATE(KEYBOARD))
+                       kdb_printf("due to Keyboard Entry\n");
+               else
+                       kdb_printf("due to KDB_ENTER()\n");
+               break;
+       case KDB_REASON_KEYBOARD:
+               KDB_STATE_SET(KEYBOARD);
+               kdb_printf("due to Keyboard Entry\n");
+               break;
+       case KDB_REASON_ENTER_SLAVE:
+               /* drop through, slaves only get released via cpu switch */
+       case KDB_REASON_SWITCH:
+               kdb_printf("due to cpu switch\n");
+               break;
+       case KDB_REASON_OOPS:
+               kdb_printf("Oops: %s\n", kdb_diemsg);
+               kdb_printf("due to oops @ " kdb_machreg_fmt "\n",
+                          instruction_pointer(regs));
+               kdb_dumpregs(regs);
+               break;
+       case KDB_REASON_SYSTEM_NMI:
+               kdb_printf("due to System NonMaskable Interrupt\n");
+               break;
+       case KDB_REASON_NMI:
+               kdb_printf("due to NonMaskable Interrupt @ "
+                          kdb_machreg_fmt "\n",
+                          instruction_pointer(regs));
+               break;
+       case KDB_REASON_SSTEP:
+       case KDB_REASON_BREAK:
+               kdb_printf("due to %s @ " kdb_machreg_fmt "\n",
+                          reason == KDB_REASON_BREAK ?
+                          "Breakpoint" : "SS trap", instruction_pointer(regs));
+               /*
+                * Determine if this breakpoint is one that we
+                * are interested in.
+                */
+               if (db_result != KDB_DB_BPT) {
+                       kdb_printf("kdb: error return from kdba_bp_trap: %d\n",
+                                  db_result);
+                       KDB_DEBUG_STATE("kdb_local 6", reason);
+                       return 0;       /* Not for us, dismiss it */
+               }
+               break;
+       case KDB_REASON_RECURSE:
+               kdb_printf("due to Recursion @ " kdb_machreg_fmt "\n",
+                          instruction_pointer(regs));
+               break;
+       default:
+               kdb_printf("kdb: unexpected reason code: %d\n", reason);
+               KDB_DEBUG_STATE("kdb_local 8", reason);
+               return 0;       /* Not for us, dismiss it */
+       }
+
+       while (1) {
+               /*
+                * Initialize pager context.
+                */
+               kdb_nextline = 1;
+               KDB_STATE_CLEAR(SUPPRESS);
+               kdb_grepping_flag = 0;
+               /* ensure the old search does not leak into '/' commands */
+               kdb_grep_string[0] = '\0';
+
+               cmdbuf = cmd_cur;
+               *cmdbuf = '\0';
+               *(cmd_hist[cmd_head]) = '\0';
+
+do_full_getstr:
+#if defined(CONFIG_SMP)
+               snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"),
+                        raw_smp_processor_id());
+#else
+               snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"));
+#endif
+               if (defcmd_in_progress)
+                       strncat(kdb_prompt_str, "[defcmd]", CMD_BUFLEN);
+
+               /*
+                * Fetch command from keyboard
+                */
+               cmdbuf = kdb_getstr(cmdbuf, CMD_BUFLEN, kdb_prompt_str);
+               if (*cmdbuf != '\n') {
+                       if (*cmdbuf < 32) {
+                               if (cmdptr == cmd_head) {
+                                       strncpy(cmd_hist[cmd_head], cmd_cur,
+                                               CMD_BUFLEN);
+                                       *(cmd_hist[cmd_head] +
+                                         strlen(cmd_hist[cmd_head])-1) = '\0';
+                               }
+                               if (!handle_ctrl_cmd(cmdbuf))
+                                       *(cmd_cur+strlen(cmd_cur)-1) = '\0';
+                               cmdbuf = cmd_cur;
+                               goto do_full_getstr;
+                       } else {
+                               strncpy(cmd_hist[cmd_head], cmd_cur,
+                                       CMD_BUFLEN);
+                       }
+
+                       cmd_head = (cmd_head+1) % KDB_CMD_HISTORY_COUNT;
+                       if (cmd_head == cmd_tail)
+                               cmd_tail = (cmd_tail+1) % KDB_CMD_HISTORY_COUNT;
+               }
+
+               cmdptr = cmd_head;
+               diag = kdb_parse(cmdbuf);
+               if (diag == KDB_NOTFOUND) {
+                       kdb_printf("Unknown kdb command: '%s'\n", cmdbuf);
+                       diag = 0;
+               }
+               if (diag == KDB_CMD_GO
+                || diag == KDB_CMD_CPU
+                || diag == KDB_CMD_SS
+                || diag == KDB_CMD_KGDB)
+                       break;
+
+               if (diag)
+                       kdb_cmderror(diag);
+       }
+       KDB_DEBUG_STATE("kdb_local 9", diag);
+       return diag;
+}
+
+
+/*
+ * kdb_print_state - Print the state data for the current processor
+ *     for debugging.
+ * Inputs:
+ *     text            Identifies the debug point
+ *     value           Any integer value to be printed, e.g. reason code.
+ */
+void kdb_print_state(const char *text, int value)
+{
+       kdb_printf("state: %s cpu %d value %d initial %d state %x\n",
+                  text, raw_smp_processor_id(), value, kdb_initial_cpu,
+                  kdb_state);
+}
+
+/*
+ * kdb_main_loop - After initial setup and assignment of the
+ *     controlling cpu, all cpus are in this loop.  One cpu is in
+ *     control and will issue the kdb prompt, the others will spin
+ *     until 'go' or cpu switch.
+ *
+ *     To get a consistent view of the kernel stacks for all
+ *     processes, this routine is invoked from the main kdb code via
+ *     an architecture specific routine.  kdba_main_loop is
+ *     responsible for making the kernel stacks consistent for all
+ *     processes, there should be no difference between a blocked
+ *     process and a running process as far as kdb is concerned.
+ * Inputs:
+ *     reason          The reason KDB was invoked
+ *     error           The hardware-defined error code
+ *     reason2         kdb's current reason code.
+ *                     Initially error but can change
+ *                     according to kdb state.
+ *     db_result       Result code from break or debug point.
+ *     regs            The exception frame at time of fault/breakpoint.
+ *                     should always be valid.
+ * Returns:
+ *     0       KDB was invoked for an event which it wasn't responsible
+ *     1       KDB handled the event for which it was invoked.
+ */
+int kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
+             kdb_dbtrap_t db_result, struct pt_regs *regs)
+{
+       int result = 1;
+       /* Stay in kdb() until 'go', 'ss[b]' or an error */
+       while (1) {
+               /*
+                * All processors except the one that is in control
+                * will spin here.
+                */
+               KDB_DEBUG_STATE("kdb_main_loop 1", reason);
+               while (KDB_STATE(HOLD_CPU)) {
+                       /* state KDB is turned off by kdb_cpu to see if the
+                        * other cpus are still live, each cpu in this loop
+                        * turns it back on.
+                        */
+                       if (!KDB_STATE(KDB))
+                               KDB_STATE_SET(KDB);
+               }
+
+               KDB_STATE_CLEAR(SUPPRESS);
+               KDB_DEBUG_STATE("kdb_main_loop 2", reason);
+               if (KDB_STATE(LEAVING))
+                       break;  /* Another cpu said 'go' */
+               /* Still using kdb, this processor is in control */
+               result = kdb_local(reason2, error, regs, db_result);
+               KDB_DEBUG_STATE("kdb_main_loop 3", result);
+
+               if (result == KDB_CMD_CPU)
+                       break;
+
+               if (result == KDB_CMD_SS) {
+                       KDB_STATE_SET(DOING_SS);
+                       break;
+               }
+
+               if (result == KDB_CMD_KGDB) {
+                       if (!KDB_STATE(DOING_KGDB))
+                               kdb_printf("Entering please attach debugger "
+                                          "or use $D#44+ or $3#33\n");
+                       break;
+               }
+               if (result && result != 1 && result != KDB_CMD_GO)
+                       kdb_printf("\nUnexpected kdb_local return code %d\n",
+                                  result);
+               KDB_DEBUG_STATE("kdb_main_loop 4", reason);
+               break;
+       }
+       if (KDB_STATE(DOING_SS))
+               KDB_STATE_CLEAR(SSBPT);
+
+       /* Clean up any keyboard devices before leaving */
+       kdb_kbd_cleanup_state();
+
+       return result;
+}
+
+/*
+ * kdb_mdr - This function implements the guts of the 'mdr', memory
+ * read command.
+ *     mdr  <addr arg>,<byte count>
+ * Inputs:
+ *     addr    Start address
+ *     count   Number of bytes
+ * Returns:
+ *     Always 0.  Any errors are detected and printed by kdb_getarea.
+ */
+static int kdb_mdr(unsigned long addr, unsigned int count)
+{
+       unsigned char c;
+       while (count--) {
+               if (kdb_getarea(c, addr))
+                       return 0;
+               kdb_printf("%02x", c);
+               addr++;
+       }
+       kdb_printf("\n");
+       return 0;
+}
+
+/*
+ * kdb_md - This function implements the 'md', 'md1', 'md2', 'md4',
+ *     'md8' 'mdr' and 'mds' commands.
+ *
+ *     md|mds  [<addr arg> [<line count> [<radix>]]]
+ *     mdWcN   [<addr arg> [<line count> [<radix>]]]
+ *             where W = is the width (1, 2, 4 or 8) and N is the count.
+ *             for eg., md1c20 reads 20 bytes, 1 at a time.
+ *     mdr  <addr arg>,<byte count>
+ */
+static void kdb_md_line(const char *fmtstr, unsigned long addr,
+                       int symbolic, int nosect, int bytesperword,
+                       int num, int repeat, int phys)
+{
+       /* print just one line of data */
+       kdb_symtab_t symtab;
+       char cbuf[32];
+       char *c = cbuf;
+       int i;
+       unsigned long word;
+
+       memset(cbuf, '\0', sizeof(cbuf));
+       if (phys)
+               kdb_printf("phys " kdb_machreg_fmt0 " ", addr);
+       else
+               kdb_printf(kdb_machreg_fmt0 " ", addr);
+
+       for (i = 0; i < num && repeat--; i++) {
+               if (phys) {
+                       if (kdb_getphysword(&word, addr, bytesperword))
+                               break;
+               } else if (kdb_getword(&word, addr, bytesperword))
+                       break;
+               kdb_printf(fmtstr, word);
+               if (symbolic)
+                       kdbnearsym(word, &symtab);
+               else
+                       memset(&symtab, 0, sizeof(symtab));
+               if (symtab.sym_name) {
+                       kdb_symbol_print(word, &symtab, 0);
+                       if (!nosect) {
+                               kdb_printf("\n");
+                               kdb_printf("                       %s %s "
+                                          kdb_machreg_fmt " "
+                                          kdb_machreg_fmt " "
+                                          kdb_machreg_fmt, symtab.mod_name,
+                                          symtab.sec_name, symtab.sec_start,
+                                          symtab.sym_start, symtab.sym_end);
+                       }
+                       addr += bytesperword;
+               } else {
+                       union {
+                               u64 word;
+                               unsigned char c[8];
+                       } wc;
+                       unsigned char *cp;
+#ifdef __BIG_ENDIAN
+                       cp = wc.c + 8 - bytesperword;
+#else
+                       cp = wc.c;
+#endif
+                       wc.word = word;
+#define printable_char(c) \
+       ({unsigned char __c = c; isascii(__c) && isprint(__c) ? __c : '.'; })
+                       switch (bytesperword) {
+                       case 8:
+                               *c++ = printable_char(*cp++);
+                               *c++ = printable_char(*cp++);
+                               *c++ = printable_char(*cp++);
+                               *c++ = printable_char(*cp++);
+                               addr += 4;
+                       case 4:
+                               *c++ = printable_char(*cp++);
+                               *c++ = printable_char(*cp++);
+                               addr += 2;
+                       case 2:
+                               *c++ = printable_char(*cp++);
+                               addr++;
+                       case 1:
+                               *c++ = printable_char(*cp++);
+                               addr++;
+                               break;
+                       }
+#undef printable_char
+               }
+       }
+       kdb_printf("%*s %s\n", (int)((num-i)*(2*bytesperword + 1)+1),
+                  " ", cbuf);
+}
+
+static int kdb_md(int argc, const char **argv)
+{
+       static unsigned long last_addr;
+       static int last_radix, last_bytesperword, last_repeat;
+       int radix = 16, mdcount = 8, bytesperword = KDB_WORD_SIZE, repeat;
+       int nosect = 0;
+       char fmtchar, fmtstr[64];
+       unsigned long addr;
+       unsigned long word;
+       long offset = 0;
+       int symbolic = 0;
+       int valid = 0;
+       int phys = 0;
+
+       kdbgetintenv("MDCOUNT", &mdcount);
+       kdbgetintenv("RADIX", &radix);
+       kdbgetintenv("BYTESPERWORD", &bytesperword);
+
+       /* Assume 'md <addr>' and start with environment values */
+       repeat = mdcount * 16 / bytesperword;
+
+       if (strcmp(argv[0], "mdr") == 0) {
+               if (argc != 2)
+                       return KDB_ARGCOUNT;
+               valid = 1;
+       } else if (isdigit(argv[0][2])) {
+               bytesperword = (int)(argv[0][2] - '0');
+               if (bytesperword == 0) {
+                       bytesperword = last_bytesperword;
+                       if (bytesperword == 0)
+                               bytesperword = 4;
+               }
+               last_bytesperword = bytesperword;
+               repeat = mdcount * 16 / bytesperword;
+               if (!argv[0][3])
+                       valid = 1;
+               else if (argv[0][3] == 'c' && argv[0][4]) {
+                       char *p;
+                       repeat = simple_strtoul(argv[0] + 4, &p, 10);
+                       mdcount = ((repeat * bytesperword) + 15) / 16;
+                       valid = !*p;
+               }
+               last_repeat = repeat;
+       } else if (strcmp(argv[0], "md") == 0)
+               valid = 1;
+       else if (strcmp(argv[0], "mds") == 0)
+               valid = 1;
+       else if (strcmp(argv[0], "mdp") == 0) {
+               phys = valid = 1;
+       }
+       if (!valid)
+               return KDB_NOTFOUND;
+
+       if (argc == 0) {
+               if (last_addr == 0)
+                       return KDB_ARGCOUNT;
+               addr = last_addr;
+               radix = last_radix;
+               bytesperword = last_bytesperword;
+               repeat = last_repeat;
+               mdcount = ((repeat * bytesperword) + 15) / 16;
+       }
+
+       if (argc) {
+               unsigned long val;
+               int diag, nextarg = 1;
+               diag = kdbgetaddrarg(argc, argv, &nextarg, &addr,
+                                    &offset, NULL);
+               if (diag)
+                       return diag;
+               if (argc > nextarg+2)
+                       return KDB_ARGCOUNT;
+
+               if (argc >= nextarg) {
+                       diag = kdbgetularg(argv[nextarg], &val);
+                       if (!diag) {
+                               mdcount = (int) val;
+                               repeat = mdcount * 16 / bytesperword;
+                       }
+               }
+               if (argc >= nextarg+1) {
+                       diag = kdbgetularg(argv[nextarg+1], &val);
+                       if (!diag)
+                               radix = (int) val;
+               }
+       }
+
+       if (strcmp(argv[0], "mdr") == 0)
+               return kdb_mdr(addr, mdcount);
+
+       switch (radix) {
+       case 10:
+               fmtchar = 'd';
+               break;
+       case 16:
+               fmtchar = 'x';
+               break;
+       case 8:
+               fmtchar = 'o';
+               break;
+       default:
+               return KDB_BADRADIX;
+       }
+
+       last_radix = radix;
+
+       if (bytesperword > KDB_WORD_SIZE)
+               return KDB_BADWIDTH;
+
+       switch (bytesperword) {
+       case 8:
+               sprintf(fmtstr, "%%16.16l%c ", fmtchar);
+               break;
+       case 4:
+               sprintf(fmtstr, "%%8.8l%c ", fmtchar);
+               break;
+       case 2:
+               sprintf(fmtstr, "%%4.4l%c ", fmtchar);
+               break;
+       case 1:
+               sprintf(fmtstr, "%%2.2l%c ", fmtchar);
+               break;
+       default:
+               return KDB_BADWIDTH;
+       }
+
+       last_repeat = repeat;
+       last_bytesperword = bytesperword;
+
+       if (strcmp(argv[0], "mds") == 0) {
+               symbolic = 1;
+               /* Do not save these changes as last_*, they are temporary mds
+                * overrides.
+                */
+               bytesperword = KDB_WORD_SIZE;
+               repeat = mdcount;
+               kdbgetintenv("NOSECT", &nosect);
+       }
+
+       /* Round address down modulo BYTESPERWORD */
+
+       addr &= ~(bytesperword-1);
+
+       while (repeat > 0) {
+               unsigned long a;
+               int n, z, num = (symbolic ? 1 : (16 / bytesperword));
+
+               if (KDB_FLAG(CMD_INTERRUPT))
+                       return 0;
+               for (a = addr, z = 0; z < repeat; a += bytesperword, ++z) {
+                       if (phys) {
+                               if (kdb_getphysword(&word, a, bytesperword)
+                                               || word)
+                                       break;
+                       } else if (kdb_getword(&word, a, bytesperword) || word)
+                               break;
+               }
+               n = min(num, repeat);
+               kdb_md_line(fmtstr, addr, symbolic, nosect, bytesperword,
+                           num, repeat, phys);
+               addr += bytesperword * n;
+               repeat -= n;
+               z = (z + num - 1) / num;
+               if (z > 2) {
+                       int s = num * (z-2);
+                       kdb_printf(kdb_machreg_fmt0 "-" kdb_machreg_fmt0
+                                  " zero suppressed\n",
+                               addr, addr + bytesperword * s - 1);
+                       addr += bytesperword * s;
+                       repeat -= s;
+               }
+       }
+       last_addr = addr;
+
+       return 0;
+}
+
+/*
+ * kdb_mm - This function implements the 'mm' command.
+ *     mm address-expression new-value
+ * Remarks:
+ *     mm works on machine words, mmW works on bytes.
+ */
+static int kdb_mm(int argc, const char **argv)
+{
+       int diag;
+       unsigned long addr;
+       long offset = 0;
+       unsigned long contents;
+       int nextarg;
+       int width;
+
+       if (argv[0][2] && !isdigit(argv[0][2]))
+               return KDB_NOTFOUND;
+
+       if (argc < 2)
+               return KDB_ARGCOUNT;
+
+       nextarg = 1;
+       diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL);
+       if (diag)
+               return diag;
+
+       if (nextarg > argc)
+               return KDB_ARGCOUNT;
+       diag = kdbgetaddrarg(argc, argv, &nextarg, &contents, NULL, NULL);
+       if (diag)
+               return diag;
+
+       if (nextarg != argc + 1)
+               return KDB_ARGCOUNT;
+
+       width = argv[0][2] ? (argv[0][2] - '0') : (KDB_WORD_SIZE);
+       diag = kdb_putword(addr, contents, width);
+       if (diag)
+               return diag;
+
+       kdb_printf(kdb_machreg_fmt " = " kdb_machreg_fmt "\n", addr, contents);
+
+       return 0;
+}
+
+/*
+ * kdb_go - This function implements the 'go' command.
+ *     go [address-expression]
+ */
+static int kdb_go(int argc, const char **argv)
+{
+       unsigned long addr;
+       int diag;
+       int nextarg;
+       long offset;
+
+       if (raw_smp_processor_id() != kdb_initial_cpu) {
+               kdb_printf("go must execute on the entry cpu, "
+                          "please use \"cpu %d\" and then execute go\n",
+                          kdb_initial_cpu);
+               return KDB_BADCPUNUM;
+       }
+       if (argc == 1) {
+               nextarg = 1;
+               diag = kdbgetaddrarg(argc, argv, &nextarg,
+                                    &addr, &offset, NULL);
+               if (diag)
+                       return diag;
+       } else if (argc) {
+               return KDB_ARGCOUNT;
+       }
+
+       diag = KDB_CMD_GO;
+       if (KDB_FLAG(CATASTROPHIC)) {
+               kdb_printf("Catastrophic error detected\n");
+               kdb_printf("kdb_continue_catastrophic=%d, ",
+                       kdb_continue_catastrophic);
+               if (kdb_continue_catastrophic == 0 && kdb_go_count++ == 0) {
+                       kdb_printf("type go a second time if you really want "
+                                  "to continue\n");
+                       return 0;
+               }
+               if (kdb_continue_catastrophic == 2) {
+                       kdb_printf("forcing reboot\n");
+                       kdb_reboot(0, NULL);
+               }
+               kdb_printf("attempting to continue\n");
+       }
+       return diag;
+}
+
+/*
+ * kdb_rd - This function implements the 'rd' command.
+ */
+static int kdb_rd(int argc, const char **argv)
+{
+       int len = kdb_check_regs();
+#if DBG_MAX_REG_NUM > 0
+       int i;
+       char *rname;
+       int rsize;
+       u64 reg64;
+       u32 reg32;
+       u16 reg16;
+       u8 reg8;
+
+       if (len)
+               return len;
+
+       for (i = 0; i < DBG_MAX_REG_NUM; i++) {
+               rsize = dbg_reg_def[i].size * 2;
+               if (rsize > 16)
+                       rsize = 2;
+               if (len + strlen(dbg_reg_def[i].name) + 4 + rsize > 80) {
+                       len = 0;
+                       kdb_printf("\n");
+               }
+               if (len)
+                       len += kdb_printf("  ");
+               switch(dbg_reg_def[i].size * 8) {
+               case 8:
+                       rname = dbg_get_reg(i, &reg8, kdb_current_regs);
+                       if (!rname)
+                               break;
+                       len += kdb_printf("%s: %02x", rname, reg8);
+                       break;
+               case 16:
+                       rname = dbg_get_reg(i, &reg16, kdb_current_regs);
+                       if (!rname)
+                               break;
+                       len += kdb_printf("%s: %04x", rname, reg16);
+                       break;
+               case 32:
+                       rname = dbg_get_reg(i, &reg32, kdb_current_regs);
+                       if (!rname)
+                               break;
+                       len += kdb_printf("%s: %08x", rname, reg32);
+                       break;
+               case 64:
+                       rname = dbg_get_reg(i, &reg64, kdb_current_regs);
+                       if (!rname)
+                               break;
+                       len += kdb_printf("%s: %016llx", rname, reg64);
+                       break;
+               default:
+                       len += kdb_printf("%s: ??", dbg_reg_def[i].name);
+               }
+       }
+       kdb_printf("\n");
+#else
+       if (len)
+               return len;
+
+       kdb_dumpregs(kdb_current_regs);
+#endif
+       return 0;
+}
+
+/*
+ * kdb_rm - This function implements the 'rm' (register modify)  command.
+ *     rm register-name new-contents
+ * Remarks:
+ *     Allows register modification with the same restrictions as gdb
+ */
+static int kdb_rm(int argc, const char **argv)
+{
+#if DBG_MAX_REG_NUM > 0
+       int diag;
+       const char *rname;
+       int i;
+       u64 reg64;
+       u32 reg32;
+       u16 reg16;
+       u8 reg8;
+
+       if (argc != 2)
+               return KDB_ARGCOUNT;
+       /*
+        * Allow presence or absence of leading '%' symbol.
+        */
+       rname = argv[1];
+       if (*rname == '%')
+               rname++;
+
+       diag = kdbgetu64arg(argv[2], &reg64);
+       if (diag)
+               return diag;
+
+       diag = kdb_check_regs();
+       if (diag)
+               return diag;
+
+       diag = KDB_BADREG;
+       for (i = 0; i < DBG_MAX_REG_NUM; i++) {
+               if (strcmp(rname, dbg_reg_def[i].name) == 0) {
+                       diag = 0;
+                       break;
+               }
+       }
+       if (!diag) {
+               switch(dbg_reg_def[i].size * 8) {
+               case 8:
+                       reg8 = reg64;
+                       dbg_set_reg(i, &reg8, kdb_current_regs);
+                       break;
+               case 16:
+                       reg16 = reg64;
+                       dbg_set_reg(i, &reg16, kdb_current_regs);
+                       break;
+               case 32:
+                       reg32 = reg64;
+                       dbg_set_reg(i, &reg32, kdb_current_regs);
+                       break;
+               case 64:
+                       dbg_set_reg(i, &reg64, kdb_current_regs);
+                       break;
+               }
+       }
+       return diag;
+#else
+       kdb_printf("ERROR: Register set currently not implemented\n");
+    return 0;
+#endif
+}
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+/*
+ * kdb_sr - This function implements the 'sr' (SYSRQ key) command
+ *     which interfaces to the soi-disant MAGIC SYSRQ functionality.
+ *             sr <magic-sysrq-code>
+ */
+static int kdb_sr(int argc, const char **argv)
+{
+       bool check_mask =
+           !kdb_check_flags(KDB_ENABLE_ALL, kdb_cmd_enabled, false);
+
+       if (argc != 1)
+               return KDB_ARGCOUNT;
+
+       kdb_trap_printk++;
+       __handle_sysrq(*argv[1], check_mask);
+       kdb_trap_printk--;
+
+       return 0;
+}
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+/*
+ * kdb_ef - This function implements the 'regs' (display exception
+ *     frame) command.  This command takes an address and expects to
+ *     find an exception frame at that address, formats and prints
+ *     it.
+ *             regs address-expression
+ * Remarks:
+ *     Not done yet.
+ */
+static int kdb_ef(int argc, const char **argv)
+{
+       int diag;
+       unsigned long addr;
+       long offset;
+       int nextarg;
+
+       if (argc != 1)
+               return KDB_ARGCOUNT;
+
+       nextarg = 1;
+       diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL);
+       if (diag)
+               return diag;
+       show_regs((struct pt_regs *)addr);
+       return 0;
+}
+
+#if defined(CONFIG_MODULES)
+/*
+ * kdb_lsmod - This function implements the 'lsmod' command.  Lists
+ *     currently loaded kernel modules.
+ *     Mostly taken from userland lsmod.
+ */
+static int kdb_lsmod(int argc, const char **argv)
+{
+       struct module *mod;
+
+       if (argc != 0)
+               return KDB_ARGCOUNT;
+
+       kdb_printf("Module                  Size  modstruct     Used by\n");
+       list_for_each_entry(mod, kdb_modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
+
+               kdb_printf("%-20s%8u  0x%p ", mod->name,
+                          mod->core_size, (void *)mod);
+#ifdef CONFIG_MODULE_UNLOAD
+               kdb_printf("%4d ", module_refcount(mod));
+#endif
+               if (mod->state == MODULE_STATE_GOING)
+                       kdb_printf(" (Unloading)");
+               else if (mod->state == MODULE_STATE_COMING)
+                       kdb_printf(" (Loading)");
+               else
+                       kdb_printf(" (Live)");
+               kdb_printf(" 0x%p", mod->module_core);
+
+#ifdef CONFIG_MODULE_UNLOAD
+               {
+                       struct module_use *use;
+                       kdb_printf(" [ ");
+                       list_for_each_entry(use, &mod->source_list,
+                                           source_list)
+                               kdb_printf("%s ", use->target->name);
+                       kdb_printf("]\n");
+               }
+#endif
+       }
+
+       return 0;
+}
+
+#endif /* CONFIG_MODULES */
+
+/*
+ * kdb_env - This function implements the 'env' command.  Display the
+ *     current environment variables.
+ */
+
+static int kdb_env(int argc, const char **argv)
+{
+       int i;
+
+       for (i = 0; i < __nenv; i++) {
+               if (__env[i])
+                       kdb_printf("%s\n", __env[i]);
+       }
+
+       if (KDB_DEBUG(MASK))
+               kdb_printf("KDBFLAGS=0x%x\n", kdb_flags);
+
+       return 0;
+}
+
+#ifdef CONFIG_PRINTK
+/*
+ * kdb_dmesg - This function implements the 'dmesg' command to display
+ *     the contents of the syslog buffer.
+ *             dmesg [lines] [adjust]
+ */
+static int kdb_dmesg(int argc, const char **argv)
+{
+       int diag;
+       int logging;
+       int lines = 0;
+       int adjust = 0;
+       int n = 0;
+       int skip = 0;
+       struct kmsg_dumper dumper = { .active = 1 };
+       size_t len;
+       char buf[201];
+
+       if (argc > 2)
+               return KDB_ARGCOUNT;
+       if (argc) {
+               char *cp;
+               lines = simple_strtol(argv[1], &cp, 0);
+               if (*cp)
+                       lines = 0;
+               if (argc > 1) {
+                       adjust = simple_strtoul(argv[2], &cp, 0);
+                       if (*cp || adjust < 0)
+                               adjust = 0;
+               }
+       }
+
+       /* disable LOGGING if set */
+       diag = kdbgetintenv("LOGGING", &logging);
+       if (!diag && logging) {
+               const char *setargs[] = { "set", "LOGGING", "0" };
+               kdb_set(2, setargs);
+       }
+
+       kmsg_dump_rewind_nolock(&dumper);
+       while (kmsg_dump_get_line_nolock(&dumper, 1, NULL, 0, NULL))
+               n++;
+
+       if (lines < 0) {
+               if (adjust >= n)
+                       kdb_printf("buffer only contains %d lines, nothing "
+                                  "printed\n", n);
+               else if (adjust - lines >= n)
+                       kdb_printf("buffer only contains %d lines, last %d "
+                                  "lines printed\n", n, n - adjust);
+               skip = adjust;
+               lines = abs(lines);
+       } else if (lines > 0) {
+               skip = n - lines - adjust;
+               lines = abs(lines);
+               if (adjust >= n) {
+                       kdb_printf("buffer only contains %d lines, "
+                                  "nothing printed\n", n);
+                       skip = n;
+               } else if (skip < 0) {
+                       lines += skip;
+                       skip = 0;
+                       kdb_printf("buffer only contains %d lines, first "
+                                  "%d lines printed\n", n, lines);
+               }
+       } else {
+               lines = n;
+       }
+
+       if (skip >= n || skip < 0)
+               return 0;
+
+       kmsg_dump_rewind_nolock(&dumper);
+       while (kmsg_dump_get_line_nolock(&dumper, 1, buf, sizeof(buf), &len)) {
+               if (skip) {
+                       skip--;
+                       continue;
+               }
+               if (!lines--)
+                       break;
+               if (KDB_FLAG(CMD_INTERRUPT))
+                       return 0;
+
+               kdb_printf("%.*s\n", (int)len - 1, buf);
+       }
+
+       return 0;
+}
+#endif /* CONFIG_PRINTK */
+
+/* Make sure we balance enable/disable calls, must disable first. */
+static atomic_t kdb_nmi_disabled;
+
+static int kdb_disable_nmi(int argc, const char *argv[])
+{
+       if (atomic_read(&kdb_nmi_disabled))
+               return 0;
+       atomic_set(&kdb_nmi_disabled, 1);
+       arch_kgdb_ops.enable_nmi(0);
+       return 0;
+}
+
+static int kdb_param_enable_nmi(const char *val, const struct kernel_param *kp)
+{
+       if (!atomic_add_unless(&kdb_nmi_disabled, -1, 0))
+               return -EINVAL;
+       arch_kgdb_ops.enable_nmi(1);
+       return 0;
+}
+
+static const struct kernel_param_ops kdb_param_ops_enable_nmi = {
+       .set = kdb_param_enable_nmi,
+};
+module_param_cb(enable_nmi, &kdb_param_ops_enable_nmi, NULL, 0600);
+
+/*
+ * kdb_cpu - This function implements the 'cpu' command.
+ *     cpu     [<cpunum>]
+ * Returns:
+ *     KDB_CMD_CPU for success, a kdb diagnostic if error
+ */
+static void kdb_cpu_status(void)
+{
+       int i, start_cpu, first_print = 1;
+       char state, prev_state = '?';
+
+       kdb_printf("Currently on cpu %d\n", raw_smp_processor_id());
+       kdb_printf("Available cpus: ");
+       for (start_cpu = -1, i = 0; i < NR_CPUS; i++) {
+               if (!cpu_online(i)) {
+                       state = 'F';    /* cpu is offline */
+               } else if (!kgdb_info[i].enter_kgdb) {
+                       state = 'D';    /* cpu is online but unresponsive */
+               } else {
+                       state = ' ';    /* cpu is responding to kdb */
+                       if (kdb_task_state_char(KDB_TSK(i)) == 'I')
+                               state = 'I';    /* idle task */
+               }
+               if (state != prev_state) {
+                       if (prev_state != '?') {
+                               if (!first_print)
+                                       kdb_printf(", ");
+                               first_print = 0;
+                               kdb_printf("%d", start_cpu);
+                               if (start_cpu < i-1)
+                                       kdb_printf("-%d", i-1);
+                               if (prev_state != ' ')
+                                       kdb_printf("(%c)", prev_state);
+                       }
+                       prev_state = state;
+                       start_cpu = i;
+               }
+       }
+       /* print the trailing cpus, ignoring them if they are all offline */
+       if (prev_state != 'F') {
+               if (!first_print)
+                       kdb_printf(", ");
+               kdb_printf("%d", start_cpu);
+               if (start_cpu < i-1)
+                       kdb_printf("-%d", i-1);
+               if (prev_state != ' ')
+                       kdb_printf("(%c)", prev_state);
+       }
+       kdb_printf("\n");
+}
+
+static int kdb_cpu(int argc, const char **argv)
+{
+       unsigned long cpunum;
+       int diag;
+
+       if (argc == 0) {
+               kdb_cpu_status();
+               return 0;
+       }
+
+       if (argc != 1)
+               return KDB_ARGCOUNT;
+
+       diag = kdbgetularg(argv[1], &cpunum);
+       if (diag)
+               return diag;
+
+       /*
+        * Validate cpunum
+        */
+       if ((cpunum >= CONFIG_NR_CPUS) || !kgdb_info[cpunum].enter_kgdb)
+               return KDB_BADCPUNUM;
+
+       dbg_switch_cpu = cpunum;
+
+       /*
+        * Switch to other cpu
+        */
+       return KDB_CMD_CPU;
+}
+
+/* The user may not realize that ps/bta with no parameters does not print idle
+ * or sleeping system daemon processes, so tell them how many were suppressed.
+ */
+void kdb_ps_suppressed(void)
+{
+       int idle = 0, daemon = 0;
+       unsigned long mask_I = kdb_task_state_string("I"),
+                     mask_M = kdb_task_state_string("M");
+       unsigned long cpu;
+       const struct task_struct *p, *g;
+       for_each_online_cpu(cpu) {
+               p = kdb_curr_task(cpu);
+               if (kdb_task_state(p, mask_I))
+                       ++idle;
+       }
+       kdb_do_each_thread(g, p) {
+               if (kdb_task_state(p, mask_M))
+                       ++daemon;
+       } kdb_while_each_thread(g, p);
+       if (idle || daemon) {
+               if (idle)
+                       kdb_printf("%d idle process%s (state I)%s\n",
+                                  idle, idle == 1 ? "" : "es",
+                                  daemon ? " and " : "");
+               if (daemon)
+                       kdb_printf("%d sleeping system daemon (state M) "
+                                  "process%s", daemon,
+                                  daemon == 1 ? "" : "es");
+               kdb_printf(" suppressed,\nuse 'ps A' to see all.\n");
+       }
+}
+
+/*
+ * kdb_ps - This function implements the 'ps' command which shows a
+ *     list of the active processes.
+ *             ps [DRSTCZEUIMA]   All processes, optionally filtered by state
+ */
+void kdb_ps1(const struct task_struct *p)
+{
+       int cpu;
+       unsigned long tmp;
+
+       if (!p || probe_kernel_read(&tmp, (char *)p, sizeof(unsigned long)))
+               return;
+
+       cpu = kdb_process_cpu(p);
+       kdb_printf("0x%p %8d %8d  %d %4d   %c  0x%p %c%s\n",
+                  (void *)p, p->pid, p->parent->pid,
+                  kdb_task_has_cpu(p), kdb_process_cpu(p),
+                  kdb_task_state_char(p),
+                  (void *)(&p->thread),
+                  p == kdb_curr_task(raw_smp_processor_id()) ? '*' : ' ',
+                  p->comm);
+       if (kdb_task_has_cpu(p)) {
+               if (!KDB_TSK(cpu)) {
+                       kdb_printf("  Error: no saved data for this cpu\n");
+               } else {
+                       if (KDB_TSK(cpu) != p)
+                               kdb_printf("  Error: does not match running "
+                                  "process table (0x%p)\n", KDB_TSK(cpu));
+               }
+       }
+}
+
+static int kdb_ps(int argc, const char **argv)
+{
+       struct task_struct *g, *p;
+       unsigned long mask, cpu;
+
+       if (argc == 0)
+               kdb_ps_suppressed();
+       kdb_printf("%-*s      Pid   Parent [*] cpu State %-*s Command\n",
+               (int)(2*sizeof(void *))+2, "Task Addr",
+               (int)(2*sizeof(void *))+2, "Thread");
+       mask = kdb_task_state_string(argc ? argv[1] : NULL);
+       /* Run the active tasks first */
+       for_each_online_cpu(cpu) {
+               if (KDB_FLAG(CMD_INTERRUPT))
+                       return 0;
+               p = kdb_curr_task(cpu);
+               if (kdb_task_state(p, mask))
+                       kdb_ps1(p);
+       }
+       kdb_printf("\n");
+       /* Now the real tasks */
+       kdb_do_each_thread(g, p) {
+               if (KDB_FLAG(CMD_INTERRUPT))
+                       return 0;
+               if (kdb_task_state(p, mask))
+                       kdb_ps1(p);
+       } kdb_while_each_thread(g, p);
+
+       return 0;
+}
+
+/*
+ * kdb_pid - This function implements the 'pid' command which switches
+ *     the currently active process.
+ *             pid [<pid> | R]
+ */
+static int kdb_pid(int argc, const char **argv)
+{
+       struct task_struct *p;
+       unsigned long val;
+       int diag;
+
+       if (argc > 1)
+               return KDB_ARGCOUNT;
+
+       if (argc) {
+               if (strcmp(argv[1], "R") == 0) {
+                       p = KDB_TSK(kdb_initial_cpu);
+               } else {
+                       diag = kdbgetularg(argv[1], &val);
+                       if (diag)
+                               return KDB_BADINT;
+
+                       p = find_task_by_pid_ns((pid_t)val,     &init_pid_ns);
+                       if (!p) {
+                               kdb_printf("No task with pid=%d\n", (pid_t)val);
+                               return 0;
+                       }
+               }
+               kdb_set_current_task(p);
+       }
+       kdb_printf("KDB current process is %s(pid=%d)\n",
+                  kdb_current_task->comm,
+                  kdb_current_task->pid);
+
+       return 0;
+}
+
+static int kdb_kgdb(int argc, const char **argv)
+{
+       return KDB_CMD_KGDB;
+}
+
+/*
+ * kdb_help - This function implements the 'help' and '?' commands.
+ */
+static int kdb_help(int argc, const char **argv)
+{
+       kdbtab_t *kt;
+       int i;
+
+       kdb_printf("%-15.15s %-20.20s %s\n", "Command", "Usage", "Description");
+       kdb_printf("-----------------------------"
+                  "-----------------------------\n");
+       for_each_kdbcmd(kt, i) {
+               char *space = "";
+               if (KDB_FLAG(CMD_INTERRUPT))
+                       return 0;
+               if (!kt->cmd_name)
+                       continue;
+               if (!kdb_check_flags(kt->cmd_flags, kdb_cmd_enabled, true))
+                       continue;
+               if (strlen(kt->cmd_usage) > 20)
+                       space = "\n                                    ";
+               kdb_printf("%-15.15s %-20s%s%s\n", kt->cmd_name,
+                          kt->cmd_usage, space, kt->cmd_help);
+       }
+       return 0;
+}
+
+/*
+ * kdb_kill - This function implements the 'kill' commands.
+ */
+static int kdb_kill(int argc, const char **argv)
+{
+       long sig, pid;
+       char *endp;
+       struct task_struct *p;
+       struct siginfo info;
+
+       if (argc != 2)
+               return KDB_ARGCOUNT;
+
+       sig = simple_strtol(argv[1], &endp, 0);
+       if (*endp)
+               return KDB_BADINT;
+       if (sig >= 0) {
+               kdb_printf("Invalid signal parameter.<-signal>\n");
+               return 0;
+       }
+       sig = -sig;
+
+       pid = simple_strtol(argv[2], &endp, 0);
+       if (*endp)
+               return KDB_BADINT;
+       if (pid <= 0) {
+               kdb_printf("Process ID must be large than 0.\n");
+               return 0;
+       }
+
+       /* Find the process. */
+       p = find_task_by_pid_ns(pid, &init_pid_ns);
+       if (!p) {
+               kdb_printf("The specified process isn't found.\n");
+               return 0;
+       }
+       p = p->group_leader;
+       info.si_signo = sig;
+       info.si_errno = 0;
+       info.si_code = SI_USER;
+       info.si_pid = pid;  /* same capabilities as process being signalled */
+       info.si_uid = 0;    /* kdb has root authority */
+       kdb_send_sig_info(p, &info);
+       return 0;
+}
+
+struct kdb_tm {
+       int tm_sec;     /* seconds */
+       int tm_min;     /* minutes */
+       int tm_hour;    /* hours */
+       int tm_mday;    /* day of the month */
+       int tm_mon;     /* month */
+       int tm_year;    /* year */
+};
+
+static void kdb_gmtime(struct timespec *tv, struct kdb_tm *tm)
+{
+       /* This will work from 1970-2099, 2100 is not a leap year */
+       static int mon_day[] = { 31, 29, 31, 30, 31, 30, 31,
+                                31, 30, 31, 30, 31 };
+       memset(tm, 0, sizeof(*tm));
+       tm->tm_sec  = tv->tv_sec % (24 * 60 * 60);
+       tm->tm_mday = tv->tv_sec / (24 * 60 * 60) +
+               (2 * 365 + 1); /* shift base from 1970 to 1968 */
+       tm->tm_min =  tm->tm_sec / 60 % 60;
+       tm->tm_hour = tm->tm_sec / 60 / 60;
+       tm->tm_sec =  tm->tm_sec % 60;
+       tm->tm_year = 68 + 4*(tm->tm_mday / (4*365+1));
+       tm->tm_mday %= (4*365+1);
+       mon_day[1] = 29;
+       while (tm->tm_mday >= mon_day[tm->tm_mon]) {
+               tm->tm_mday -= mon_day[tm->tm_mon];
+               if (++tm->tm_mon == 12) {
+                       tm->tm_mon = 0;
+                       ++tm->tm_year;
+                       mon_day[1] = 28;
+               }
+       }
+       ++tm->tm_mday;
+}
+
+/*
+ * Most of this code has been lifted from kernel/timer.c::sys_sysinfo().
+ * I cannot call that code directly from kdb, it has an unconditional
+ * cli()/sti() and calls routines that take locks which can stop the debugger.
+ */
+static void kdb_sysinfo(struct sysinfo *val)
+{
+       struct timespec uptime;
+       ktime_get_ts(&uptime);
+       memset(val, 0, sizeof(*val));
+       val->uptime = uptime.tv_sec;
+       val->loads[0] = avenrun[0];
+       val->loads[1] = avenrun[1];
+       val->loads[2] = avenrun[2];
+       val->procs = nr_threads-1;
+       si_meminfo(val);
+
+       return;
+}
+
+/*
+ * kdb_summary - This function implements the 'summary' command.
+ */
+static int kdb_summary(int argc, const char **argv)
+{
+       struct timespec now;
+       struct kdb_tm tm;
+       struct sysinfo val;
+
+       if (argc)
+               return KDB_ARGCOUNT;
+
+       kdb_printf("sysname    %s\n", init_uts_ns.name.sysname);
+       kdb_printf("release    %s\n", init_uts_ns.name.release);
+       kdb_printf("version    %s\n", init_uts_ns.name.version);
+       kdb_printf("machine    %s\n", init_uts_ns.name.machine);
+       kdb_printf("nodename   %s\n", init_uts_ns.name.nodename);
+       kdb_printf("domainname %s\n", init_uts_ns.name.domainname);
+       kdb_printf("ccversion  %s\n", __stringify(CCVERSION));
+
+       now = __current_kernel_time();
+       kdb_gmtime(&now, &tm);
+       kdb_printf("date       %04d-%02d-%02d %02d:%02d:%02d "
+                  "tz_minuteswest %d\n",
+               1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
+               tm.tm_hour, tm.tm_min, tm.tm_sec,
+               sys_tz.tz_minuteswest);
+
+       kdb_sysinfo(&val);
+       kdb_printf("uptime     ");
+       if (val.uptime > (24*60*60)) {
+               int days = val.uptime / (24*60*60);
+               val.uptime %= (24*60*60);
+               kdb_printf("%d day%s ", days, days == 1 ? "" : "s");
+       }
+       kdb_printf("%02ld:%02ld\n", val.uptime/(60*60), (val.uptime/60)%60);
+
+       /* lifted from fs/proc/proc_misc.c::loadavg_read_proc() */
+
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+       kdb_printf("load avg   %ld.%02ld %ld.%02ld %ld.%02ld\n",
+               LOAD_INT(val.loads[0]), LOAD_FRAC(val.loads[0]),
+               LOAD_INT(val.loads[1]), LOAD_FRAC(val.loads[1]),
+               LOAD_INT(val.loads[2]), LOAD_FRAC(val.loads[2]));
+#undef LOAD_INT
+#undef LOAD_FRAC
+       /* Display in kilobytes */
+#define K(x) ((x) << (PAGE_SHIFT - 10))
+       kdb_printf("\nMemTotal:       %8lu kB\nMemFree:        %8lu kB\n"
+                  "Buffers:        %8lu kB\n",
+                  K(val.totalram), K(val.freeram), K(val.bufferram));
+       return 0;
+}
+
+/*
+ * kdb_per_cpu - This function implements the 'per_cpu' command.
+ */
+static int kdb_per_cpu(int argc, const char **argv)
+{
+       char fmtstr[64];
+       int cpu, diag, nextarg = 1;
+       unsigned long addr, symaddr, val, bytesperword = 0, whichcpu = ~0UL;
+
+       if (argc < 1 || argc > 3)
+               return KDB_ARGCOUNT;
+
+       diag = kdbgetaddrarg(argc, argv, &nextarg, &symaddr, NULL, NULL);
+       if (diag)
+               return diag;
+
+       if (argc >= 2) {
+               diag = kdbgetularg(argv[2], &bytesperword);
+               if (diag)
+                       return diag;
+       }
+       if (!bytesperword)
+               bytesperword = KDB_WORD_SIZE;
+       else if (bytesperword > KDB_WORD_SIZE)
+               return KDB_BADWIDTH;
+       sprintf(fmtstr, "%%0%dlx ", (int)(2*bytesperword));
+       if (argc >= 3) {
+               diag = kdbgetularg(argv[3], &whichcpu);
+               if (diag)
+                       return diag;
+               if (!cpu_online(whichcpu)) {
+                       kdb_printf("cpu %ld is not online\n", whichcpu);
+                       return KDB_BADCPUNUM;
+               }
+       }
+
+       /* Most architectures use __per_cpu_offset[cpu], some use
+        * __per_cpu_offset(cpu), smp has no __per_cpu_offset.
+        */
+#ifdef __per_cpu_offset
+#define KDB_PCU(cpu) __per_cpu_offset(cpu)
+#else
+#ifdef CONFIG_SMP
+#define KDB_PCU(cpu) __per_cpu_offset[cpu]
+#else
+#define KDB_PCU(cpu) 0
+#endif
+#endif
+       for_each_online_cpu(cpu) {
+               if (KDB_FLAG(CMD_INTERRUPT))
+                       return 0;
+
+               if (whichcpu != ~0UL && whichcpu != cpu)
+                       continue;
+               addr = symaddr + KDB_PCU(cpu);
+               diag = kdb_getword(&val, addr, bytesperword);
+               if (diag) {
+                       kdb_printf("%5d " kdb_bfd_vma_fmt0 " - unable to "
+                                  "read, diag=%d\n", cpu, addr, diag);
+                       continue;
+               }
+               kdb_printf("%5d ", cpu);
+               kdb_md_line(fmtstr, addr,
+                       bytesperword == KDB_WORD_SIZE,
+                       1, bytesperword, 1, 1, 0);
+       }
+#undef KDB_PCU
+       return 0;
+}
+
+/*
+ * display help for the use of cmd | grep pattern
+ */
+static int kdb_grep_help(int argc, const char **argv)
+{
+       kdb_printf("Usage of  cmd args | grep pattern:\n");
+       kdb_printf("  Any command's output may be filtered through an ");
+       kdb_printf("emulated 'pipe'.\n");
+       kdb_printf("  'grep' is just a key word.\n");
+       kdb_printf("  The pattern may include a very limited set of "
+                  "metacharacters:\n");
+       kdb_printf("   pattern or ^pattern or pattern$ or ^pattern$\n");
+       kdb_printf("  And if there are spaces in the pattern, you may "
+                  "quote it:\n");
+       kdb_printf("   \"pat tern\" or \"^pat tern\" or \"pat tern$\""
+                  " or \"^pat tern$\"\n");
+       return 0;
+}
+
+/*
+ * kdb_register_flags - This function is used to register a kernel
+ *     debugger command.
+ * Inputs:
+ *     cmd     Command name
+ *     func    Function to execute the command
+ *     usage   A simple usage string showing arguments
+ *     help    A simple help string describing command
+ *     repeat  Does the command auto repeat on enter?
+ * Returns:
+ *     zero for success, one if a duplicate command.
+ */
+#define kdb_command_extend 50  /* arbitrary */
+int kdb_register_flags(char *cmd,
+                      kdb_func_t func,
+                      char *usage,
+                      char *help,
+                      short minlen,
+                      kdb_cmdflags_t flags)
+{
+       int i;
+       kdbtab_t *kp;
+
+       /*
+        *  Brute force method to determine duplicates
+        */
+       for_each_kdbcmd(kp, i) {
+               if (kp->cmd_name && (strcmp(kp->cmd_name, cmd) == 0)) {
+                       kdb_printf("Duplicate kdb command registered: "
+                               "%s, func %p help %s\n", cmd, func, help);
+                       return 1;
+               }
+       }
+
+       /*
+        * Insert command into first available location in table
+        */
+       for_each_kdbcmd(kp, i) {
+               if (kp->cmd_name == NULL)
+                       break;
+       }
+
+       if (i >= kdb_max_commands) {
+               kdbtab_t *new = kmalloc((kdb_max_commands - KDB_BASE_CMD_MAX +
+                        kdb_command_extend) * sizeof(*new), GFP_KDB);
+               if (!new) {
+                       kdb_printf("Could not allocate new kdb_command "
+                                  "table\n");
+                       return 1;
+               }
+               if (kdb_commands) {
+                       memcpy(new, kdb_commands,
+                         (kdb_max_commands - KDB_BASE_CMD_MAX) * sizeof(*new));
+                       kfree(kdb_commands);
+               }
+               memset(new + kdb_max_commands - KDB_BASE_CMD_MAX, 0,
+                      kdb_command_extend * sizeof(*new));
+               kdb_commands = new;
+               kp = kdb_commands + kdb_max_commands - KDB_BASE_CMD_MAX;
+               kdb_max_commands += kdb_command_extend;
+       }
+
+       kp->cmd_name   = cmd;
+       kp->cmd_func   = func;
+       kp->cmd_usage  = usage;
+       kp->cmd_help   = help;
+       kp->cmd_minlen = minlen;
+       kp->cmd_flags  = flags;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(kdb_register_flags);
+
+
+/*
+ * kdb_register - Compatibility register function for commands that do
+ *     not need to specify a repeat state.  Equivalent to
+ *     kdb_register_flags with flags set to 0.
+ * Inputs:
+ *     cmd     Command name
+ *     func    Function to execute the command
+ *     usage   A simple usage string showing arguments
+ *     help    A simple help string describing command
+ * Returns:
+ *     zero for success, one if a duplicate command.
+ */
+int kdb_register(char *cmd,
+            kdb_func_t func,
+            char *usage,
+            char *help,
+            short minlen)
+{
+       return kdb_register_flags(cmd, func, usage, help, minlen, 0);
+}
+EXPORT_SYMBOL_GPL(kdb_register);
+
+/*
+ * kdb_unregister - This function is used to unregister a kernel
+ *     debugger command.  It is generally called when a module which
+ *     implements kdb commands is unloaded.
+ * Inputs:
+ *     cmd     Command name
+ * Returns:
+ *     zero for success, one command not registered.
+ */
+int kdb_unregister(char *cmd)
+{
+       int i;
+       kdbtab_t *kp;
+
+       /*
+        *  find the command.
+        */
+       for_each_kdbcmd(kp, i) {
+               if (kp->cmd_name && (strcmp(kp->cmd_name, cmd) == 0)) {
+                       kp->cmd_name = NULL;
+                       return 0;
+               }
+       }
+
+       /* Couldn't find it.  */
+       return 1;
+}
+EXPORT_SYMBOL_GPL(kdb_unregister);
+
+/* Initialize the kdb command table. */
+static void __init kdb_inittab(void)
+{
+       int i;
+       kdbtab_t *kp;
+
+       for_each_kdbcmd(kp, i)
+               kp->cmd_name = NULL;
+
+       kdb_register_flags("md", kdb_md, "<vaddr>",
+         "Display Memory Contents, also mdWcN, e.g. md8c1", 1,
+         KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("mdr", kdb_md, "<vaddr> <bytes>",
+         "Display Raw Memory", 0,
+         KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("mdp", kdb_md, "<paddr> <bytes>",
+         "Display Physical Memory", 0,
+         KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("mds", kdb_md, "<vaddr>",
+         "Display Memory Symbolically", 0,
+         KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("mm", kdb_mm, "<vaddr> <contents>",
+         "Modify Memory Contents", 0,
+         KDB_ENABLE_MEM_WRITE | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("go", kdb_go, "[<vaddr>]",
+         "Continue Execution", 1,
+         KDB_ENABLE_REG_WRITE | KDB_ENABLE_ALWAYS_SAFE_NO_ARGS);
+       kdb_register_flags("rd", kdb_rd, "",
+         "Display Registers", 0,
+         KDB_ENABLE_REG_READ);
+       kdb_register_flags("rm", kdb_rm, "<reg> <contents>",
+         "Modify Registers", 0,
+         KDB_ENABLE_REG_WRITE);
+       kdb_register_flags("ef", kdb_ef, "<vaddr>",
+         "Display exception frame", 0,
+         KDB_ENABLE_MEM_READ);
+       kdb_register_flags("bt", kdb_bt, "[<vaddr>]",
+         "Stack traceback", 1,
+         KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS);
+       kdb_register_flags("btp", kdb_bt, "<pid>",
+         "Display stack for process <pid>", 0,
+         KDB_ENABLE_INSPECT);
+       kdb_register_flags("bta", kdb_bt, "[D|R|S|T|C|Z|E|U|I|M|A]",
+         "Backtrace all processes matching state flag", 0,
+         KDB_ENABLE_INSPECT);
+       kdb_register_flags("btc", kdb_bt, "",
+         "Backtrace current process on each cpu", 0,
+         KDB_ENABLE_INSPECT);
+       kdb_register_flags("btt", kdb_bt, "<vaddr>",
+         "Backtrace process given its struct task address", 0,
+         KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS);
+       kdb_register_flags("env", kdb_env, "",
+         "Show environment variables", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("set", kdb_set, "",
+         "Set environment variables", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("help", kdb_help, "",
+         "Display Help Message", 1,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("?", kdb_help, "",
+         "Display Help Message", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("cpu", kdb_cpu, "<cpunum>",
+         "Switch to new cpu", 0,
+         KDB_ENABLE_ALWAYS_SAFE_NO_ARGS);
+       kdb_register_flags("kgdb", kdb_kgdb, "",
+         "Enter kgdb mode", 0, 0);
+       kdb_register_flags("ps", kdb_ps, "[<flags>|A]",
+         "Display active task list", 0,
+         KDB_ENABLE_INSPECT);
+       kdb_register_flags("pid", kdb_pid, "<pidnum>",
+         "Switch to another task", 0,
+         KDB_ENABLE_INSPECT);
+       kdb_register_flags("reboot", kdb_reboot, "",
+         "Reboot the machine immediately", 0,
+         KDB_ENABLE_REBOOT);
+#if defined(CONFIG_MODULES)
+       kdb_register_flags("lsmod", kdb_lsmod, "",
+         "List loaded kernel modules", 0,
+         KDB_ENABLE_INSPECT);
+#endif
+#if defined(CONFIG_MAGIC_SYSRQ)
+       kdb_register_flags("sr", kdb_sr, "<key>",
+         "Magic SysRq key", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+#endif
+#if defined(CONFIG_PRINTK)
+       kdb_register_flags("dmesg", kdb_dmesg, "[lines]",
+         "Display syslog buffer", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+#endif
+       if (arch_kgdb_ops.enable_nmi) {
+               kdb_register_flags("disable_nmi", kdb_disable_nmi, "",
+                 "Disable NMI entry to KDB", 0,
+                 KDB_ENABLE_ALWAYS_SAFE);
+       }
+       kdb_register_flags("defcmd", kdb_defcmd, "name \"usage\" \"help\"",
+         "Define a set of commands, down to endefcmd", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("kill", kdb_kill, "<-signal> <pid>",
+         "Send a signal to a process", 0,
+         KDB_ENABLE_SIGNAL);
+       kdb_register_flags("summary", kdb_summary, "",
+         "Summarize the system", 4,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("per_cpu", kdb_per_cpu, "<sym> [<bytes>] [<cpu>]",
+         "Display per_cpu variables", 3,
+         KDB_ENABLE_MEM_READ);
+       kdb_register_flags("grephelp", kdb_grep_help, "",
+         "Display help on | grep", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+}
+
+/* Execute any commands defined in kdb_cmds.  */
+static void __init kdb_cmd_init(void)
+{
+       int i, diag;
+       for (i = 0; kdb_cmds[i]; ++i) {
+               diag = kdb_parse(kdb_cmds[i]);
+               if (diag)
+                       kdb_printf("kdb command %s failed, kdb diag %d\n",
+                               kdb_cmds[i], diag);
+       }
+       if (defcmd_in_progress) {
+               kdb_printf("Incomplete 'defcmd' set, forcing endefcmd\n");
+               kdb_parse("endefcmd");
+       }
+}
+
+/* Initialize kdb_printf, breakpoint tables and kdb state */
+void __init kdb_init(int lvl)
+{
+       static int kdb_init_lvl = KDB_NOT_INITIALIZED;
+       int i;
+
+       if (kdb_init_lvl == KDB_INIT_FULL || lvl <= kdb_init_lvl)
+               return;
+       for (i = kdb_init_lvl; i < lvl; i++) {
+               switch (i) {
+               case KDB_NOT_INITIALIZED:
+                       kdb_inittab();          /* Initialize Command Table */
+                       kdb_initbptab();        /* Initialize Breakpoints */
+                       break;
+               case KDB_INIT_EARLY:
+                       kdb_cmd_init();         /* Build kdb_cmds tables */
+                       break;
+               }
+       }
+       kdb_init_lvl = lvl;
+}