xref: /netbsd-src/sys/ddb/db_variables.c (revision 5a4646458a79167b3f7246cd799fcfc09fbe2b05)
1 /*	$NetBSD: db_variables.c,v 1.47 2020/03/10 15:58:37 christos 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.47 2020/03/10 15:58:37 christos 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
51 int		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
59 int		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
67 int		db_tee_msgbuf = DDB_TEE_MSGBUF;
68 
69 #ifndef DDB_PANICSTACKFRAMES
70 #define DDB_PANICSTACKFRAMES 65535
71 #endif
72 int		db_panicstackframes = DDB_PANICSTACKFRAMES;
73 
74 #ifndef DDB_DUMPSTACK
75 #define DDB_DUMPSTACK 1
76 #endif
77 int 		db_dumpstack = DDB_DUMPSTACK;
78 
79 static int	db_rw_internal_variable(const struct db_variable *, db_expr_t *,
80 		    int);
81 static int	db_find_variable(const struct db_variable **);
82 
83 /* XXX must all be ints for sysctl. */
84 const struct db_variable db_vars[] = {
85 	{
86 		.name = "fromconsole",
87 		.valuep = &db_fromconsole,
88 		.fcn = db_rw_internal_variable,
89 		.modif = NULL,
90 	},
91 	{
92 		.name = "maxoff",
93 		.valuep = &db_maxoff,
94 		.fcn = db_rw_internal_variable,
95 		.modif = NULL,
96 	},
97 	{
98 		.name = "maxwidth",
99 		.valuep = &db_max_width,
100 		.fcn = db_rw_internal_variable,
101 		.modif = NULL,
102 	},
103 	{
104 		.name = "lines",
105 		.valuep = &db_max_line,
106 		.fcn = db_rw_internal_variable,
107 		.modif = NULL,
108 	},
109 	{
110 		.name = "onpanic",
111 		.valuep = &db_onpanic,
112 		.fcn = db_rw_internal_variable,
113 		.modif = NULL,
114 	},
115 	{
116 		.name = "panicstackframes",
117 		.valuep = &db_panicstackframes,
118 		.fcn = db_rw_internal_variable,
119 		.modif = NULL,
120 	},
121 	{
122 		.name = "dumpstack",
123 		.valuep = &db_dumpstack,
124 		.fcn = db_rw_internal_variable,
125 		.modif = NULL,
126 	},
127 	{
128 		.name = "radix",
129 		.valuep = &db_radix,
130 		.fcn = db_rw_internal_variable,
131 		.modif = NULL,
132 	},
133 	{
134 		.name = "tabstops",
135 		.valuep = &db_tab_stop_width,
136 		.fcn = db_rw_internal_variable,
137 		.modif = NULL,
138 	},
139 	{
140 		.name = "tee_msgbuf",
141 		.valuep = &db_tee_msgbuf,
142 		.fcn = db_rw_internal_variable,
143 		.modif = NULL,
144 	},
145 };
146 const struct db_variable * const db_evars = db_vars + __arraycount(db_vars);
147 
148 /*
149  * ddb command line access to the DDB variables defined above.
150  */
151 static int
db_rw_internal_variable(const struct db_variable * vp,db_expr_t * valp,int rw)152 db_rw_internal_variable(const struct db_variable *vp, db_expr_t *valp, int rw)
153 {
154 
155 	if (rw == DB_VAR_GET)
156 		*valp = *(int *)vp->valuep;
157 	else
158 		*(int *)vp->valuep = *valp;
159 	return (0);
160 }
161 
162 /*
163  * sysctl(3) access to the DDB variables defined above.
164  */
165 #ifdef _KERNEL
166 SYSCTL_SETUP(sysctl_ddb_setup, "sysctl ddb subtree setup")
167 {
168 
169 	sysctl_createv(clog, 0, NULL, NULL,
170 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
171 		       CTLTYPE_INT, "radix",
172 		       SYSCTL_DESCR("Input and output radix"),
173 		       NULL, 0, &db_radix, 0,
174 		       CTL_DDB, DDBCTL_RADIX, CTL_EOL);
175 	sysctl_createv(clog, 0, NULL, NULL,
176 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
177 		       CTLTYPE_INT, "maxoff",
178 		       SYSCTL_DESCR("Maximum symbol offset"),
179 		       NULL, 0, &db_maxoff, 0,
180 		       CTL_DDB, DDBCTL_MAXOFF, CTL_EOL);
181 	sysctl_createv(clog, 0, NULL, NULL,
182 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
183 		       CTLTYPE_INT, "maxwidth",
184 		       SYSCTL_DESCR("Maximum output line width"),
185 		       NULL, 0, &db_max_width, 0,
186 		       CTL_DDB, DDBCTL_MAXWIDTH, CTL_EOL);
187 	sysctl_createv(clog, 0, NULL, NULL,
188 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
189 		       CTLTYPE_INT, "lines",
190 		       SYSCTL_DESCR("Number of display lines"),
191 		       NULL, 0, &db_max_line, 0,
192 		       CTL_DDB, DDBCTL_LINES, CTL_EOL);
193 	sysctl_createv(clog, 0, NULL, NULL,
194 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
195 		       CTLTYPE_INT, "tabstops",
196 		       SYSCTL_DESCR("Output tab width"),
197 		       NULL, 0, &db_tab_stop_width, 0,
198 		       CTL_DDB, DDBCTL_TABSTOPS, CTL_EOL);
199 	sysctl_createv(clog, 0, NULL, NULL,
200 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
201 		       CTLTYPE_INT, "onpanic",
202 		       SYSCTL_DESCR("Whether to enter ddb on a kernel panic"),
203 		       NULL, 0, &db_onpanic, 0,
204 		       CTL_DDB, DDBCTL_ONPANIC, CTL_EOL);
205 	sysctl_createv(clog, 0, NULL, NULL,
206 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
207 		       CTLTYPE_INT, "fromconsole",
208 		       SYSCTL_DESCR("Whether ddb can be entered from the "
209 				    "console"),
210 		       NULL, 0, &db_fromconsole, 0,
211 		       CTL_DDB, DDBCTL_FROMCONSOLE, CTL_EOL);
212 	sysctl_createv(clog, 0, NULL, NULL,
213 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
214 		       CTLTYPE_INT, "tee_msgbuf",
215 		       SYSCTL_DESCR("Whether to tee ddb output to the msgbuf"),
216 		       NULL, 0, &db_tee_msgbuf, 0,
217 		       CTL_DDB, CTL_CREATE, CTL_EOL);
218 	sysctl_createv(clog, 0, NULL, NULL,
219 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
220 		       CTLTYPE_STRING, "commandonenter",
221 		       SYSCTL_DESCR("Command to be executed on each ddb enter"),
222 		       NULL, 0, db_cmd_on_enter, DB_LINE_MAXLEN,
223 		       CTL_DDB, CTL_CREATE, CTL_EOL);
224 	sysctl_createv(clog, 0, NULL, NULL,
225 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
226 		       CTLTYPE_INT, "panicstackframes",
227 		       SYSCTL_DESCR("Number of stack frames to print on panic"),
228 		       NULL, 0, &db_panicstackframes, 0,
229 		       CTL_DDB, CTL_CREATE, CTL_EOL);
230 	sysctl_createv(clog, 0, NULL, NULL,
231 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
232 		       CTLTYPE_INT, "dumpstack",
233 		       SYSCTL_DESCR("On panic print stack trace"),
234 		       NULL, 0, &db_dumpstack, 0,
235 		       CTL_DDB, CTL_CREATE, CTL_EOL);
236 }
237 #endif	/* _KERNEL */
238 
239 int
db_find_variable(const struct db_variable ** varp)240 db_find_variable(const struct db_variable **varp)
241 {
242 	int	t;
243 	const struct db_variable *vp;
244 
245 	t = db_read_token();
246 	if (t == tIDENT) {
247 		for (vp = db_vars; vp < db_evars; vp++) {
248 			if (!strcmp(db_tok_string, vp->name)) {
249 				*varp = vp;
250 				return (1);
251 			}
252 		}
253 #ifdef _KERNEL
254 		for (vp = db_regs; vp < db_eregs; vp++) {
255 			if (!strcmp(db_tok_string, vp->name)) {
256 				*varp = vp;
257 				return (1);
258 			}
259 		}
260 #endif
261 	}
262 	db_error("Unknown variable\n");
263 	/*NOTREACHED*/
264 	return 0;
265 }
266 
267 int
db_get_variable(db_expr_t * valuep)268 db_get_variable(db_expr_t *valuep)
269 {
270 	const struct db_variable *vp;
271 
272 	if (!db_find_variable(&vp))
273 		return (0);
274 
275 	db_read_variable(vp, valuep);
276 
277 	return (1);
278 }
279 
280 int
db_set_variable(db_expr_t value)281 db_set_variable(db_expr_t value)
282 {
283 	const struct db_variable *vp;
284 
285 	if (!db_find_variable(&vp))
286 		return (0);
287 
288 	db_write_variable(vp, &value);
289 
290 	return (1);
291 }
292 
293 
294 void
db_read_variable(const struct db_variable * vp,db_expr_t * valuep)295 db_read_variable(const struct db_variable *vp, db_expr_t *valuep)
296 {
297 	int (*func)(const struct db_variable *, db_expr_t *, int) = vp->fcn;
298 
299 	if (func == FCN_NULL)
300 		*valuep = *(db_expr_t *)vp->valuep;
301 	else
302 		(*func)(vp, valuep, DB_VAR_GET);
303 }
304 
305 void
db_write_variable(const struct db_variable * vp,db_expr_t * valuep)306 db_write_variable(const struct db_variable *vp, db_expr_t *valuep)
307 {
308 	int (*func)(const struct db_variable *, db_expr_t *, int) = vp->fcn;
309 
310 	if (func == FCN_NULL)
311 		*(db_expr_t *)vp->valuep = *valuep;
312 	else
313 		(*func)(vp, valuep, DB_VAR_SET);
314 }
315 
316 /*ARGSUSED*/
317 void
db_set_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)318 db_set_cmd(db_expr_t addr, bool have_addr,
319     db_expr_t count, const char *modif)
320 {
321 	db_expr_t	value;
322 	db_expr_t	old_value;
323 	const struct db_variable *vp = NULL;	/* XXX: GCC */
324 	int	t;
325 
326 	t = db_read_token();
327 	if (t != tDOLLAR) {
328 		db_error("Unknown variable\n");
329 		/*NOTREACHED*/
330 	}
331 	if (!db_find_variable(&vp)) {
332 		db_error("Unknown variable\n");
333 		/*NOTREACHED*/
334 	}
335 
336 	t = db_read_token();
337 	if (t != tEQ)
338 		db_unread_token(t);
339 
340 	if (!db_expression(&value)) {
341 		db_error("No value\n");
342 		/*NOTREACHED*/
343 	}
344 	if (db_read_token() != tEOL) {
345 		db_error("?\n");
346 		/*NOTREACHED*/
347 	}
348 
349 	db_read_variable(vp, &old_value);
350 	db_printf("$%s\t\t%s = ", vp->name, db_num_to_str(old_value));
351 	db_printf("%s\n", db_num_to_str(value));
352 	db_write_variable(vp, &value);
353 }
354