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