Commit 3cfb0774 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for_linux-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb

Pull KGDB/KDB fixes and cleanups from Jason Wessel:
 "For a change we removed more code than we added.  If people aren't
  using it we shouldn't be carrying it.  :-)

  Cleanups:
   - Remove kdb ssb command - there is no in kernel disassembler to
     support it

   - Remove kdb ll command - Always caused a kernel oops and there were
     no bug reports so no one was using this command

   - Use kernel ARRAY_SIZE macro instead of array computations

  Fixes:
   - Stop oops in kdb if user executes kdb_defcmd with args

   - kdb help command truncated text

   - ppc64 support for kgdbts

   - Add missing kconfig option from original kdb port for dealing with
     catastrophic kernel crashes such that you can reboot automatically
     on continue from kdb"

* tag 'for_linux-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb:
  kdb: Remove unhandled ssb command
  kdb: Prevent kernel oops with kdb_defcmd
  kdb: Remove the ll command
  kdb_main: fix help print
  kdb: Fix overlap in buffers with strcpy
  Fixed dead ifdef block by adding missing Kconfig option.
  kdb: Setup basic kdb state before invoking commands via kgdb
  kdb: use ARRAY_SIZE where possible
  kgdb/kgdbts: support ppc64
  kdb: A fix for kdb command table expansion
