@ -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_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 ( " 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. */