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