KGDB/KDB fixes and cleanups
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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJRMhJPAAoJEIciOldedpOj25gP+wZn/u3YxOGkhL3CIBOegEwW KFte7FFNeLNzw8tyEzBMVXok85PJ+/lvm+Xi+a4hhtV7/S+WvwGoWeIg0zCDtrAu im4m2X1u00Egcztcr4tCk8Lwc6vNm5KZsBsUsbKKi0K8twaWifkxLMEWeq+3WLzh +1d4TDkziwdZfcLpUHvohmCsCyg1EdjUxTYnWpSJvLrq5lhNvTQBowHWZH06GBcI MmhC+aHp3myk2/Vwd1AuDq+jIRbH3ORV50wfRONBR7OJ58sOoD9nV8Mr+fy8QLRN BPv8WxeRSm7X/Hl6nPm9PX7oNQSg+Ba1+5helIIJMdGGWhJbl9AZslFEU40Zn3yS V7FmS3mwRSA8NCgfZ+CO6311tirSCvtf34+5ttXEntyK1ujaplSPffBP4Ya26y6q TB2wLr91+3L0LhzrVRj20P13qexsWUW4t9inLzqtDApD3Zljl9Kuwd0febCiLg0r mgGkpZjK0VI7S7RfkxpmEyU4bFP2lCTzBOKAKOfIV6O88bfqFdv5QCTHODJArf22 ugDGPX3tw++Lyc9otGxyPbxmc7npYGqTD1UEM8xK/7sEBiWJm71jjwHN1bwRwB3o EC5bcZ6TJgDJnnvYGBTQec74PnUiCu/UnQVFFabzhowQCJTIWSJkPxjnI2BKK1V5 3exPqogclusAhhwopOtG =Hwbq -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
3cfb07743a
|
@ -103,6 +103,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
#define v1printk(a...) do { \
|
||||
if (verbose) \
|
||||
|
@ -222,6 +223,7 @@ static unsigned long lookup_addr(char *arg)
|
|||
addr = (unsigned long)do_fork;
|
||||
else if (!strcmp(arg, "hw_break_val"))
|
||||
addr = (unsigned long)&hw_break_val;
|
||||
addr = (unsigned long) dereference_function_descriptor((void *)addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,8 @@ extern int dbg_kdb_mode;
|
|||
#ifdef CONFIG_KGDB_KDB
|
||||
extern int kdb_stub(struct kgdb_state *ks);
|
||||
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 */
|
||||
static inline int kdb_stub(struct kgdb_state *ks)
|
||||
{
|
||||
|
|
|
@ -783,7 +783,10 @@ static void gdb_cmd_query(struct kgdb_state *ks)
|
|||
len = len / 2;
|
||||
remcom_out_buffer[len++] = 0;
|
||||
|
||||
kdb_common_init_state(ks);
|
||||
kdb_parse(remcom_out_buffer);
|
||||
kdb_common_deinit_state();
|
||||
|
||||
strcpy(remcom_out_buffer, "OK");
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -486,11 +486,9 @@ static int kdb_bc(int argc, const char **argv)
|
|||
/*
|
||||
* kdb_ss
|
||||
*
|
||||
* Process the 'ss' (Single Step) and 'ssb' (Single Step to Branch)
|
||||
* commands.
|
||||
* Process the 'ss' (Single Step) command.
|
||||
*
|
||||
* ss
|
||||
* ssb
|
||||
*
|
||||
* Parameters:
|
||||
* argc Argument count
|
||||
|
@ -498,35 +496,23 @@ static int kdb_bc(int argc, const char **argv)
|
|||
* Outputs:
|
||||
* None.
|
||||
* Returns:
|
||||
* KDB_CMD_SS[B] for success, a kdb error if failure.
|
||||
* KDB_CMD_SS for success, a kdb error if failure.
|
||||
* Locking:
|
||||
* None.
|
||||
* Remarks:
|
||||
*
|
||||
* Set the arch specific option to trigger a debug trap after the next
|
||||
* 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)
|
||||
{
|
||||
int ssb = 0;
|
||||
|
||||
ssb = (strcmp(argv[0], "ssb") == 0);
|
||||
if (argc != 0)
|
||||
return KDB_ARGCOUNT;
|
||||
/*
|
||||
* Set trace flag and go.
|
||||
*/
|
||||
KDB_STATE_SET(DOING_SS);
|
||||
if (ssb) {
|
||||
KDB_STATE_SET(DOING_SSB);
|
||||
return KDB_CMD_SSB;
|
||||
}
|
||||
return KDB_CMD_SS;
|
||||
}
|
||||
|
||||
|
@ -561,8 +547,6 @@ void __init kdb_initbptab(void)
|
|||
|
||||
kdb_register_repeat("ss", kdb_ss, "",
|
||||
"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.
|
||||
*/
|
||||
|
|
|
@ -34,6 +34,22 @@ EXPORT_SYMBOL_GPL(kdb_poll_idx);
|
|||
|
||||
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 error = 0;
|
||||
|
@ -94,13 +110,10 @@ int kdb_stub(struct kgdb_state *ks)
|
|||
}
|
||||
/* Set initial kdb state variables */
|
||||
KDB_STATE_CLEAR(KGDB_TRANS);
|
||||
kdb_initial_cpu = atomic_read(&kgdb_active);
|
||||
kdb_current_task = kgdb_info[ks->cpu].task;
|
||||
kdb_current_regs = kgdb_info[ks->cpu].debuggerinfo;
|
||||
kdb_common_init_state(ks);
|
||||
/* Remove any breakpoints as needed by kdb and clear single step */
|
||||
kdb_bp_remove();
|
||||
KDB_STATE_CLEAR(DOING_SS);
|
||||
KDB_STATE_CLEAR(DOING_SSB);
|
||||
KDB_STATE_SET(PAGER);
|
||||
/* zero out any offline cpu data */
|
||||
for_each_present_cpu(i) {
|
||||
|
@ -125,9 +138,7 @@ int kdb_stub(struct kgdb_state *ks)
|
|||
* Upon exit from the kdb main loop setup break points and restart
|
||||
* the system based on the requested continue state
|
||||
*/
|
||||
kdb_initial_cpu = -1;
|
||||
kdb_current_task = NULL;
|
||||
kdb_current_regs = NULL;
|
||||
kdb_common_deinit_state();
|
||||
KDB_STATE_CLEAR(PAGER);
|
||||
kdbnearsym_cleanup();
|
||||
if (error == KDB_CMD_KGDB) {
|
||||
|
|
|
@ -124,7 +124,7 @@ static kdbmsg_t kdbmsgs[] = {
|
|||
};
|
||||
#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[] = {
|
|||
(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)
|
||||
{
|
||||
|
@ -681,34 +681,50 @@ static int kdb_defcmd(int argc, const char **argv)
|
|||
}
|
||||
if (argc != 3)
|
||||
return KDB_ARGCOUNT;
|
||||
defcmd_set = kmalloc((defcmd_set_count + 1) * sizeof(*defcmd_set),
|
||||
GFP_KDB);
|
||||
if (!defcmd_set) {
|
||||
kdb_printf("Could not allocate new defcmd_set entry for %s\n",
|
||||
argv[1]);
|
||||
defcmd_set = save_defcmd_set;
|
||||
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));
|
||||
kfree(save_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, s->usage+1);
|
||||
strcpy(s->usage, argv[2]+1);
|
||||
s->usage[strlen(s->usage)-1] = '\0';
|
||||
}
|
||||
if (s->help[0] == '"') {
|
||||
strcpy(s->help, s->help+1);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1112,7 +1128,6 @@ void kdb_set_current_task(struct task_struct *p)
|
|||
* KDB_CMD_GO User typed 'go'.
|
||||
* KDB_CMD_CPU User switched to another cpu.
|
||||
* 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,
|
||||
kdb_dbtrap_t db_result)
|
||||
|
@ -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",
|
||||
instruction_pointer(regs));
|
||||
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:
|
||||
break;
|
||||
case KDB_DB_SSBPT:
|
||||
|
@ -1281,7 +1288,6 @@ do_full_getstr:
|
|||
if (diag == KDB_CMD_GO
|
||||
|| diag == KDB_CMD_CPU
|
||||
|| diag == KDB_CMD_SS
|
||||
|| diag == KDB_CMD_SSB
|
||||
|| diag == KDB_CMD_KGDB)
|
||||
break;
|
||||
|
||||
|
@ -1368,12 +1374,6 @@ int kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
|
|||
break;
|
||||
}
|
||||
|
||||
if (result == KDB_CMD_SSB) {
|
||||
KDB_STATE_SET(DOING_SS);
|
||||
KDB_STATE_SET(DOING_SSB);
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == KDB_CMD_KGDB) {
|
||||
if (!KDB_STATE(DOING_KGDB))
|
||||
kdb_printf("Entering please attach debugger "
|
||||
|
@ -2350,69 +2350,6 @@ static int kdb_pid(int argc, const char **argv)
|
|||
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)
|
||||
{
|
||||
return KDB_CMD_KGDB;
|
||||
|
@ -2430,11 +2367,15 @@ static int kdb_help(int argc, const char **argv)
|
|||
kdb_printf("-----------------------------"
|
||||
"-----------------------------\n");
|
||||
for_each_kdbcmd(kt, i) {
|
||||
if (kt->cmd_name)
|
||||
kdb_printf("%-15.15s %-20.20s %s\n", kt->cmd_name,
|
||||
kt->cmd_usage, kt->cmd_help);
|
||||
char *space = "";
|
||||
if (KDB_FLAG(CMD_INTERRUPT))
|
||||
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;
|
||||
}
|
||||
|
@ -2739,7 +2680,7 @@ int kdb_register_repeat(char *cmd,
|
|||
(kdb_max_commands - KDB_BASE_CMD_MAX) * sizeof(*new));
|
||||
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_commands = new;
|
||||
kp = kdb_commands + kdb_max_commands - KDB_BASE_CMD_MAX;
|
||||
|
@ -2843,15 +2784,13 @@ static void __init kdb_inittab(void)
|
|||
"Stack traceback", 1, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("btp", kdb_bt, "<pid>",
|
||||
"Display stack for process <pid>", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("bta", kdb_bt, "[DRSTCZEUIMA]",
|
||||
"Display stack all processes", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("bta", kdb_bt, "[D|R|S|T|C|Z|E|U|I|M|A]",
|
||||
"Backtrace all processes matching state flag", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("btc", kdb_bt, "",
|
||||
"Backtrace current process on each cpu", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("btt", kdb_bt, "<vaddr>",
|
||||
"Backtrace process given its struct task address", 0,
|
||||
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, "",
|
||||
"Show environment variables", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("set", kdb_set, "",
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#define KDB_CMD_GO (-1001)
|
||||
#define KDB_CMD_CPU (-1002)
|
||||
#define KDB_CMD_SS (-1003)
|
||||
#define KDB_CMD_SSB (-1004)
|
||||
#define KDB_CMD_KGDB (-1005)
|
||||
|
||||
/* Internal debug flags */
|
||||
|
@ -125,8 +124,6 @@ extern int kdb_state;
|
|||
* kdb control */
|
||||
#define KDB_STATE_HOLD_CPU 0x00000010 /* Hold this cpu inside kdb */
|
||||
#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
|
||||
* after one ss, independent of
|
||||
* DOING_SS */
|
||||
|
@ -191,7 +188,6 @@ extern void kdb_bp_remove(void);
|
|||
typedef enum {
|
||||
KDB_DB_BPT, /* Breakpoint */
|
||||
KDB_DB_SS, /* Single-step trap */
|
||||
KDB_DB_SSB, /* Single step to branch */
|
||||
KDB_DB_SSBPT, /* Single step over breakpoint */
|
||||
KDB_DB_NOBPT /* Spurious breakpoint */
|
||||
} kdb_dbtrap_t;
|
||||
|
|
|
@ -80,4 +80,22 @@ config KDB_KEYBOARD
|
|||
help
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue