1/* $NetBSD: db_variables.c,v 1.41 2009/03/07 22:02:17 ad Exp $ */ 2 3/* 4 * Mach Operating System 5 * Copyright (c) 1991,1990 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: db_variables.c,v 1.41 2009/03/07 22:02:17 ad Exp $"); 31 32#ifdef _KERNEL_OPT 33#include "opt_ddbparam.h" 34#endif 35 36#include <sys/param.h> 37#include <sys/proc.h> 38#include <uvm/uvm_extern.h> 39#include <sys/sysctl.h> 40 41#include <ddb/ddb.h> 42#include <ddb/ddbvar.h> 43 44/* 45 * If this is non-zero, the DDB will be entered when the system 46 * panics. Initialize it so that it's patchable. 47 */ 48#ifndef DDB_ONPANIC 49#define DDB_ONPANIC 1 50#endif 51int db_onpanic = DDB_ONPANIC; 52 53/* 54 * Can DDB can be entered from the console? 55 */ 56#ifndef DDB_FROMCONSOLE 57#define DDB_FROMCONSOLE 1 58#endif 59int db_fromconsole = DDB_FROMCONSOLE; 60 61/* 62 * Output DDB output to the message buffer? 63 */ 64#ifndef DDB_TEE_MSGBUF 65#define DDB_TEE_MSGBUF 0 66#endif 67int db_tee_msgbuf = DDB_TEE_MSGBUF; 68 69 70static int db_rw_internal_variable(const struct db_variable *, db_expr_t *, 71 int); 72static int db_find_variable(const struct db_variable **); 73 74/* XXX must all be ints for sysctl. */ 75const struct db_variable db_vars[] = { 76 { "radix", (void *)&db_radix, db_rw_internal_variable, NULL }, 77 { "maxoff", (void *)&db_maxoff, db_rw_internal_variable, NULL }, 78 { "maxwidth", (void *)&db_max_width, db_rw_internal_variable, NULL }, 79 { "tabstops", (void *)&db_tab_stop_width, db_rw_internal_variable, NULL }, 80 { "lines", (void *)&db_max_line, db_rw_internal_variable, NULL }, 81 { "onpanic", (void *)&db_onpanic, db_rw_internal_variable, NULL }, 82 { "fromconsole", (void *)&db_fromconsole, db_rw_internal_variable, NULL }, 83 { "tee_msgbuf", (void *)&db_tee_msgbuf, db_rw_internal_variable, NULL }, 84}; 85const struct db_variable * const db_evars = db_vars + sizeof(db_vars)/sizeof(db_vars[0]); 86 87/* 88 * ddb command line access to the DDB variables defined above. 89 */ 90static int 91db_rw_internal_variable(const struct db_variable *vp, db_expr_t *valp, int rw) 92{ 93 94 if (rw == DB_VAR_GET) 95 *valp = *(int *)vp->valuep; 96 else 97 *(int *)vp->valuep = *valp; 98 return (0); 99} 100 101/* 102 * sysctl(3) access to the DDB variables defined above. 103 */ 104#ifdef _KERNEL 105SYSCTL_SETUP(sysctl_ddb_setup, "sysctl ddb subtree setup") 106{ 107 108 sysctl_createv(clog, 0, NULL, NULL, 109 CTLFLAG_PERMANENT, 110 CTLTYPE_NODE, "ddb", NULL, 111 NULL, 0, NULL, 0, 112 CTL_DDB, CTL_EOL); 113 114 sysctl_createv(clog, 0, NULL, NULL, 115 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 116 CTLTYPE_INT, "radix", 117 SYSCTL_DESCR("Input and output radix"), 118 NULL, 0, &db_radix, 0, 119 CTL_DDB, DDBCTL_RADIX, CTL_EOL); 120 sysctl_createv(clog, 0, NULL, NULL, 121 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 122 CTLTYPE_INT, "maxoff", 123 SYSCTL_DESCR("Maximum symbol offset"), 124 NULL, 0, &db_maxoff, 0, 125 CTL_DDB, DDBCTL_MAXOFF, CTL_EOL); 126 sysctl_createv(clog, 0, NULL, NULL, 127 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 128 CTLTYPE_INT, "maxwidth", 129 SYSCTL_DESCR("Maximum output line width"), 130 NULL, 0, &db_max_width, 0, 131 CTL_DDB, DDBCTL_MAXWIDTH, CTL_EOL); 132 sysctl_createv(clog, 0, NULL, NULL, 133 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 134 CTLTYPE_INT, "lines", 135 SYSCTL_DESCR("Number of display lines"), 136 NULL, 0, &db_max_line, 0, 137 CTL_DDB, DDBCTL_LINES, CTL_EOL); 138 sysctl_createv(clog, 0, NULL, NULL, 139 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 140 CTLTYPE_INT, "tabstops", 141 SYSCTL_DESCR("Output tab width"), 142 NULL, 0, &db_tab_stop_width, 0, 143 CTL_DDB, DDBCTL_TABSTOPS, CTL_EOL); 144 sysctl_createv(clog, 0, NULL, NULL, 145 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 146 CTLTYPE_INT, "onpanic", 147 SYSCTL_DESCR("Whether to enter ddb on a kernel panic"), 148 NULL, 0, &db_onpanic, 0, 149 CTL_DDB, DDBCTL_ONPANIC, CTL_EOL); 150 sysctl_createv(clog, 0, NULL, NULL, 151 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 152 CTLTYPE_INT, "fromconsole", 153 SYSCTL_DESCR("Whether ddb can be entered from the " 154 "console"), 155 NULL, 0, &db_fromconsole, 0, 156 CTL_DDB, DDBCTL_FROMCONSOLE, CTL_EOL); 157 sysctl_createv(clog, 0, NULL, NULL, 158 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 159 CTLTYPE_INT, "tee_msgbuf", 160 SYSCTL_DESCR("Whether to tee ddb output to the msgbuf"), 161 NULL, 0, &db_tee_msgbuf, 0, 162 CTL_DDB, CTL_CREATE, CTL_EOL); 163 164 sysctl_createv(clog, 0, NULL, NULL, 165 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 166 CTLTYPE_STRING, "commandonenter", 167 SYSCTL_DESCR("Command to be executed on each ddb enter"), 168 NULL, 0, &db_cmd_on_enter, DB_LINE_MAXLEN, 169 CTL_DDB, CTL_CREATE, CTL_EOL); 170} 171#endif /* _KERNEL */ 172 173int 174db_find_variable(const struct db_variable **varp) 175{ 176 int t; 177 const struct db_variable *vp; 178 179 t = db_read_token(); 180 if (t == tIDENT) { 181 for (vp = db_vars; vp < db_evars; vp++) { 182 if (!strcmp(db_tok_string, vp->name)) { 183 *varp = vp; 184 return (1); 185 } 186 } 187 for (vp = db_regs; vp < db_eregs; vp++) { 188 if (!strcmp(db_tok_string, vp->name)) { 189 *varp = vp; 190 return (1); 191 } 192 } 193 } 194 db_error("Unknown variable\n"); 195 /*NOTREACHED*/ 196 return 0; 197} 198 199int 200db_get_variable(db_expr_t *valuep) 201{ 202 const struct db_variable *vp; 203 204 if (!db_find_variable(&vp)) 205 return (0); 206 207 db_read_variable(vp, valuep); 208 209 return (1); 210} 211 212int 213db_set_variable(db_expr_t value) 214{ 215 const struct db_variable *vp; 216 217 if (!db_find_variable(&vp)) 218 return (0); 219 220 db_write_variable(vp, &value); 221 222 return (1); 223} 224 225 226void 227db_read_variable(const struct db_variable *vp, db_expr_t *valuep) 228{ 229 int (*func)(const struct db_variable *, db_expr_t *, int) = vp->fcn; 230 231 if (func == FCN_NULL) 232 *valuep = *(vp->valuep); 233 else 234 (*func)(vp, valuep, DB_VAR_GET); 235} 236 237void 238db_write_variable(const struct db_variable *vp, db_expr_t *valuep) 239{ 240 int (*func)(const struct db_variable *, db_expr_t *, int) = vp->fcn; 241 242 if (func == FCN_NULL) 243 *(vp->valuep) = *valuep; 244 else 245 (*func)(vp, valuep, DB_VAR_SET); 246} 247 248/*ARGSUSED*/ 249void 250db_set_cmd(db_expr_t addr, bool have_addr, 251 db_expr_t count, const char *modif) 252{ 253 db_expr_t value; 254 db_expr_t old_value; 255 const struct db_variable *vp = NULL; /* XXX: GCC */ 256 int t; 257 258 t = db_read_token(); 259 if (t != tDOLLAR) { 260 db_error("Unknown variable\n"); 261 /*NOTREACHED*/ 262 } 263 if (!db_find_variable(&vp)) { 264 db_error("Unknown variable\n"); 265 /*NOTREACHED*/ 266 } 267 268 t = db_read_token(); 269 if (t != tEQ) 270 db_unread_token(t); 271 272 if (!db_expression(&value)) { 273 db_error("No value\n"); 274 /*NOTREACHED*/ 275 } 276 if (db_read_token() != tEOL) { 277 db_error("?\n"); 278 /*NOTREACHED*/ 279 } 280 281 db_read_variable(vp, &old_value); 282 db_printf("$%s\t\t%s = ", vp->name, db_num_to_str(old_value)); 283 db_printf("%s\n", db_num_to_str(value)); 284 db_write_variable(vp, &value); 285} 286