mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 12:21:37 +00:00
KGDB/KDB fixes and cleanups
Cleanups kdb: Remove unused command flags, repeat flags and KDB_REPEAT_NONE Fixes kgdb/kdb: Allow access on a single core, if a CPU round up is deemed impossible, which will allow inspection of the now "trashed" kernel kdb: Add enable mask for the command groups kdb: access controls to restrict sensitive commands -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUrq8WAAoJEIciOldedpOj+C8P/AjSUVBZdBLWzCU2VG150sQ0 UacwFVLve9heoColHBF7VqIDCRkZokIKJmCbHUBPZTbs22auLRpNI+D6CY5lZD17 jEHxrkKY4ragRRc/W3Y1MSc3aeGnS0i5AR8PJermMWxyUBfN3FBxgFHzTaLB2ZTT 8A+tvmwiG4mHue52gSiYZPCl/52WWOh+NjDe7T9OZ+mNmQKwZ5ssQZmmyUkxrs3b LKXVXVtTUXxfEgB2x+lYTYAztcTsM5h+NbkT74FpSmwPjvU/p81Ptqveh+3JTdmX H+Jz/SqD1/NfxC1Eenh5Mc++p/UVxeRbBulV9jwqjOyJqDjw3qHs1cjm8tZZj1qG J3LODKi3GWhujMCfwdu5EJRnrFxgHCPiWInc2708oLbRi5SyOe6P6hNQ3K3Y4JtF VkYa62wSaI0fDNQUFRc3bXUOUdMOCXjuzw3BtTi93tcUNcQwCXuYCmWtVvBgmK1h LTrFCJmzbopiwpomxCwZ4BQm8id9HxP5pod95ypYb8K5aheXHCuSgibqj0nswWMm ix0YTd4UNTn79r6p4d0fXFjOOYpXZA80ojeVI27D9zW7dBYc5CGVA1IDNH0ZfiPo qySPUNUMXIjiTSOGZdUehByEC7tliLZczelRPnNh/9fmhJkJ745S7zs3DNQ7Ypg4 xDKthlRGNjn6cXOPl7gX =cf1c -----END PGP SIGNATURE----- Merge tag 'for_linus-3.19-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb Pull kgdb/kdb fixes from Jason Wessel: "These have been around since 3.17 and in kgdb-next for the last 9 weeks and some will go back to -stable. Summary of changes: Cleanups - kdb: Remove unused command flags, repeat flags and KDB_REPEAT_NONE Fixes - kgdb/kdb: Allow access on a single core, if a CPU round up is deemed impossible, which will allow inspection of the now "trashed" kernel - kdb: Add enable mask for the command groups - kdb: access controls to restrict sensitive commands" * tag 'for_linus-3.19-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb: kernel/debug/debug_core.c: Logging clean-up kgdb: timeout if secondary CPUs ignore the roundup kdb: Allow access to sensitive commands to be restricted by default kdb: Add enable mask for groups of commands kdb: Categorize kdb commands (similar to SysRq categorization) kdb: Remove KDB_REPEAT_NONE flag kdb: Use KDB_REPEAT_* values as flags kdb: Rename kdb_register_repeat() to kdb_register_flags() kdb: Rename kdb_repeat_t to kdb_cmdflags_t, cmd_repeat to cmd_flags kdb: Remove currently unused kdbtab_t->cmd_flags
This commit is contained in:
commit
aa9291355e
@ -13,11 +13,54 @@
|
||||
* Copyright (C) 2009 Jason Wessel <jason.wessel@windriver.com>
|
||||
*/
|
||||
|
||||
/* Shifted versions of the command enable bits are be used if the command
|
||||
* has no arguments (see kdb_check_flags). This allows commands, such as
|
||||
* go, to have different permissions depending upon whether it is called
|
||||
* with an argument.
|
||||
*/
|
||||
#define KDB_ENABLE_NO_ARGS_SHIFT 10
|
||||
|
||||
typedef enum {
|
||||
KDB_REPEAT_NONE = 0, /* Do not repeat this command */
|
||||
KDB_REPEAT_NO_ARGS, /* Repeat the command without arguments */
|
||||
KDB_REPEAT_WITH_ARGS, /* Repeat the command including its arguments */
|
||||
} kdb_repeat_t;
|
||||
KDB_ENABLE_ALL = (1 << 0), /* Enable everything */
|
||||
KDB_ENABLE_MEM_READ = (1 << 1),
|
||||
KDB_ENABLE_MEM_WRITE = (1 << 2),
|
||||
KDB_ENABLE_REG_READ = (1 << 3),
|
||||
KDB_ENABLE_REG_WRITE = (1 << 4),
|
||||
KDB_ENABLE_INSPECT = (1 << 5),
|
||||
KDB_ENABLE_FLOW_CTRL = (1 << 6),
|
||||
KDB_ENABLE_SIGNAL = (1 << 7),
|
||||
KDB_ENABLE_REBOOT = (1 << 8),
|
||||
/* User exposed values stop here, all remaining flags are
|
||||
* exclusively used to describe a commands behaviour.
|
||||
*/
|
||||
|
||||
KDB_ENABLE_ALWAYS_SAFE = (1 << 9),
|
||||
KDB_ENABLE_MASK = (1 << KDB_ENABLE_NO_ARGS_SHIFT) - 1,
|
||||
|
||||
KDB_ENABLE_ALL_NO_ARGS = KDB_ENABLE_ALL << KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
KDB_ENABLE_MEM_READ_NO_ARGS = KDB_ENABLE_MEM_READ
|
||||
<< KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
KDB_ENABLE_MEM_WRITE_NO_ARGS = KDB_ENABLE_MEM_WRITE
|
||||
<< KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
KDB_ENABLE_REG_READ_NO_ARGS = KDB_ENABLE_REG_READ
|
||||
<< KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
KDB_ENABLE_REG_WRITE_NO_ARGS = KDB_ENABLE_REG_WRITE
|
||||
<< KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
KDB_ENABLE_INSPECT_NO_ARGS = KDB_ENABLE_INSPECT
|
||||
<< KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
KDB_ENABLE_FLOW_CTRL_NO_ARGS = KDB_ENABLE_FLOW_CTRL
|
||||
<< KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
KDB_ENABLE_SIGNAL_NO_ARGS = KDB_ENABLE_SIGNAL
|
||||
<< KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
KDB_ENABLE_REBOOT_NO_ARGS = KDB_ENABLE_REBOOT
|
||||
<< KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
KDB_ENABLE_ALWAYS_SAFE_NO_ARGS = KDB_ENABLE_ALWAYS_SAFE
|
||||
<< KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
KDB_ENABLE_MASK_NO_ARGS = KDB_ENABLE_MASK << KDB_ENABLE_NO_ARGS_SHIFT,
|
||||
|
||||
KDB_REPEAT_NO_ARGS = 0x40000000, /* Repeat the command w/o arguments */
|
||||
KDB_REPEAT_WITH_ARGS = 0x80000000, /* Repeat the command with args */
|
||||
} kdb_cmdflags_t;
|
||||
|
||||
typedef int (*kdb_func_t)(int, const char **);
|
||||
|
||||
@ -62,6 +105,7 @@ extern atomic_t kdb_event;
|
||||
#define KDB_BADLENGTH (-19)
|
||||
#define KDB_NOBP (-20)
|
||||
#define KDB_BADADDR (-21)
|
||||
#define KDB_NOPERM (-22)
|
||||
|
||||
/*
|
||||
* kdb_diemsg
|
||||
@ -146,17 +190,17 @@ static inline const char *kdb_walk_kallsyms(loff_t *pos)
|
||||
|
||||
/* Dynamic kdb shell command registration */
|
||||
extern int kdb_register(char *, kdb_func_t, char *, char *, short);
|
||||
extern int kdb_register_repeat(char *, kdb_func_t, char *, char *,
|
||||
short, kdb_repeat_t);
|
||||
extern int kdb_register_flags(char *, kdb_func_t, char *, char *,
|
||||
short, kdb_cmdflags_t);
|
||||
extern int kdb_unregister(char *);
|
||||
#else /* ! CONFIG_KGDB_KDB */
|
||||
static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; }
|
||||
static inline void kdb_init(int level) {}
|
||||
static inline int kdb_register(char *cmd, kdb_func_t func, char *usage,
|
||||
char *help, short minlen) { return 0; }
|
||||
static inline int kdb_register_repeat(char *cmd, kdb_func_t func, char *usage,
|
||||
char *help, short minlen,
|
||||
kdb_repeat_t repeat) { return 0; }
|
||||
static inline int kdb_register_flags(char *cmd, kdb_func_t func, char *usage,
|
||||
char *help, short minlen,
|
||||
kdb_cmdflags_t flags) { return 0; }
|
||||
static inline int kdb_unregister(char *cmd) { return 0; }
|
||||
#endif /* CONFIG_KGDB_KDB */
|
||||
enum {
|
||||
|
@ -27,6 +27,9 @@
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "KGDB: " fmt
|
||||
|
||||
#include <linux/pid_namespace.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/serial_core.h>
|
||||
@ -196,8 +199,8 @@ int __weak kgdb_validate_break_address(unsigned long addr)
|
||||
return err;
|
||||
err = kgdb_arch_remove_breakpoint(&tmp);
|
||||
if (err)
|
||||
printk(KERN_ERR "KGDB: Critical breakpoint error, kernel "
|
||||
"memory destroyed at: %lx", addr);
|
||||
pr_err("Critical breakpoint error, kernel memory destroyed at: %lx\n",
|
||||
addr);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -256,8 +259,8 @@ int dbg_activate_sw_breakpoints(void)
|
||||
error = kgdb_arch_set_breakpoint(&kgdb_break[i]);
|
||||
if (error) {
|
||||
ret = error;
|
||||
printk(KERN_INFO "KGDB: BP install failed: %lx",
|
||||
kgdb_break[i].bpt_addr);
|
||||
pr_info("BP install failed: %lx\n",
|
||||
kgdb_break[i].bpt_addr);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -319,8 +322,8 @@ int dbg_deactivate_sw_breakpoints(void)
|
||||
continue;
|
||||
error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
|
||||
if (error) {
|
||||
printk(KERN_INFO "KGDB: BP remove failed: %lx\n",
|
||||
kgdb_break[i].bpt_addr);
|
||||
pr_info("BP remove failed: %lx\n",
|
||||
kgdb_break[i].bpt_addr);
|
||||
ret = error;
|
||||
}
|
||||
|
||||
@ -367,7 +370,7 @@ int dbg_remove_all_break(void)
|
||||
goto setundefined;
|
||||
error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
|
||||
if (error)
|
||||
printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n",
|
||||
pr_err("breakpoint remove failed: %lx\n",
|
||||
kgdb_break[i].bpt_addr);
|
||||
setundefined:
|
||||
kgdb_break[i].state = BP_UNDEFINED;
|
||||
@ -400,9 +403,9 @@ static int kgdb_io_ready(int print_wait)
|
||||
if (print_wait) {
|
||||
#ifdef CONFIG_KGDB_KDB
|
||||
if (!dbg_kdb_mode)
|
||||
printk(KERN_CRIT "KGDB: waiting... or $3#33 for KDB\n");
|
||||
pr_crit("waiting... or $3#33 for KDB\n");
|
||||
#else
|
||||
printk(KERN_CRIT "KGDB: Waiting for remote debugger\n");
|
||||
pr_crit("Waiting for remote debugger\n");
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
@ -430,8 +433,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks)
|
||||
exception_level = 0;
|
||||
kgdb_skipexception(ks->ex_vector, ks->linux_regs);
|
||||
dbg_activate_sw_breakpoints();
|
||||
printk(KERN_CRIT "KGDB: re-enter error: breakpoint removed %lx\n",
|
||||
addr);
|
||||
pr_crit("re-enter error: breakpoint removed %lx\n", addr);
|
||||
WARN_ON_ONCE(1);
|
||||
|
||||
return 1;
|
||||
@ -444,7 +446,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks)
|
||||
panic("Recursive entry to debugger");
|
||||
}
|
||||
|
||||
printk(KERN_CRIT "KGDB: re-enter exception: ALL breakpoints killed\n");
|
||||
pr_crit("re-enter exception: ALL breakpoints killed\n");
|
||||
#ifdef CONFIG_KGDB_KDB
|
||||
/* Allow kdb to debug itself one level */
|
||||
return 0;
|
||||
@ -471,6 +473,7 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
|
||||
int cpu;
|
||||
int trace_on = 0;
|
||||
int online_cpus = num_online_cpus();
|
||||
u64 time_left;
|
||||
|
||||
kgdb_info[ks->cpu].enter_kgdb++;
|
||||
kgdb_info[ks->cpu].exception_state |= exception_state;
|
||||
@ -595,9 +598,13 @@ return_normal:
|
||||
/*
|
||||
* Wait for the other CPUs to be notified and be waiting for us:
|
||||
*/
|
||||
while (kgdb_do_roundup && (atomic_read(&masters_in_kgdb) +
|
||||
atomic_read(&slaves_in_kgdb)) != online_cpus)
|
||||
time_left = loops_per_jiffy * HZ;
|
||||
while (kgdb_do_roundup && --time_left &&
|
||||
(atomic_read(&masters_in_kgdb) + atomic_read(&slaves_in_kgdb)) !=
|
||||
online_cpus)
|
||||
cpu_relax();
|
||||
if (!time_left)
|
||||
pr_crit("KGDB: Timed out waiting for secondary CPUs.\n");
|
||||
|
||||
/*
|
||||
* At this point the primary processor is completely
|
||||
@ -795,15 +802,15 @@ static struct console kgdbcons = {
|
||||
static void sysrq_handle_dbg(int key)
|
||||
{
|
||||
if (!dbg_io_ops) {
|
||||
printk(KERN_CRIT "ERROR: No KGDB I/O module available\n");
|
||||
pr_crit("ERROR: No KGDB I/O module available\n");
|
||||
return;
|
||||
}
|
||||
if (!kgdb_connected) {
|
||||
#ifdef CONFIG_KGDB_KDB
|
||||
if (!dbg_kdb_mode)
|
||||
printk(KERN_CRIT "KGDB or $3#33 for KDB\n");
|
||||
pr_crit("KGDB or $3#33 for KDB\n");
|
||||
#else
|
||||
printk(KERN_CRIT "Entering KGDB\n");
|
||||
pr_crit("Entering KGDB\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -945,7 +952,7 @@ static void kgdb_initial_breakpoint(void)
|
||||
{
|
||||
kgdb_break_asap = 0;
|
||||
|
||||
printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n");
|
||||
pr_crit("Waiting for connection from remote gdb...\n");
|
||||
kgdb_breakpoint();
|
||||
}
|
||||
|
||||
@ -964,8 +971,7 @@ int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops)
|
||||
if (dbg_io_ops) {
|
||||
spin_unlock(&kgdb_registration_lock);
|
||||
|
||||
printk(KERN_ERR "kgdb: Another I/O driver is already "
|
||||
"registered with KGDB.\n");
|
||||
pr_err("Another I/O driver is already registered with KGDB\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@ -981,8 +987,7 @@ int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops)
|
||||
|
||||
spin_unlock(&kgdb_registration_lock);
|
||||
|
||||
printk(KERN_INFO "kgdb: Registered I/O driver %s.\n",
|
||||
new_dbg_io_ops->name);
|
||||
pr_info("Registered I/O driver %s\n", new_dbg_io_ops->name);
|
||||
|
||||
/* Arm KGDB now. */
|
||||
kgdb_register_callbacks();
|
||||
@ -1017,8 +1022,7 @@ void kgdb_unregister_io_module(struct kgdb_io *old_dbg_io_ops)
|
||||
|
||||
spin_unlock(&kgdb_registration_lock);
|
||||
|
||||
printk(KERN_INFO
|
||||
"kgdb: Unregistered I/O driver %s, debugger disabled.\n",
|
||||
pr_info("Unregistered I/O driver %s, debugger disabled\n",
|
||||
old_dbg_io_ops->name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
|
||||
|
@ -531,22 +531,29 @@ void __init kdb_initbptab(void)
|
||||
for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++)
|
||||
bp->bp_free = 1;
|
||||
|
||||
kdb_register_repeat("bp", kdb_bp, "[<vaddr>]",
|
||||
"Set/Display breakpoints", 0, KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_repeat("bl", kdb_bp, "[<vaddr>]",
|
||||
"Display breakpoints", 0, KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_flags("bp", kdb_bp, "[<vaddr>]",
|
||||
"Set/Display breakpoints", 0,
|
||||
KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_flags("bl", kdb_bp, "[<vaddr>]",
|
||||
"Display breakpoints", 0,
|
||||
KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
|
||||
if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT)
|
||||
kdb_register_repeat("bph", kdb_bp, "[<vaddr>]",
|
||||
"[datar [length]|dataw [length]] Set hw brk", 0, KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_repeat("bc", kdb_bc, "<bpnum>",
|
||||
"Clear Breakpoint", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("be", kdb_bc, "<bpnum>",
|
||||
"Enable Breakpoint", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("bd", kdb_bc, "<bpnum>",
|
||||
"Disable Breakpoint", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_flags("bph", kdb_bp, "[<vaddr>]",
|
||||
"[datar [length]|dataw [length]] Set hw brk", 0,
|
||||
KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_flags("bc", kdb_bc, "<bpnum>",
|
||||
"Clear Breakpoint", 0,
|
||||
KDB_ENABLE_FLOW_CTRL);
|
||||
kdb_register_flags("be", kdb_bc, "<bpnum>",
|
||||
"Enable Breakpoint", 0,
|
||||
KDB_ENABLE_FLOW_CTRL);
|
||||
kdb_register_flags("bd", kdb_bc, "<bpnum>",
|
||||
"Disable Breakpoint", 0,
|
||||
KDB_ENABLE_FLOW_CTRL);
|
||||
|
||||
kdb_register_repeat("ss", kdb_ss, "",
|
||||
"Single Step", 1, KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_flags("ss", kdb_ss, "",
|
||||
"Single Step", 1,
|
||||
KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
|
||||
/*
|
||||
* Architecture dependent initialization.
|
||||
*/
|
||||
|
@ -129,6 +129,10 @@ int kdb_stub(struct kgdb_state *ks)
|
||||
ks->pass_exception = 1;
|
||||
KDB_FLAG_SET(CATASTROPHIC);
|
||||
}
|
||||
/* set CATASTROPHIC if the system contains unresponsive processors */
|
||||
for_each_online_cpu(i)
|
||||
if (!kgdb_info[i].enter_kgdb)
|
||||
KDB_FLAG_SET(CATASTROPHIC);
|
||||
if (KDB_STATE(SSBPT) && reason == KDB_REASON_SSTEP) {
|
||||
KDB_STATE_CLEAR(SSBPT);
|
||||
KDB_STATE_CLEAR(DOING_SS);
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kmsg_dump.h>
|
||||
@ -23,6 +24,7 @@
|
||||
#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>
|
||||
@ -42,6 +44,12 @@
|
||||
#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);
|
||||
|
||||
#define GREP_LEN 256
|
||||
char kdb_grep_string[GREP_LEN];
|
||||
int kdb_grepping_flag;
|
||||
@ -121,6 +129,7 @@ static kdbmsg_t kdbmsgs[] = {
|
||||
KDBMSG(BADLENGTH, "Invalid length field"),
|
||||
KDBMSG(NOBP, "No Breakpoint exists"),
|
||||
KDBMSG(BADADDR, "Invalid address"),
|
||||
KDBMSG(NOPERM, "Permission denied"),
|
||||
};
|
||||
#undef KDBMSG
|
||||
|
||||
@ -187,6 +196,26 @@ struct task_struct *kdb_curr_task(int cpu)
|
||||
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.
|
||||
@ -475,6 +504,15 @@ int kdbgetaddrarg(int argc, const char **argv, int *nextarg,
|
||||
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:
|
||||
*
|
||||
@ -641,8 +679,13 @@ static int kdb_defcmd2(const char *cmdstr, const char *argv0)
|
||||
if (!s->count)
|
||||
s->usable = 0;
|
||||
if (s->usable)
|
||||
kdb_register(s->name, kdb_exec_defcmd,
|
||||
s->usage, s->help, 0);
|
||||
/* 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)
|
||||
@ -1003,25 +1046,22 @@ int kdb_parse(const char *cmdstr)
|
||||
|
||||
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);
|
||||
switch (tp->cmd_repeat) {
|
||||
case KDB_REPEAT_NONE:
|
||||
argc = 0;
|
||||
if (argv[0])
|
||||
*(argv[0]) = '\0';
|
||||
break;
|
||||
case KDB_REPEAT_NO_ARGS:
|
||||
argc = 1;
|
||||
if (argv[1])
|
||||
*(argv[1]) = '\0';
|
||||
break;
|
||||
case KDB_REPEAT_WITH_ARGS:
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1921,10 +1961,14 @@ static int kdb_rm(int argc, const char **argv)
|
||||
*/
|
||||
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], false);
|
||||
__handle_sysrq(*argv[1], check_mask);
|
||||
kdb_trap_printk--;
|
||||
|
||||
return 0;
|
||||
@ -2157,6 +2201,8 @@ static void kdb_cpu_status(void)
|
||||
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')
|
||||
@ -2210,7 +2256,7 @@ static int kdb_cpu(int argc, const char **argv)
|
||||
/*
|
||||
* Validate cpunum
|
||||
*/
|
||||
if ((cpunum > NR_CPUS) || !cpu_online(cpunum))
|
||||
if ((cpunum > NR_CPUS) || !kgdb_info[cpunum].enter_kgdb)
|
||||
return KDB_BADCPUNUM;
|
||||
|
||||
dbg_switch_cpu = cpunum;
|
||||
@ -2375,6 +2421,8 @@ static int kdb_help(int argc, const char **argv)
|
||||
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,
|
||||
@ -2629,7 +2677,7 @@ static int kdb_grep_help(int argc, const char **argv)
|
||||
}
|
||||
|
||||
/*
|
||||
* kdb_register_repeat - This function is used to register a kernel
|
||||
* kdb_register_flags - This function is used to register a kernel
|
||||
* debugger command.
|
||||
* Inputs:
|
||||
* cmd Command name
|
||||
@ -2641,12 +2689,12 @@ static int kdb_grep_help(int argc, const char **argv)
|
||||
* zero for success, one if a duplicate command.
|
||||
*/
|
||||
#define kdb_command_extend 50 /* arbitrary */
|
||||
int kdb_register_repeat(char *cmd,
|
||||
kdb_func_t func,
|
||||
char *usage,
|
||||
char *help,
|
||||
short minlen,
|
||||
kdb_repeat_t repeat)
|
||||
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;
|
||||
@ -2694,19 +2742,18 @@ int kdb_register_repeat(char *cmd,
|
||||
kp->cmd_func = func;
|
||||
kp->cmd_usage = usage;
|
||||
kp->cmd_help = help;
|
||||
kp->cmd_flags = 0;
|
||||
kp->cmd_minlen = minlen;
|
||||
kp->cmd_repeat = repeat;
|
||||
kp->cmd_flags = flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kdb_register_repeat);
|
||||
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_repeat with KDB_REPEAT_NONE.
|
||||
* kdb_register_flags with flags set to 0.
|
||||
* Inputs:
|
||||
* cmd Command name
|
||||
* func Function to execute the command
|
||||
@ -2721,8 +2768,7 @@ int kdb_register(char *cmd,
|
||||
char *help,
|
||||
short minlen)
|
||||
{
|
||||
return kdb_register_repeat(cmd, func, usage, help, minlen,
|
||||
KDB_REPEAT_NONE);
|
||||
return kdb_register_flags(cmd, func, usage, help, minlen, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kdb_register);
|
||||
|
||||
@ -2764,80 +2810,109 @@ static void __init kdb_inittab(void)
|
||||
for_each_kdbcmd(kp, i)
|
||||
kp->cmd_name = NULL;
|
||||
|
||||
kdb_register_repeat("md", kdb_md, "<vaddr>",
|
||||
kdb_register_flags("md", kdb_md, "<vaddr>",
|
||||
"Display Memory Contents, also mdWcN, e.g. md8c1", 1,
|
||||
KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_repeat("mdr", kdb_md, "<vaddr> <bytes>",
|
||||
"Display Raw Memory", 0, KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_repeat("mdp", kdb_md, "<paddr> <bytes>",
|
||||
"Display Physical Memory", 0, KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_repeat("mds", kdb_md, "<vaddr>",
|
||||
"Display Memory Symbolically", 0, KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_repeat("mm", kdb_mm, "<vaddr> <contents>",
|
||||
"Modify Memory Contents", 0, KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_repeat("go", kdb_go, "[<vaddr>]",
|
||||
"Continue Execution", 1, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("rd", kdb_rd, "",
|
||||
"Display Registers", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("rm", kdb_rm, "<reg> <contents>",
|
||||
"Modify Registers", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("ef", kdb_ef, "<vaddr>",
|
||||
"Display exception frame", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("bt", kdb_bt, "[<vaddr>]",
|
||||
"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, "[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>",
|
||||
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_REPEAT_NONE);
|
||||
kdb_register_repeat("env", kdb_env, "",
|
||||
"Show environment variables", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("set", kdb_set, "",
|
||||
"Set environment variables", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("help", kdb_help, "",
|
||||
"Display Help Message", 1, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("?", kdb_help, "",
|
||||
"Display Help Message", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("cpu", kdb_cpu, "<cpunum>",
|
||||
"Switch to new cpu", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("kgdb", kdb_kgdb, "",
|
||||
"Enter kgdb mode", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("ps", kdb_ps, "[<flags>|A]",
|
||||
"Display active task list", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("pid", kdb_pid, "<pidnum>",
|
||||
"Switch to another task", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("reboot", kdb_reboot, "",
|
||||
"Reboot the machine immediately", 0, KDB_REPEAT_NONE);
|
||||
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_repeat("lsmod", kdb_lsmod, "",
|
||||
"List loaded kernel modules", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_flags("lsmod", kdb_lsmod, "",
|
||||
"List loaded kernel modules", 0,
|
||||
KDB_ENABLE_INSPECT);
|
||||
#endif
|
||||
#if defined(CONFIG_MAGIC_SYSRQ)
|
||||
kdb_register_repeat("sr", kdb_sr, "<key>",
|
||||
"Magic SysRq key", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_flags("sr", kdb_sr, "<key>",
|
||||
"Magic SysRq key", 0,
|
||||
KDB_ENABLE_ALWAYS_SAFE);
|
||||
#endif
|
||||
#if defined(CONFIG_PRINTK)
|
||||
kdb_register_repeat("dmesg", kdb_dmesg, "[lines]",
|
||||
"Display syslog buffer", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_flags("dmesg", kdb_dmesg, "[lines]",
|
||||
"Display syslog buffer", 0,
|
||||
KDB_ENABLE_ALWAYS_SAFE);
|
||||
#endif
|
||||
if (arch_kgdb_ops.enable_nmi) {
|
||||
kdb_register_repeat("disable_nmi", kdb_disable_nmi, "",
|
||||
"Disable NMI entry to KDB", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_flags("disable_nmi", kdb_disable_nmi, "",
|
||||
"Disable NMI entry to KDB", 0,
|
||||
KDB_ENABLE_ALWAYS_SAFE);
|
||||
}
|
||||
kdb_register_repeat("defcmd", kdb_defcmd, "name \"usage\" \"help\"",
|
||||
"Define a set of commands, down to endefcmd", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("kill", kdb_kill, "<-signal> <pid>",
|
||||
"Send a signal to a process", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("summary", kdb_summary, "",
|
||||
"Summarize the system", 4, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("per_cpu", kdb_per_cpu, "<sym> [<bytes>] [<cpu>]",
|
||||
"Display per_cpu variables", 3, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("grephelp", kdb_grep_help, "",
|
||||
"Display help on | grep", 0, KDB_REPEAT_NONE);
|
||||
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. */
|
||||
|
@ -172,10 +172,9 @@ typedef struct _kdbtab {
|
||||
kdb_func_t cmd_func; /* Function to execute command */
|
||||
char *cmd_usage; /* Usage String for this command */
|
||||
char *cmd_help; /* Help message for this command */
|
||||
short cmd_flags; /* Parsing flags */
|
||||
short cmd_minlen; /* Minimum legal # command
|
||||
* chars required */
|
||||
kdb_repeat_t cmd_repeat; /* Does command auto repeat on enter? */
|
||||
kdb_cmdflags_t cmd_flags; /* Command behaviour flags */
|
||||
} kdbtab_t;
|
||||
|
||||
extern int kdb_bt(int, const char **); /* KDB display back trace */
|
||||
|
@ -132,8 +132,8 @@ static int kdb_ftdump(int argc, const char **argv)
|
||||
|
||||
static __init int kdb_ftrace_register(void)
|
||||
{
|
||||
kdb_register_repeat("ftdump", kdb_ftdump, "[skip_#lines] [cpu]",
|
||||
"Dump ftrace log", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_flags("ftdump", kdb_ftdump, "[skip_#lines] [cpu]",
|
||||
"Dump ftrace log", 0, KDB_ENABLE_ALWAYS_SAFE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,31 @@ config KGDB_KDB
|
||||
help
|
||||
KDB frontend for kernel
|
||||
|
||||
config KDB_DEFAULT_ENABLE
|
||||
hex "KDB: Select kdb command functions to be enabled by default"
|
||||
depends on KGDB_KDB
|
||||
default 0x1
|
||||
help
|
||||
Specifiers which kdb commands are enabled by default. This may
|
||||
be set to 1 or 0 to enable all commands or disable almost all
|
||||
commands.
|
||||
|
||||
Alternatively the following bitmask applies:
|
||||
|
||||
0x0002 - allow arbitrary reads from memory and symbol lookup
|
||||
0x0004 - allow arbitrary writes to memory
|
||||
0x0008 - allow current register state to be inspected
|
||||
0x0010 - allow current register state to be modified
|
||||
0x0020 - allow passive inspection (backtrace, process list, lsmod)
|
||||
0x0040 - allow flow control management (breakpoint, single step)
|
||||
0x0080 - enable signalling of processes
|
||||
0x0100 - allow machine to be rebooted
|
||||
|
||||
The config option merely sets the default at boot time. Both
|
||||
issuing 'echo X > /sys/module/kdb/parameters/cmd_enable' or
|
||||
setting with kdb.cmd_enable=X kernel command line option will
|
||||
override the default settings.
|
||||
|
||||
config KDB_KEYBOARD
|
||||
bool "KGDB_KDB: keyboard as input device"
|
||||
depends on VT && KGDB_KDB
|
||||
|
Loading…
Reference in New Issue
Block a user