/* * Kernel Debugger Architecture Independent Main Code * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> * Xscale (R) modifications copyright (C) 2003 Intel Corporation. * Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved. */ #include <linux/ctype.h>#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/kmsg_dump.h>#include <linux/reboot.h>#include <linux/sched.h>#include <linux/sched/loadavg.h>#include <linux/sched/stat.h>#include <linux/sched/debug.h>#include <linux/sysrq.h>#include <linux/smp.h>#include <linux/utsname.h>#include <linux/vmalloc.h>#include <linux/atomic.h>#include <linux/moduleparam.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/kallsyms.h>#include <linux/kgdb.h>#include <linux/kdb.h>#include <linux/notifier.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/nmi.h>#include <linux/time.h>#include <linux/ptrace.h>#include <linux/sysctl.h>#include <linux/cpu.h>#include <linux/kdebug.h>#include <linux/proc_fs.h>#include <linux/uaccess.h>#include <linux/slab.h>#include <linux/security.h>#include "kdb_private.h" #undef MODULE_PARAM_PREFIX#define MODULE_PARAM_PREFIX "kdb." static int kdb_cmd_enabled = CONFIG_KDB_DEFAULT_ENABLE;module_param_named(cmd_enable, kdb_cmd_enabled, int, 0600); char kdb_grep_string[KDB_GREP_STRLEN];int kdb_grepping_flag;EXPORT_SYMBOL(kdb_grepping_flag);int kdb_grep_leading;int kdb_grep_trailing; /* * Kernel debugger state flags */unsigned int kdb_flags; /* * kdb_lock protects updates to kdb_initial_cpu. Used to * single thread processors through the kernel debugger. */int kdb_initial_cpu = -1; /* cpu number that owns kdb */int kdb_nextline = 1;int kdb_state; /* General KDB state */ struct task_struct *kdb_current_task;struct pt_regs *kdb_current_regs; const char *kdb_diemsg;static int kdb_go_count;#ifdef CONFIG_KDB_CONTINUE_CATASTROPHICstatic unsigned int kdb_continue_catastrophic = CONFIG_KDB_CONTINUE_CATASTROPHIC;#elsestatic unsigned int kdb_continue_catastrophic;#endif /* kdb_cmds_head describes the available commands. */static LIST_HEAD(kdb_cmds_head); typedef struct _kdbmsg { int km_diag; /* kdb diagnostic */ char *km_msg; /* Corresponding message text */} kdbmsg_t; #define KDBMSG(msgnum, text) \ { KDB_##msgnum, text } static kdbmsg_t kdbmsgs[] = { KDBMSG(NOTFOUND, "Command Not Found"), KDBMSG(ARGCOUNT, "Improper argument count, see usage."), KDBMSG(BADWIDTH, "Illegal value for BYTESPERWORD use 1, 2, 4 or 8, " "8 is only allowed on 64 bit systems"), KDBMSG(BADRADIX, "Illegal value for RADIX use 8, 10 or 16"), KDBMSG(NOTENV, "Cannot find environment variable"), KDBMSG(NOENVVALUE, "Environment variable should have value"), KDBMSG(NOTIMP, "Command not implemented"), KDBMSG(ENVFULL, "Environment full"), KDBMSG(ENVBUFFULL, "Environment buffer full"), KDBMSG(TOOMANYBPT, "Too many breakpoints defined"),#ifdef CONFIG_CPU_XSCALE KDBMSG(TOOMANYDBREGS, "More breakpoints than ibcr registers defined"),#else KDBMSG(TOOMANYDBREGS, "More breakpoints than db registers defined"),#endif KDBMSG(DUPBPT, "Duplicate breakpoint address"), KDBMSG(BPTNOTFOUND, "Breakpoint not found"), KDBMSG(BADMODE, "Invalid IDMODE"), KDBMSG(BADINT, "Illegal numeric value"), KDBMSG(INVADDRFMT, "Invalid symbolic address format"), KDBMSG(BADREG, "Invalid register name"), KDBMSG(BADCPUNUM, "Invalid cpu number"), KDBMSG(BADLENGTH, "Invalid length field"), KDBMSG(NOBP, "No Breakpoint exists"), KDBMSG(BADADDR, "Invalid address"), KDBMSG(NOPERM, "Permission denied"),};#undef KDBMSG static const int __nkdb_err = ARRAY_SIZE(kdbmsgs); /* * Initial environment. This is all kept static and local to * this file. We don't want to rely on the memory allocation * mechanisms in the kernel, so we use a very limited allocate-only * heap for new and altered environment variables. The entire * environment is limited to a fixed number of entries (add more * to __env[] if required) and a fixed amount of heap (add more to * KDB_ENVBUFSIZE if required). */ static char *__env[31] = {#if defined(CONFIG_SMP) "PROMPT=[%d]kdb> ",#else "PROMPT=kdb> ",#endif "MOREPROMPT=more> ", "RADIX=16", "MDCOUNT=8", /* lines of md output */ KDB_PLATFORM_ENV, "DTABCOUNT=30", "NOSECT=1",}; static const int __nenv = ARRAY_SIZE(__env); struct task_struct *kdb_curr_task(int cpu){ struct task_struct *p = curr_task(cpu);#ifdef _TIF_MCA_INIT if ((task_thread_info(p)->flags & _TIF_MCA_INIT) && KDB_TSK(cpu)) p = krp->p;#endif return p;} /* * Update the permissions flags (kdb_cmd_enabled) to match the * current lockdown state. * * Within this function the calls to security_locked_down() are "lazy". We * avoid calling them if the current value of kdb_cmd_enabled already excludes * flags that might be subject to lockdown. Additionally we deliberately check * the lockdown flags independently (even though read lockdown implies write * lockdown) since that results in both simpler code and clearer messages to * the user on first-time debugger entry. * * The permission masks during a read+write lockdown permits the following * flags: INSPECT, SIGNAL, REBOOT (and ALWAYS_SAFE). * * The INSPECT commands are not blocked during lockdown because they are * not arbitrary memory reads. INSPECT covers the backtrace family (sometimes * forcing them to have no arguments) and lsmod. These commands do expose * some kernel state but do not allow the developer seated at the console to * choose what state is reported. SIGNAL and REBOOT should not be controversial, * given these are allowed for root during lockdown already. */static void kdb_check_for_lockdown(void){ const int write_flags = KDB_ENABLE_MEM_WRITE | KDB_ENABLE_REG_WRITE | KDB_ENABLE_FLOW_CTRL; const int read_flags = KDB_ENABLE_MEM_READ | KDB_ENABLE_REG_READ; bool need_to_lockdown_write = false; bool need_to_lockdown_read = false; if (kdb_cmd_enabled & (KDB_ENABLE_ALL | write_flags)) need_to_lockdown_write = security_locked_down(LOCKDOWN_DBG_WRITE_KERNEL); if (kdb_cmd_enabled & (KDB_ENABLE_ALL | read_flags)) need_to_lockdown_read = security_locked_down(LOCKDOWN_DBG_READ_KERNEL); /* De-compose KDB_ENABLE_ALL if required */ if (need_to_lockdown_write || need_to_lockdown_read) if (kdb_cmd_enabled & KDB_ENABLE_ALL) kdb_cmd_enabled = KDB_ENABLE_MASK & ~KDB_ENABLE_ALL; if (need_to_lockdown_write) kdb_cmd_enabled &= ~write_flags; if (need_to_lockdown_read) kdb_cmd_enabled &= ~read_flags;} /* * Check whether the flags of the current command, the permissions of the kdb * console and the lockdown state allow a command to be run. */static bool kdb_check_flags(kdb_cmdflags_t flags, int permissions, bool no_args){ /* permissions comes from userspace so needs massaging slightly */ permissions &= KDB_ENABLE_MASK; permissions |= KDB_ENABLE_ALWAYS_SAFE; /* some commands change group when launched with no arguments */ if (no_args) permissions |= permissions << KDB_ENABLE_NO_ARGS_SHIFT; flags |= KDB_ENABLE_ALL; return permissions & flags;} /* * kdbgetenv - This function will return the character string value of * an environment variable. * Parameters: * match A character string representing an environment variable. * Returns: * NULL No environment variable matches 'match' * char* Pointer to string value of environment variable. */char *kdbgetenv(const char *match){ char **ep = __env; int matchlen = strlen(match); int i; for (i = 0; i < __nenv; i++) { char *e = *ep++; if (!e) continue; if ((strncmp(match, e, matchlen) == 0) && ((e[matchlen] == '\0') || (e[matchlen] == '='))) { char *cp = strchr(e, '='); return cp ? ++cp : ""; } } return NULL;} /* * kdballocenv - This function is used to allocate bytes for * environment entries. * Parameters: * bytes The number of bytes to allocate in the static buffer. * Returns: * A pointer to the allocated space in the buffer on success. * NULL if bytes > size available in the envbuffer. * Remarks: * We use a static environment buffer (envbuffer) to hold the values * of dynamically generated environment variables (see kdb_set). Buffer * space once allocated is never free'd, so over time, the amount of space * (currently 512 bytes) will be exhausted if env variables are changed * frequently. */static char *kdballocenv(size_t bytes){#define KDB_ENVBUFSIZE 512 static char envbuffer[KDB_ENVBUFSIZE]; static int envbufsize; char *ep = NULL; if ((KDB_ENVBUFSIZE - envbufsize) >= bytes) { ep = &envbuffer[envbufsize]; envbufsize += bytes; } return ep;} /* * kdbgetulenv - This function will return the value of an unsigned * long-valued environment variable. * Parameters: * match A character string representing a numeric value * Outputs: * *value the unsigned long representation of the env variable 'match' * Returns: * Zero on success, a kdb diagnostic on failure. */static int kdbgetulenv(const char *match, unsigned long *value){ char *ep; ep = kdbgetenv(match); if (!ep) return KDB_NOTENV; if (strlen(ep) == 0) return KDB_NOENVVALUE; *value = simple_strtoul(ep, NULL, 0); return 0;} /* * kdbgetintenv - This function will return the value of an * integer-valued environment variable. * Parameters: * match A character string representing an integer-valued env variable * Outputs: * *value the integer representation of the environment variable 'match' * Returns: * Zero on success, a kdb diagnostic on failure. */int kdbgetintenv(const char *match, int *value){ unsigned long val; int diag; diag = kdbgetulenv(match, &val); if (!diag) *value = (int) val; return diag;} /* * kdb_setenv() - Alter an existing environment variable or create a new one. * @var: Name of the variable * @val: Value of the variable * * Return: Zero on success, a kdb diagnostic on failure. */static int kdb_setenv(const char *var, const char *val){ int i; char *ep; size_t varlen, vallen; varlen = strlen(var); vallen = strlen(val); ep = kdballocenv(varlen + vallen + 2); if (ep == (char *)0) return KDB_ENVBUFFULL; sprintf(ep, "%s=%s", var, val); for (i = 0; i < __nenv; i++) { if (__env[i] && ((strncmp(__env[i], var, varlen) == 0) && ((__env[i][varlen] == '\0') || (__env[i][varlen] == '=')))) { __env[i] = ep; return 0; } } /* * Wasn't existing variable. Fit into slot. */ for (i = 0; i < __nenv-1; i++) { if (__env[i] == (char *)0) { __env[i] = ep; return 0; } } return KDB_ENVFULL;} /* * kdb_printenv() - Display the current environment variables. */static void kdb_printenv(void){ int i; for (i = 0; i < __nenv; i++) { if (__env[i]) kdb_printf("%s\n", __env[i]); }} /* * kdbgetularg - This function will convert a numeric string into an * unsigned long value. * Parameters: * arg A character string representing a numeric value * Outputs: * *value the unsigned long representation of arg. * Returns: * Zero on success, a kdb diagnostic on failure. */int kdbgetularg(const char *arg, unsigned long *value){ char *endp; unsigned long val; val = simple_strtoul(arg, &endp, 0); if (endp == arg) { /* * Also try base 16, for us folks too lazy to type the * leading 0x... */ val = simple_strtoul(arg, &endp, 16); if (endp == arg) return KDB_BADINT; } *value = val; return 0;} int kdbgetu64arg(const char *arg, u64 *value){ char *endp; u64 val; val = simple_strtoull(arg, &endp, 0); if (endp == arg) { val = simple_strtoull(arg, &endp, 16); if (endp == arg) return KDB_BADINT; } *value = val; return 0;} /* * kdb_set - This function implements the 'set' command. Alter an * existing environment variable or create a new one. */int kdb_set(int argc, const char **argv){ /* * we can be invoked two ways: * set var=value argv[1]="var", argv[2]="value" * set var = value argv[1]="var", argv[2]="=", argv[3]="value" * - if the latter, shift 'em down. */ if (argc == 3) { argv[2] = argv[3]; argc--; } if (argc != 2) return KDB_ARGCOUNT; /* * Censor sensitive variables */ if (strcmp(argv[1], "PROMPT") == 0 && !kdb_check_flags(KDB_ENABLE_MEM_READ, kdb_cmd_enabled, false)) return KDB_NOPERM; /* * Check for internal variables */ if (strcmp(argv[1], "KDBDEBUG") == 0) { unsigned int debugflags; char *cp; debugflags = simple_strtoul(argv[2], &cp, 0); if (cp == argv[2] || debugflags & ~KDB_DEBUG_FLAG_MASK) { kdb_printf("kdb: illegal debug flags '%s'\n", argv[2]); return 0; } kdb_flags = (kdb_flags & ~KDB_DEBUG(MASK)) | (debugflags << KDB_DEBUG_FLAG_SHIFT); return 0; } /*Lines 1–500 of 2936. Load more
/* * Kernel Debugger Architecture Independent Main Code * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> * Xscale (R) modifications copyright (C) 2003 Intel Corporation. * Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved. */ #include <linux/ctype.h> #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/kmsg_dump.h> #include <linux/reboot.h> #include <linux/sched.h> #include <linux/sched/loadavg.h> #include <linux/sched/stat.h> #include <linux/sched/debug.h> #include <linux/sysrq.h> #include <linux/smp.h> #include <linux/utsname.h> #include <linux/vmalloc.h> #include <linux/atomic.h> #include <linux/moduleparam.h> #include <linux/mm.h> #include <linux/init.h> #include <linux/kallsyms.h> #include <linux/kgdb.h> #include <linux/kdb.h> #include <linux/notifier.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/nmi.h> #include <linux/time.h> #include <linux/ptrace.h> #include <linux/sysctl.h> #include <linux/cpu.h> #include <linux/kdebug.h> #include <linux/proc_fs.h> #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/security.h> #include "kdb_private.h" #undef MODULE_PARAM_PREFIX #define MODULE_PARAM_PREFIX "kdb." static int kdb_cmd_enabled = CONFIG_KDB_DEFAULT_ENABLE; module_param_named(cmd_enable, kdb_cmd_enabled, int, 0600); char kdb_grep_string[KDB_GREP_STRLEN]; int kdb_grepping_flag; EXPORT_SYMBOL(kdb_grepping_flag); int kdb_grep_leading; int kdb_grep_trailing; /* * Kernel debugger state flags */ unsigned int kdb_flags; /* * kdb_lock protects updates to kdb_initial_cpu. Used to * single thread processors through the kernel debugger. */ int kdb_initial_cpu = -1; /* cpu number that owns kdb */ int kdb_nextline = 1; int kdb_state; /* General KDB state */ struct task_struct *kdb_current_task; struct pt_regs *kdb_current_regs; const char *kdb_diemsg; static int kdb_go_count; #ifdef CONFIG_KDB_CONTINUE_CATASTROPHIC static unsigned int kdb_continue_catastrophic = CONFIG_KDB_CONTINUE_CATASTROPHIC; #else static unsigned int kdb_continue_catastrophic; #endif /* kdb_cmds_head describes the available commands. */ static LIST_HEAD(kdb_cmds_head); typedef struct _kdbmsg { int km_diag; /* kdb diagnostic */ char *km_msg; /* Corresponding message text */ } kdbmsg_t; #define KDBMSG(msgnum, text) \ { KDB_##msgnum, text } static kdbmsg_t kdbmsgs[] = { KDBMSG(NOTFOUND, "Command Not Found"), KDBMSG(ARGCOUNT, "Improper argument count, see usage."), KDBMSG(BADWIDTH, "Illegal value for BYTESPERWORD use 1, 2, 4 or 8, " "8 is only allowed on 64 bit systems"), KDBMSG(BADRADIX, "Illegal value for RADIX use 8, 10 or 16"), KDBMSG(NOTENV, "Cannot find environment variable"), KDBMSG(NOENVVALUE, "Environment variable should have value"), KDBMSG(NOTIMP, "Command not implemented"), KDBMSG(ENVFULL, "Environment full"), KDBMSG(ENVBUFFULL, "Environment buffer full"), KDBMSG(TOOMANYBPT, "Too many breakpoints defined"), #ifdef CONFIG_CPU_XSCALE KDBMSG(TOOMANYDBREGS, "More breakpoints than ibcr registers defined"), #else KDBMSG(TOOMANYDBREGS, "More breakpoints than db registers defined"), #endif KDBMSG(DUPBPT, "Duplicate breakpoint address"), KDBMSG(BPTNOTFOUND, "Breakpoint not found"), KDBMSG(BADMODE, "Invalid IDMODE"), KDBMSG(BADINT, "Illegal numeric value"), KDBMSG(INVADDRFMT, "Invalid symbolic address format"), KDBMSG(BADREG, "Invalid register name"), KDBMSG(BADCPUNUM, "Invalid cpu number"), KDBMSG(BADLENGTH, "Invalid length field"), KDBMSG(NOBP, "No Breakpoint exists"), KDBMSG(BADADDR, "Invalid address"), KDBMSG(NOPERM, "Permission denied"), }; #undef KDBMSG static const int __nkdb_err = ARRAY_SIZE(kdbmsgs); /* * Initial environment. This is all kept static and local to * this file. We don't want to rely on the memory allocation * mechanisms in the kernel, so we use a very limited allocate-only * heap for new and altered environment variables. The entire * environment is limited to a fixed number of entries (add more * to __env[] if required) and a fixed amount of heap (add more to * KDB_ENVBUFSIZE if required). */ static char *__env[31] = { #if defined(CONFIG_SMP) "PROMPT=[%d]kdb> ", #else "PROMPT=kdb> ", #endif "MOREPROMPT=more> ", "RADIX=16", "MDCOUNT=8", /* lines of md output */ KDB_PLATFORM_ENV, "DTABCOUNT=30", "NOSECT=1", }; static const int __nenv = ARRAY_SIZE(__env); struct task_struct *kdb_curr_task(int cpu) { struct task_struct *p = curr_task(cpu); #ifdef _TIF_MCA_INIT if ((task_thread_info(p)->flags & _TIF_MCA_INIT) && KDB_TSK(cpu)) p = krp->p; #endif return p; } /* * Update the permissions flags (kdb_cmd_enabled) to match the * current lockdown state. * * Within this function the calls to security_locked_down() are "lazy". We * avoid calling them if the current value of kdb_cmd_enabled already excludes * flags that might be subject to lockdown. Additionally we deliberately check * the lockdown flags independently (even though read lockdown implies write * lockdown) since that results in both simpler code and clearer messages to * the user on first-time debugger entry. * * The permission masks during a read+write lockdown permits the following * flags: INSPECT, SIGNAL, REBOOT (and ALWAYS_SAFE). * * The INSPECT commands are not blocked during lockdown because they are * not arbitrary memory reads. INSPECT covers the backtrace family (sometimes * forcing them to have no arguments) and lsmod. These commands do expose * some kernel state but do not allow the developer seated at the console to * choose what state is reported. SIGNAL and REBOOT should not be controversial, * given these are allowed for root during lockdown already. */ static void kdb_check_for_lockdown(void) { const int write_flags = KDB_ENABLE_MEM_WRITE | KDB_ENABLE_REG_WRITE | KDB_ENABLE_FLOW_CTRL; const int read_flags = KDB_ENABLE_MEM_READ | KDB_ENABLE_REG_READ; bool need_to_lockdown_write = false; bool need_to_lockdown_read = false; if (kdb_cmd_enabled & (KDB_ENABLE_ALL | write_flags)) need_to_lockdown_write = security_locked_down(LOCKDOWN_DBG_WRITE_KERNEL); if (kdb_cmd_enabled & (KDB_ENABLE_ALL | read_flags)) need_to_lockdown_read = security_locked_down(LOCKDOWN_DBG_READ_KERNEL); /* De-compose KDB_ENABLE_ALL if required */ if (need_to_lockdown_write || need_to_lockdown_read) if (kdb_cmd_enabled & KDB_ENABLE_ALL) kdb_cmd_enabled = KDB_ENABLE_MASK & ~KDB_ENABLE_ALL; if (need_to_lockdown_write) kdb_cmd_enabled &= ~write_flags; if (need_to_lockdown_read) kdb_cmd_enabled &= ~read_flags; } /* * Check whether the flags of the current command, the permissions of the kdb * console and the lockdown state allow a command to be run. */ static bool kdb_check_flags(kdb_cmdflags_t flags, int permissions, bool no_args) { /* permissions comes from userspace so needs massaging slightly */ permissions &= KDB_ENABLE_MASK; permissions |= KDB_ENABLE_ALWAYS_SAFE; /* some commands change group when launched with no arguments */ if (no_args) permissions |= permissions << KDB_ENABLE_NO_ARGS_SHIFT; flags |= KDB_ENABLE_ALL; return permissions & flags; } /* * kdbgetenv - This function will return the character string value of * an environment variable. * Parameters: * match A character string representing an environment variable. * Returns: * NULL No environment variable matches 'match' * char* Pointer to string value of environment variable. */ char *kdbgetenv(const char *match) { char **ep = __env; int matchlen = strlen(match); int i; for (i = 0; i < __nenv; i++) { char *e = *ep++; if (!e) continue; if ((strncmp(match, e, matchlen) == 0) && ((e[matchlen] == '\0') || (e[matchlen] == '='))) { char *cp = strchr(e, '='); return cp ? ++cp : ""; } } return NULL; } /* * kdballocenv - This function is used to allocate bytes for * environment entries. * Parameters: * bytes The number of bytes to allocate in the static buffer. * Returns: * A pointer to the allocated space in the buffer on success. * NULL if bytes > size available in the envbuffer. * Remarks: * We use a static environment buffer (envbuffer) to hold the values * of dynamically generated environment variables (see kdb_set). Buffer * space once allocated is never free'd, so over time, the amount of space * (currently 512 bytes) will be exhausted if env variables are changed * frequently. */ static char *kdballocenv(size_t bytes) { #define KDB_ENVBUFSIZE 512 static char envbuffer[KDB_ENVBUFSIZE]; static int envbufsize; char *ep = NULL; if ((KDB_ENVBUFSIZE - envbufsize) >= bytes) { ep = &envbuffer[envbufsize]; envbufsize += bytes; } return ep; } /* * kdbgetulenv - This function will return the value of an unsigned * long-valued environment variable. * Parameters: * match A character string representing a numeric value * Outputs: * *value the unsigned long representation of the env variable 'match' * Returns: * Zero on success, a kdb diagnostic on failure. */ static int kdbgetulenv(const char *match, unsigned long *value) { char *ep; ep = kdbgetenv(match); if (!ep) return KDB_NOTENV; if (strlen(ep) == 0) return KDB_NOENVVALUE; *value = simple_strtoul(ep, NULL, 0); return 0; } /* * kdbgetintenv - This function will return the value of an * integer-valued environment variable. * Parameters: * match A character string representing an integer-valued env variable * Outputs: * *value the integer representation of the environment variable 'match' * Returns: * Zero on success, a kdb diagnostic on failure. */ int kdbgetintenv(const char *match, int *value) { unsigned long val; int diag; diag = kdbgetulenv(match, &val); if (!diag) *value = (int) val; return diag; } /* * kdb_setenv() - Alter an existing environment variable or create a new one. * @var: Name of the variable * @val: Value of the variable * * Return: Zero on success, a kdb diagnostic on failure. */ static int kdb_setenv(const char *var, const char *val) { int i; char *ep; size_t varlen, vallen; varlen = strlen(var); vallen = strlen(val); ep = kdballocenv(varlen + vallen + 2); if (ep == (char *)0) return KDB_ENVBUFFULL; sprintf(ep, "%s=%s", var, val); for (i = 0; i < __nenv; i++) { if (__env[i] && ((strncmp(__env[i], var, varlen) == 0) && ((__env[i][varlen] == '\0') || (__env[i][varlen] == '=')))) { __env[i] = ep; return 0; } } /* * Wasn't existing variable. Fit into slot. */ for (i = 0; i < __nenv-1; i++) { if (__env[i] == (char *)0) { __env[i] = ep; return 0; } } return KDB_ENVFULL; } /* * kdb_printenv() - Display the current environment variables. */ static void kdb_printenv(void) { int i; for (i = 0; i < __nenv; i++) { if (__env[i]) kdb_printf("%s\n", __env[i]); } } /* * kdbgetularg - This function will convert a numeric string into an * unsigned long value. * Parameters: * arg A character string representing a numeric value * Outputs: * *value the unsigned long representation of arg. * Returns: * Zero on success, a kdb diagnostic on failure. */ int kdbgetularg(const char *arg, unsigned long *value) { char *endp; unsigned long val; val = simple_strtoul(arg, &endp, 0); if (endp == arg) { /* * Also try base 16, for us folks too lazy to type the * leading 0x... */ val = simple_strtoul(arg, &endp, 16); if (endp == arg) return KDB_BADINT; } *value = val; return 0; } int kdbgetu64arg(const char *arg, u64 *value) { char *endp; u64 val; val = simple_strtoull(arg, &endp, 0); if (endp == arg) { val = simple_strtoull(arg, &endp, 16); if (endp == arg) return KDB_BADINT; } *value = val; return 0; } /* * kdb_set - This function implements the 'set' command. Alter an * existing environment variable or create a new one. */ int kdb_set(int argc, const char **argv) { /* * we can be invoked two ways: * set var=value argv[1]="var", argv[2]="value" * set var = value argv[1]="var", argv[2]="=", argv[3]="value" * - if the latter, shift 'em down. */ if (argc == 3) { argv[2] = argv[3]; argc--; } if (argc != 2) return KDB_ARGCOUNT; /* * Censor sensitive variables */ if (strcmp(argv[1], "PROMPT") == 0 && !kdb_check_flags(KDB_ENABLE_MEM_READ, kdb_cmd_enabled, false)) return KDB_NOPERM; /* * Check for internal variables */ if (strcmp(argv[1], "KDBDEBUG") == 0) { unsigned int debugflags; char *cp; debugflags = simple_strtoul(argv[2], &cp, 0); if (cp == argv[2] || debugflags & ~KDB_DEBUG_FLAG_MASK) { kdb_printf("kdb: illegal debug flags '%s'\n", argv[2]); return 0; } kdb_flags = (kdb_flags & ~KDB_DEBUG(MASK)) | (debugflags << KDB_DEBUG_FLAG_SHIFT); return 0; } /*