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, ®8, 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, ®16, 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, ®32, 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, ®64, 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], ®64); 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, ®8, kdb_current_regs); 199062306a36Sopenharmony_ci break; 199162306a36Sopenharmony_ci case 16: 199262306a36Sopenharmony_ci reg16 = reg64; 199362306a36Sopenharmony_ci dbg_set_reg(i, ®16, kdb_current_regs); 199462306a36Sopenharmony_ci break; 199562306a36Sopenharmony_ci case 32: 199662306a36Sopenharmony_ci reg32 = reg64; 199762306a36Sopenharmony_ci dbg_set_reg(i, ®32, kdb_current_regs); 199862306a36Sopenharmony_ci break; 199962306a36Sopenharmony_ci case 64: 200062306a36Sopenharmony_ci dbg_set_reg(i, ®64, 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