2811 lines · 66.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Kernel Debugger Architecture Independent Main Code * * 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/sched/loadavg.h>#include <linux/sched/stat.h>#include <linux/sched/debug.h>#include <linux/sysrq.h>#include <linux/smp.h>#include <linux/utsname.h>#include <linux/vmalloc.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 <linux/security.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 */unsigned int kdb_flags; /* * 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;struct pt_regs *kdb_current_regs; const char *kdb_diemsg;static int kdb_go_count;#ifdef CONFIG_KDB_CONTINUE_CATASTROPHICstatic unsigned int kdb_continue_catastrophic =	CONFIG_KDB_CONTINUE_CATASTROPHIC;#elsestatic unsigned int kdb_continue_catastrophic;#endif /* kdb_cmds_head describes the available commands. */static LIST_HEAD(kdb_cmds_head); 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(KMALLOCFAILED, "Failed to allocate memory"),	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. * The entire environment is limited to a fixed number of entries * (add more to __env[] if required) */ static char *__env[31] = {#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",}; static const int __nenv = ARRAY_SIZE(__env); /* * Update the permissions flags (kdb_cmd_enabled) to match the * current lockdown state. * * Within this function the calls to security_locked_down() are "lazy". We * avoid calling them if the current value of kdb_cmd_enabled already excludes * flags that might be subject to lockdown. Additionally we deliberately check * the lockdown flags independently (even though read lockdown implies write * lockdown) since that results in both simpler code and clearer messages to * the user on first-time debugger entry. * * The permission masks during a read+write lockdown permits the following * flags: INSPECT, SIGNAL, REBOOT (and ALWAYS_SAFE). * * The INSPECT commands are not blocked during lockdown because they are * not arbitrary memory reads. INSPECT covers the backtrace family (sometimes * forcing them to have no arguments) and lsmod. These commands do expose * some kernel state but do not allow the developer seated at the console to * choose what state is reported. SIGNAL and REBOOT should not be controversial, * given these are allowed for root during lockdown already. */static void kdb_check_for_lockdown(void){	const int write_flags = KDB_ENABLE_MEM_WRITE |				KDB_ENABLE_REG_WRITE |				KDB_ENABLE_FLOW_CTRL;	const int read_flags = KDB_ENABLE_MEM_READ |			       KDB_ENABLE_REG_READ; 	bool need_to_lockdown_write = false;	bool need_to_lockdown_read = false; 	if (kdb_cmd_enabled & (KDB_ENABLE_ALL | write_flags))		need_to_lockdown_write =			security_locked_down(LOCKDOWN_DBG_WRITE_KERNEL); 	if (kdb_cmd_enabled & (KDB_ENABLE_ALL | read_flags))		need_to_lockdown_read =			security_locked_down(LOCKDOWN_DBG_READ_KERNEL); 	/* De-compose KDB_ENABLE_ALL if required */	if (need_to_lockdown_write || need_to_lockdown_read)		if (kdb_cmd_enabled & KDB_ENABLE_ALL)			kdb_cmd_enabled = KDB_ENABLE_MASK & ~KDB_ENABLE_ALL; 	if (need_to_lockdown_write)		kdb_cmd_enabled &= ~write_flags; 	if (need_to_lockdown_read)		kdb_cmd_enabled &= ~read_flags;} /* * Check whether the flags of the current command, the permissions of the kdb * console and the lockdown state allow a command to be run. */static 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;} /* * 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 representation 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;	if (kstrtoul(ep, 0, value))		return KDB_BADINT; 	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;} /* * kdb_setenv() - Alter an existing environment variable or create a new one. * @var: Name of the variable * @val: Value of the variable * * Return: Zero on success, a kdb diagnostic on failure. */static int kdb_setenv(const char *var, const char *val){	int i;	char *ep;	size_t varlen, vallen; 	varlen = strlen(var);	vallen = strlen(val);	ep = kmalloc(varlen + vallen + 2, GFP_KDB);	if (!ep)		return KDB_KMALLOCFAILED; 	sprintf(ep, "%s=%s", var, val); 	for (i = 0; i < __nenv; i++) {		if (__env[i]		 && ((strncmp(__env[i], var, varlen) == 0)		   && ((__env[i][varlen] == '\0')		    || (__env[i][varlen] == '=')))) {			kfree_const(__env[i]);			__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;} /* * kdb_printenv() - Display the current environment variables. */static void kdb_printenv(void){	int i; 	for (i = 0; i < __nenv; i++) {		if (__env[i])			kdb_printf("%s\n", __env[i]);	}} /* * 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 representation of arg. * Returns: *	Zero on success, a kdb diagnostic on failure. */int kdbgetularg(const char *arg, unsigned long *value){	if (kstrtoul(arg, 0, value))		return KDB_BADINT;	return 0;} int kdbgetu64arg(const char *arg, u64 *value){	if (kstrtou64(arg, 0, value))		return KDB_BADINT;	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){	/*	 * 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; 	/*	 * Censor sensitive variables	 */	if (strcmp(argv[1], "PROMPT") == 0 &&	    !kdb_check_flags(KDB_ENABLE_MEM_READ, kdb_cmd_enabled, false))		return KDB_NOPERM; 	/*	 * Check for internal variables	 */	if (strcmp(argv[1], "KDBDEBUG") == 0) {		unsigned int debugflags;		int ret; 		ret = kstrtouint(argv[2], 0, &debugflags);		if (ret || debugflags & ~KDB_DEBUG_FLAG_MASK) {			kdb_printf("kdb: illegal debug flags '%s'\n",				    argv[2]);			return 0;		}		kdb_flags = (kdb_flags & ~KDB_DEBUG(MASK))			| (debugflags << KDB_DEBUG_FLAG_SHIFT); 		return 0;	} 	/*	 * Tokenizer squashed the '=' sign.  argv[1] is variable	 * name, argv[2] = value.	 */	return kdb_setenv(argv[1], argv[2]);} 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 *	hexadecimal), 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)

Lines 1–500 of 2811.