162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Kernel Debugger Architecture Independent Main Code
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
562306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
662306a36Sopenharmony_ci * for more details.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 1999-2004 Silicon Graphics, Inc.  All Rights Reserved.
962306a36Sopenharmony_ci * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
1062306a36Sopenharmony_ci * Xscale (R) modifications copyright (C) 2003 Intel Corporation.
1162306a36Sopenharmony_ci * Copyright (c) 2009 Wind River Systems, Inc.  All Rights Reserved.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/ctype.h>
1562306a36Sopenharmony_ci#include <linux/types.h>
1662306a36Sopenharmony_ci#include <linux/string.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/kmsg_dump.h>
1962306a36Sopenharmony_ci#include <linux/reboot.h>
2062306a36Sopenharmony_ci#include <linux/sched.h>
2162306a36Sopenharmony_ci#include <linux/sched/loadavg.h>
2262306a36Sopenharmony_ci#include <linux/sched/stat.h>
2362306a36Sopenharmony_ci#include <linux/sched/debug.h>
2462306a36Sopenharmony_ci#include <linux/sysrq.h>
2562306a36Sopenharmony_ci#include <linux/smp.h>
2662306a36Sopenharmony_ci#include <linux/utsname.h>
2762306a36Sopenharmony_ci#include <linux/vmalloc.h>
2862306a36Sopenharmony_ci#include <linux/atomic.h>
2962306a36Sopenharmony_ci#include <linux/moduleparam.h>
3062306a36Sopenharmony_ci#include <linux/mm.h>
3162306a36Sopenharmony_ci#include <linux/init.h>
3262306a36Sopenharmony_ci#include <linux/kallsyms.h>
3362306a36Sopenharmony_ci#include <linux/kgdb.h>
3462306a36Sopenharmony_ci#include <linux/kdb.h>
3562306a36Sopenharmony_ci#include <linux/notifier.h>
3662306a36Sopenharmony_ci#include <linux/interrupt.h>
3762306a36Sopenharmony_ci#include <linux/delay.h>
3862306a36Sopenharmony_ci#include <linux/nmi.h>
3962306a36Sopenharmony_ci#include <linux/time.h>
4062306a36Sopenharmony_ci#include <linux/ptrace.h>
4162306a36Sopenharmony_ci#include <linux/sysctl.h>
4262306a36Sopenharmony_ci#include <linux/cpu.h>
4362306a36Sopenharmony_ci#include <linux/kdebug.h>
4462306a36Sopenharmony_ci#include <linux/proc_fs.h>
4562306a36Sopenharmony_ci#include <linux/uaccess.h>
4662306a36Sopenharmony_ci#include <linux/slab.h>
4762306a36Sopenharmony_ci#include <linux/security.h>
4862306a36Sopenharmony_ci#include "kdb_private.h"
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#undef	MODULE_PARAM_PREFIX
5162306a36Sopenharmony_ci#define	MODULE_PARAM_PREFIX "kdb."
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int kdb_cmd_enabled = CONFIG_KDB_DEFAULT_ENABLE;
5462306a36Sopenharmony_cimodule_param_named(cmd_enable, kdb_cmd_enabled, int, 0600);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cichar kdb_grep_string[KDB_GREP_STRLEN];
5762306a36Sopenharmony_ciint kdb_grepping_flag;
5862306a36Sopenharmony_ciEXPORT_SYMBOL(kdb_grepping_flag);
5962306a36Sopenharmony_ciint kdb_grep_leading;
6062306a36Sopenharmony_ciint kdb_grep_trailing;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * Kernel debugger state flags
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ciunsigned int kdb_flags;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/*
6862306a36Sopenharmony_ci * kdb_lock protects updates to kdb_initial_cpu.  Used to
6962306a36Sopenharmony_ci * single thread processors through the kernel debugger.
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_ciint kdb_initial_cpu = -1;	/* cpu number that owns kdb */
7262306a36Sopenharmony_ciint kdb_nextline = 1;
7362306a36Sopenharmony_ciint kdb_state;			/* General KDB state */
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistruct task_struct *kdb_current_task;
7662306a36Sopenharmony_cistruct pt_regs *kdb_current_regs;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciconst char *kdb_diemsg;
7962306a36Sopenharmony_cistatic int kdb_go_count;
8062306a36Sopenharmony_ci#ifdef CONFIG_KDB_CONTINUE_CATASTROPHIC
8162306a36Sopenharmony_cistatic unsigned int kdb_continue_catastrophic =
8262306a36Sopenharmony_ci	CONFIG_KDB_CONTINUE_CATASTROPHIC;
8362306a36Sopenharmony_ci#else
8462306a36Sopenharmony_cistatic unsigned int kdb_continue_catastrophic;
8562306a36Sopenharmony_ci#endif
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* kdb_cmds_head describes the available commands. */
8862306a36Sopenharmony_cistatic LIST_HEAD(kdb_cmds_head);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_citypedef struct _kdbmsg {
9162306a36Sopenharmony_ci	int	km_diag;	/* kdb diagnostic */
9262306a36Sopenharmony_ci	char	*km_msg;	/* Corresponding message text */
9362306a36Sopenharmony_ci} kdbmsg_t;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define KDBMSG(msgnum, text) \
9662306a36Sopenharmony_ci	{ KDB_##msgnum, text }
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic kdbmsg_t kdbmsgs[] = {
9962306a36Sopenharmony_ci	KDBMSG(NOTFOUND, "Command Not Found"),
10062306a36Sopenharmony_ci	KDBMSG(ARGCOUNT, "Improper argument count, see usage."),
10162306a36Sopenharmony_ci	KDBMSG(BADWIDTH, "Illegal value for BYTESPERWORD use 1, 2, 4 or 8, "
10262306a36Sopenharmony_ci	       "8 is only allowed on 64 bit systems"),
10362306a36Sopenharmony_ci	KDBMSG(BADRADIX, "Illegal value for RADIX use 8, 10 or 16"),
10462306a36Sopenharmony_ci	KDBMSG(NOTENV, "Cannot find environment variable"),
10562306a36Sopenharmony_ci	KDBMSG(NOENVVALUE, "Environment variable should have value"),
10662306a36Sopenharmony_ci	KDBMSG(NOTIMP, "Command not implemented"),
10762306a36Sopenharmony_ci	KDBMSG(ENVFULL, "Environment full"),
10862306a36Sopenharmony_ci	KDBMSG(ENVBUFFULL, "Environment buffer full"),
10962306a36Sopenharmony_ci	KDBMSG(TOOMANYBPT, "Too many breakpoints defined"),
11062306a36Sopenharmony_ci#ifdef CONFIG_CPU_XSCALE
11162306a36Sopenharmony_ci	KDBMSG(TOOMANYDBREGS, "More breakpoints than ibcr registers defined"),
11262306a36Sopenharmony_ci#else
11362306a36Sopenharmony_ci	KDBMSG(TOOMANYDBREGS, "More breakpoints than db registers defined"),
11462306a36Sopenharmony_ci#endif
11562306a36Sopenharmony_ci	KDBMSG(DUPBPT, "Duplicate breakpoint address"),
11662306a36Sopenharmony_ci	KDBMSG(BPTNOTFOUND, "Breakpoint not found"),
11762306a36Sopenharmony_ci	KDBMSG(BADMODE, "Invalid IDMODE"),
11862306a36Sopenharmony_ci	KDBMSG(BADINT, "Illegal numeric value"),
11962306a36Sopenharmony_ci	KDBMSG(INVADDRFMT, "Invalid symbolic address format"),
12062306a36Sopenharmony_ci	KDBMSG(BADREG, "Invalid register name"),
12162306a36Sopenharmony_ci	KDBMSG(BADCPUNUM, "Invalid cpu number"),
12262306a36Sopenharmony_ci	KDBMSG(BADLENGTH, "Invalid length field"),
12362306a36Sopenharmony_ci	KDBMSG(NOBP, "No Breakpoint exists"),
12462306a36Sopenharmony_ci	KDBMSG(BADADDR, "Invalid address"),
12562306a36Sopenharmony_ci	KDBMSG(NOPERM, "Permission denied"),
12662306a36Sopenharmony_ci};
12762306a36Sopenharmony_ci#undef KDBMSG
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic const int __nkdb_err = ARRAY_SIZE(kdbmsgs);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/*
13362306a36Sopenharmony_ci * Initial environment.   This is all kept static and local to
13462306a36Sopenharmony_ci * this file.   We don't want to rely on the memory allocation
13562306a36Sopenharmony_ci * mechanisms in the kernel, so we use a very limited allocate-only
13662306a36Sopenharmony_ci * heap for new and altered environment variables.  The entire
13762306a36Sopenharmony_ci * environment is limited to a fixed number of entries (add more
13862306a36Sopenharmony_ci * to __env[] if required) and a fixed amount of heap (add more to
13962306a36Sopenharmony_ci * KDB_ENVBUFSIZE if required).
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic char *__env[31] = {
14362306a36Sopenharmony_ci#if defined(CONFIG_SMP)
14462306a36Sopenharmony_ci	"PROMPT=[%d]kdb> ",
14562306a36Sopenharmony_ci#else
14662306a36Sopenharmony_ci	"PROMPT=kdb> ",
14762306a36Sopenharmony_ci#endif
14862306a36Sopenharmony_ci	"MOREPROMPT=more> ",
14962306a36Sopenharmony_ci	"RADIX=16",
15062306a36Sopenharmony_ci	"MDCOUNT=8",		/* lines of md output */
15162306a36Sopenharmony_ci	KDB_PLATFORM_ENV,
15262306a36Sopenharmony_ci	"DTABCOUNT=30",
15362306a36Sopenharmony_ci	"NOSECT=1",
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic const int __nenv = ARRAY_SIZE(__env);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistruct task_struct *kdb_curr_task(int cpu)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct task_struct *p = curr_task(cpu);
16162306a36Sopenharmony_ci#ifdef	_TIF_MCA_INIT
16262306a36Sopenharmony_ci	if ((task_thread_info(p)->flags & _TIF_MCA_INIT) && KDB_TSK(cpu))
16362306a36Sopenharmony_ci		p = krp->p;
16462306a36Sopenharmony_ci#endif
16562306a36Sopenharmony_ci	return p;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/*
16962306a36Sopenharmony_ci * Update the permissions flags (kdb_cmd_enabled) to match the
17062306a36Sopenharmony_ci * current lockdown state.
17162306a36Sopenharmony_ci *
17262306a36Sopenharmony_ci * Within this function the calls to security_locked_down() are "lazy". We
17362306a36Sopenharmony_ci * avoid calling them if the current value of kdb_cmd_enabled already excludes
17462306a36Sopenharmony_ci * flags that might be subject to lockdown. Additionally we deliberately check
17562306a36Sopenharmony_ci * the lockdown flags independently (even though read lockdown implies write
17662306a36Sopenharmony_ci * lockdown) since that results in both simpler code and clearer messages to
17762306a36Sopenharmony_ci * the user on first-time debugger entry.
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * The permission masks during a read+write lockdown permits the following
18062306a36Sopenharmony_ci * flags: INSPECT, SIGNAL, REBOOT (and ALWAYS_SAFE).
18162306a36Sopenharmony_ci *
18262306a36Sopenharmony_ci * The INSPECT commands are not blocked during lockdown because they are
18362306a36Sopenharmony_ci * not arbitrary memory reads. INSPECT covers the backtrace family (sometimes
18462306a36Sopenharmony_ci * forcing them to have no arguments) and lsmod. These commands do expose
18562306a36Sopenharmony_ci * some kernel state but do not allow the developer seated at the console to
18662306a36Sopenharmony_ci * choose what state is reported. SIGNAL and REBOOT should not be controversial,
18762306a36Sopenharmony_ci * given these are allowed for root during lockdown already.
18862306a36Sopenharmony_ci */
18962306a36Sopenharmony_cistatic void kdb_check_for_lockdown(void)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	const int write_flags = KDB_ENABLE_MEM_WRITE |
19262306a36Sopenharmony_ci				KDB_ENABLE_REG_WRITE |
19362306a36Sopenharmony_ci				KDB_ENABLE_FLOW_CTRL;
19462306a36Sopenharmony_ci	const int read_flags = KDB_ENABLE_MEM_READ |
19562306a36Sopenharmony_ci			       KDB_ENABLE_REG_READ;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	bool need_to_lockdown_write = false;
19862306a36Sopenharmony_ci	bool need_to_lockdown_read = false;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (kdb_cmd_enabled & (KDB_ENABLE_ALL | write_flags))
20162306a36Sopenharmony_ci		need_to_lockdown_write =
20262306a36Sopenharmony_ci			security_locked_down(LOCKDOWN_DBG_WRITE_KERNEL);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (kdb_cmd_enabled & (KDB_ENABLE_ALL | read_flags))
20562306a36Sopenharmony_ci		need_to_lockdown_read =
20662306a36Sopenharmony_ci			security_locked_down(LOCKDOWN_DBG_READ_KERNEL);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* De-compose KDB_ENABLE_ALL if required */
20962306a36Sopenharmony_ci	if (need_to_lockdown_write || need_to_lockdown_read)
21062306a36Sopenharmony_ci		if (kdb_cmd_enabled & KDB_ENABLE_ALL)
21162306a36Sopenharmony_ci			kdb_cmd_enabled = KDB_ENABLE_MASK & ~KDB_ENABLE_ALL;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (need_to_lockdown_write)
21462306a36Sopenharmony_ci		kdb_cmd_enabled &= ~write_flags;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (need_to_lockdown_read)
21762306a36Sopenharmony_ci		kdb_cmd_enabled &= ~read_flags;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/*
22162306a36Sopenharmony_ci * Check whether the flags of the current command, the permissions of the kdb
22262306a36Sopenharmony_ci * console and the lockdown state allow a command to be run.
22362306a36Sopenharmony_ci */
22462306a36Sopenharmony_cistatic bool kdb_check_flags(kdb_cmdflags_t flags, int permissions,
22562306a36Sopenharmony_ci				   bool no_args)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	/* permissions comes from userspace so needs massaging slightly */
22862306a36Sopenharmony_ci	permissions &= KDB_ENABLE_MASK;
22962306a36Sopenharmony_ci	permissions |= KDB_ENABLE_ALWAYS_SAFE;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/* some commands change group when launched with no arguments */
23262306a36Sopenharmony_ci	if (no_args)
23362306a36Sopenharmony_ci		permissions |= permissions << KDB_ENABLE_NO_ARGS_SHIFT;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	flags |= KDB_ENABLE_ALL;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return permissions & flags;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/*
24162306a36Sopenharmony_ci * kdbgetenv - This function will return the character string value of
24262306a36Sopenharmony_ci *	an environment variable.
24362306a36Sopenharmony_ci * Parameters:
24462306a36Sopenharmony_ci *	match	A character string representing an environment variable.
24562306a36Sopenharmony_ci * Returns:
24662306a36Sopenharmony_ci *	NULL	No environment variable matches 'match'
24762306a36Sopenharmony_ci *	char*	Pointer to string value of environment variable.
24862306a36Sopenharmony_ci */
24962306a36Sopenharmony_cichar *kdbgetenv(const char *match)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	char **ep = __env;
25262306a36Sopenharmony_ci	int matchlen = strlen(match);
25362306a36Sopenharmony_ci	int i;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	for (i = 0; i < __nenv; i++) {
25662306a36Sopenharmony_ci		char *e = *ep++;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		if (!e)
25962306a36Sopenharmony_ci			continue;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		if ((strncmp(match, e, matchlen) == 0)
26262306a36Sopenharmony_ci		 && ((e[matchlen] == '\0')
26362306a36Sopenharmony_ci		   || (e[matchlen] == '='))) {
26462306a36Sopenharmony_ci			char *cp = strchr(e, '=');
26562306a36Sopenharmony_ci			return cp ? ++cp : "";
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci	return NULL;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/*
27262306a36Sopenharmony_ci * kdballocenv - This function is used to allocate bytes for
27362306a36Sopenharmony_ci *	environment entries.
27462306a36Sopenharmony_ci * Parameters:
27562306a36Sopenharmony_ci *	match	A character string representing a numeric value
27662306a36Sopenharmony_ci * Outputs:
27762306a36Sopenharmony_ci *	*value  the unsigned long representation of the env variable 'match'
27862306a36Sopenharmony_ci * Returns:
27962306a36Sopenharmony_ci *	Zero on success, a kdb diagnostic on failure.
28062306a36Sopenharmony_ci * Remarks:
28162306a36Sopenharmony_ci *	We use a static environment buffer (envbuffer) to hold the values
28262306a36Sopenharmony_ci *	of dynamically generated environment variables (see kdb_set).  Buffer
28362306a36Sopenharmony_ci *	space once allocated is never free'd, so over time, the amount of space
28462306a36Sopenharmony_ci *	(currently 512 bytes) will be exhausted if env variables are changed
28562306a36Sopenharmony_ci *	frequently.
28662306a36Sopenharmony_ci */
28762306a36Sopenharmony_cistatic char *kdballocenv(size_t bytes)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci#define	KDB_ENVBUFSIZE	512
29062306a36Sopenharmony_ci	static char envbuffer[KDB_ENVBUFSIZE];
29162306a36Sopenharmony_ci	static int envbufsize;
29262306a36Sopenharmony_ci	char *ep = NULL;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if ((KDB_ENVBUFSIZE - envbufsize) >= bytes) {
29562306a36Sopenharmony_ci		ep = &envbuffer[envbufsize];
29662306a36Sopenharmony_ci		envbufsize += bytes;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci	return ep;
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci/*
30262306a36Sopenharmony_ci * kdbgetulenv - This function will return the value of an unsigned
30362306a36Sopenharmony_ci *	long-valued environment variable.
30462306a36Sopenharmony_ci * Parameters:
30562306a36Sopenharmony_ci *	match	A character string representing a numeric value
30662306a36Sopenharmony_ci * Outputs:
30762306a36Sopenharmony_ci *	*value  the unsigned long representation of the env variable 'match'
30862306a36Sopenharmony_ci * Returns:
30962306a36Sopenharmony_ci *	Zero on success, a kdb diagnostic on failure.
31062306a36Sopenharmony_ci */
31162306a36Sopenharmony_cistatic int kdbgetulenv(const char *match, unsigned long *value)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	char *ep;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	ep = kdbgetenv(match);
31662306a36Sopenharmony_ci	if (!ep)
31762306a36Sopenharmony_ci		return KDB_NOTENV;
31862306a36Sopenharmony_ci	if (strlen(ep) == 0)
31962306a36Sopenharmony_ci		return KDB_NOENVVALUE;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	*value = simple_strtoul(ep, NULL, 0);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return 0;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/*
32762306a36Sopenharmony_ci * kdbgetintenv - This function will return the value of an
32862306a36Sopenharmony_ci *	integer-valued environment variable.
32962306a36Sopenharmony_ci * Parameters:
33062306a36Sopenharmony_ci *	match	A character string representing an integer-valued env variable
33162306a36Sopenharmony_ci * Outputs:
33262306a36Sopenharmony_ci *	*value  the integer representation of the environment variable 'match'
33362306a36Sopenharmony_ci * Returns:
33462306a36Sopenharmony_ci *	Zero on success, a kdb diagnostic on failure.
33562306a36Sopenharmony_ci */
33662306a36Sopenharmony_ciint kdbgetintenv(const char *match, int *value)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	unsigned long val;
33962306a36Sopenharmony_ci	int diag;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	diag = kdbgetulenv(match, &val);
34262306a36Sopenharmony_ci	if (!diag)
34362306a36Sopenharmony_ci		*value = (int) val;
34462306a36Sopenharmony_ci	return diag;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci/*
34862306a36Sopenharmony_ci * kdb_setenv() - Alter an existing environment variable or create a new one.
34962306a36Sopenharmony_ci * @var: Name of the variable
35062306a36Sopenharmony_ci * @val: Value of the variable
35162306a36Sopenharmony_ci *
35262306a36Sopenharmony_ci * Return: Zero on success, a kdb diagnostic on failure.
35362306a36Sopenharmony_ci */
35462306a36Sopenharmony_cistatic int kdb_setenv(const char *var, const char *val)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	int i;
35762306a36Sopenharmony_ci	char *ep;
35862306a36Sopenharmony_ci	size_t varlen, vallen;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	varlen = strlen(var);
36162306a36Sopenharmony_ci	vallen = strlen(val);
36262306a36Sopenharmony_ci	ep = kdballocenv(varlen + vallen + 2);
36362306a36Sopenharmony_ci	if (ep == (char *)0)
36462306a36Sopenharmony_ci		return KDB_ENVBUFFULL;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	sprintf(ep, "%s=%s", var, val);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	for (i = 0; i < __nenv; i++) {
36962306a36Sopenharmony_ci		if (__env[i]
37062306a36Sopenharmony_ci		 && ((strncmp(__env[i], var, varlen) == 0)
37162306a36Sopenharmony_ci		   && ((__env[i][varlen] == '\0')
37262306a36Sopenharmony_ci		    || (__env[i][varlen] == '=')))) {
37362306a36Sopenharmony_ci			__env[i] = ep;
37462306a36Sopenharmony_ci			return 0;
37562306a36Sopenharmony_ci		}
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/*
37962306a36Sopenharmony_ci	 * Wasn't existing variable.  Fit into slot.
38062306a36Sopenharmony_ci	 */
38162306a36Sopenharmony_ci	for (i = 0; i < __nenv-1; i++) {
38262306a36Sopenharmony_ci		if (__env[i] == (char *)0) {
38362306a36Sopenharmony_ci			__env[i] = ep;
38462306a36Sopenharmony_ci			return 0;
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	return KDB_ENVFULL;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci/*
39262306a36Sopenharmony_ci * kdb_printenv() - Display the current environment variables.
39362306a36Sopenharmony_ci */
39462306a36Sopenharmony_cistatic void kdb_printenv(void)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	int i;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	for (i = 0; i < __nenv; i++) {
39962306a36Sopenharmony_ci		if (__env[i])
40062306a36Sopenharmony_ci			kdb_printf("%s\n", __env[i]);
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci/*
40562306a36Sopenharmony_ci * kdbgetularg - This function will convert a numeric string into an
40662306a36Sopenharmony_ci *	unsigned long value.
40762306a36Sopenharmony_ci * Parameters:
40862306a36Sopenharmony_ci *	arg	A character string representing a numeric value
40962306a36Sopenharmony_ci * Outputs:
41062306a36Sopenharmony_ci *	*value  the unsigned long representation of arg.
41162306a36Sopenharmony_ci * Returns:
41262306a36Sopenharmony_ci *	Zero on success, a kdb diagnostic on failure.
41362306a36Sopenharmony_ci */
41462306a36Sopenharmony_ciint kdbgetularg(const char *arg, unsigned long *value)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	char *endp;
41762306a36Sopenharmony_ci	unsigned long val;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	val = simple_strtoul(arg, &endp, 0);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	if (endp == arg) {
42262306a36Sopenharmony_ci		/*
42362306a36Sopenharmony_ci		 * Also try base 16, for us folks too lazy to type the
42462306a36Sopenharmony_ci		 * leading 0x...
42562306a36Sopenharmony_ci		 */
42662306a36Sopenharmony_ci		val = simple_strtoul(arg, &endp, 16);
42762306a36Sopenharmony_ci		if (endp == arg)
42862306a36Sopenharmony_ci			return KDB_BADINT;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	*value = val;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ciint kdbgetu64arg(const char *arg, u64 *value)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	char *endp;
43962306a36Sopenharmony_ci	u64 val;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	val = simple_strtoull(arg, &endp, 0);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (endp == arg) {
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		val = simple_strtoull(arg, &endp, 16);
44662306a36Sopenharmony_ci		if (endp == arg)
44762306a36Sopenharmony_ci			return KDB_BADINT;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	*value = val;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	return 0;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci/*
45662306a36Sopenharmony_ci * kdb_set - This function implements the 'set' command.  Alter an
45762306a36Sopenharmony_ci *	existing environment variable or create a new one.
45862306a36Sopenharmony_ci */
45962306a36Sopenharmony_ciint kdb_set(int argc, const char **argv)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	/*
46262306a36Sopenharmony_ci	 * we can be invoked two ways:
46362306a36Sopenharmony_ci	 *   set var=value    argv[1]="var", argv[2]="value"
46462306a36Sopenharmony_ci	 *   set var = value  argv[1]="var", argv[2]="=", argv[3]="value"
46562306a36Sopenharmony_ci	 * - if the latter, shift 'em down.
46662306a36Sopenharmony_ci	 */
46762306a36Sopenharmony_ci	if (argc == 3) {
46862306a36Sopenharmony_ci		argv[2] = argv[3];
46962306a36Sopenharmony_ci		argc--;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (argc != 2)
47362306a36Sopenharmony_ci		return KDB_ARGCOUNT;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	/*
47662306a36Sopenharmony_ci	 * Censor sensitive variables
47762306a36Sopenharmony_ci	 */
47862306a36Sopenharmony_ci	if (strcmp(argv[1], "PROMPT") == 0 &&
47962306a36Sopenharmony_ci	    !kdb_check_flags(KDB_ENABLE_MEM_READ, kdb_cmd_enabled, false))
48062306a36Sopenharmony_ci		return KDB_NOPERM;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/*
48362306a36Sopenharmony_ci	 * Check for internal variables
48462306a36Sopenharmony_ci	 */
48562306a36Sopenharmony_ci	if (strcmp(argv[1], "KDBDEBUG") == 0) {
48662306a36Sopenharmony_ci		unsigned int debugflags;
48762306a36Sopenharmony_ci		char *cp;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci		debugflags = simple_strtoul(argv[2], &cp, 0);
49062306a36Sopenharmony_ci		if (cp == argv[2] || debugflags & ~KDB_DEBUG_FLAG_MASK) {
49162306a36Sopenharmony_ci			kdb_printf("kdb: illegal debug flags '%s'\n",
49262306a36Sopenharmony_ci				    argv[2]);
49362306a36Sopenharmony_ci			return 0;
49462306a36Sopenharmony_ci		}
49562306a36Sopenharmony_ci		kdb_flags = (kdb_flags & ~KDB_DEBUG(MASK))
49662306a36Sopenharmony_ci			| (debugflags << KDB_DEBUG_FLAG_SHIFT);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci		return 0;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/*
50262306a36Sopenharmony_ci	 * Tokenizer squashed the '=' sign.  argv[1] is variable
50362306a36Sopenharmony_ci	 * name, argv[2] = value.
50462306a36Sopenharmony_ci	 */
50562306a36Sopenharmony_ci	return kdb_setenv(argv[1], argv[2]);
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic int kdb_check_regs(void)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	if (!kdb_current_regs) {
51162306a36Sopenharmony_ci		kdb_printf("No current kdb registers."
51262306a36Sopenharmony_ci			   "  You may need to select another task\n");
51362306a36Sopenharmony_ci		return KDB_BADREG;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci	return 0;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci/*
51962306a36Sopenharmony_ci * kdbgetaddrarg - This function is responsible for parsing an
52062306a36Sopenharmony_ci *	address-expression and returning the value of the expression,
52162306a36Sopenharmony_ci *	symbol name, and offset to the caller.
52262306a36Sopenharmony_ci *
52362306a36Sopenharmony_ci *	The argument may consist of a numeric value (decimal or
52462306a36Sopenharmony_ci *	hexadecimal), a symbol name, a register name (preceded by the
52562306a36Sopenharmony_ci *	percent sign), an environment variable with a numeric value
52662306a36Sopenharmony_ci *	(preceded by a dollar sign) or a simple arithmetic expression
52762306a36Sopenharmony_ci *	consisting of a symbol name, +/-, and a numeric constant value
52862306a36Sopenharmony_ci *	(offset).
52962306a36Sopenharmony_ci * Parameters:
53062306a36Sopenharmony_ci *	argc	- count of arguments in argv
53162306a36Sopenharmony_ci *	argv	- argument vector
53262306a36Sopenharmony_ci *	*nextarg - index to next unparsed argument in argv[]
53362306a36Sopenharmony_ci *	regs	- Register state at time of KDB entry
53462306a36Sopenharmony_ci * Outputs:
53562306a36Sopenharmony_ci *	*value	- receives the value of the address-expression
53662306a36Sopenharmony_ci *	*offset - receives the offset specified, if any
53762306a36Sopenharmony_ci *	*name   - receives the symbol name, if any
53862306a36Sopenharmony_ci *	*nextarg - index to next unparsed argument in argv[]
53962306a36Sopenharmony_ci * Returns:
54062306a36Sopenharmony_ci *	zero is returned on success, a kdb diagnostic code is
54162306a36Sopenharmony_ci *      returned on error.
54262306a36Sopenharmony_ci */
54362306a36Sopenharmony_ciint kdbgetaddrarg(int argc, const char **argv, int *nextarg,
54462306a36Sopenharmony_ci		  unsigned long *value,  long *offset,
54562306a36Sopenharmony_ci		  char **name)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	unsigned long addr;
54862306a36Sopenharmony_ci	unsigned long off = 0;
54962306a36Sopenharmony_ci	int positive;
55062306a36Sopenharmony_ci	int diag;
55162306a36Sopenharmony_ci	int found = 0;
55262306a36Sopenharmony_ci	char *symname;
55362306a36Sopenharmony_ci	char symbol = '\0';
55462306a36Sopenharmony_ci	char *cp;
55562306a36Sopenharmony_ci	kdb_symtab_t symtab;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	/*
55862306a36Sopenharmony_ci	 * If the enable flags prohibit both arbitrary memory access
55962306a36Sopenharmony_ci	 * and flow control then there are no reasonable grounds to
56062306a36Sopenharmony_ci	 * provide symbol lookup.
56162306a36Sopenharmony_ci	 */
56262306a36Sopenharmony_ci	if (!kdb_check_flags(KDB_ENABLE_MEM_READ | KDB_ENABLE_FLOW_CTRL,
56362306a36Sopenharmony_ci			     kdb_cmd_enabled, false))
56462306a36Sopenharmony_ci		return KDB_NOPERM;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	/*
56762306a36Sopenharmony_ci	 * Process arguments which follow the following syntax:
56862306a36Sopenharmony_ci	 *
56962306a36Sopenharmony_ci	 *  symbol | numeric-address [+/- numeric-offset]
57062306a36Sopenharmony_ci	 *  %register
57162306a36Sopenharmony_ci	 *  $environment-variable
57262306a36Sopenharmony_ci	 */
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	if (*nextarg > argc)
57562306a36Sopenharmony_ci		return KDB_ARGCOUNT;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	symname = (char *)argv[*nextarg];
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/*
58062306a36Sopenharmony_ci	 * If there is no whitespace between the symbol
58162306a36Sopenharmony_ci	 * or address and the '+' or '-' symbols, we
58262306a36Sopenharmony_ci	 * remember the character and replace it with a
58362306a36Sopenharmony_ci	 * null so the symbol/value can be properly parsed
58462306a36Sopenharmony_ci	 */
58562306a36Sopenharmony_ci	cp = strpbrk(symname, "+-");
58662306a36Sopenharmony_ci	if (cp != NULL) {
58762306a36Sopenharmony_ci		symbol = *cp;
58862306a36Sopenharmony_ci		*cp++ = '\0';
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (symname[0] == '$') {
59262306a36Sopenharmony_ci		diag = kdbgetulenv(&symname[1], &addr);
59362306a36Sopenharmony_ci		if (diag)
59462306a36Sopenharmony_ci			return diag;
59562306a36Sopenharmony_ci	} else if (symname[0] == '%') {
59662306a36Sopenharmony_ci		diag = kdb_check_regs();
59762306a36Sopenharmony_ci		if (diag)
59862306a36Sopenharmony_ci			return diag;
59962306a36Sopenharmony_ci		/* Implement register values with % at a later time as it is
60062306a36Sopenharmony_ci		 * arch optional.
60162306a36Sopenharmony_ci		 */
60262306a36Sopenharmony_ci		return KDB_NOTIMP;
60362306a36Sopenharmony_ci	} else {
60462306a36Sopenharmony_ci		found = kdbgetsymval(symname, &symtab);
60562306a36Sopenharmony_ci		if (found) {
60662306a36Sopenharmony_ci			addr = symtab.sym_start;
60762306a36Sopenharmony_ci		} else {
60862306a36Sopenharmony_ci			diag = kdbgetularg(argv[*nextarg], &addr);
60962306a36Sopenharmony_ci			if (diag)
61062306a36Sopenharmony_ci				return diag;
61162306a36Sopenharmony_ci		}
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (!found)
61562306a36Sopenharmony_ci		found = kdbnearsym(addr, &symtab);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	(*nextarg)++;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (name)
62062306a36Sopenharmony_ci		*name = symname;
62162306a36Sopenharmony_ci	if (value)
62262306a36Sopenharmony_ci		*value = addr;
62362306a36Sopenharmony_ci	if (offset && name && *name)
62462306a36Sopenharmony_ci		*offset = addr - symtab.sym_start;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if ((*nextarg > argc)
62762306a36Sopenharmony_ci	 && (symbol == '\0'))
62862306a36Sopenharmony_ci		return 0;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/*
63162306a36Sopenharmony_ci	 * check for +/- and offset
63262306a36Sopenharmony_ci	 */
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (symbol == '\0') {
63562306a36Sopenharmony_ci		if ((argv[*nextarg][0] != '+')
63662306a36Sopenharmony_ci		 && (argv[*nextarg][0] != '-')) {
63762306a36Sopenharmony_ci			/*
63862306a36Sopenharmony_ci			 * Not our argument.  Return.
63962306a36Sopenharmony_ci			 */
64062306a36Sopenharmony_ci			return 0;
64162306a36Sopenharmony_ci		} else {
64262306a36Sopenharmony_ci			positive = (argv[*nextarg][0] == '+');
64362306a36Sopenharmony_ci			(*nextarg)++;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci	} else
64662306a36Sopenharmony_ci		positive = (symbol == '+');
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/*
64962306a36Sopenharmony_ci	 * Now there must be an offset!
65062306a36Sopenharmony_ci	 */
65162306a36Sopenharmony_ci	if ((*nextarg > argc)
65262306a36Sopenharmony_ci	 && (symbol == '\0')) {
65362306a36Sopenharmony_ci		return KDB_INVADDRFMT;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if (!symbol) {
65762306a36Sopenharmony_ci		cp = (char *)argv[*nextarg];
65862306a36Sopenharmony_ci		(*nextarg)++;
65962306a36Sopenharmony_ci	}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	diag = kdbgetularg(cp, &off);
66262306a36Sopenharmony_ci	if (diag)
66362306a36Sopenharmony_ci		return diag;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (!positive)
66662306a36Sopenharmony_ci		off = -off;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	if (offset)
66962306a36Sopenharmony_ci		*offset += off;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (value)
67262306a36Sopenharmony_ci		*value += off;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	return 0;
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic void kdb_cmderror(int diag)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	int i;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (diag >= 0) {
68262306a36Sopenharmony_ci		kdb_printf("no error detected (diagnostic is %d)\n", diag);
68362306a36Sopenharmony_ci		return;
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	for (i = 0; i < __nkdb_err; i++) {
68762306a36Sopenharmony_ci		if (kdbmsgs[i].km_diag == diag) {
68862306a36Sopenharmony_ci			kdb_printf("diag: %d: %s\n", diag, kdbmsgs[i].km_msg);
68962306a36Sopenharmony_ci			return;
69062306a36Sopenharmony_ci		}
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	kdb_printf("Unknown diag %d\n", -diag);
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci/*
69762306a36Sopenharmony_ci * kdb_defcmd, kdb_defcmd2 - This function implements the 'defcmd'
69862306a36Sopenharmony_ci *	command which defines one command as a set of other commands,
69962306a36Sopenharmony_ci *	terminated by endefcmd.  kdb_defcmd processes the initial
70062306a36Sopenharmony_ci *	'defcmd' command, kdb_defcmd2 is invoked from kdb_parse for
70162306a36Sopenharmony_ci *	the following commands until 'endefcmd'.
70262306a36Sopenharmony_ci * Inputs:
70362306a36Sopenharmony_ci *	argc	argument count
70462306a36Sopenharmony_ci *	argv	argument vector
70562306a36Sopenharmony_ci * Returns:
70662306a36Sopenharmony_ci *	zero for success, a kdb diagnostic if error
70762306a36Sopenharmony_ci */
70862306a36Sopenharmony_cistruct kdb_macro {
70962306a36Sopenharmony_ci	kdbtab_t cmd;			/* Macro command */
71062306a36Sopenharmony_ci	struct list_head statements;	/* Associated statement list */
71162306a36Sopenharmony_ci};
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistruct kdb_macro_statement {
71462306a36Sopenharmony_ci	char *statement;		/* Statement text */
71562306a36Sopenharmony_ci	struct list_head list_node;	/* Statement list node */
71662306a36Sopenharmony_ci};
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic struct kdb_macro *kdb_macro;
71962306a36Sopenharmony_cistatic bool defcmd_in_progress;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci/* Forward references */
72262306a36Sopenharmony_cistatic int kdb_exec_defcmd(int argc, const char **argv);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic int kdb_defcmd2(const char *cmdstr, const char *argv0)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	struct kdb_macro_statement *kms;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (!kdb_macro)
72962306a36Sopenharmony_ci		return KDB_NOTIMP;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (strcmp(argv0, "endefcmd") == 0) {
73262306a36Sopenharmony_ci		defcmd_in_progress = false;
73362306a36Sopenharmony_ci		if (!list_empty(&kdb_macro->statements))
73462306a36Sopenharmony_ci			kdb_register(&kdb_macro->cmd);
73562306a36Sopenharmony_ci		return 0;
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	kms = kmalloc(sizeof(*kms), GFP_KDB);
73962306a36Sopenharmony_ci	if (!kms) {
74062306a36Sopenharmony_ci		kdb_printf("Could not allocate new kdb macro command: %s\n",
74162306a36Sopenharmony_ci			   cmdstr);
74262306a36Sopenharmony_ci		return KDB_NOTIMP;
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	kms->statement = kdb_strdup(cmdstr, GFP_KDB);
74662306a36Sopenharmony_ci	list_add_tail(&kms->list_node, &kdb_macro->statements);
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	return 0;
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic int kdb_defcmd(int argc, const char **argv)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	kdbtab_t *mp;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (defcmd_in_progress) {
75662306a36Sopenharmony_ci		kdb_printf("kdb: nested defcmd detected, assuming missing "
75762306a36Sopenharmony_ci			   "endefcmd\n");
75862306a36Sopenharmony_ci		kdb_defcmd2("endefcmd", "endefcmd");
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci	if (argc == 0) {
76162306a36Sopenharmony_ci		kdbtab_t *kp;
76262306a36Sopenharmony_ci		struct kdb_macro *kmp;
76362306a36Sopenharmony_ci		struct kdb_macro_statement *kms;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		list_for_each_entry(kp, &kdb_cmds_head, list_node) {
76662306a36Sopenharmony_ci			if (kp->func == kdb_exec_defcmd) {
76762306a36Sopenharmony_ci				kdb_printf("defcmd %s \"%s\" \"%s\"\n",
76862306a36Sopenharmony_ci					   kp->name, kp->usage, kp->help);
76962306a36Sopenharmony_ci				kmp = container_of(kp, struct kdb_macro, cmd);
77062306a36Sopenharmony_ci				list_for_each_entry(kms, &kmp->statements,
77162306a36Sopenharmony_ci						    list_node)
77262306a36Sopenharmony_ci					kdb_printf("%s", kms->statement);
77362306a36Sopenharmony_ci				kdb_printf("endefcmd\n");
77462306a36Sopenharmony_ci			}
77562306a36Sopenharmony_ci		}
77662306a36Sopenharmony_ci		return 0;
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci	if (argc != 3)
77962306a36Sopenharmony_ci		return KDB_ARGCOUNT;
78062306a36Sopenharmony_ci	if (in_dbg_master()) {
78162306a36Sopenharmony_ci		kdb_printf("Command only available during kdb_init()\n");
78262306a36Sopenharmony_ci		return KDB_NOTIMP;
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci	kdb_macro = kzalloc(sizeof(*kdb_macro), GFP_KDB);
78562306a36Sopenharmony_ci	if (!kdb_macro)
78662306a36Sopenharmony_ci		goto fail_defcmd;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	mp = &kdb_macro->cmd;
78962306a36Sopenharmony_ci	mp->func = kdb_exec_defcmd;
79062306a36Sopenharmony_ci	mp->minlen = 0;
79162306a36Sopenharmony_ci	mp->flags = KDB_ENABLE_ALWAYS_SAFE;
79262306a36Sopenharmony_ci	mp->name = kdb_strdup(argv[1], GFP_KDB);
79362306a36Sopenharmony_ci	if (!mp->name)
79462306a36Sopenharmony_ci		goto fail_name;
79562306a36Sopenharmony_ci	mp->usage = kdb_strdup(argv[2], GFP_KDB);
79662306a36Sopenharmony_ci	if (!mp->usage)
79762306a36Sopenharmony_ci		goto fail_usage;
79862306a36Sopenharmony_ci	mp->help = kdb_strdup(argv[3], GFP_KDB);
79962306a36Sopenharmony_ci	if (!mp->help)
80062306a36Sopenharmony_ci		goto fail_help;
80162306a36Sopenharmony_ci	if (mp->usage[0] == '"') {
80262306a36Sopenharmony_ci		strcpy(mp->usage, argv[2]+1);
80362306a36Sopenharmony_ci		mp->usage[strlen(mp->usage)-1] = '\0';
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci	if (mp->help[0] == '"') {
80662306a36Sopenharmony_ci		strcpy(mp->help, argv[3]+1);
80762306a36Sopenharmony_ci		mp->help[strlen(mp->help)-1] = '\0';
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	INIT_LIST_HEAD(&kdb_macro->statements);
81162306a36Sopenharmony_ci	defcmd_in_progress = true;
81262306a36Sopenharmony_ci	return 0;
81362306a36Sopenharmony_cifail_help:
81462306a36Sopenharmony_ci	kfree(mp->usage);
81562306a36Sopenharmony_cifail_usage:
81662306a36Sopenharmony_ci	kfree(mp->name);
81762306a36Sopenharmony_cifail_name:
81862306a36Sopenharmony_ci	kfree(kdb_macro);
81962306a36Sopenharmony_cifail_defcmd:
82062306a36Sopenharmony_ci	kdb_printf("Could not allocate new kdb_macro entry for %s\n", argv[1]);
82162306a36Sopenharmony_ci	return KDB_NOTIMP;
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci/*
82562306a36Sopenharmony_ci * kdb_exec_defcmd - Execute the set of commands associated with this
82662306a36Sopenharmony_ci *	defcmd name.
82762306a36Sopenharmony_ci * Inputs:
82862306a36Sopenharmony_ci *	argc	argument count
82962306a36Sopenharmony_ci *	argv	argument vector
83062306a36Sopenharmony_ci * Returns:
83162306a36Sopenharmony_ci *	zero for success, a kdb diagnostic if error
83262306a36Sopenharmony_ci */
83362306a36Sopenharmony_cistatic int kdb_exec_defcmd(int argc, const char **argv)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	int ret;
83662306a36Sopenharmony_ci	kdbtab_t *kp;
83762306a36Sopenharmony_ci	struct kdb_macro *kmp;
83862306a36Sopenharmony_ci	struct kdb_macro_statement *kms;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	if (argc != 0)
84162306a36Sopenharmony_ci		return KDB_ARGCOUNT;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	list_for_each_entry(kp, &kdb_cmds_head, list_node) {
84462306a36Sopenharmony_ci		if (strcmp(kp->name, argv[0]) == 0)
84562306a36Sopenharmony_ci			break;
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci	if (list_entry_is_head(kp, &kdb_cmds_head, list_node)) {
84862306a36Sopenharmony_ci		kdb_printf("kdb_exec_defcmd: could not find commands for %s\n",
84962306a36Sopenharmony_ci			   argv[0]);
85062306a36Sopenharmony_ci		return KDB_NOTIMP;
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci	kmp = container_of(kp, struct kdb_macro, cmd);
85362306a36Sopenharmony_ci	list_for_each_entry(kms, &kmp->statements, list_node) {
85462306a36Sopenharmony_ci		/*
85562306a36Sopenharmony_ci		 * Recursive use of kdb_parse, do not use argv after this point.
85662306a36Sopenharmony_ci		 */
85762306a36Sopenharmony_ci		argv = NULL;
85862306a36Sopenharmony_ci		kdb_printf("[%s]kdb> %s\n", kmp->cmd.name, kms->statement);
85962306a36Sopenharmony_ci		ret = kdb_parse(kms->statement);
86062306a36Sopenharmony_ci		if (ret)
86162306a36Sopenharmony_ci			return ret;
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci	return 0;
86462306a36Sopenharmony_ci}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci/* Command history */
86762306a36Sopenharmony_ci#define KDB_CMD_HISTORY_COUNT	32
86862306a36Sopenharmony_ci#define CMD_BUFLEN		200	/* kdb_printf: max printline
86962306a36Sopenharmony_ci					 * size == 256 */
87062306a36Sopenharmony_cistatic unsigned int cmd_head, cmd_tail;
87162306a36Sopenharmony_cistatic unsigned int cmdptr;
87262306a36Sopenharmony_cistatic char cmd_hist[KDB_CMD_HISTORY_COUNT][CMD_BUFLEN];
87362306a36Sopenharmony_cistatic char cmd_cur[CMD_BUFLEN];
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci/*
87662306a36Sopenharmony_ci * The "str" argument may point to something like  | grep xyz
87762306a36Sopenharmony_ci */
87862306a36Sopenharmony_cistatic void parse_grep(const char *str)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	int	len;
88162306a36Sopenharmony_ci	char	*cp = (char *)str, *cp2;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/* sanity check: we should have been called with the \ first */
88462306a36Sopenharmony_ci	if (*cp != '|')
88562306a36Sopenharmony_ci		return;
88662306a36Sopenharmony_ci	cp++;
88762306a36Sopenharmony_ci	while (isspace(*cp))
88862306a36Sopenharmony_ci		cp++;
88962306a36Sopenharmony_ci	if (!str_has_prefix(cp, "grep ")) {
89062306a36Sopenharmony_ci		kdb_printf("invalid 'pipe', see grephelp\n");
89162306a36Sopenharmony_ci		return;
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci	cp += 5;
89462306a36Sopenharmony_ci	while (isspace(*cp))
89562306a36Sopenharmony_ci		cp++;
89662306a36Sopenharmony_ci	cp2 = strchr(cp, '\n');
89762306a36Sopenharmony_ci	if (cp2)
89862306a36Sopenharmony_ci		*cp2 = '\0'; /* remove the trailing newline */
89962306a36Sopenharmony_ci	len = strlen(cp);
90062306a36Sopenharmony_ci	if (len == 0) {
90162306a36Sopenharmony_ci		kdb_printf("invalid 'pipe', see grephelp\n");
90262306a36Sopenharmony_ci		return;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci	/* now cp points to a nonzero length search string */
90562306a36Sopenharmony_ci	if (*cp == '"') {
90662306a36Sopenharmony_ci		/* allow it be "x y z" by removing the "'s - there must
90762306a36Sopenharmony_ci		   be two of them */
90862306a36Sopenharmony_ci		cp++;
90962306a36Sopenharmony_ci		cp2 = strchr(cp, '"');
91062306a36Sopenharmony_ci		if (!cp2) {
91162306a36Sopenharmony_ci			kdb_printf("invalid quoted string, see grephelp\n");
91262306a36Sopenharmony_ci			return;
91362306a36Sopenharmony_ci		}
91462306a36Sopenharmony_ci		*cp2 = '\0'; /* end the string where the 2nd " was */
91562306a36Sopenharmony_ci	}
91662306a36Sopenharmony_ci	kdb_grep_leading = 0;
91762306a36Sopenharmony_ci	if (*cp == '^') {
91862306a36Sopenharmony_ci		kdb_grep_leading = 1;
91962306a36Sopenharmony_ci		cp++;
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci	len = strlen(cp);
92262306a36Sopenharmony_ci	kdb_grep_trailing = 0;
92362306a36Sopenharmony_ci	if (*(cp+len-1) == '$') {
92462306a36Sopenharmony_ci		kdb_grep_trailing = 1;
92562306a36Sopenharmony_ci		*(cp+len-1) = '\0';
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci	len = strlen(cp);
92862306a36Sopenharmony_ci	if (!len)
92962306a36Sopenharmony_ci		return;
93062306a36Sopenharmony_ci	if (len >= KDB_GREP_STRLEN) {
93162306a36Sopenharmony_ci		kdb_printf("search string too long\n");
93262306a36Sopenharmony_ci		return;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci	strcpy(kdb_grep_string, cp);
93562306a36Sopenharmony_ci	kdb_grepping_flag++;
93662306a36Sopenharmony_ci	return;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci/*
94062306a36Sopenharmony_ci * kdb_parse - Parse the command line, search the command table for a
94162306a36Sopenharmony_ci *	matching command and invoke the command function.  This
94262306a36Sopenharmony_ci *	function may be called recursively, if it is, the second call
94362306a36Sopenharmony_ci *	will overwrite argv and cbuf.  It is the caller's
94462306a36Sopenharmony_ci *	responsibility to save their argv if they recursively call
94562306a36Sopenharmony_ci *	kdb_parse().
94662306a36Sopenharmony_ci * Parameters:
94762306a36Sopenharmony_ci *      cmdstr	The input command line to be parsed.
94862306a36Sopenharmony_ci *	regs	The registers at the time kdb was entered.
94962306a36Sopenharmony_ci * Returns:
95062306a36Sopenharmony_ci *	Zero for success, a kdb diagnostic if failure.
95162306a36Sopenharmony_ci * Remarks:
95262306a36Sopenharmony_ci *	Limited to 20 tokens.
95362306a36Sopenharmony_ci *
95462306a36Sopenharmony_ci *	Real rudimentary tokenization. Basically only whitespace
95562306a36Sopenharmony_ci *	is considered a token delimiter (but special consideration
95662306a36Sopenharmony_ci *	is taken of the '=' sign as used by the 'set' command).
95762306a36Sopenharmony_ci *
95862306a36Sopenharmony_ci *	The algorithm used to tokenize the input string relies on
95962306a36Sopenharmony_ci *	there being at least one whitespace (or otherwise useless)
96062306a36Sopenharmony_ci *	character between tokens as the character immediately following
96162306a36Sopenharmony_ci *	the token is altered in-place to a null-byte to terminate the
96262306a36Sopenharmony_ci *	token string.
96362306a36Sopenharmony_ci */
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci#define MAXARGC	20
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ciint kdb_parse(const char *cmdstr)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	static char *argv[MAXARGC];
97062306a36Sopenharmony_ci	static int argc;
97162306a36Sopenharmony_ci	static char cbuf[CMD_BUFLEN+2];
97262306a36Sopenharmony_ci	char *cp;
97362306a36Sopenharmony_ci	char *cpp, quoted;
97462306a36Sopenharmony_ci	kdbtab_t *tp;
97562306a36Sopenharmony_ci	int escaped, ignore_errors = 0, check_grep = 0;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/*
97862306a36Sopenharmony_ci	 * First tokenize the command string.
97962306a36Sopenharmony_ci	 */
98062306a36Sopenharmony_ci	cp = (char *)cmdstr;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	if (KDB_FLAG(CMD_INTERRUPT)) {
98362306a36Sopenharmony_ci		/* Previous command was interrupted, newline must not
98462306a36Sopenharmony_ci		 * repeat the command */
98562306a36Sopenharmony_ci		KDB_FLAG_CLEAR(CMD_INTERRUPT);
98662306a36Sopenharmony_ci		KDB_STATE_SET(PAGER);
98762306a36Sopenharmony_ci		argc = 0;	/* no repeat */
98862306a36Sopenharmony_ci	}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (*cp != '\n' && *cp != '\0') {
99162306a36Sopenharmony_ci		argc = 0;
99262306a36Sopenharmony_ci		cpp = cbuf;
99362306a36Sopenharmony_ci		while (*cp) {
99462306a36Sopenharmony_ci			/* skip whitespace */
99562306a36Sopenharmony_ci			while (isspace(*cp))
99662306a36Sopenharmony_ci				cp++;
99762306a36Sopenharmony_ci			if ((*cp == '\0') || (*cp == '\n') ||
99862306a36Sopenharmony_ci			    (*cp == '#' && !defcmd_in_progress))
99962306a36Sopenharmony_ci				break;
100062306a36Sopenharmony_ci			/* special case: check for | grep pattern */
100162306a36Sopenharmony_ci			if (*cp == '|') {
100262306a36Sopenharmony_ci				check_grep++;
100362306a36Sopenharmony_ci				break;
100462306a36Sopenharmony_ci			}
100562306a36Sopenharmony_ci			if (cpp >= cbuf + CMD_BUFLEN) {
100662306a36Sopenharmony_ci				kdb_printf("kdb_parse: command buffer "
100762306a36Sopenharmony_ci					   "overflow, command ignored\n%s\n",
100862306a36Sopenharmony_ci					   cmdstr);
100962306a36Sopenharmony_ci				return KDB_NOTFOUND;
101062306a36Sopenharmony_ci			}
101162306a36Sopenharmony_ci			if (argc >= MAXARGC - 1) {
101262306a36Sopenharmony_ci				kdb_printf("kdb_parse: too many arguments, "
101362306a36Sopenharmony_ci					   "command ignored\n%s\n", cmdstr);
101462306a36Sopenharmony_ci				return KDB_NOTFOUND;
101562306a36Sopenharmony_ci			}
101662306a36Sopenharmony_ci			argv[argc++] = cpp;
101762306a36Sopenharmony_ci			escaped = 0;
101862306a36Sopenharmony_ci			quoted = '\0';
101962306a36Sopenharmony_ci			/* Copy to next unquoted and unescaped
102062306a36Sopenharmony_ci			 * whitespace or '=' */
102162306a36Sopenharmony_ci			while (*cp && *cp != '\n' &&
102262306a36Sopenharmony_ci			       (escaped || quoted || !isspace(*cp))) {
102362306a36Sopenharmony_ci				if (cpp >= cbuf + CMD_BUFLEN)
102462306a36Sopenharmony_ci					break;
102562306a36Sopenharmony_ci				if (escaped) {
102662306a36Sopenharmony_ci					escaped = 0;
102762306a36Sopenharmony_ci					*cpp++ = *cp++;
102862306a36Sopenharmony_ci					continue;
102962306a36Sopenharmony_ci				}
103062306a36Sopenharmony_ci				if (*cp == '\\') {
103162306a36Sopenharmony_ci					escaped = 1;
103262306a36Sopenharmony_ci					++cp;
103362306a36Sopenharmony_ci					continue;
103462306a36Sopenharmony_ci				}
103562306a36Sopenharmony_ci				if (*cp == quoted)
103662306a36Sopenharmony_ci					quoted = '\0';
103762306a36Sopenharmony_ci				else if (*cp == '\'' || *cp == '"')
103862306a36Sopenharmony_ci					quoted = *cp;
103962306a36Sopenharmony_ci				*cpp = *cp++;
104062306a36Sopenharmony_ci				if (*cpp == '=' && !quoted)
104162306a36Sopenharmony_ci					break;
104262306a36Sopenharmony_ci				++cpp;
104362306a36Sopenharmony_ci			}
104462306a36Sopenharmony_ci			*cpp++ = '\0';	/* Squash a ws or '=' character */
104562306a36Sopenharmony_ci		}
104662306a36Sopenharmony_ci	}
104762306a36Sopenharmony_ci	if (!argc)
104862306a36Sopenharmony_ci		return 0;
104962306a36Sopenharmony_ci	if (check_grep)
105062306a36Sopenharmony_ci		parse_grep(cp);
105162306a36Sopenharmony_ci	if (defcmd_in_progress) {
105262306a36Sopenharmony_ci		int result = kdb_defcmd2(cmdstr, argv[0]);
105362306a36Sopenharmony_ci		if (!defcmd_in_progress) {
105462306a36Sopenharmony_ci			argc = 0;	/* avoid repeat on endefcmd */
105562306a36Sopenharmony_ci			*(argv[0]) = '\0';
105662306a36Sopenharmony_ci		}
105762306a36Sopenharmony_ci		return result;
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci	if (argv[0][0] == '-' && argv[0][1] &&
106062306a36Sopenharmony_ci	    (argv[0][1] < '0' || argv[0][1] > '9')) {
106162306a36Sopenharmony_ci		ignore_errors = 1;
106262306a36Sopenharmony_ci		++argv[0];
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	list_for_each_entry(tp, &kdb_cmds_head, list_node) {
106662306a36Sopenharmony_ci		/*
106762306a36Sopenharmony_ci		 * If this command is allowed to be abbreviated,
106862306a36Sopenharmony_ci		 * check to see if this is it.
106962306a36Sopenharmony_ci		 */
107062306a36Sopenharmony_ci		if (tp->minlen && (strlen(argv[0]) <= tp->minlen) &&
107162306a36Sopenharmony_ci		    (strncmp(argv[0], tp->name, tp->minlen) == 0))
107262306a36Sopenharmony_ci			break;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci		if (strcmp(argv[0], tp->name) == 0)
107562306a36Sopenharmony_ci			break;
107662306a36Sopenharmony_ci	}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	/*
107962306a36Sopenharmony_ci	 * If we don't find a command by this name, see if the first
108062306a36Sopenharmony_ci	 * few characters of this match any of the known commands.
108162306a36Sopenharmony_ci	 * e.g., md1c20 should match md.
108262306a36Sopenharmony_ci	 */
108362306a36Sopenharmony_ci	if (list_entry_is_head(tp, &kdb_cmds_head, list_node)) {
108462306a36Sopenharmony_ci		list_for_each_entry(tp, &kdb_cmds_head, list_node) {
108562306a36Sopenharmony_ci			if (strncmp(argv[0], tp->name, strlen(tp->name)) == 0)
108662306a36Sopenharmony_ci				break;
108762306a36Sopenharmony_ci		}
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (!list_entry_is_head(tp, &kdb_cmds_head, list_node)) {
109162306a36Sopenharmony_ci		int result;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci		if (!kdb_check_flags(tp->flags, kdb_cmd_enabled, argc <= 1))
109462306a36Sopenharmony_ci			return KDB_NOPERM;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci		KDB_STATE_SET(CMD);
109762306a36Sopenharmony_ci		result = (*tp->func)(argc-1, (const char **)argv);
109862306a36Sopenharmony_ci		if (result && ignore_errors && result > KDB_CMD_GO)
109962306a36Sopenharmony_ci			result = 0;
110062306a36Sopenharmony_ci		KDB_STATE_CLEAR(CMD);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci		if (tp->flags & KDB_REPEAT_WITH_ARGS)
110362306a36Sopenharmony_ci			return result;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci		argc = tp->flags & KDB_REPEAT_NO_ARGS ? 1 : 0;
110662306a36Sopenharmony_ci		if (argv[argc])
110762306a36Sopenharmony_ci			*(argv[argc]) = '\0';
110862306a36Sopenharmony_ci		return result;
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	/*
111262306a36Sopenharmony_ci	 * If the input with which we were presented does not
111362306a36Sopenharmony_ci	 * map to an existing command, attempt to parse it as an
111462306a36Sopenharmony_ci	 * address argument and display the result.   Useful for
111562306a36Sopenharmony_ci	 * obtaining the address of a variable, or the nearest symbol
111662306a36Sopenharmony_ci	 * to an address contained in a register.
111762306a36Sopenharmony_ci	 */
111862306a36Sopenharmony_ci	{
111962306a36Sopenharmony_ci		unsigned long value;
112062306a36Sopenharmony_ci		char *name = NULL;
112162306a36Sopenharmony_ci		long offset;
112262306a36Sopenharmony_ci		int nextarg = 0;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci		if (kdbgetaddrarg(0, (const char **)argv, &nextarg,
112562306a36Sopenharmony_ci				  &value, &offset, &name)) {
112662306a36Sopenharmony_ci			return KDB_NOTFOUND;
112762306a36Sopenharmony_ci		}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci		kdb_printf("%s = ", argv[0]);
113062306a36Sopenharmony_ci		kdb_symbol_print(value, NULL, KDB_SP_DEFAULT);
113162306a36Sopenharmony_ci		kdb_printf("\n");
113262306a36Sopenharmony_ci		return 0;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_cistatic int handle_ctrl_cmd(char *cmd)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci#define CTRL_P	16
114062306a36Sopenharmony_ci#define CTRL_N	14
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	/* initial situation */
114362306a36Sopenharmony_ci	if (cmd_head == cmd_tail)
114462306a36Sopenharmony_ci		return 0;
114562306a36Sopenharmony_ci	switch (*cmd) {
114662306a36Sopenharmony_ci	case CTRL_P:
114762306a36Sopenharmony_ci		if (cmdptr != cmd_tail)
114862306a36Sopenharmony_ci			cmdptr = (cmdptr + KDB_CMD_HISTORY_COUNT - 1) %
114962306a36Sopenharmony_ci				 KDB_CMD_HISTORY_COUNT;
115062306a36Sopenharmony_ci		strscpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN);
115162306a36Sopenharmony_ci		return 1;
115262306a36Sopenharmony_ci	case CTRL_N:
115362306a36Sopenharmony_ci		if (cmdptr != cmd_head)
115462306a36Sopenharmony_ci			cmdptr = (cmdptr+1) % KDB_CMD_HISTORY_COUNT;
115562306a36Sopenharmony_ci		strscpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN);
115662306a36Sopenharmony_ci		return 1;
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci	return 0;
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci/*
116262306a36Sopenharmony_ci * kdb_reboot - This function implements the 'reboot' command.  Reboot
116362306a36Sopenharmony_ci *	the system immediately, or loop for ever on failure.
116462306a36Sopenharmony_ci */
116562306a36Sopenharmony_cistatic int kdb_reboot(int argc, const char **argv)
116662306a36Sopenharmony_ci{
116762306a36Sopenharmony_ci	emergency_restart();
116862306a36Sopenharmony_ci	kdb_printf("Hmm, kdb_reboot did not reboot, spinning here\n");
116962306a36Sopenharmony_ci	while (1)
117062306a36Sopenharmony_ci		cpu_relax();
117162306a36Sopenharmony_ci	/* NOTREACHED */
117262306a36Sopenharmony_ci	return 0;
117362306a36Sopenharmony_ci}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_cistatic void kdb_dumpregs(struct pt_regs *regs)
117662306a36Sopenharmony_ci{
117762306a36Sopenharmony_ci	int old_lvl = console_loglevel;
117862306a36Sopenharmony_ci	console_loglevel = CONSOLE_LOGLEVEL_MOTORMOUTH;
117962306a36Sopenharmony_ci	kdb_trap_printk++;
118062306a36Sopenharmony_ci	show_regs(regs);
118162306a36Sopenharmony_ci	kdb_trap_printk--;
118262306a36Sopenharmony_ci	kdb_printf("\n");
118362306a36Sopenharmony_ci	console_loglevel = old_lvl;
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cistatic void kdb_set_current_task(struct task_struct *p)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	kdb_current_task = p;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	if (kdb_task_has_cpu(p)) {
119162306a36Sopenharmony_ci		kdb_current_regs = KDB_TSKREGS(kdb_process_cpu(p));
119262306a36Sopenharmony_ci		return;
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci	kdb_current_regs = NULL;
119562306a36Sopenharmony_ci}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_cistatic void drop_newline(char *buf)
119862306a36Sopenharmony_ci{
119962306a36Sopenharmony_ci	size_t len = strlen(buf);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (len == 0)
120262306a36Sopenharmony_ci		return;
120362306a36Sopenharmony_ci	if (*(buf + len - 1) == '\n')
120462306a36Sopenharmony_ci		*(buf + len - 1) = '\0';
120562306a36Sopenharmony_ci}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci/*
120862306a36Sopenharmony_ci * kdb_local - The main code for kdb.  This routine is invoked on a
120962306a36Sopenharmony_ci *	specific processor, it is not global.  The main kdb() routine
121062306a36Sopenharmony_ci *	ensures that only one processor at a time is in this routine.
121162306a36Sopenharmony_ci *	This code is called with the real reason code on the first
121262306a36Sopenharmony_ci *	entry to a kdb session, thereafter it is called with reason
121362306a36Sopenharmony_ci *	SWITCH, even if the user goes back to the original cpu.
121462306a36Sopenharmony_ci * Inputs:
121562306a36Sopenharmony_ci *	reason		The reason KDB was invoked
121662306a36Sopenharmony_ci *	error		The hardware-defined error code
121762306a36Sopenharmony_ci *	regs		The exception frame at time of fault/breakpoint.
121862306a36Sopenharmony_ci *	db_result	Result code from the break or debug point.
121962306a36Sopenharmony_ci * Returns:
122062306a36Sopenharmony_ci *	0	KDB was invoked for an event which it wasn't responsible
122162306a36Sopenharmony_ci *	1	KDB handled the event for which it was invoked.
122262306a36Sopenharmony_ci *	KDB_CMD_GO	User typed 'go'.
122362306a36Sopenharmony_ci *	KDB_CMD_CPU	User switched to another cpu.
122462306a36Sopenharmony_ci *	KDB_CMD_SS	Single step.
122562306a36Sopenharmony_ci */
122662306a36Sopenharmony_cistatic int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
122762306a36Sopenharmony_ci		     kdb_dbtrap_t db_result)
122862306a36Sopenharmony_ci{
122962306a36Sopenharmony_ci	char *cmdbuf;
123062306a36Sopenharmony_ci	int diag;
123162306a36Sopenharmony_ci	struct task_struct *kdb_current =
123262306a36Sopenharmony_ci		kdb_curr_task(raw_smp_processor_id());
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	KDB_DEBUG_STATE("kdb_local 1", reason);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	kdb_check_for_lockdown();
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	kdb_go_count = 0;
123962306a36Sopenharmony_ci	if (reason == KDB_REASON_DEBUG) {
124062306a36Sopenharmony_ci		/* special case below */
124162306a36Sopenharmony_ci	} else {
124262306a36Sopenharmony_ci		kdb_printf("\nEntering kdb (current=0x%px, pid %d) ",
124362306a36Sopenharmony_ci			   kdb_current, kdb_current ? kdb_current->pid : 0);
124462306a36Sopenharmony_ci#if defined(CONFIG_SMP)
124562306a36Sopenharmony_ci		kdb_printf("on processor %d ", raw_smp_processor_id());
124662306a36Sopenharmony_ci#endif
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	switch (reason) {
125062306a36Sopenharmony_ci	case KDB_REASON_DEBUG:
125162306a36Sopenharmony_ci	{
125262306a36Sopenharmony_ci		/*
125362306a36Sopenharmony_ci		 * If re-entering kdb after a single step
125462306a36Sopenharmony_ci		 * command, don't print the message.
125562306a36Sopenharmony_ci		 */
125662306a36Sopenharmony_ci		switch (db_result) {
125762306a36Sopenharmony_ci		case KDB_DB_BPT:
125862306a36Sopenharmony_ci			kdb_printf("\nEntering kdb (0x%px, pid %d) ",
125962306a36Sopenharmony_ci				   kdb_current, kdb_current->pid);
126062306a36Sopenharmony_ci#if defined(CONFIG_SMP)
126162306a36Sopenharmony_ci			kdb_printf("on processor %d ", raw_smp_processor_id());
126262306a36Sopenharmony_ci#endif
126362306a36Sopenharmony_ci			kdb_printf("due to Debug @ " kdb_machreg_fmt "\n",
126462306a36Sopenharmony_ci				   instruction_pointer(regs));
126562306a36Sopenharmony_ci			break;
126662306a36Sopenharmony_ci		case KDB_DB_SS:
126762306a36Sopenharmony_ci			break;
126862306a36Sopenharmony_ci		case KDB_DB_SSBPT:
126962306a36Sopenharmony_ci			KDB_DEBUG_STATE("kdb_local 4", reason);
127062306a36Sopenharmony_ci			return 1;	/* kdba_db_trap did the work */
127162306a36Sopenharmony_ci		default:
127262306a36Sopenharmony_ci			kdb_printf("kdb: Bad result from kdba_db_trap: %d\n",
127362306a36Sopenharmony_ci				   db_result);
127462306a36Sopenharmony_ci			break;
127562306a36Sopenharmony_ci		}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	}
127862306a36Sopenharmony_ci		break;
127962306a36Sopenharmony_ci	case KDB_REASON_ENTER:
128062306a36Sopenharmony_ci		if (KDB_STATE(KEYBOARD))
128162306a36Sopenharmony_ci			kdb_printf("due to Keyboard Entry\n");
128262306a36Sopenharmony_ci		else
128362306a36Sopenharmony_ci			kdb_printf("due to KDB_ENTER()\n");
128462306a36Sopenharmony_ci		break;
128562306a36Sopenharmony_ci	case KDB_REASON_KEYBOARD:
128662306a36Sopenharmony_ci		KDB_STATE_SET(KEYBOARD);
128762306a36Sopenharmony_ci		kdb_printf("due to Keyboard Entry\n");
128862306a36Sopenharmony_ci		break;
128962306a36Sopenharmony_ci	case KDB_REASON_ENTER_SLAVE:
129062306a36Sopenharmony_ci		/* drop through, slaves only get released via cpu switch */
129162306a36Sopenharmony_ci	case KDB_REASON_SWITCH:
129262306a36Sopenharmony_ci		kdb_printf("due to cpu switch\n");
129362306a36Sopenharmony_ci		break;
129462306a36Sopenharmony_ci	case KDB_REASON_OOPS:
129562306a36Sopenharmony_ci		kdb_printf("Oops: %s\n", kdb_diemsg);
129662306a36Sopenharmony_ci		kdb_printf("due to oops @ " kdb_machreg_fmt "\n",
129762306a36Sopenharmony_ci			   instruction_pointer(regs));
129862306a36Sopenharmony_ci		kdb_dumpregs(regs);
129962306a36Sopenharmony_ci		break;
130062306a36Sopenharmony_ci	case KDB_REASON_SYSTEM_NMI:
130162306a36Sopenharmony_ci		kdb_printf("due to System NonMaskable Interrupt\n");
130262306a36Sopenharmony_ci		break;
130362306a36Sopenharmony_ci	case KDB_REASON_NMI:
130462306a36Sopenharmony_ci		kdb_printf("due to NonMaskable Interrupt @ "
130562306a36Sopenharmony_ci			   kdb_machreg_fmt "\n",
130662306a36Sopenharmony_ci			   instruction_pointer(regs));
130762306a36Sopenharmony_ci		break;
130862306a36Sopenharmony_ci	case KDB_REASON_SSTEP:
130962306a36Sopenharmony_ci	case KDB_REASON_BREAK:
131062306a36Sopenharmony_ci		kdb_printf("due to %s @ " kdb_machreg_fmt "\n",
131162306a36Sopenharmony_ci			   reason == KDB_REASON_BREAK ?
131262306a36Sopenharmony_ci			   "Breakpoint" : "SS trap", instruction_pointer(regs));
131362306a36Sopenharmony_ci		/*
131462306a36Sopenharmony_ci		 * Determine if this breakpoint is one that we
131562306a36Sopenharmony_ci		 * are interested in.
131662306a36Sopenharmony_ci		 */
131762306a36Sopenharmony_ci		if (db_result != KDB_DB_BPT) {
131862306a36Sopenharmony_ci			kdb_printf("kdb: error return from kdba_bp_trap: %d\n",
131962306a36Sopenharmony_ci				   db_result);
132062306a36Sopenharmony_ci			KDB_DEBUG_STATE("kdb_local 6", reason);
132162306a36Sopenharmony_ci			return 0;	/* Not for us, dismiss it */
132262306a36Sopenharmony_ci		}
132362306a36Sopenharmony_ci		break;
132462306a36Sopenharmony_ci	case KDB_REASON_RECURSE:
132562306a36Sopenharmony_ci		kdb_printf("due to Recursion @ " kdb_machreg_fmt "\n",
132662306a36Sopenharmony_ci			   instruction_pointer(regs));
132762306a36Sopenharmony_ci		break;
132862306a36Sopenharmony_ci	default:
132962306a36Sopenharmony_ci		kdb_printf("kdb: unexpected reason code: %d\n", reason);
133062306a36Sopenharmony_ci		KDB_DEBUG_STATE("kdb_local 8", reason);
133162306a36Sopenharmony_ci		return 0;	/* Not for us, dismiss it */
133262306a36Sopenharmony_ci	}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	while (1) {
133562306a36Sopenharmony_ci		/*
133662306a36Sopenharmony_ci		 * Initialize pager context.
133762306a36Sopenharmony_ci		 */
133862306a36Sopenharmony_ci		kdb_nextline = 1;
133962306a36Sopenharmony_ci		KDB_STATE_CLEAR(SUPPRESS);
134062306a36Sopenharmony_ci		kdb_grepping_flag = 0;
134162306a36Sopenharmony_ci		/* ensure the old search does not leak into '/' commands */
134262306a36Sopenharmony_ci		kdb_grep_string[0] = '\0';
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci		cmdbuf = cmd_cur;
134562306a36Sopenharmony_ci		*cmdbuf = '\0';
134662306a36Sopenharmony_ci		*(cmd_hist[cmd_head]) = '\0';
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_cido_full_getstr:
134962306a36Sopenharmony_ci		/* PROMPT can only be set if we have MEM_READ permission. */
135062306a36Sopenharmony_ci		snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"),
135162306a36Sopenharmony_ci			 raw_smp_processor_id());
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci		/*
135462306a36Sopenharmony_ci		 * Fetch command from keyboard
135562306a36Sopenharmony_ci		 */
135662306a36Sopenharmony_ci		cmdbuf = kdb_getstr(cmdbuf, CMD_BUFLEN, kdb_prompt_str);
135762306a36Sopenharmony_ci		if (*cmdbuf != '\n') {
135862306a36Sopenharmony_ci			if (*cmdbuf < 32) {
135962306a36Sopenharmony_ci				if (cmdptr == cmd_head) {
136062306a36Sopenharmony_ci					strscpy(cmd_hist[cmd_head], cmd_cur,
136162306a36Sopenharmony_ci						CMD_BUFLEN);
136262306a36Sopenharmony_ci					*(cmd_hist[cmd_head] +
136362306a36Sopenharmony_ci					  strlen(cmd_hist[cmd_head])-1) = '\0';
136462306a36Sopenharmony_ci				}
136562306a36Sopenharmony_ci				if (!handle_ctrl_cmd(cmdbuf))
136662306a36Sopenharmony_ci					*(cmd_cur+strlen(cmd_cur)-1) = '\0';
136762306a36Sopenharmony_ci				cmdbuf = cmd_cur;
136862306a36Sopenharmony_ci				goto do_full_getstr;
136962306a36Sopenharmony_ci			} else {
137062306a36Sopenharmony_ci				strscpy(cmd_hist[cmd_head], cmd_cur,
137162306a36Sopenharmony_ci					CMD_BUFLEN);
137262306a36Sopenharmony_ci			}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci			cmd_head = (cmd_head+1) % KDB_CMD_HISTORY_COUNT;
137562306a36Sopenharmony_ci			if (cmd_head == cmd_tail)
137662306a36Sopenharmony_ci				cmd_tail = (cmd_tail+1) % KDB_CMD_HISTORY_COUNT;
137762306a36Sopenharmony_ci		}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci		cmdptr = cmd_head;
138062306a36Sopenharmony_ci		diag = kdb_parse(cmdbuf);
138162306a36Sopenharmony_ci		if (diag == KDB_NOTFOUND) {
138262306a36Sopenharmony_ci			drop_newline(cmdbuf);
138362306a36Sopenharmony_ci			kdb_printf("Unknown kdb command: '%s'\n", cmdbuf);
138462306a36Sopenharmony_ci			diag = 0;
138562306a36Sopenharmony_ci		}
138662306a36Sopenharmony_ci		if (diag == KDB_CMD_GO
138762306a36Sopenharmony_ci		 || diag == KDB_CMD_CPU
138862306a36Sopenharmony_ci		 || diag == KDB_CMD_SS
138962306a36Sopenharmony_ci		 || diag == KDB_CMD_KGDB)
139062306a36Sopenharmony_ci			break;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci		if (diag)
139362306a36Sopenharmony_ci			kdb_cmderror(diag);
139462306a36Sopenharmony_ci	}
139562306a36Sopenharmony_ci	KDB_DEBUG_STATE("kdb_local 9", diag);
139662306a36Sopenharmony_ci	return diag;
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci/*
140162306a36Sopenharmony_ci * kdb_print_state - Print the state data for the current processor
140262306a36Sopenharmony_ci *	for debugging.
140362306a36Sopenharmony_ci * Inputs:
140462306a36Sopenharmony_ci *	text		Identifies the debug point
140562306a36Sopenharmony_ci *	value		Any integer value to be printed, e.g. reason code.
140662306a36Sopenharmony_ci */
140762306a36Sopenharmony_civoid kdb_print_state(const char *text, int value)
140862306a36Sopenharmony_ci{
140962306a36Sopenharmony_ci	kdb_printf("state: %s cpu %d value %d initial %d state %x\n",
141062306a36Sopenharmony_ci		   text, raw_smp_processor_id(), value, kdb_initial_cpu,
141162306a36Sopenharmony_ci		   kdb_state);
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci/*
141562306a36Sopenharmony_ci * kdb_main_loop - After initial setup and assignment of the
141662306a36Sopenharmony_ci *	controlling cpu, all cpus are in this loop.  One cpu is in
141762306a36Sopenharmony_ci *	control and will issue the kdb prompt, the others will spin
141862306a36Sopenharmony_ci *	until 'go' or cpu switch.
141962306a36Sopenharmony_ci *
142062306a36Sopenharmony_ci *	To get a consistent view of the kernel stacks for all
142162306a36Sopenharmony_ci *	processes, this routine is invoked from the main kdb code via
142262306a36Sopenharmony_ci *	an architecture specific routine.  kdba_main_loop is
142362306a36Sopenharmony_ci *	responsible for making the kernel stacks consistent for all
142462306a36Sopenharmony_ci *	processes, there should be no difference between a blocked
142562306a36Sopenharmony_ci *	process and a running process as far as kdb is concerned.
142662306a36Sopenharmony_ci * Inputs:
142762306a36Sopenharmony_ci *	reason		The reason KDB was invoked
142862306a36Sopenharmony_ci *	error		The hardware-defined error code
142962306a36Sopenharmony_ci *	reason2		kdb's current reason code.
143062306a36Sopenharmony_ci *			Initially error but can change
143162306a36Sopenharmony_ci *			according to kdb state.
143262306a36Sopenharmony_ci *	db_result	Result code from break or debug point.
143362306a36Sopenharmony_ci *	regs		The exception frame at time of fault/breakpoint.
143462306a36Sopenharmony_ci *			should always be valid.
143562306a36Sopenharmony_ci * Returns:
143662306a36Sopenharmony_ci *	0	KDB was invoked for an event which it wasn't responsible
143762306a36Sopenharmony_ci *	1	KDB handled the event for which it was invoked.
143862306a36Sopenharmony_ci */
143962306a36Sopenharmony_ciint kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
144062306a36Sopenharmony_ci	      kdb_dbtrap_t db_result, struct pt_regs *regs)
144162306a36Sopenharmony_ci{
144262306a36Sopenharmony_ci	int result = 1;
144362306a36Sopenharmony_ci	/* Stay in kdb() until 'go', 'ss[b]' or an error */
144462306a36Sopenharmony_ci	while (1) {
144562306a36Sopenharmony_ci		/*
144662306a36Sopenharmony_ci		 * All processors except the one that is in control
144762306a36Sopenharmony_ci		 * will spin here.
144862306a36Sopenharmony_ci		 */
144962306a36Sopenharmony_ci		KDB_DEBUG_STATE("kdb_main_loop 1", reason);
145062306a36Sopenharmony_ci		while (KDB_STATE(HOLD_CPU)) {
145162306a36Sopenharmony_ci			/* state KDB is turned off by kdb_cpu to see if the
145262306a36Sopenharmony_ci			 * other cpus are still live, each cpu in this loop
145362306a36Sopenharmony_ci			 * turns it back on.
145462306a36Sopenharmony_ci			 */
145562306a36Sopenharmony_ci			if (!KDB_STATE(KDB))
145662306a36Sopenharmony_ci				KDB_STATE_SET(KDB);
145762306a36Sopenharmony_ci		}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci		KDB_STATE_CLEAR(SUPPRESS);
146062306a36Sopenharmony_ci		KDB_DEBUG_STATE("kdb_main_loop 2", reason);
146162306a36Sopenharmony_ci		if (KDB_STATE(LEAVING))
146262306a36Sopenharmony_ci			break;	/* Another cpu said 'go' */
146362306a36Sopenharmony_ci		/* Still using kdb, this processor is in control */
146462306a36Sopenharmony_ci		result = kdb_local(reason2, error, regs, db_result);
146562306a36Sopenharmony_ci		KDB_DEBUG_STATE("kdb_main_loop 3", result);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci		if (result == KDB_CMD_CPU)
146862306a36Sopenharmony_ci			break;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci		if (result == KDB_CMD_SS) {
147162306a36Sopenharmony_ci			KDB_STATE_SET(DOING_SS);
147262306a36Sopenharmony_ci			break;
147362306a36Sopenharmony_ci		}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci		if (result == KDB_CMD_KGDB) {
147662306a36Sopenharmony_ci			if (!KDB_STATE(DOING_KGDB))
147762306a36Sopenharmony_ci				kdb_printf("Entering please attach debugger "
147862306a36Sopenharmony_ci					   "or use $D#44+ or $3#33\n");
147962306a36Sopenharmony_ci			break;
148062306a36Sopenharmony_ci		}
148162306a36Sopenharmony_ci		if (result && result != 1 && result != KDB_CMD_GO)
148262306a36Sopenharmony_ci			kdb_printf("\nUnexpected kdb_local return code %d\n",
148362306a36Sopenharmony_ci				   result);
148462306a36Sopenharmony_ci		KDB_DEBUG_STATE("kdb_main_loop 4", reason);
148562306a36Sopenharmony_ci		break;
148662306a36Sopenharmony_ci	}
148762306a36Sopenharmony_ci	if (KDB_STATE(DOING_SS))
148862306a36Sopenharmony_ci		KDB_STATE_CLEAR(SSBPT);
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	/* Clean up any keyboard devices before leaving */
149162306a36Sopenharmony_ci	kdb_kbd_cleanup_state();
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	return result;
149462306a36Sopenharmony_ci}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci/*
149762306a36Sopenharmony_ci * kdb_mdr - This function implements the guts of the 'mdr', memory
149862306a36Sopenharmony_ci * read command.
149962306a36Sopenharmony_ci *	mdr  <addr arg>,<byte count>
150062306a36Sopenharmony_ci * Inputs:
150162306a36Sopenharmony_ci *	addr	Start address
150262306a36Sopenharmony_ci *	count	Number of bytes
150362306a36Sopenharmony_ci * Returns:
150462306a36Sopenharmony_ci *	Always 0.  Any errors are detected and printed by kdb_getarea.
150562306a36Sopenharmony_ci */
150662306a36Sopenharmony_cistatic int kdb_mdr(unsigned long addr, unsigned int count)
150762306a36Sopenharmony_ci{
150862306a36Sopenharmony_ci	unsigned char c;
150962306a36Sopenharmony_ci	while (count--) {
151062306a36Sopenharmony_ci		if (kdb_getarea(c, addr))
151162306a36Sopenharmony_ci			return 0;
151262306a36Sopenharmony_ci		kdb_printf("%02x", c);
151362306a36Sopenharmony_ci		addr++;
151462306a36Sopenharmony_ci	}
151562306a36Sopenharmony_ci	kdb_printf("\n");
151662306a36Sopenharmony_ci	return 0;
151762306a36Sopenharmony_ci}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci/*
152062306a36Sopenharmony_ci * kdb_md - This function implements the 'md', 'md1', 'md2', 'md4',
152162306a36Sopenharmony_ci *	'md8' 'mdr' and 'mds' commands.
152262306a36Sopenharmony_ci *
152362306a36Sopenharmony_ci *	md|mds  [<addr arg> [<line count> [<radix>]]]
152462306a36Sopenharmony_ci *	mdWcN	[<addr arg> [<line count> [<radix>]]]
152562306a36Sopenharmony_ci *		where W = is the width (1, 2, 4 or 8) and N is the count.
152662306a36Sopenharmony_ci *		for eg., md1c20 reads 20 bytes, 1 at a time.
152762306a36Sopenharmony_ci *	mdr  <addr arg>,<byte count>
152862306a36Sopenharmony_ci */
152962306a36Sopenharmony_cistatic void kdb_md_line(const char *fmtstr, unsigned long addr,
153062306a36Sopenharmony_ci			int symbolic, int nosect, int bytesperword,
153162306a36Sopenharmony_ci			int num, int repeat, int phys)
153262306a36Sopenharmony_ci{
153362306a36Sopenharmony_ci	/* print just one line of data */
153462306a36Sopenharmony_ci	kdb_symtab_t symtab;
153562306a36Sopenharmony_ci	char cbuf[32];
153662306a36Sopenharmony_ci	char *c = cbuf;
153762306a36Sopenharmony_ci	int i;
153862306a36Sopenharmony_ci	int j;
153962306a36Sopenharmony_ci	unsigned long word;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	memset(cbuf, '\0', sizeof(cbuf));
154262306a36Sopenharmony_ci	if (phys)
154362306a36Sopenharmony_ci		kdb_printf("phys " kdb_machreg_fmt0 " ", addr);
154462306a36Sopenharmony_ci	else
154562306a36Sopenharmony_ci		kdb_printf(kdb_machreg_fmt0 " ", addr);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	for (i = 0; i < num && repeat--; i++) {
154862306a36Sopenharmony_ci		if (phys) {
154962306a36Sopenharmony_ci			if (kdb_getphysword(&word, addr, bytesperword))
155062306a36Sopenharmony_ci				break;
155162306a36Sopenharmony_ci		} else if (kdb_getword(&word, addr, bytesperword))
155262306a36Sopenharmony_ci			break;
155362306a36Sopenharmony_ci		kdb_printf(fmtstr, word);
155462306a36Sopenharmony_ci		if (symbolic)
155562306a36Sopenharmony_ci			kdbnearsym(word, &symtab);
155662306a36Sopenharmony_ci		else
155762306a36Sopenharmony_ci			memset(&symtab, 0, sizeof(symtab));
155862306a36Sopenharmony_ci		if (symtab.sym_name) {
155962306a36Sopenharmony_ci			kdb_symbol_print(word, &symtab, 0);
156062306a36Sopenharmony_ci			if (!nosect) {
156162306a36Sopenharmony_ci				kdb_printf("\n");
156262306a36Sopenharmony_ci				kdb_printf("                       %s %s "
156362306a36Sopenharmony_ci					   kdb_machreg_fmt " "
156462306a36Sopenharmony_ci					   kdb_machreg_fmt " "
156562306a36Sopenharmony_ci					   kdb_machreg_fmt, symtab.mod_name,
156662306a36Sopenharmony_ci					   symtab.sec_name, symtab.sec_start,
156762306a36Sopenharmony_ci					   symtab.sym_start, symtab.sym_end);
156862306a36Sopenharmony_ci			}
156962306a36Sopenharmony_ci			addr += bytesperword;
157062306a36Sopenharmony_ci		} else {
157162306a36Sopenharmony_ci			union {
157262306a36Sopenharmony_ci				u64 word;
157362306a36Sopenharmony_ci				unsigned char c[8];
157462306a36Sopenharmony_ci			} wc;
157562306a36Sopenharmony_ci			unsigned char *cp;
157662306a36Sopenharmony_ci#ifdef	__BIG_ENDIAN
157762306a36Sopenharmony_ci			cp = wc.c + 8 - bytesperword;
157862306a36Sopenharmony_ci#else
157962306a36Sopenharmony_ci			cp = wc.c;
158062306a36Sopenharmony_ci#endif
158162306a36Sopenharmony_ci			wc.word = word;
158262306a36Sopenharmony_ci#define printable_char(c) \
158362306a36Sopenharmony_ci	({unsigned char __c = c; isascii(__c) && isprint(__c) ? __c : '.'; })
158462306a36Sopenharmony_ci			for (j = 0; j < bytesperword; j++)
158562306a36Sopenharmony_ci				*c++ = printable_char(*cp++);
158662306a36Sopenharmony_ci			addr += bytesperword;
158762306a36Sopenharmony_ci#undef printable_char
158862306a36Sopenharmony_ci		}
158962306a36Sopenharmony_ci	}
159062306a36Sopenharmony_ci	kdb_printf("%*s %s\n", (int)((num-i)*(2*bytesperword + 1)+1),
159162306a36Sopenharmony_ci		   " ", cbuf);
159262306a36Sopenharmony_ci}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_cistatic int kdb_md(int argc, const char **argv)
159562306a36Sopenharmony_ci{
159662306a36Sopenharmony_ci	static unsigned long last_addr;
159762306a36Sopenharmony_ci	static int last_radix, last_bytesperword, last_repeat;
159862306a36Sopenharmony_ci	int radix = 16, mdcount = 8, bytesperword = KDB_WORD_SIZE, repeat;
159962306a36Sopenharmony_ci	int nosect = 0;
160062306a36Sopenharmony_ci	char fmtchar, fmtstr[64];
160162306a36Sopenharmony_ci	unsigned long addr;
160262306a36Sopenharmony_ci	unsigned long word;
160362306a36Sopenharmony_ci	long offset = 0;
160462306a36Sopenharmony_ci	int symbolic = 0;
160562306a36Sopenharmony_ci	int valid = 0;
160662306a36Sopenharmony_ci	int phys = 0;
160762306a36Sopenharmony_ci	int raw = 0;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	kdbgetintenv("MDCOUNT", &mdcount);
161062306a36Sopenharmony_ci	kdbgetintenv("RADIX", &radix);
161162306a36Sopenharmony_ci	kdbgetintenv("BYTESPERWORD", &bytesperword);
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	/* Assume 'md <addr>' and start with environment values */
161462306a36Sopenharmony_ci	repeat = mdcount * 16 / bytesperword;
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	if (strcmp(argv[0], "mdr") == 0) {
161762306a36Sopenharmony_ci		if (argc == 2 || (argc == 0 && last_addr != 0))
161862306a36Sopenharmony_ci			valid = raw = 1;
161962306a36Sopenharmony_ci		else
162062306a36Sopenharmony_ci			return KDB_ARGCOUNT;
162162306a36Sopenharmony_ci	} else if (isdigit(argv[0][2])) {
162262306a36Sopenharmony_ci		bytesperword = (int)(argv[0][2] - '0');
162362306a36Sopenharmony_ci		if (bytesperword == 0) {
162462306a36Sopenharmony_ci			bytesperword = last_bytesperword;
162562306a36Sopenharmony_ci			if (bytesperword == 0)
162662306a36Sopenharmony_ci				bytesperword = 4;
162762306a36Sopenharmony_ci		}
162862306a36Sopenharmony_ci		last_bytesperword = bytesperword;
162962306a36Sopenharmony_ci		repeat = mdcount * 16 / bytesperword;
163062306a36Sopenharmony_ci		if (!argv[0][3])
163162306a36Sopenharmony_ci			valid = 1;
163262306a36Sopenharmony_ci		else if (argv[0][3] == 'c' && argv[0][4]) {
163362306a36Sopenharmony_ci			char *p;
163462306a36Sopenharmony_ci			repeat = simple_strtoul(argv[0] + 4, &p, 10);
163562306a36Sopenharmony_ci			mdcount = ((repeat * bytesperword) + 15) / 16;
163662306a36Sopenharmony_ci			valid = !*p;
163762306a36Sopenharmony_ci		}
163862306a36Sopenharmony_ci		last_repeat = repeat;
163962306a36Sopenharmony_ci	} else if (strcmp(argv[0], "md") == 0)
164062306a36Sopenharmony_ci		valid = 1;
164162306a36Sopenharmony_ci	else if (strcmp(argv[0], "mds") == 0)
164262306a36Sopenharmony_ci		valid = 1;
164362306a36Sopenharmony_ci	else if (strcmp(argv[0], "mdp") == 0) {
164462306a36Sopenharmony_ci		phys = valid = 1;
164562306a36Sopenharmony_ci	}
164662306a36Sopenharmony_ci	if (!valid)
164762306a36Sopenharmony_ci		return KDB_NOTFOUND;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	if (argc == 0) {
165062306a36Sopenharmony_ci		if (last_addr == 0)
165162306a36Sopenharmony_ci			return KDB_ARGCOUNT;
165262306a36Sopenharmony_ci		addr = last_addr;
165362306a36Sopenharmony_ci		radix = last_radix;
165462306a36Sopenharmony_ci		bytesperword = last_bytesperword;
165562306a36Sopenharmony_ci		repeat = last_repeat;
165662306a36Sopenharmony_ci		if (raw)
165762306a36Sopenharmony_ci			mdcount = repeat;
165862306a36Sopenharmony_ci		else
165962306a36Sopenharmony_ci			mdcount = ((repeat * bytesperword) + 15) / 16;
166062306a36Sopenharmony_ci	}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	if (argc) {
166362306a36Sopenharmony_ci		unsigned long val;
166462306a36Sopenharmony_ci		int diag, nextarg = 1;
166562306a36Sopenharmony_ci		diag = kdbgetaddrarg(argc, argv, &nextarg, &addr,
166662306a36Sopenharmony_ci				     &offset, NULL);
166762306a36Sopenharmony_ci		if (diag)
166862306a36Sopenharmony_ci			return diag;
166962306a36Sopenharmony_ci		if (argc > nextarg+2)
167062306a36Sopenharmony_ci			return KDB_ARGCOUNT;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci		if (argc >= nextarg) {
167362306a36Sopenharmony_ci			diag = kdbgetularg(argv[nextarg], &val);
167462306a36Sopenharmony_ci			if (!diag) {
167562306a36Sopenharmony_ci				mdcount = (int) val;
167662306a36Sopenharmony_ci				if (raw)
167762306a36Sopenharmony_ci					repeat = mdcount;
167862306a36Sopenharmony_ci				else
167962306a36Sopenharmony_ci					repeat = mdcount * 16 / bytesperword;
168062306a36Sopenharmony_ci			}
168162306a36Sopenharmony_ci		}
168262306a36Sopenharmony_ci		if (argc >= nextarg+1) {
168362306a36Sopenharmony_ci			diag = kdbgetularg(argv[nextarg+1], &val);
168462306a36Sopenharmony_ci			if (!diag)
168562306a36Sopenharmony_ci				radix = (int) val;
168662306a36Sopenharmony_ci		}
168762306a36Sopenharmony_ci	}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	if (strcmp(argv[0], "mdr") == 0) {
169062306a36Sopenharmony_ci		int ret;
169162306a36Sopenharmony_ci		last_addr = addr;
169262306a36Sopenharmony_ci		ret = kdb_mdr(addr, mdcount);
169362306a36Sopenharmony_ci		last_addr += mdcount;
169462306a36Sopenharmony_ci		last_repeat = mdcount;
169562306a36Sopenharmony_ci		last_bytesperword = bytesperword; // to make REPEAT happy
169662306a36Sopenharmony_ci		return ret;
169762306a36Sopenharmony_ci	}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	switch (radix) {
170062306a36Sopenharmony_ci	case 10:
170162306a36Sopenharmony_ci		fmtchar = 'd';
170262306a36Sopenharmony_ci		break;
170362306a36Sopenharmony_ci	case 16:
170462306a36Sopenharmony_ci		fmtchar = 'x';
170562306a36Sopenharmony_ci		break;
170662306a36Sopenharmony_ci	case 8:
170762306a36Sopenharmony_ci		fmtchar = 'o';
170862306a36Sopenharmony_ci		break;
170962306a36Sopenharmony_ci	default:
171062306a36Sopenharmony_ci		return KDB_BADRADIX;
171162306a36Sopenharmony_ci	}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	last_radix = radix;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	if (bytesperword > KDB_WORD_SIZE)
171662306a36Sopenharmony_ci		return KDB_BADWIDTH;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	switch (bytesperword) {
171962306a36Sopenharmony_ci	case 8:
172062306a36Sopenharmony_ci		sprintf(fmtstr, "%%16.16l%c ", fmtchar);
172162306a36Sopenharmony_ci		break;
172262306a36Sopenharmony_ci	case 4:
172362306a36Sopenharmony_ci		sprintf(fmtstr, "%%8.8l%c ", fmtchar);
172462306a36Sopenharmony_ci		break;
172562306a36Sopenharmony_ci	case 2:
172662306a36Sopenharmony_ci		sprintf(fmtstr, "%%4.4l%c ", fmtchar);
172762306a36Sopenharmony_ci		break;
172862306a36Sopenharmony_ci	case 1:
172962306a36Sopenharmony_ci		sprintf(fmtstr, "%%2.2l%c ", fmtchar);
173062306a36Sopenharmony_ci		break;
173162306a36Sopenharmony_ci	default:
173262306a36Sopenharmony_ci		return KDB_BADWIDTH;
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	last_repeat = repeat;
173662306a36Sopenharmony_ci	last_bytesperword = bytesperword;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	if (strcmp(argv[0], "mds") == 0) {
173962306a36Sopenharmony_ci		symbolic = 1;
174062306a36Sopenharmony_ci		/* Do not save these changes as last_*, they are temporary mds
174162306a36Sopenharmony_ci		 * overrides.
174262306a36Sopenharmony_ci		 */
174362306a36Sopenharmony_ci		bytesperword = KDB_WORD_SIZE;
174462306a36Sopenharmony_ci		repeat = mdcount;
174562306a36Sopenharmony_ci		kdbgetintenv("NOSECT", &nosect);
174662306a36Sopenharmony_ci	}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	/* Round address down modulo BYTESPERWORD */
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	addr &= ~(bytesperword-1);
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	while (repeat > 0) {
175362306a36Sopenharmony_ci		unsigned long a;
175462306a36Sopenharmony_ci		int n, z, num = (symbolic ? 1 : (16 / bytesperword));
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci		if (KDB_FLAG(CMD_INTERRUPT))
175762306a36Sopenharmony_ci			return 0;
175862306a36Sopenharmony_ci		for (a = addr, z = 0; z < repeat; a += bytesperword, ++z) {
175962306a36Sopenharmony_ci			if (phys) {
176062306a36Sopenharmony_ci				if (kdb_getphysword(&word, a, bytesperword)
176162306a36Sopenharmony_ci						|| word)
176262306a36Sopenharmony_ci					break;
176362306a36Sopenharmony_ci			} else if (kdb_getword(&word, a, bytesperword) || word)
176462306a36Sopenharmony_ci				break;
176562306a36Sopenharmony_ci		}
176662306a36Sopenharmony_ci		n = min(num, repeat);
176762306a36Sopenharmony_ci		kdb_md_line(fmtstr, addr, symbolic, nosect, bytesperword,
176862306a36Sopenharmony_ci			    num, repeat, phys);
176962306a36Sopenharmony_ci		addr += bytesperword * n;
177062306a36Sopenharmony_ci		repeat -= n;
177162306a36Sopenharmony_ci		z = (z + num - 1) / num;
177262306a36Sopenharmony_ci		if (z > 2) {
177362306a36Sopenharmony_ci			int s = num * (z-2);
177462306a36Sopenharmony_ci			kdb_printf(kdb_machreg_fmt0 "-" kdb_machreg_fmt0
177562306a36Sopenharmony_ci				   " zero suppressed\n",
177662306a36Sopenharmony_ci				addr, addr + bytesperword * s - 1);
177762306a36Sopenharmony_ci			addr += bytesperword * s;
177862306a36Sopenharmony_ci			repeat -= s;
177962306a36Sopenharmony_ci		}
178062306a36Sopenharmony_ci	}
178162306a36Sopenharmony_ci	last_addr = addr;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	return 0;
178462306a36Sopenharmony_ci}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci/*
178762306a36Sopenharmony_ci * kdb_mm - This function implements the 'mm' command.
178862306a36Sopenharmony_ci *	mm address-expression new-value
178962306a36Sopenharmony_ci * Remarks:
179062306a36Sopenharmony_ci *	mm works on machine words, mmW works on bytes.
179162306a36Sopenharmony_ci */
179262306a36Sopenharmony_cistatic int kdb_mm(int argc, const char **argv)
179362306a36Sopenharmony_ci{
179462306a36Sopenharmony_ci	int diag;
179562306a36Sopenharmony_ci	unsigned long addr;
179662306a36Sopenharmony_ci	long offset = 0;
179762306a36Sopenharmony_ci	unsigned long contents;
179862306a36Sopenharmony_ci	int nextarg;
179962306a36Sopenharmony_ci	int width;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	if (argv[0][2] && !isdigit(argv[0][2]))
180262306a36Sopenharmony_ci		return KDB_NOTFOUND;
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	if (argc < 2)
180562306a36Sopenharmony_ci		return KDB_ARGCOUNT;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	nextarg = 1;
180862306a36Sopenharmony_ci	diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL);
180962306a36Sopenharmony_ci	if (diag)
181062306a36Sopenharmony_ci		return diag;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	if (nextarg > argc)
181362306a36Sopenharmony_ci		return KDB_ARGCOUNT;
181462306a36Sopenharmony_ci	diag = kdbgetaddrarg(argc, argv, &nextarg, &contents, NULL, NULL);
181562306a36Sopenharmony_ci	if (diag)
181662306a36Sopenharmony_ci		return diag;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	if (nextarg != argc + 1)
181962306a36Sopenharmony_ci		return KDB_ARGCOUNT;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	width = argv[0][2] ? (argv[0][2] - '0') : (KDB_WORD_SIZE);
182262306a36Sopenharmony_ci	diag = kdb_putword(addr, contents, width);
182362306a36Sopenharmony_ci	if (diag)
182462306a36Sopenharmony_ci		return diag;
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	kdb_printf(kdb_machreg_fmt " = " kdb_machreg_fmt "\n", addr, contents);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	return 0;
182962306a36Sopenharmony_ci}
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci/*
183262306a36Sopenharmony_ci * kdb_go - This function implements the 'go' command.
183362306a36Sopenharmony_ci *	go [address-expression]
183462306a36Sopenharmony_ci */
183562306a36Sopenharmony_cistatic int kdb_go(int argc, const char **argv)
183662306a36Sopenharmony_ci{
183762306a36Sopenharmony_ci	unsigned long addr;
183862306a36Sopenharmony_ci	int diag;
183962306a36Sopenharmony_ci	int nextarg;
184062306a36Sopenharmony_ci	long offset;
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	if (raw_smp_processor_id() != kdb_initial_cpu) {
184362306a36Sopenharmony_ci		kdb_printf("go must execute on the entry cpu, "
184462306a36Sopenharmony_ci			   "please use \"cpu %d\" and then execute go\n",
184562306a36Sopenharmony_ci			   kdb_initial_cpu);
184662306a36Sopenharmony_ci		return KDB_BADCPUNUM;
184762306a36Sopenharmony_ci	}
184862306a36Sopenharmony_ci	if (argc == 1) {
184962306a36Sopenharmony_ci		nextarg = 1;
185062306a36Sopenharmony_ci		diag = kdbgetaddrarg(argc, argv, &nextarg,
185162306a36Sopenharmony_ci				     &addr, &offset, NULL);
185262306a36Sopenharmony_ci		if (diag)
185362306a36Sopenharmony_ci			return diag;
185462306a36Sopenharmony_ci	} else if (argc) {
185562306a36Sopenharmony_ci		return KDB_ARGCOUNT;
185662306a36Sopenharmony_ci	}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	diag = KDB_CMD_GO;
185962306a36Sopenharmony_ci	if (KDB_FLAG(CATASTROPHIC)) {
186062306a36Sopenharmony_ci		kdb_printf("Catastrophic error detected\n");
186162306a36Sopenharmony_ci		kdb_printf("kdb_continue_catastrophic=%d, ",
186262306a36Sopenharmony_ci			kdb_continue_catastrophic);
186362306a36Sopenharmony_ci		if (kdb_continue_catastrophic == 0 && kdb_go_count++ == 0) {
186462306a36Sopenharmony_ci			kdb_printf("type go a second time if you really want "
186562306a36Sopenharmony_ci				   "to continue\n");
186662306a36Sopenharmony_ci			return 0;
186762306a36Sopenharmony_ci		}
186862306a36Sopenharmony_ci		if (kdb_continue_catastrophic == 2) {
186962306a36Sopenharmony_ci			kdb_printf("forcing reboot\n");
187062306a36Sopenharmony_ci			kdb_reboot(0, NULL);
187162306a36Sopenharmony_ci		}
187262306a36Sopenharmony_ci		kdb_printf("attempting to continue\n");
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci	return diag;
187562306a36Sopenharmony_ci}
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci/*
187862306a36Sopenharmony_ci * kdb_rd - This function implements the 'rd' command.
187962306a36Sopenharmony_ci */
188062306a36Sopenharmony_cistatic int kdb_rd(int argc, const char **argv)
188162306a36Sopenharmony_ci{
188262306a36Sopenharmony_ci	int len = kdb_check_regs();
188362306a36Sopenharmony_ci#if DBG_MAX_REG_NUM > 0
188462306a36Sopenharmony_ci	int i;
188562306a36Sopenharmony_ci	char *rname;
188662306a36Sopenharmony_ci	int rsize;
188762306a36Sopenharmony_ci	u64 reg64;
188862306a36Sopenharmony_ci	u32 reg32;
188962306a36Sopenharmony_ci	u16 reg16;
189062306a36Sopenharmony_ci	u8 reg8;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	if (len)
189362306a36Sopenharmony_ci		return len;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	for (i = 0; i < DBG_MAX_REG_NUM; i++) {
189662306a36Sopenharmony_ci		rsize = dbg_reg_def[i].size * 2;
189762306a36Sopenharmony_ci		if (rsize > 16)
189862306a36Sopenharmony_ci			rsize = 2;
189962306a36Sopenharmony_ci		if (len + strlen(dbg_reg_def[i].name) + 4 + rsize > 80) {
190062306a36Sopenharmony_ci			len = 0;
190162306a36Sopenharmony_ci			kdb_printf("\n");
190262306a36Sopenharmony_ci		}
190362306a36Sopenharmony_ci		if (len)
190462306a36Sopenharmony_ci			len += kdb_printf("  ");
190562306a36Sopenharmony_ci		switch(dbg_reg_def[i].size * 8) {
190662306a36Sopenharmony_ci		case 8:
190762306a36Sopenharmony_ci			rname = dbg_get_reg(i, &reg8, kdb_current_regs);
190862306a36Sopenharmony_ci			if (!rname)
190962306a36Sopenharmony_ci				break;
191062306a36Sopenharmony_ci			len += kdb_printf("%s: %02x", rname, reg8);
191162306a36Sopenharmony_ci			break;
191262306a36Sopenharmony_ci		case 16:
191362306a36Sopenharmony_ci			rname = dbg_get_reg(i, &reg16, kdb_current_regs);
191462306a36Sopenharmony_ci			if (!rname)
191562306a36Sopenharmony_ci				break;
191662306a36Sopenharmony_ci			len += kdb_printf("%s: %04x", rname, reg16);
191762306a36Sopenharmony_ci			break;
191862306a36Sopenharmony_ci		case 32:
191962306a36Sopenharmony_ci			rname = dbg_get_reg(i, &reg32, kdb_current_regs);
192062306a36Sopenharmony_ci			if (!rname)
192162306a36Sopenharmony_ci				break;
192262306a36Sopenharmony_ci			len += kdb_printf("%s: %08x", rname, reg32);
192362306a36Sopenharmony_ci			break;
192462306a36Sopenharmony_ci		case 64:
192562306a36Sopenharmony_ci			rname = dbg_get_reg(i, &reg64, kdb_current_regs);
192662306a36Sopenharmony_ci			if (!rname)
192762306a36Sopenharmony_ci				break;
192862306a36Sopenharmony_ci			len += kdb_printf("%s: %016llx", rname, reg64);
192962306a36Sopenharmony_ci			break;
193062306a36Sopenharmony_ci		default:
193162306a36Sopenharmony_ci			len += kdb_printf("%s: ??", dbg_reg_def[i].name);
193262306a36Sopenharmony_ci		}
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci	kdb_printf("\n");
193562306a36Sopenharmony_ci#else
193662306a36Sopenharmony_ci	if (len)
193762306a36Sopenharmony_ci		return len;
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	kdb_dumpregs(kdb_current_regs);
194062306a36Sopenharmony_ci#endif
194162306a36Sopenharmony_ci	return 0;
194262306a36Sopenharmony_ci}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci/*
194562306a36Sopenharmony_ci * kdb_rm - This function implements the 'rm' (register modify)  command.
194662306a36Sopenharmony_ci *	rm register-name new-contents
194762306a36Sopenharmony_ci * Remarks:
194862306a36Sopenharmony_ci *	Allows register modification with the same restrictions as gdb
194962306a36Sopenharmony_ci */
195062306a36Sopenharmony_cistatic int kdb_rm(int argc, const char **argv)
195162306a36Sopenharmony_ci{
195262306a36Sopenharmony_ci#if DBG_MAX_REG_NUM > 0
195362306a36Sopenharmony_ci	int diag;
195462306a36Sopenharmony_ci	const char *rname;
195562306a36Sopenharmony_ci	int i;
195662306a36Sopenharmony_ci	u64 reg64;
195762306a36Sopenharmony_ci	u32 reg32;
195862306a36Sopenharmony_ci	u16 reg16;
195962306a36Sopenharmony_ci	u8 reg8;
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	if (argc != 2)
196262306a36Sopenharmony_ci		return KDB_ARGCOUNT;
196362306a36Sopenharmony_ci	/*
196462306a36Sopenharmony_ci	 * Allow presence or absence of leading '%' symbol.
196562306a36Sopenharmony_ci	 */
196662306a36Sopenharmony_ci	rname = argv[1];
196762306a36Sopenharmony_ci	if (*rname == '%')
196862306a36Sopenharmony_ci		rname++;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	diag = kdbgetu64arg(argv[2], &reg64);
197162306a36Sopenharmony_ci	if (diag)
197262306a36Sopenharmony_ci		return diag;
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	diag = kdb_check_regs();
197562306a36Sopenharmony_ci	if (diag)
197662306a36Sopenharmony_ci		return diag;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	diag = KDB_BADREG;
197962306a36Sopenharmony_ci	for (i = 0; i < DBG_MAX_REG_NUM; i++) {
198062306a36Sopenharmony_ci		if (strcmp(rname, dbg_reg_def[i].name) == 0) {
198162306a36Sopenharmony_ci			diag = 0;
198262306a36Sopenharmony_ci			break;
198362306a36Sopenharmony_ci		}
198462306a36Sopenharmony_ci	}
198562306a36Sopenharmony_ci	if (!diag) {
198662306a36Sopenharmony_ci		switch(dbg_reg_def[i].size * 8) {
198762306a36Sopenharmony_ci		case 8:
198862306a36Sopenharmony_ci			reg8 = reg64;
198962306a36Sopenharmony_ci			dbg_set_reg(i, &reg8, kdb_current_regs);
199062306a36Sopenharmony_ci			break;
199162306a36Sopenharmony_ci		case 16:
199262306a36Sopenharmony_ci			reg16 = reg64;
199362306a36Sopenharmony_ci			dbg_set_reg(i, &reg16, kdb_current_regs);
199462306a36Sopenharmony_ci			break;
199562306a36Sopenharmony_ci		case 32:
199662306a36Sopenharmony_ci			reg32 = reg64;
199762306a36Sopenharmony_ci			dbg_set_reg(i, &reg32, kdb_current_regs);
199862306a36Sopenharmony_ci			break;
199962306a36Sopenharmony_ci		case 64:
200062306a36Sopenharmony_ci			dbg_set_reg(i, &reg64, kdb_current_regs);
200162306a36Sopenharmony_ci			break;
200262306a36Sopenharmony_ci		}
200362306a36Sopenharmony_ci	}
200462306a36Sopenharmony_ci	return diag;
200562306a36Sopenharmony_ci#else
200662306a36Sopenharmony_ci	kdb_printf("ERROR: Register set currently not implemented\n");
200762306a36Sopenharmony_ci    return 0;
200862306a36Sopenharmony_ci#endif
200962306a36Sopenharmony_ci}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci#if defined(CONFIG_MAGIC_SYSRQ)
201262306a36Sopenharmony_ci/*
201362306a36Sopenharmony_ci * kdb_sr - This function implements the 'sr' (SYSRQ key) command
201462306a36Sopenharmony_ci *	which interfaces to the soi-disant MAGIC SYSRQ functionality.
201562306a36Sopenharmony_ci *		sr <magic-sysrq-code>
201662306a36Sopenharmony_ci */
201762306a36Sopenharmony_cistatic int kdb_sr(int argc, const char **argv)
201862306a36Sopenharmony_ci{
201962306a36Sopenharmony_ci	bool check_mask =
202062306a36Sopenharmony_ci	    !kdb_check_flags(KDB_ENABLE_ALL, kdb_cmd_enabled, false);
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	if (argc != 1)
202362306a36Sopenharmony_ci		return KDB_ARGCOUNT;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	kdb_trap_printk++;
202662306a36Sopenharmony_ci	__handle_sysrq(*argv[1], check_mask);
202762306a36Sopenharmony_ci	kdb_trap_printk--;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	return 0;
203062306a36Sopenharmony_ci}
203162306a36Sopenharmony_ci#endif	/* CONFIG_MAGIC_SYSRQ */
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci/*
203462306a36Sopenharmony_ci * kdb_ef - This function implements the 'regs' (display exception
203562306a36Sopenharmony_ci *	frame) command.  This command takes an address and expects to
203662306a36Sopenharmony_ci *	find an exception frame at that address, formats and prints
203762306a36Sopenharmony_ci *	it.
203862306a36Sopenharmony_ci *		regs address-expression
203962306a36Sopenharmony_ci * Remarks:
204062306a36Sopenharmony_ci *	Not done yet.
204162306a36Sopenharmony_ci */
204262306a36Sopenharmony_cistatic int kdb_ef(int argc, const char **argv)
204362306a36Sopenharmony_ci{
204462306a36Sopenharmony_ci	int diag;
204562306a36Sopenharmony_ci	unsigned long addr;
204662306a36Sopenharmony_ci	long offset;
204762306a36Sopenharmony_ci	int nextarg;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	if (argc != 1)
205062306a36Sopenharmony_ci		return KDB_ARGCOUNT;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	nextarg = 1;
205362306a36Sopenharmony_ci	diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL);
205462306a36Sopenharmony_ci	if (diag)
205562306a36Sopenharmony_ci		return diag;
205662306a36Sopenharmony_ci	show_regs((struct pt_regs *)addr);
205762306a36Sopenharmony_ci	return 0;
205862306a36Sopenharmony_ci}
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci/*
206162306a36Sopenharmony_ci * kdb_env - This function implements the 'env' command.  Display the
206262306a36Sopenharmony_ci *	current environment variables.
206362306a36Sopenharmony_ci */
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_cistatic int kdb_env(int argc, const char **argv)
206662306a36Sopenharmony_ci{
206762306a36Sopenharmony_ci	kdb_printenv();
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	if (KDB_DEBUG(MASK))
207062306a36Sopenharmony_ci		kdb_printf("KDBDEBUG=0x%x\n",
207162306a36Sopenharmony_ci			(kdb_flags & KDB_DEBUG(MASK)) >> KDB_DEBUG_FLAG_SHIFT);
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	return 0;
207462306a36Sopenharmony_ci}
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci#ifdef CONFIG_PRINTK
207762306a36Sopenharmony_ci/*
207862306a36Sopenharmony_ci * kdb_dmesg - This function implements the 'dmesg' command to display
207962306a36Sopenharmony_ci *	the contents of the syslog buffer.
208062306a36Sopenharmony_ci *		dmesg [lines] [adjust]
208162306a36Sopenharmony_ci */
208262306a36Sopenharmony_cistatic int kdb_dmesg(int argc, const char **argv)
208362306a36Sopenharmony_ci{
208462306a36Sopenharmony_ci	int diag;
208562306a36Sopenharmony_ci	int logging;
208662306a36Sopenharmony_ci	int lines = 0;
208762306a36Sopenharmony_ci	int adjust = 0;
208862306a36Sopenharmony_ci	int n = 0;
208962306a36Sopenharmony_ci	int skip = 0;
209062306a36Sopenharmony_ci	struct kmsg_dump_iter iter;
209162306a36Sopenharmony_ci	size_t len;
209262306a36Sopenharmony_ci	char buf[201];
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	if (argc > 2)
209562306a36Sopenharmony_ci		return KDB_ARGCOUNT;
209662306a36Sopenharmony_ci	if (argc) {
209762306a36Sopenharmony_ci		char *cp;
209862306a36Sopenharmony_ci		lines = simple_strtol(argv[1], &cp, 0);
209962306a36Sopenharmony_ci		if (*cp)
210062306a36Sopenharmony_ci			lines = 0;
210162306a36Sopenharmony_ci		if (argc > 1) {
210262306a36Sopenharmony_ci			adjust = simple_strtoul(argv[2], &cp, 0);
210362306a36Sopenharmony_ci			if (*cp || adjust < 0)
210462306a36Sopenharmony_ci				adjust = 0;
210562306a36Sopenharmony_ci		}
210662306a36Sopenharmony_ci	}
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	/* disable LOGGING if set */
210962306a36Sopenharmony_ci	diag = kdbgetintenv("LOGGING", &logging);
211062306a36Sopenharmony_ci	if (!diag && logging) {
211162306a36Sopenharmony_ci		const char *setargs[] = { "set", "LOGGING", "0" };
211262306a36Sopenharmony_ci		kdb_set(2, setargs);
211362306a36Sopenharmony_ci	}
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	kmsg_dump_rewind(&iter);
211662306a36Sopenharmony_ci	while (kmsg_dump_get_line(&iter, 1, NULL, 0, NULL))
211762306a36Sopenharmony_ci		n++;
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	if (lines < 0) {
212062306a36Sopenharmony_ci		if (adjust >= n)
212162306a36Sopenharmony_ci			kdb_printf("buffer only contains %d lines, nothing "
212262306a36Sopenharmony_ci				   "printed\n", n);
212362306a36Sopenharmony_ci		else if (adjust - lines >= n)
212462306a36Sopenharmony_ci			kdb_printf("buffer only contains %d lines, last %d "
212562306a36Sopenharmony_ci				   "lines printed\n", n, n - adjust);
212662306a36Sopenharmony_ci		skip = adjust;
212762306a36Sopenharmony_ci		lines = abs(lines);
212862306a36Sopenharmony_ci	} else if (lines > 0) {
212962306a36Sopenharmony_ci		skip = n - lines - adjust;
213062306a36Sopenharmony_ci		lines = abs(lines);
213162306a36Sopenharmony_ci		if (adjust >= n) {
213262306a36Sopenharmony_ci			kdb_printf("buffer only contains %d lines, "
213362306a36Sopenharmony_ci				   "nothing printed\n", n);
213462306a36Sopenharmony_ci			skip = n;
213562306a36Sopenharmony_ci		} else if (skip < 0) {
213662306a36Sopenharmony_ci			lines += skip;
213762306a36Sopenharmony_ci			skip = 0;
213862306a36Sopenharmony_ci			kdb_printf("buffer only contains %d lines, first "
213962306a36Sopenharmony_ci				   "%d lines printed\n", n, lines);
214062306a36Sopenharmony_ci		}
214162306a36Sopenharmony_ci	} else {
214262306a36Sopenharmony_ci		lines = n;
214362306a36Sopenharmony_ci	}
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	if (skip >= n || skip < 0)
214662306a36Sopenharmony_ci		return 0;
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	kmsg_dump_rewind(&iter);
214962306a36Sopenharmony_ci	while (kmsg_dump_get_line(&iter, 1, buf, sizeof(buf), &len)) {
215062306a36Sopenharmony_ci		if (skip) {
215162306a36Sopenharmony_ci			skip--;
215262306a36Sopenharmony_ci			continue;
215362306a36Sopenharmony_ci		}
215462306a36Sopenharmony_ci		if (!lines--)
215562306a36Sopenharmony_ci			break;
215662306a36Sopenharmony_ci		if (KDB_FLAG(CMD_INTERRUPT))
215762306a36Sopenharmony_ci			return 0;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci		kdb_printf("%.*s\n", (int)len - 1, buf);
216062306a36Sopenharmony_ci	}
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci	return 0;
216362306a36Sopenharmony_ci}
216462306a36Sopenharmony_ci#endif /* CONFIG_PRINTK */
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci/* Make sure we balance enable/disable calls, must disable first. */
216762306a36Sopenharmony_cistatic atomic_t kdb_nmi_disabled;
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_cistatic int kdb_disable_nmi(int argc, const char *argv[])
217062306a36Sopenharmony_ci{
217162306a36Sopenharmony_ci	if (atomic_read(&kdb_nmi_disabled))
217262306a36Sopenharmony_ci		return 0;
217362306a36Sopenharmony_ci	atomic_set(&kdb_nmi_disabled, 1);
217462306a36Sopenharmony_ci	arch_kgdb_ops.enable_nmi(0);
217562306a36Sopenharmony_ci	return 0;
217662306a36Sopenharmony_ci}
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_cistatic int kdb_param_enable_nmi(const char *val, const struct kernel_param *kp)
217962306a36Sopenharmony_ci{
218062306a36Sopenharmony_ci	if (!atomic_add_unless(&kdb_nmi_disabled, -1, 0))
218162306a36Sopenharmony_ci		return -EINVAL;
218262306a36Sopenharmony_ci	arch_kgdb_ops.enable_nmi(1);
218362306a36Sopenharmony_ci	return 0;
218462306a36Sopenharmony_ci}
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_cistatic const struct kernel_param_ops kdb_param_ops_enable_nmi = {
218762306a36Sopenharmony_ci	.set = kdb_param_enable_nmi,
218862306a36Sopenharmony_ci};
218962306a36Sopenharmony_cimodule_param_cb(enable_nmi, &kdb_param_ops_enable_nmi, NULL, 0600);
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci/*
219262306a36Sopenharmony_ci * kdb_cpu - This function implements the 'cpu' command.
219362306a36Sopenharmony_ci *	cpu	[<cpunum>]
219462306a36Sopenharmony_ci * Returns:
219562306a36Sopenharmony_ci *	KDB_CMD_CPU for success, a kdb diagnostic if error
219662306a36Sopenharmony_ci */
219762306a36Sopenharmony_cistatic void kdb_cpu_status(void)
219862306a36Sopenharmony_ci{
219962306a36Sopenharmony_ci	int i, start_cpu, first_print = 1;
220062306a36Sopenharmony_ci	char state, prev_state = '?';
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	kdb_printf("Currently on cpu %d\n", raw_smp_processor_id());
220362306a36Sopenharmony_ci	kdb_printf("Available cpus: ");
220462306a36Sopenharmony_ci	for (start_cpu = -1, i = 0; i < NR_CPUS; i++) {
220562306a36Sopenharmony_ci		if (!cpu_online(i)) {
220662306a36Sopenharmony_ci			state = 'F';	/* cpu is offline */
220762306a36Sopenharmony_ci		} else if (!kgdb_info[i].enter_kgdb) {
220862306a36Sopenharmony_ci			state = 'D';	/* cpu is online but unresponsive */
220962306a36Sopenharmony_ci		} else {
221062306a36Sopenharmony_ci			state = ' ';	/* cpu is responding to kdb */
221162306a36Sopenharmony_ci			if (kdb_task_state_char(KDB_TSK(i)) == '-')
221262306a36Sopenharmony_ci				state = '-';	/* idle task */
221362306a36Sopenharmony_ci		}
221462306a36Sopenharmony_ci		if (state != prev_state) {
221562306a36Sopenharmony_ci			if (prev_state != '?') {
221662306a36Sopenharmony_ci				if (!first_print)
221762306a36Sopenharmony_ci					kdb_printf(", ");
221862306a36Sopenharmony_ci				first_print = 0;
221962306a36Sopenharmony_ci				kdb_printf("%d", start_cpu);
222062306a36Sopenharmony_ci				if (start_cpu < i-1)
222162306a36Sopenharmony_ci					kdb_printf("-%d", i-1);
222262306a36Sopenharmony_ci				if (prev_state != ' ')
222362306a36Sopenharmony_ci					kdb_printf("(%c)", prev_state);
222462306a36Sopenharmony_ci			}
222562306a36Sopenharmony_ci			prev_state = state;
222662306a36Sopenharmony_ci			start_cpu = i;
222762306a36Sopenharmony_ci		}
222862306a36Sopenharmony_ci	}
222962306a36Sopenharmony_ci	/* print the trailing cpus, ignoring them if they are all offline */
223062306a36Sopenharmony_ci	if (prev_state != 'F') {
223162306a36Sopenharmony_ci		if (!first_print)
223262306a36Sopenharmony_ci			kdb_printf(", ");
223362306a36Sopenharmony_ci		kdb_printf("%d", start_cpu);
223462306a36Sopenharmony_ci		if (start_cpu < i-1)
223562306a36Sopenharmony_ci			kdb_printf("-%d", i-1);
223662306a36Sopenharmony_ci		if (prev_state != ' ')
223762306a36Sopenharmony_ci			kdb_printf("(%c)", prev_state);
223862306a36Sopenharmony_ci	}
223962306a36Sopenharmony_ci	kdb_printf("\n");
224062306a36Sopenharmony_ci}
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_cistatic int kdb_cpu(int argc, const char **argv)
224362306a36Sopenharmony_ci{
224462306a36Sopenharmony_ci	unsigned long cpunum;
224562306a36Sopenharmony_ci	int diag;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	if (argc == 0) {
224862306a36Sopenharmony_ci		kdb_cpu_status();
224962306a36Sopenharmony_ci		return 0;
225062306a36Sopenharmony_ci	}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	if (argc != 1)
225362306a36Sopenharmony_ci		return KDB_ARGCOUNT;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	diag = kdbgetularg(argv[1], &cpunum);
225662306a36Sopenharmony_ci	if (diag)
225762306a36Sopenharmony_ci		return diag;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	/*
226062306a36Sopenharmony_ci	 * Validate cpunum
226162306a36Sopenharmony_ci	 */
226262306a36Sopenharmony_ci	if ((cpunum >= CONFIG_NR_CPUS) || !kgdb_info[cpunum].enter_kgdb)
226362306a36Sopenharmony_ci		return KDB_BADCPUNUM;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	dbg_switch_cpu = cpunum;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	/*
226862306a36Sopenharmony_ci	 * Switch to other cpu
226962306a36Sopenharmony_ci	 */
227062306a36Sopenharmony_ci	return KDB_CMD_CPU;
227162306a36Sopenharmony_ci}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci/* The user may not realize that ps/bta with no parameters does not print idle
227462306a36Sopenharmony_ci * or sleeping system daemon processes, so tell them how many were suppressed.
227562306a36Sopenharmony_ci */
227662306a36Sopenharmony_civoid kdb_ps_suppressed(void)
227762306a36Sopenharmony_ci{
227862306a36Sopenharmony_ci	int idle = 0, daemon = 0;
227962306a36Sopenharmony_ci	unsigned long cpu;
228062306a36Sopenharmony_ci	const struct task_struct *p, *g;
228162306a36Sopenharmony_ci	for_each_online_cpu(cpu) {
228262306a36Sopenharmony_ci		p = kdb_curr_task(cpu);
228362306a36Sopenharmony_ci		if (kdb_task_state(p, "-"))
228462306a36Sopenharmony_ci			++idle;
228562306a36Sopenharmony_ci	}
228662306a36Sopenharmony_ci	for_each_process_thread(g, p) {
228762306a36Sopenharmony_ci		if (kdb_task_state(p, "ims"))
228862306a36Sopenharmony_ci			++daemon;
228962306a36Sopenharmony_ci	}
229062306a36Sopenharmony_ci	if (idle || daemon) {
229162306a36Sopenharmony_ci		if (idle)
229262306a36Sopenharmony_ci			kdb_printf("%d idle process%s (state -)%s\n",
229362306a36Sopenharmony_ci				   idle, idle == 1 ? "" : "es",
229462306a36Sopenharmony_ci				   daemon ? " and " : "");
229562306a36Sopenharmony_ci		if (daemon)
229662306a36Sopenharmony_ci			kdb_printf("%d sleeping system daemon (state [ims]) "
229762306a36Sopenharmony_ci				   "process%s", daemon,
229862306a36Sopenharmony_ci				   daemon == 1 ? "" : "es");
229962306a36Sopenharmony_ci		kdb_printf(" suppressed,\nuse 'ps A' to see all.\n");
230062306a36Sopenharmony_ci	}
230162306a36Sopenharmony_ci}
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_civoid kdb_ps1(const struct task_struct *p)
230462306a36Sopenharmony_ci{
230562306a36Sopenharmony_ci	int cpu;
230662306a36Sopenharmony_ci	unsigned long tmp;
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	if (!p ||
230962306a36Sopenharmony_ci	    copy_from_kernel_nofault(&tmp, (char *)p, sizeof(unsigned long)))
231062306a36Sopenharmony_ci		return;
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	cpu = kdb_process_cpu(p);
231362306a36Sopenharmony_ci	kdb_printf("0x%px %8d %8d  %d %4d   %c  0x%px %c%s\n",
231462306a36Sopenharmony_ci		   (void *)p, p->pid, p->parent->pid,
231562306a36Sopenharmony_ci		   kdb_task_has_cpu(p), kdb_process_cpu(p),
231662306a36Sopenharmony_ci		   kdb_task_state_char(p),
231762306a36Sopenharmony_ci		   (void *)(&p->thread),
231862306a36Sopenharmony_ci		   p == kdb_curr_task(raw_smp_processor_id()) ? '*' : ' ',
231962306a36Sopenharmony_ci		   p->comm);
232062306a36Sopenharmony_ci	if (kdb_task_has_cpu(p)) {
232162306a36Sopenharmony_ci		if (!KDB_TSK(cpu)) {
232262306a36Sopenharmony_ci			kdb_printf("  Error: no saved data for this cpu\n");
232362306a36Sopenharmony_ci		} else {
232462306a36Sopenharmony_ci			if (KDB_TSK(cpu) != p)
232562306a36Sopenharmony_ci				kdb_printf("  Error: does not match running "
232662306a36Sopenharmony_ci				   "process table (0x%px)\n", KDB_TSK(cpu));
232762306a36Sopenharmony_ci		}
232862306a36Sopenharmony_ci	}
232962306a36Sopenharmony_ci}
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci/*
233262306a36Sopenharmony_ci * kdb_ps - This function implements the 'ps' command which shows a
233362306a36Sopenharmony_ci *	    list of the active processes.
233462306a36Sopenharmony_ci *
233562306a36Sopenharmony_ci * ps [<state_chars>]   Show processes, optionally selecting only those whose
233662306a36Sopenharmony_ci *                      state character is found in <state_chars>.
233762306a36Sopenharmony_ci */
233862306a36Sopenharmony_cistatic int kdb_ps(int argc, const char **argv)
233962306a36Sopenharmony_ci{
234062306a36Sopenharmony_ci	struct task_struct *g, *p;
234162306a36Sopenharmony_ci	const char *mask;
234262306a36Sopenharmony_ci	unsigned long cpu;
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	if (argc == 0)
234562306a36Sopenharmony_ci		kdb_ps_suppressed();
234662306a36Sopenharmony_ci	kdb_printf("%-*s      Pid   Parent [*] cpu State %-*s Command\n",
234762306a36Sopenharmony_ci		(int)(2*sizeof(void *))+2, "Task Addr",
234862306a36Sopenharmony_ci		(int)(2*sizeof(void *))+2, "Thread");
234962306a36Sopenharmony_ci	mask = argc ? argv[1] : kdbgetenv("PS");
235062306a36Sopenharmony_ci	/* Run the active tasks first */
235162306a36Sopenharmony_ci	for_each_online_cpu(cpu) {
235262306a36Sopenharmony_ci		if (KDB_FLAG(CMD_INTERRUPT))
235362306a36Sopenharmony_ci			return 0;
235462306a36Sopenharmony_ci		p = kdb_curr_task(cpu);
235562306a36Sopenharmony_ci		if (kdb_task_state(p, mask))
235662306a36Sopenharmony_ci			kdb_ps1(p);
235762306a36Sopenharmony_ci	}
235862306a36Sopenharmony_ci	kdb_printf("\n");
235962306a36Sopenharmony_ci	/* Now the real tasks */
236062306a36Sopenharmony_ci	for_each_process_thread(g, p) {
236162306a36Sopenharmony_ci		if (KDB_FLAG(CMD_INTERRUPT))
236262306a36Sopenharmony_ci			return 0;
236362306a36Sopenharmony_ci		if (kdb_task_state(p, mask))
236462306a36Sopenharmony_ci			kdb_ps1(p);
236562306a36Sopenharmony_ci	}
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	return 0;
236862306a36Sopenharmony_ci}
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci/*
237162306a36Sopenharmony_ci * kdb_pid - This function implements the 'pid' command which switches
237262306a36Sopenharmony_ci *	the currently active process.
237362306a36Sopenharmony_ci *		pid [<pid> | R]
237462306a36Sopenharmony_ci */
237562306a36Sopenharmony_cistatic int kdb_pid(int argc, const char **argv)
237662306a36Sopenharmony_ci{
237762306a36Sopenharmony_ci	struct task_struct *p;
237862306a36Sopenharmony_ci	unsigned long val;
237962306a36Sopenharmony_ci	int diag;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	if (argc > 1)
238262306a36Sopenharmony_ci		return KDB_ARGCOUNT;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	if (argc) {
238562306a36Sopenharmony_ci		if (strcmp(argv[1], "R") == 0) {
238662306a36Sopenharmony_ci			p = KDB_TSK(kdb_initial_cpu);
238762306a36Sopenharmony_ci		} else {
238862306a36Sopenharmony_ci			diag = kdbgetularg(argv[1], &val);
238962306a36Sopenharmony_ci			if (diag)
239062306a36Sopenharmony_ci				return KDB_BADINT;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci			p = find_task_by_pid_ns((pid_t)val,	&init_pid_ns);
239362306a36Sopenharmony_ci			if (!p) {
239462306a36Sopenharmony_ci				kdb_printf("No task with pid=%d\n", (pid_t)val);
239562306a36Sopenharmony_ci				return 0;
239662306a36Sopenharmony_ci			}
239762306a36Sopenharmony_ci		}
239862306a36Sopenharmony_ci		kdb_set_current_task(p);
239962306a36Sopenharmony_ci	}
240062306a36Sopenharmony_ci	kdb_printf("KDB current process is %s(pid=%d)\n",
240162306a36Sopenharmony_ci		   kdb_current_task->comm,
240262306a36Sopenharmony_ci		   kdb_current_task->pid);
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	return 0;
240562306a36Sopenharmony_ci}
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_cistatic int kdb_kgdb(int argc, const char **argv)
240862306a36Sopenharmony_ci{
240962306a36Sopenharmony_ci	return KDB_CMD_KGDB;
241062306a36Sopenharmony_ci}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci/*
241362306a36Sopenharmony_ci * kdb_help - This function implements the 'help' and '?' commands.
241462306a36Sopenharmony_ci */
241562306a36Sopenharmony_cistatic int kdb_help(int argc, const char **argv)
241662306a36Sopenharmony_ci{
241762306a36Sopenharmony_ci	kdbtab_t *kt;
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	kdb_printf("%-15.15s %-20.20s %s\n", "Command", "Usage", "Description");
242062306a36Sopenharmony_ci	kdb_printf("-----------------------------"
242162306a36Sopenharmony_ci		   "-----------------------------\n");
242262306a36Sopenharmony_ci	list_for_each_entry(kt, &kdb_cmds_head, list_node) {
242362306a36Sopenharmony_ci		char *space = "";
242462306a36Sopenharmony_ci		if (KDB_FLAG(CMD_INTERRUPT))
242562306a36Sopenharmony_ci			return 0;
242662306a36Sopenharmony_ci		if (!kdb_check_flags(kt->flags, kdb_cmd_enabled, true))
242762306a36Sopenharmony_ci			continue;
242862306a36Sopenharmony_ci		if (strlen(kt->usage) > 20)
242962306a36Sopenharmony_ci			space = "\n                                    ";
243062306a36Sopenharmony_ci		kdb_printf("%-15.15s %-20s%s%s\n", kt->name,
243162306a36Sopenharmony_ci			   kt->usage, space, kt->help);
243262306a36Sopenharmony_ci	}
243362306a36Sopenharmony_ci	return 0;
243462306a36Sopenharmony_ci}
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci/*
243762306a36Sopenharmony_ci * kdb_kill - This function implements the 'kill' commands.
243862306a36Sopenharmony_ci */
243962306a36Sopenharmony_cistatic int kdb_kill(int argc, const char **argv)
244062306a36Sopenharmony_ci{
244162306a36Sopenharmony_ci	long sig, pid;
244262306a36Sopenharmony_ci	char *endp;
244362306a36Sopenharmony_ci	struct task_struct *p;
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci	if (argc != 2)
244662306a36Sopenharmony_ci		return KDB_ARGCOUNT;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	sig = simple_strtol(argv[1], &endp, 0);
244962306a36Sopenharmony_ci	if (*endp)
245062306a36Sopenharmony_ci		return KDB_BADINT;
245162306a36Sopenharmony_ci	if ((sig >= 0) || !valid_signal(-sig)) {
245262306a36Sopenharmony_ci		kdb_printf("Invalid signal parameter.<-signal>\n");
245362306a36Sopenharmony_ci		return 0;
245462306a36Sopenharmony_ci	}
245562306a36Sopenharmony_ci	sig = -sig;
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	pid = simple_strtol(argv[2], &endp, 0);
245862306a36Sopenharmony_ci	if (*endp)
245962306a36Sopenharmony_ci		return KDB_BADINT;
246062306a36Sopenharmony_ci	if (pid <= 0) {
246162306a36Sopenharmony_ci		kdb_printf("Process ID must be large than 0.\n");
246262306a36Sopenharmony_ci		return 0;
246362306a36Sopenharmony_ci	}
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	/* Find the process. */
246662306a36Sopenharmony_ci	p = find_task_by_pid_ns(pid, &init_pid_ns);
246762306a36Sopenharmony_ci	if (!p) {
246862306a36Sopenharmony_ci		kdb_printf("The specified process isn't found.\n");
246962306a36Sopenharmony_ci		return 0;
247062306a36Sopenharmony_ci	}
247162306a36Sopenharmony_ci	p = p->group_leader;
247262306a36Sopenharmony_ci	kdb_send_sig(p, sig);
247362306a36Sopenharmony_ci	return 0;
247462306a36Sopenharmony_ci}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci/*
247762306a36Sopenharmony_ci * Most of this code has been lifted from kernel/timer.c::sys_sysinfo().
247862306a36Sopenharmony_ci * I cannot call that code directly from kdb, it has an unconditional
247962306a36Sopenharmony_ci * cli()/sti() and calls routines that take locks which can stop the debugger.
248062306a36Sopenharmony_ci */
248162306a36Sopenharmony_cistatic void kdb_sysinfo(struct sysinfo *val)
248262306a36Sopenharmony_ci{
248362306a36Sopenharmony_ci	u64 uptime = ktime_get_mono_fast_ns();
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	memset(val, 0, sizeof(*val));
248662306a36Sopenharmony_ci	val->uptime = div_u64(uptime, NSEC_PER_SEC);
248762306a36Sopenharmony_ci	val->loads[0] = avenrun[0];
248862306a36Sopenharmony_ci	val->loads[1] = avenrun[1];
248962306a36Sopenharmony_ci	val->loads[2] = avenrun[2];
249062306a36Sopenharmony_ci	val->procs = nr_threads-1;
249162306a36Sopenharmony_ci	si_meminfo(val);
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	return;
249462306a36Sopenharmony_ci}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci/*
249762306a36Sopenharmony_ci * kdb_summary - This function implements the 'summary' command.
249862306a36Sopenharmony_ci */
249962306a36Sopenharmony_cistatic int kdb_summary(int argc, const char **argv)
250062306a36Sopenharmony_ci{
250162306a36Sopenharmony_ci	time64_t now;
250262306a36Sopenharmony_ci	struct sysinfo val;
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci	if (argc)
250562306a36Sopenharmony_ci		return KDB_ARGCOUNT;
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	kdb_printf("sysname    %s\n", init_uts_ns.name.sysname);
250862306a36Sopenharmony_ci	kdb_printf("release    %s\n", init_uts_ns.name.release);
250962306a36Sopenharmony_ci	kdb_printf("version    %s\n", init_uts_ns.name.version);
251062306a36Sopenharmony_ci	kdb_printf("machine    %s\n", init_uts_ns.name.machine);
251162306a36Sopenharmony_ci	kdb_printf("nodename   %s\n", init_uts_ns.name.nodename);
251262306a36Sopenharmony_ci	kdb_printf("domainname %s\n", init_uts_ns.name.domainname);
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	now = __ktime_get_real_seconds();
251562306a36Sopenharmony_ci	kdb_printf("date       %ptTs tz_minuteswest %d\n", &now, sys_tz.tz_minuteswest);
251662306a36Sopenharmony_ci	kdb_sysinfo(&val);
251762306a36Sopenharmony_ci	kdb_printf("uptime     ");
251862306a36Sopenharmony_ci	if (val.uptime > (24*60*60)) {
251962306a36Sopenharmony_ci		int days = val.uptime / (24*60*60);
252062306a36Sopenharmony_ci		val.uptime %= (24*60*60);
252162306a36Sopenharmony_ci		kdb_printf("%d day%s ", days, days == 1 ? "" : "s");
252262306a36Sopenharmony_ci	}
252362306a36Sopenharmony_ci	kdb_printf("%02ld:%02ld\n", val.uptime/(60*60), (val.uptime/60)%60);
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	kdb_printf("load avg   %ld.%02ld %ld.%02ld %ld.%02ld\n",
252662306a36Sopenharmony_ci		LOAD_INT(val.loads[0]), LOAD_FRAC(val.loads[0]),
252762306a36Sopenharmony_ci		LOAD_INT(val.loads[1]), LOAD_FRAC(val.loads[1]),
252862306a36Sopenharmony_ci		LOAD_INT(val.loads[2]), LOAD_FRAC(val.loads[2]));
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	/* Display in kilobytes */
253162306a36Sopenharmony_ci#define K(x) ((x) << (PAGE_SHIFT - 10))
253262306a36Sopenharmony_ci	kdb_printf("\nMemTotal:       %8lu kB\nMemFree:        %8lu kB\n"
253362306a36Sopenharmony_ci		   "Buffers:        %8lu kB\n",
253462306a36Sopenharmony_ci		   K(val.totalram), K(val.freeram), K(val.bufferram));
253562306a36Sopenharmony_ci	return 0;
253662306a36Sopenharmony_ci}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci/*
253962306a36Sopenharmony_ci * kdb_per_cpu - This function implements the 'per_cpu' command.
254062306a36Sopenharmony_ci */
254162306a36Sopenharmony_cistatic int kdb_per_cpu(int argc, const char **argv)
254262306a36Sopenharmony_ci{
254362306a36Sopenharmony_ci	char fmtstr[64];
254462306a36Sopenharmony_ci	int cpu, diag, nextarg = 1;
254562306a36Sopenharmony_ci	unsigned long addr, symaddr, val, bytesperword = 0, whichcpu = ~0UL;
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	if (argc < 1 || argc > 3)
254862306a36Sopenharmony_ci		return KDB_ARGCOUNT;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	diag = kdbgetaddrarg(argc, argv, &nextarg, &symaddr, NULL, NULL);
255162306a36Sopenharmony_ci	if (diag)
255262306a36Sopenharmony_ci		return diag;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	if (argc >= 2) {
255562306a36Sopenharmony_ci		diag = kdbgetularg(argv[2], &bytesperword);
255662306a36Sopenharmony_ci		if (diag)
255762306a36Sopenharmony_ci			return diag;
255862306a36Sopenharmony_ci	}
255962306a36Sopenharmony_ci	if (!bytesperword)
256062306a36Sopenharmony_ci		bytesperword = KDB_WORD_SIZE;
256162306a36Sopenharmony_ci	else if (bytesperword > KDB_WORD_SIZE)
256262306a36Sopenharmony_ci		return KDB_BADWIDTH;
256362306a36Sopenharmony_ci	sprintf(fmtstr, "%%0%dlx ", (int)(2*bytesperword));
256462306a36Sopenharmony_ci	if (argc >= 3) {
256562306a36Sopenharmony_ci		diag = kdbgetularg(argv[3], &whichcpu);
256662306a36Sopenharmony_ci		if (diag)
256762306a36Sopenharmony_ci			return diag;
256862306a36Sopenharmony_ci		if (whichcpu >= nr_cpu_ids || !cpu_online(whichcpu)) {
256962306a36Sopenharmony_ci			kdb_printf("cpu %ld is not online\n", whichcpu);
257062306a36Sopenharmony_ci			return KDB_BADCPUNUM;
257162306a36Sopenharmony_ci		}
257262306a36Sopenharmony_ci	}
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci	/* Most architectures use __per_cpu_offset[cpu], some use
257562306a36Sopenharmony_ci	 * __per_cpu_offset(cpu), smp has no __per_cpu_offset.
257662306a36Sopenharmony_ci	 */
257762306a36Sopenharmony_ci#ifdef	__per_cpu_offset
257862306a36Sopenharmony_ci#define KDB_PCU(cpu) __per_cpu_offset(cpu)
257962306a36Sopenharmony_ci#else
258062306a36Sopenharmony_ci#ifdef	CONFIG_SMP
258162306a36Sopenharmony_ci#define KDB_PCU(cpu) __per_cpu_offset[cpu]
258262306a36Sopenharmony_ci#else
258362306a36Sopenharmony_ci#define KDB_PCU(cpu) 0
258462306a36Sopenharmony_ci#endif
258562306a36Sopenharmony_ci#endif
258662306a36Sopenharmony_ci	for_each_online_cpu(cpu) {
258762306a36Sopenharmony_ci		if (KDB_FLAG(CMD_INTERRUPT))
258862306a36Sopenharmony_ci			return 0;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci		if (whichcpu != ~0UL && whichcpu != cpu)
259162306a36Sopenharmony_ci			continue;
259262306a36Sopenharmony_ci		addr = symaddr + KDB_PCU(cpu);
259362306a36Sopenharmony_ci		diag = kdb_getword(&val, addr, bytesperword);
259462306a36Sopenharmony_ci		if (diag) {
259562306a36Sopenharmony_ci			kdb_printf("%5d " kdb_bfd_vma_fmt0 " - unable to "
259662306a36Sopenharmony_ci				   "read, diag=%d\n", cpu, addr, diag);
259762306a36Sopenharmony_ci			continue;
259862306a36Sopenharmony_ci		}
259962306a36Sopenharmony_ci		kdb_printf("%5d ", cpu);
260062306a36Sopenharmony_ci		kdb_md_line(fmtstr, addr,
260162306a36Sopenharmony_ci			bytesperword == KDB_WORD_SIZE,
260262306a36Sopenharmony_ci			1, bytesperword, 1, 1, 0);
260362306a36Sopenharmony_ci	}
260462306a36Sopenharmony_ci#undef KDB_PCU
260562306a36Sopenharmony_ci	return 0;
260662306a36Sopenharmony_ci}
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ci/*
260962306a36Sopenharmony_ci * display help for the use of cmd | grep pattern
261062306a36Sopenharmony_ci */
261162306a36Sopenharmony_cistatic int kdb_grep_help(int argc, const char **argv)
261262306a36Sopenharmony_ci{
261362306a36Sopenharmony_ci	kdb_printf("Usage of  cmd args | grep pattern:\n");
261462306a36Sopenharmony_ci	kdb_printf("  Any command's output may be filtered through an ");
261562306a36Sopenharmony_ci	kdb_printf("emulated 'pipe'.\n");
261662306a36Sopenharmony_ci	kdb_printf("  'grep' is just a key word.\n");
261762306a36Sopenharmony_ci	kdb_printf("  The pattern may include a very limited set of "
261862306a36Sopenharmony_ci		   "metacharacters:\n");
261962306a36Sopenharmony_ci	kdb_printf("   pattern or ^pattern or pattern$ or ^pattern$\n");
262062306a36Sopenharmony_ci	kdb_printf("  And if there are spaces in the pattern, you may "
262162306a36Sopenharmony_ci		   "quote it:\n");
262262306a36Sopenharmony_ci	kdb_printf("   \"pat tern\" or \"^pat tern\" or \"pat tern$\""
262362306a36Sopenharmony_ci		   " or \"^pat tern$\"\n");
262462306a36Sopenharmony_ci	return 0;
262562306a36Sopenharmony_ci}
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci/**
262862306a36Sopenharmony_ci * kdb_register() - This function is used to register a kernel debugger
262962306a36Sopenharmony_ci *                  command.
263062306a36Sopenharmony_ci * @cmd: pointer to kdb command
263162306a36Sopenharmony_ci *
263262306a36Sopenharmony_ci * Note that it's the job of the caller to keep the memory for the cmd
263362306a36Sopenharmony_ci * allocated until unregister is called.
263462306a36Sopenharmony_ci */
263562306a36Sopenharmony_ciint kdb_register(kdbtab_t *cmd)
263662306a36Sopenharmony_ci{
263762306a36Sopenharmony_ci	kdbtab_t *kp;
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	list_for_each_entry(kp, &kdb_cmds_head, list_node) {
264062306a36Sopenharmony_ci		if (strcmp(kp->name, cmd->name) == 0) {
264162306a36Sopenharmony_ci			kdb_printf("Duplicate kdb cmd: %s, func %p help %s\n",
264262306a36Sopenharmony_ci				   cmd->name, cmd->func, cmd->help);
264362306a36Sopenharmony_ci			return 1;
264462306a36Sopenharmony_ci		}
264562306a36Sopenharmony_ci	}
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	list_add_tail(&cmd->list_node, &kdb_cmds_head);
264862306a36Sopenharmony_ci	return 0;
264962306a36Sopenharmony_ci}
265062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kdb_register);
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci/**
265362306a36Sopenharmony_ci * kdb_register_table() - This function is used to register a kdb command
265462306a36Sopenharmony_ci *                        table.
265562306a36Sopenharmony_ci * @kp: pointer to kdb command table
265662306a36Sopenharmony_ci * @len: length of kdb command table
265762306a36Sopenharmony_ci */
265862306a36Sopenharmony_civoid kdb_register_table(kdbtab_t *kp, size_t len)
265962306a36Sopenharmony_ci{
266062306a36Sopenharmony_ci	while (len--) {
266162306a36Sopenharmony_ci		list_add_tail(&kp->list_node, &kdb_cmds_head);
266262306a36Sopenharmony_ci		kp++;
266362306a36Sopenharmony_ci	}
266462306a36Sopenharmony_ci}
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci/**
266762306a36Sopenharmony_ci * kdb_unregister() - This function is used to unregister a kernel debugger
266862306a36Sopenharmony_ci *                    command. It is generally called when a module which
266962306a36Sopenharmony_ci *                    implements kdb command is unloaded.
267062306a36Sopenharmony_ci * @cmd: pointer to kdb command
267162306a36Sopenharmony_ci */
267262306a36Sopenharmony_civoid kdb_unregister(kdbtab_t *cmd)
267362306a36Sopenharmony_ci{
267462306a36Sopenharmony_ci	list_del(&cmd->list_node);
267562306a36Sopenharmony_ci}
267662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kdb_unregister);
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_cistatic kdbtab_t maintab[] = {
267962306a36Sopenharmony_ci	{	.name = "md",
268062306a36Sopenharmony_ci		.func = kdb_md,
268162306a36Sopenharmony_ci		.usage = "<vaddr>",
268262306a36Sopenharmony_ci		.help = "Display Memory Contents, also mdWcN, e.g. md8c1",
268362306a36Sopenharmony_ci		.minlen = 1,
268462306a36Sopenharmony_ci		.flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS,
268562306a36Sopenharmony_ci	},
268662306a36Sopenharmony_ci	{	.name = "mdr",
268762306a36Sopenharmony_ci		.func = kdb_md,
268862306a36Sopenharmony_ci		.usage = "<vaddr> <bytes>",
268962306a36Sopenharmony_ci		.help = "Display Raw Memory",
269062306a36Sopenharmony_ci		.flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS,
269162306a36Sopenharmony_ci	},
269262306a36Sopenharmony_ci	{	.name = "mdp",
269362306a36Sopenharmony_ci		.func = kdb_md,
269462306a36Sopenharmony_ci		.usage = "<paddr> <bytes>",
269562306a36Sopenharmony_ci		.help = "Display Physical Memory",
269662306a36Sopenharmony_ci		.flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS,
269762306a36Sopenharmony_ci	},
269862306a36Sopenharmony_ci	{	.name = "mds",
269962306a36Sopenharmony_ci		.func = kdb_md,
270062306a36Sopenharmony_ci		.usage = "<vaddr>",
270162306a36Sopenharmony_ci		.help = "Display Memory Symbolically",
270262306a36Sopenharmony_ci		.flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS,
270362306a36Sopenharmony_ci	},
270462306a36Sopenharmony_ci	{	.name = "mm",
270562306a36Sopenharmony_ci		.func = kdb_mm,
270662306a36Sopenharmony_ci		.usage = "<vaddr> <contents>",
270762306a36Sopenharmony_ci		.help = "Modify Memory Contents",
270862306a36Sopenharmony_ci		.flags = KDB_ENABLE_MEM_WRITE | KDB_REPEAT_NO_ARGS,
270962306a36Sopenharmony_ci	},
271062306a36Sopenharmony_ci	{	.name = "go",
271162306a36Sopenharmony_ci		.func = kdb_go,
271262306a36Sopenharmony_ci		.usage = "[<vaddr>]",
271362306a36Sopenharmony_ci		.help = "Continue Execution",
271462306a36Sopenharmony_ci		.minlen = 1,
271562306a36Sopenharmony_ci		.flags = KDB_ENABLE_REG_WRITE |
271662306a36Sopenharmony_ci			     KDB_ENABLE_ALWAYS_SAFE_NO_ARGS,
271762306a36Sopenharmony_ci	},
271862306a36Sopenharmony_ci	{	.name = "rd",
271962306a36Sopenharmony_ci		.func = kdb_rd,
272062306a36Sopenharmony_ci		.usage = "",
272162306a36Sopenharmony_ci		.help = "Display Registers",
272262306a36Sopenharmony_ci		.flags = KDB_ENABLE_REG_READ,
272362306a36Sopenharmony_ci	},
272462306a36Sopenharmony_ci	{	.name = "rm",
272562306a36Sopenharmony_ci		.func = kdb_rm,
272662306a36Sopenharmony_ci		.usage = "<reg> <contents>",
272762306a36Sopenharmony_ci		.help = "Modify Registers",
272862306a36Sopenharmony_ci		.flags = KDB_ENABLE_REG_WRITE,
272962306a36Sopenharmony_ci	},
273062306a36Sopenharmony_ci	{	.name = "ef",
273162306a36Sopenharmony_ci		.func = kdb_ef,
273262306a36Sopenharmony_ci		.usage = "<vaddr>",
273362306a36Sopenharmony_ci		.help = "Display exception frame",
273462306a36Sopenharmony_ci		.flags = KDB_ENABLE_MEM_READ,
273562306a36Sopenharmony_ci	},
273662306a36Sopenharmony_ci	{	.name = "bt",
273762306a36Sopenharmony_ci		.func = kdb_bt,
273862306a36Sopenharmony_ci		.usage = "[<vaddr>]",
273962306a36Sopenharmony_ci		.help = "Stack traceback",
274062306a36Sopenharmony_ci		.minlen = 1,
274162306a36Sopenharmony_ci		.flags = KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS,
274262306a36Sopenharmony_ci	},
274362306a36Sopenharmony_ci	{	.name = "btp",
274462306a36Sopenharmony_ci		.func = kdb_bt,
274562306a36Sopenharmony_ci		.usage = "<pid>",
274662306a36Sopenharmony_ci		.help = "Display stack for process <pid>",
274762306a36Sopenharmony_ci		.flags = KDB_ENABLE_INSPECT,
274862306a36Sopenharmony_ci	},
274962306a36Sopenharmony_ci	{	.name = "bta",
275062306a36Sopenharmony_ci		.func = kdb_bt,
275162306a36Sopenharmony_ci		.usage = "[<state_chars>|A]",
275262306a36Sopenharmony_ci		.help = "Backtrace all processes whose state matches",
275362306a36Sopenharmony_ci		.flags = KDB_ENABLE_INSPECT,
275462306a36Sopenharmony_ci	},
275562306a36Sopenharmony_ci	{	.name = "btc",
275662306a36Sopenharmony_ci		.func = kdb_bt,
275762306a36Sopenharmony_ci		.usage = "",
275862306a36Sopenharmony_ci		.help = "Backtrace current process on each cpu",
275962306a36Sopenharmony_ci		.flags = KDB_ENABLE_INSPECT,
276062306a36Sopenharmony_ci	},
276162306a36Sopenharmony_ci	{	.name = "btt",
276262306a36Sopenharmony_ci		.func = kdb_bt,
276362306a36Sopenharmony_ci		.usage = "<vaddr>",
276462306a36Sopenharmony_ci		.help = "Backtrace process given its struct task address",
276562306a36Sopenharmony_ci		.flags = KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS,
276662306a36Sopenharmony_ci	},
276762306a36Sopenharmony_ci	{	.name = "env",
276862306a36Sopenharmony_ci		.func = kdb_env,
276962306a36Sopenharmony_ci		.usage = "",
277062306a36Sopenharmony_ci		.help = "Show environment variables",
277162306a36Sopenharmony_ci		.flags = KDB_ENABLE_ALWAYS_SAFE,
277262306a36Sopenharmony_ci	},
277362306a36Sopenharmony_ci	{	.name = "set",
277462306a36Sopenharmony_ci		.func = kdb_set,
277562306a36Sopenharmony_ci		.usage = "",
277662306a36Sopenharmony_ci		.help = "Set environment variables",
277762306a36Sopenharmony_ci		.flags = KDB_ENABLE_ALWAYS_SAFE,
277862306a36Sopenharmony_ci	},
277962306a36Sopenharmony_ci	{	.name = "help",
278062306a36Sopenharmony_ci		.func = kdb_help,
278162306a36Sopenharmony_ci		.usage = "",
278262306a36Sopenharmony_ci		.help = "Display Help Message",
278362306a36Sopenharmony_ci		.minlen = 1,
278462306a36Sopenharmony_ci		.flags = KDB_ENABLE_ALWAYS_SAFE,
278562306a36Sopenharmony_ci	},
278662306a36Sopenharmony_ci	{	.name = "?",
278762306a36Sopenharmony_ci		.func = kdb_help,
278862306a36Sopenharmony_ci		.usage = "",
278962306a36Sopenharmony_ci		.help = "Display Help Message",
279062306a36Sopenharmony_ci		.flags = KDB_ENABLE_ALWAYS_SAFE,
279162306a36Sopenharmony_ci	},
279262306a36Sopenharmony_ci	{	.name = "cpu",
279362306a36Sopenharmony_ci		.func = kdb_cpu,
279462306a36Sopenharmony_ci		.usage = "<cpunum>",
279562306a36Sopenharmony_ci		.help = "Switch to new cpu",
279662306a36Sopenharmony_ci		.flags = KDB_ENABLE_ALWAYS_SAFE_NO_ARGS,
279762306a36Sopenharmony_ci	},
279862306a36Sopenharmony_ci	{	.name = "kgdb",
279962306a36Sopenharmony_ci		.func = kdb_kgdb,
280062306a36Sopenharmony_ci		.usage = "",
280162306a36Sopenharmony_ci		.help = "Enter kgdb mode",
280262306a36Sopenharmony_ci		.flags = 0,
280362306a36Sopenharmony_ci	},
280462306a36Sopenharmony_ci	{	.name = "ps",
280562306a36Sopenharmony_ci		.func = kdb_ps,
280662306a36Sopenharmony_ci		.usage = "[<state_chars>|A]",
280762306a36Sopenharmony_ci		.help = "Display active task list",
280862306a36Sopenharmony_ci		.flags = KDB_ENABLE_INSPECT,
280962306a36Sopenharmony_ci	},
281062306a36Sopenharmony_ci	{	.name = "pid",
281162306a36Sopenharmony_ci		.func = kdb_pid,
281262306a36Sopenharmony_ci		.usage = "<pidnum>",
281362306a36Sopenharmony_ci		.help = "Switch to another task",
281462306a36Sopenharmony_ci		.flags = KDB_ENABLE_INSPECT,
281562306a36Sopenharmony_ci	},
281662306a36Sopenharmony_ci	{	.name = "reboot",
281762306a36Sopenharmony_ci		.func = kdb_reboot,
281862306a36Sopenharmony_ci		.usage = "",
281962306a36Sopenharmony_ci		.help = "Reboot the machine immediately",
282062306a36Sopenharmony_ci		.flags = KDB_ENABLE_REBOOT,
282162306a36Sopenharmony_ci	},
282262306a36Sopenharmony_ci#if defined(CONFIG_MODULES)
282362306a36Sopenharmony_ci	{	.name = "lsmod",
282462306a36Sopenharmony_ci		.func = kdb_lsmod,
282562306a36Sopenharmony_ci		.usage = "",
282662306a36Sopenharmony_ci		.help = "List loaded kernel modules",
282762306a36Sopenharmony_ci		.flags = KDB_ENABLE_INSPECT,
282862306a36Sopenharmony_ci	},
282962306a36Sopenharmony_ci#endif
283062306a36Sopenharmony_ci#if defined(CONFIG_MAGIC_SYSRQ)
283162306a36Sopenharmony_ci	{	.name = "sr",
283262306a36Sopenharmony_ci		.func = kdb_sr,
283362306a36Sopenharmony_ci		.usage = "<key>",
283462306a36Sopenharmony_ci		.help = "Magic SysRq key",
283562306a36Sopenharmony_ci		.flags = KDB_ENABLE_ALWAYS_SAFE,
283662306a36Sopenharmony_ci	},
283762306a36Sopenharmony_ci#endif
283862306a36Sopenharmony_ci#if defined(CONFIG_PRINTK)
283962306a36Sopenharmony_ci	{	.name = "dmesg",
284062306a36Sopenharmony_ci		.func = kdb_dmesg,
284162306a36Sopenharmony_ci		.usage = "[lines]",
284262306a36Sopenharmony_ci		.help = "Display syslog buffer",
284362306a36Sopenharmony_ci		.flags = KDB_ENABLE_ALWAYS_SAFE,
284462306a36Sopenharmony_ci	},
284562306a36Sopenharmony_ci#endif
284662306a36Sopenharmony_ci	{	.name = "defcmd",
284762306a36Sopenharmony_ci		.func = kdb_defcmd,
284862306a36Sopenharmony_ci		.usage = "name \"usage\" \"help\"",
284962306a36Sopenharmony_ci		.help = "Define a set of commands, down to endefcmd",
285062306a36Sopenharmony_ci		/*
285162306a36Sopenharmony_ci		 * Macros are always safe because when executed each
285262306a36Sopenharmony_ci		 * internal command re-enters kdb_parse() and is safety
285362306a36Sopenharmony_ci		 * checked individually.
285462306a36Sopenharmony_ci		 */
285562306a36Sopenharmony_ci		.flags = KDB_ENABLE_ALWAYS_SAFE,
285662306a36Sopenharmony_ci	},
285762306a36Sopenharmony_ci	{	.name = "kill",
285862306a36Sopenharmony_ci		.func = kdb_kill,
285962306a36Sopenharmony_ci		.usage = "<-signal> <pid>",
286062306a36Sopenharmony_ci		.help = "Send a signal to a process",
286162306a36Sopenharmony_ci		.flags = KDB_ENABLE_SIGNAL,
286262306a36Sopenharmony_ci	},
286362306a36Sopenharmony_ci	{	.name = "summary",
286462306a36Sopenharmony_ci		.func = kdb_summary,
286562306a36Sopenharmony_ci		.usage = "",
286662306a36Sopenharmony_ci		.help = "Summarize the system",
286762306a36Sopenharmony_ci		.minlen = 4,
286862306a36Sopenharmony_ci		.flags = KDB_ENABLE_ALWAYS_SAFE,
286962306a36Sopenharmony_ci	},
287062306a36Sopenharmony_ci	{	.name = "per_cpu",
287162306a36Sopenharmony_ci		.func = kdb_per_cpu,
287262306a36Sopenharmony_ci		.usage = "<sym> [<bytes>] [<cpu>]",
287362306a36Sopenharmony_ci		.help = "Display per_cpu variables",
287462306a36Sopenharmony_ci		.minlen = 3,
287562306a36Sopenharmony_ci		.flags = KDB_ENABLE_MEM_READ,
287662306a36Sopenharmony_ci	},
287762306a36Sopenharmony_ci	{	.name = "grephelp",
287862306a36Sopenharmony_ci		.func = kdb_grep_help,
287962306a36Sopenharmony_ci		.usage = "",
288062306a36Sopenharmony_ci		.help = "Display help on | grep",
288162306a36Sopenharmony_ci		.flags = KDB_ENABLE_ALWAYS_SAFE,
288262306a36Sopenharmony_ci	},
288362306a36Sopenharmony_ci};
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_cistatic kdbtab_t nmicmd = {
288662306a36Sopenharmony_ci	.name = "disable_nmi",
288762306a36Sopenharmony_ci	.func = kdb_disable_nmi,
288862306a36Sopenharmony_ci	.usage = "",
288962306a36Sopenharmony_ci	.help = "Disable NMI entry to KDB",
289062306a36Sopenharmony_ci	.flags = KDB_ENABLE_ALWAYS_SAFE,
289162306a36Sopenharmony_ci};
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci/* Initialize the kdb command table. */
289462306a36Sopenharmony_cistatic void __init kdb_inittab(void)
289562306a36Sopenharmony_ci{
289662306a36Sopenharmony_ci	kdb_register_table(maintab, ARRAY_SIZE(maintab));
289762306a36Sopenharmony_ci	if (arch_kgdb_ops.enable_nmi)
289862306a36Sopenharmony_ci		kdb_register_table(&nmicmd, 1);
289962306a36Sopenharmony_ci}
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_ci/* Execute any commands defined in kdb_cmds.  */
290262306a36Sopenharmony_cistatic void __init kdb_cmd_init(void)
290362306a36Sopenharmony_ci{
290462306a36Sopenharmony_ci	int i, diag;
290562306a36Sopenharmony_ci	for (i = 0; kdb_cmds[i]; ++i) {
290662306a36Sopenharmony_ci		diag = kdb_parse(kdb_cmds[i]);
290762306a36Sopenharmony_ci		if (diag)
290862306a36Sopenharmony_ci			kdb_printf("kdb command %s failed, kdb diag %d\n",
290962306a36Sopenharmony_ci				kdb_cmds[i], diag);
291062306a36Sopenharmony_ci	}
291162306a36Sopenharmony_ci	if (defcmd_in_progress) {
291262306a36Sopenharmony_ci		kdb_printf("Incomplete 'defcmd' set, forcing endefcmd\n");
291362306a36Sopenharmony_ci		kdb_parse("endefcmd");
291462306a36Sopenharmony_ci	}
291562306a36Sopenharmony_ci}
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci/* Initialize kdb_printf, breakpoint tables and kdb state */
291862306a36Sopenharmony_civoid __init kdb_init(int lvl)
291962306a36Sopenharmony_ci{
292062306a36Sopenharmony_ci	static int kdb_init_lvl = KDB_NOT_INITIALIZED;
292162306a36Sopenharmony_ci	int i;
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ci	if (kdb_init_lvl == KDB_INIT_FULL || lvl <= kdb_init_lvl)
292462306a36Sopenharmony_ci		return;
292562306a36Sopenharmony_ci	for (i = kdb_init_lvl; i < lvl; i++) {
292662306a36Sopenharmony_ci		switch (i) {
292762306a36Sopenharmony_ci		case KDB_NOT_INITIALIZED:
292862306a36Sopenharmony_ci			kdb_inittab();		/* Initialize Command Table */
292962306a36Sopenharmony_ci			kdb_initbptab();	/* Initialize Breakpoints */
293062306a36Sopenharmony_ci			break;
293162306a36Sopenharmony_ci		case KDB_INIT_EARLY:
293262306a36Sopenharmony_ci			kdb_cmd_init();		/* Build kdb_cmds tables */
293362306a36Sopenharmony_ci			break;
293462306a36Sopenharmony_ci		}
293562306a36Sopenharmony_ci	}
293662306a36Sopenharmony_ci	kdb_init_lvl = lvl;
293762306a36Sopenharmony_ci}
2938