parents e23b6225 36dfea42
...@@ -103,6 +103,7 @@ ...@@ -103,6 +103,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/module.h> #include <linux/module.h>
#include <asm/sections.h>
#define v1printk(a...) do { \ #define v1printk(a...) do { \
if (verbose) \ if (verbose) \
...@@ -222,6 +223,7 @@ static unsigned long lookup_addr(char *arg) ...@@ -222,6 +223,7 @@ static unsigned long lookup_addr(char *arg)
addr = (unsigned long)do_fork; addr = (unsigned long)do_fork;
else if (!strcmp(arg, "hw_break_val")) else if (!strcmp(arg, "hw_break_val"))
addr = (unsigned long)&hw_break_val; addr = (unsigned long)&hw_break_val;
addr = (unsigned long) dereference_function_descriptor((void *)addr);
return addr; return addr;
} }
......
...@@ -72,6 +72,8 @@ extern int dbg_kdb_mode; ...@@ -72,6 +72,8 @@ extern int dbg_kdb_mode;
#ifdef CONFIG_KGDB_KDB #ifdef CONFIG_KGDB_KDB
extern int kdb_stub(struct kgdb_state *ks); extern int kdb_stub(struct kgdb_state *ks);
extern int kdb_parse(const char *cmdstr); extern int kdb_parse(const char *cmdstr);
extern int kdb_common_init_state(struct kgdb_state *ks);
extern int kdb_common_deinit_state(void);
#else /* ! CONFIG_KGDB_KDB */ #else /* ! CONFIG_KGDB_KDB */
static inline int kdb_stub(struct kgdb_state *ks) static inline int kdb_stub(struct kgdb_state *ks)
{ {
......
...@@ -783,7 +783,10 @@ static void gdb_cmd_query(struct kgdb_state *ks) ...@@ -783,7 +783,10 @@ static void gdb_cmd_query(struct kgdb_state *ks)
len = len / 2; len = len / 2;
remcom_out_buffer[len++] = 0; remcom_out_buffer[len++] = 0;
kdb_common_init_state(ks);
kdb_parse(remcom_out_buffer); kdb_parse(remcom_out_buffer);
kdb_common_deinit_state();
strcpy(remcom_out_buffer, "OK"); strcpy(remcom_out_buffer, "OK");
} }
break; break;
......
...@@ -486,11 +486,9 @@ static int kdb_bc(int argc, const char **argv) ...@@ -486,11 +486,9 @@ static int kdb_bc(int argc, const char **argv)
/* /*
* kdb_ss * kdb_ss
* *
* Process the 'ss' (Single Step) and 'ssb' (Single Step to Branch) * Process the 'ss' (Single Step) command.
* commands.
* *
* ss * ss
* ssb
* *
* Parameters: * Parameters:
* argc Argument count * argc Argument count
...@@ -498,35 +496,23 @@ static int kdb_bc(int argc, const char **argv) ...@@ -498,35 +496,23 @@ static int kdb_bc(int argc, const char **argv)
* Outputs: * Outputs:
* None. * None.
* Returns: * Returns:
* KDB_CMD_SS[B] for success, a kdb error if failure. * KDB_CMD_SS for success, a kdb error if failure.
* Locking: * Locking:
* None. * None.
* Remarks: * Remarks:
* *
* Set the arch specific option to trigger a debug trap after the next * Set the arch specific option to trigger a debug trap after the next
* instruction. * instruction.
*
* For 'ssb', set the trace flag in the debug trap handler
* after printing the current insn and return directly without
* invoking the kdb command processor, until a branch instruction
* is encountered.
*/ */
static int kdb_ss(int argc, const char **argv) static int kdb_ss(int argc, const char **argv)
{ {
int ssb = 0;
ssb = (strcmp(argv[0], "ssb") == 0);
if (argc != 0) if (argc != 0)
return KDB_ARGCOUNT; return KDB_ARGCOUNT;
/* /*
* Set trace flag and go. * Set trace flag and go.
*/ */
KDB_STATE_SET(DOING_SS); KDB_STATE_SET(DOING_SS);
if (ssb) {
KDB_STATE_SET(DOING_SSB);
return KDB_CMD_SSB;
}
return KDB_CMD_SS; return KDB_CMD_SS;
} }
...@@ -561,8 +547,6 @@ void __init kdb_initbptab(void) ...@@ -561,8 +547,6 @@ void __init kdb_initbptab(void)
kdb_register_repeat("ss", kdb_ss, "", kdb_register_repeat("ss", kdb_ss, "",
"Single Step", 1, KDB_REPEAT_NO_ARGS); "Single Step", 1, KDB_REPEAT_NO_ARGS);
kdb_register_repeat("ssb", kdb_ss, "",
"Single step to branch/call", 0, KDB_REPEAT_NO_ARGS);
/* /*
* Architecture dependent initialization. * Architecture dependent initialization.
*/ */
......
...@@ -34,6 +34,22 @@ EXPORT_SYMBOL_GPL(kdb_poll_idx); ...@@ -34,6 +34,22 @@ EXPORT_SYMBOL_GPL(kdb_poll_idx);
static struct kgdb_state *kdb_ks; static struct kgdb_state *kdb_ks;
int kdb_common_init_state(struct kgdb_state *ks)
{
kdb_initial_cpu = atomic_read(&kgdb_active);
kdb_current_task = kgdb_info[ks->cpu].task;
kdb_current_regs = kgdb_info[ks->cpu].debuggerinfo;
return 0;
}
int kdb_common_deinit_state(void)
{
kdb_initial_cpu = -1;
kdb_current_task = NULL;
kdb_current_regs = NULL;
return 0;
}
int kdb_stub(struct kgdb_state *ks) int kdb_stub(struct kgdb_state *ks)
{ {
int error = 0; int error = 0;
...@@ -94,13 +110,10 @@ int kdb_stub(struct kgdb_state *ks) ...@@ -94,13 +110,10 @@ int kdb_stub(struct kgdb_state *ks)
} }
/* Set initial kdb state variables */ /* Set initial kdb state variables */
KDB_STATE_CLEAR(KGDB_TRANS); KDB_STATE_CLEAR(KGDB_TRANS);
kdb_initial_cpu = atomic_read(&kgdb_active); kdb_common_init_state(ks);
kdb_current_task = kgdb_info[ks->cpu].task;
kdb_current_regs = kgdb_info[ks->cpu].debuggerinfo;
/* Remove any breakpoints as needed by kdb and clear single step */ /* Remove any breakpoints as needed by kdb and clear single step */
kdb_bp_remove(); kdb_bp_remove();
KDB_STATE_CLEAR(DOING_SS); KDB_STATE_CLEAR(DOING_SS);
KDB_STATE_CLEAR(DOING_SSB);
KDB_STATE_SET(PAGER); KDB_STATE_SET(PAGER);
/* zero out any offline cpu data */ /* zero out any offline cpu data */
for_each_present_cpu(i) { for_each_present_cpu(i) {
...@@ -125,9 +138,7 @@ int kdb_stub(struct kgdb_state *ks) ...@@ -125,9 +138,7 @@ int kdb_stub(struct kgdb_state *ks)
* Upon exit from the kdb main loop setup break points and restart * Upon exit from the kdb main loop setup break points and restart
* the system based on the requested continue state * the system based on the requested continue state
*/ */
kdb_initial_cpu = -1; kdb_common_deinit_state();
kdb_current_task = NULL;
kdb_current_regs = NULL;
KDB_STATE_CLEAR(PAGER); KDB_STATE_CLEAR(PAGER);
kdbnearsym_cleanup(); kdbnearsym_cleanup();
if (error == KDB_CMD_KGDB) { if (error == KDB_CMD_KGDB) {
......
...@@ -124,7 +124,7 @@ static kdbmsg_t kdbmsgs[] = { ...@@ -124,7 +124,7 @@ static kdbmsg_t kdbmsgs[] = {
}; };
#undef KDBMSG #undef KDBMSG
static const int __nkdb_err = sizeof(kdbmsgs) / sizeof(kdbmsg_t); static const int __nkdb_err = ARRAY_SIZE(kdbmsgs);
/* /*
...@@ -175,7 +175,7 @@ static char *__env[] = { ...@@ -175,7 +175,7 @@ static char *__env[] = {
(char *)0, (char *)0,
}; };
static const int __nenv = (sizeof(__env) / sizeof(char *)); static const int __nenv = ARRAY_SIZE(__env);
struct task_struct *kdb_curr_task(int cpu) struct task_struct *kdb_curr_task(int cpu)
{ {
...@@ -681,34 +681,50 @@ static int kdb_defcmd(int argc, const char **argv) ...@@ -681,34 +681,50 @@ static int kdb_defcmd(int argc, const char **argv)
} }
if (argc != 3) if (argc != 3)
return KDB_ARGCOUNT; return KDB_ARGCOUNT;
defcmd_set = kmalloc((defcmd_set_count + 1) * sizeof(*defcmd_set), if (in_dbg_master()) {
GFP_KDB); kdb_printf("Command only available during kdb_init()\n");
if (!defcmd_set) {
kdb_printf("Could not allocate new defcmd_set entry for %s\n",
argv[1]);
defcmd_set = save_defcmd_set;
return KDB_NOTIMP; 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, memcpy(defcmd_set, save_defcmd_set,
defcmd_set_count * sizeof(*defcmd_set)); defcmd_set_count * sizeof(*defcmd_set));
kfree(save_defcmd_set);
s = defcmd_set + defcmd_set_count; s = defcmd_set + defcmd_set_count;
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
s->usable = 1; s->usable = 1;
s->name = kdb_strdup(argv[1], GFP_KDB); s->name = kdb_strdup(argv[1], GFP_KDB);
if (!s->name)
goto fail_name;
s->usage = kdb_strdup(argv[2], GFP_KDB); s->usage = kdb_strdup(argv[2], GFP_KDB);
if (!s->usage)
goto fail_usage;
s->help = kdb_strdup(argv[3], GFP_KDB); s->help = kdb_strdup(argv[3], GFP_KDB);
if (!s->help)
goto fail_help;
if (s->usage[0] == '"') { if (s->usage[0] == '"') {
strcpy(s->usage, s->usage+1); strcpy(s->usage, argv[2]+1);
s->usage[strlen(s->usage)-1] = '\0'; s->usage[strlen(s->usage)-1] = '\0';
} }
if (s->help[0] == '"') { if (s->help[0] == '"') {
strcpy(s->help, s->help+1); strcpy(s->help, argv[3]+1);
s->help[strlen(s->help)-1] = '\0'; s->help[strlen(s->help)-1] = '\0';
} }
++defcmd_set_count; ++defcmd_set_count;
defcmd_in_progress = 1; defcmd_in_progress = 1;
kfree(save_defcmd_set);
return 0; 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;
} }
/* /*
...@@ -1112,7 +1128,6 @@ void kdb_set_current_task(struct task_struct *p) ...@@ -1112,7 +1128,6 @@ void kdb_set_current_task(struct task_struct *p)
* KDB_CMD_GO User typed 'go'. * KDB_CMD_GO User typed 'go'.
* KDB_CMD_CPU User switched to another cpu. * KDB_CMD_CPU User switched to another cpu.
* KDB_CMD_SS Single step. * KDB_CMD_SS Single step.
* KDB_CMD_SSB Single step until branch.
*/ */
static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs, static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
kdb_dbtrap_t db_result) kdb_dbtrap_t db_result)
...@@ -1151,14 +1166,6 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs, ...@@ -1151,14 +1166,6 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
kdb_printf("due to Debug @ " kdb_machreg_fmt "\n", kdb_printf("due to Debug @ " kdb_machreg_fmt "\n",
instruction_pointer(regs)); instruction_pointer(regs));
break; break;
case KDB_DB_SSB:
/*
* In the midst of ssb command. Just return.
*/
KDB_DEBUG_STATE("kdb_local 3", reason);
return KDB_CMD_SSB; /* Continue with SSB command */
break;
case KDB_DB_SS: case KDB_DB_SS:
break; break;
case KDB_DB_SSBPT: case KDB_DB_SSBPT:
...@@ -1281,7 +1288,6 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs, ...@@ -1281,7 +1288,6 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
if (diag == KDB_CMD_GO if (diag == KDB_CMD_GO
|| diag == KDB_CMD_CPU || diag == KDB_CMD_CPU
|| diag == KDB_CMD_SS || diag == KDB_CMD_SS
|| diag == KDB_CMD_SSB
|| diag == KDB_CMD_KGDB) || diag == KDB_CMD_KGDB)
break; break;
...@@ -1368,12 +1374,6 @@ int kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, ...@@ -1368,12 +1374,6 @@ int kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
break; break;
} }
if (result == KDB_CMD_SSB) {
KDB_STATE_SET(DOING_SS);
KDB_STATE_SET(DOING_SSB);
break;
}
if (result == KDB_CMD_KGDB) { if (result == KDB_CMD_KGDB) {
if (!KDB_STATE(DOING_KGDB)) if (!KDB_STATE(DOING_KGDB))
kdb_printf("Entering please attach debugger " kdb_printf("Entering please attach debugger "
...@@ -2350,69 +2350,6 @@ static int kdb_pid(int argc, const char **argv) ...@@ -2350,69 +2350,6 @@ static int kdb_pid(int argc, const char **argv)
return 0; return 0;
} }
/*
* kdb_ll - This function implements the 'll' command which follows a
* linked list and executes an arbitrary command for each
* element.
*/
static int kdb_ll(int argc, const char **argv)
{
int diag = 0;
unsigned long addr;
long offset = 0;
unsigned long va;
unsigned long linkoffset;
int nextarg;
const char *command;
if (argc != 3)
return KDB_ARGCOUNT;
nextarg = 1;
diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL);
if (diag)
return diag;
diag = kdbgetularg(argv[2], &linkoffset);
if (diag)
return diag;
/*
* Using the starting address as
* the first element in the list, and assuming that
* the list ends with a null pointer.
*/
va = addr;
command = kdb_strdup(argv[3], GFP_KDB);
if (!command) {
kdb_printf("%s: cannot duplicate command\n", __func__);
return 0;
}
/* Recursive use of kdb_parse, do not use argv after this point */
argv = NULL;
while (va) {
char buf[80];
if (KDB_FLAG(CMD_INTERRUPT))
goto out;
sprintf(buf, "%s " kdb_machreg_fmt "\n", command, va);
diag = kdb_parse(buf);
if (diag)
goto out;
addr = va + linkoffset;
if (kdb_getword(&va, addr, sizeof(va)))
goto out;
}
out:
kfree(command);
return diag;
}
static int kdb_kgdb(int argc, const char **argv) static int kdb_kgdb(int argc, const char **argv)
{ {
return KDB_CMD_KGDB; return KDB_CMD_KGDB;
...@@ -2430,11 +2367,15 @@ static int kdb_help(int argc, const char **argv) ...@@ -2430,11 +2367,15 @@ static int kdb_help(int argc, const char **argv)
kdb_printf("-----------------------------" kdb_printf("-----------------------------"
"-----------------------------\n"); "-----------------------------\n");
for_each_kdbcmd(kt, i) { for_each_kdbcmd(kt, i) {
if (kt->cmd_name) char *space = "";
kdb_printf("%-15.15s %-20.20s %s\n", kt->cmd_name,
kt->cmd_usage, kt->cmd_help);
if (KDB_FLAG(CMD_INTERRUPT)) if (KDB_FLAG(CMD_INTERRUPT))
return 0; return 0;
if (!kt->cmd_name)
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; return 0;
} }
...@@ -2739,7 +2680,7 @@ int kdb_register_repeat(char *cmd, ...@@ -2739,7 +2680,7 @@ int kdb_register_repeat(char *cmd,
(kdb_max_commands - KDB_BASE_CMD_MAX) * sizeof(*new)); (kdb_max_commands - KDB_BASE_CMD_MAX) * sizeof(*new));
kfree(kdb_commands); kfree(kdb_commands);
} }
memset(new + kdb_max_commands, 0, memset(new + kdb_max_commands - KDB_BASE_CMD_MAX, 0,
kdb_command_extend * sizeof(*new)); kdb_command_extend * sizeof(*new));
kdb_commands = new; kdb_commands = new;
kp = kdb_commands + kdb_max_commands - KDB_BASE_CMD_MAX; kp = kdb_commands + kdb_max_commands - KDB_BASE_CMD_MAX;
...@@ -2843,15 +2784,13 @@ static void __init kdb_inittab(void) ...@@ -2843,15 +2784,13 @@ static void __init kdb_inittab(void)
"Stack traceback", 1, KDB_REPEAT_NONE); "Stack traceback", 1, KDB_REPEAT_NONE);
kdb_register_repeat("btp", kdb_bt, "<pid>", kdb_register_repeat("btp", kdb_bt, "<pid>",
"Display stack for process <pid>", 0, KDB_REPEAT_NONE); "Display stack for process <pid>", 0, KDB_REPEAT_NONE);
kdb_register_repeat("bta", kdb_bt, "[DRSTCZEUIMA]", kdb_register_repeat("bta", kdb_bt, "[D|R|S|T|C|Z|E|U|I|M|A]",
"Display stack all processes", 0, KDB_REPEAT_NONE); "Backtrace all processes matching state flag", 0, KDB_REPEAT_NONE);
kdb_register_repeat("btc", kdb_bt, "", kdb_register_repeat("btc", kdb_bt, "",
"Backtrace current process on each cpu", 0, KDB_REPEAT_NONE); "Backtrace current process on each cpu", 0, KDB_REPEAT_NONE);
kdb_register_repeat("btt", kdb_bt, "<vaddr>", kdb_register_repeat("btt", kdb_bt, "<vaddr>",
"Backtrace process given its struct task address", 0, "Backtrace process given its struct task address", 0,
KDB_REPEAT_NONE); KDB_REPEAT_NONE);
kdb_register_repeat("ll", kdb_ll, "<first-element> <linkoffset> <cmd>",
"Execute cmd for each element in linked list", 0, KDB_REPEAT_NONE);
kdb_register_repeat("env", kdb_env, "", kdb_register_repeat("env", kdb_env, "",
"Show environment variables", 0, KDB_REPEAT_NONE); "Show environment variables", 0, KDB_REPEAT_NONE);
kdb_register_repeat("set", kdb_set, "", kdb_register_repeat("set", kdb_set, "",
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#define KDB_CMD_GO (-1001) #define KDB_CMD_GO (-1001)
#define KDB_CMD_CPU (-1002) #define KDB_CMD_CPU (-1002)
#define KDB_CMD_SS (-1003) #define KDB_CMD_SS (-1003)
#define KDB_CMD_SSB (-1004)
#define KDB_CMD_KGDB (-1005) #define KDB_CMD_KGDB (-1005)
/* Internal debug flags */ /* Internal debug flags */
...@@ -125,8 +124,6 @@ extern int kdb_state; ...@@ -125,8 +124,6 @@ extern int kdb_state;
* kdb control */ * kdb control */
#define KDB_STATE_HOLD_CPU 0x00000010 /* Hold this cpu inside kdb */ #define KDB_STATE_HOLD_CPU 0x00000010 /* Hold this cpu inside kdb */
#define KDB_STATE_DOING_SS 0x00000020 /* Doing ss command */ #define KDB_STATE_DOING_SS 0x00000020 /* Doing ss command */
#define KDB_STATE_DOING_SSB 0x00000040 /* Doing ssb command,
* DOING_SS is also set */
#define KDB_STATE_SSBPT 0x00000080 /* Install breakpoint #define KDB_STATE_SSBPT 0x00000080 /* Install breakpoint
* after one ss, independent of * after one ss, independent of
* DOING_SS */ * DOING_SS */
...@@ -191,7 +188,6 @@ extern void kdb_bp_remove(void); ...@@ -191,7 +188,6 @@ extern void kdb_bp_remove(void);
typedef enum { typedef enum {
KDB_DB_BPT, /* Breakpoint */ KDB_DB_BPT, /* Breakpoint */
KDB_DB_SS, /* Single-step trap */ KDB_DB_SS, /* Single-step trap */
KDB_DB_SSB, /* Single step to branch */
KDB_DB_SSBPT, /* Single step over breakpoint */ KDB_DB_SSBPT, /* Single step over breakpoint */
KDB_DB_NOBPT /* Spurious breakpoint */ KDB_DB_NOBPT /* Spurious breakpoint */
} kdb_dbtrap_t; } kdb_dbtrap_t;
......
...@@ -80,4 +80,22 @@ config KDB_KEYBOARD ...@@ -80,4 +80,22 @@ config KDB_KEYBOARD
help help
KDB can use a PS/2 type keyboard for an input device KDB can use a PS/2 type keyboard for an input device
config KDB_CONTINUE_CATASTROPHIC
int "KDB: continue after catastrophic errors"
depends on KGDB_KDB
default "0"
help
This integer controls the behaviour of kdb when the kernel gets a
catastrophic error, i.e. for a panic or oops.
When KDB is active and a catastrophic error occurs, nothing extra
will happen until you type 'go'.
CONFIG_KDB_CONTINUE_CATASTROPHIC == 0 (default). The first time
you type 'go', you will be warned by kdb. The secend time you type
'go', KDB tries to continue. No guarantees that the
kernel is still usable in this situation.
CONFIG_KDB_CONTINUE_CATASTROPHIC == 1. KDB tries to continue.
No guarantees that the kernel is still usable in this situation.
CONFIG_KDB_CONTINUE_CATASTROPHIC == 2. KDB forces a reboot.
If you are not sure, say 0.
endif # KGDB endif # KGDB
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment