1/* $NetBSD: db_variables.c,v 1.44 2014/02/25 18:30:09 pooka 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.44 2014/02/25 18:30:09 pooka 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|CTLFLAG_READWRITE,
110 CTLTYPE_INT, "radix",
111 SYSCTL_DESCR("Input and output radix"),
112 NULL, 0, &db_radix, 0,
113 CTL_DDB, DDBCTL_RADIX, CTL_EOL);
114 sysctl_createv(clog, 0, NULL, NULL,
115 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
116 CTLTYPE_INT, "maxoff",
117 SYSCTL_DESCR("Maximum symbol offset"),
118 NULL, 0, &db_maxoff, 0,
119 CTL_DDB, DDBCTL_MAXOFF, CTL_EOL);
120 sysctl_createv(clog, 0, NULL, NULL,
121 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
122 CTLTYPE_INT, "maxwidth",
123 SYSCTL_DESCR("Maximum output line width"),
124 NULL, 0, &db_max_width, 0,
125 CTL_DDB, DDBCTL_MAXWIDTH, CTL_EOL);
126 sysctl_createv(clog, 0, NULL, NULL,
127 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
128 CTLTYPE_INT, "lines",
129 SYSCTL_DESCR("Number of display lines"),
130 NULL, 0, &db_max_line, 0,
131 CTL_DDB, DDBCTL_LINES, CTL_EOL);
132 sysctl_createv(clog, 0, NULL, NULL,
133 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
134 CTLTYPE_INT, "tabstops",
135 SYSCTL_DESCR("Output tab width"),
136 NULL, 0, &db_tab_stop_width, 0,
137 CTL_DDB, DDBCTL_TABSTOPS, CTL_EOL);
138 sysctl_createv(clog, 0, NULL, NULL,
139 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
140 CTLTYPE_INT, "onpanic",
141 SYSCTL_DESCR("Whether to enter ddb on a kernel panic"),
142 NULL, 0, &db_onpanic, 0,
143 CTL_DDB, DDBCTL_ONPANIC, CTL_EOL);
144 sysctl_createv(clog, 0, NULL, NULL,
145 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
146 CTLTYPE_INT, "fromconsole",
147 SYSCTL_DESCR("Whether ddb can be entered from the "
148 "console"),
149 NULL, 0, &db_fromconsole, 0,
150 CTL_DDB, DDBCTL_FROMCONSOLE, CTL_EOL);
151 sysctl_createv(clog, 0, NULL, NULL,
152 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
153 CTLTYPE_INT, "tee_msgbuf",
154 SYSCTL_DESCR("Whether to tee ddb output to the msgbuf"),
155 NULL, 0, &db_tee_msgbuf, 0,
156 CTL_DDB, CTL_CREATE, CTL_EOL);
157
158 sysctl_createv(clog, 0, NULL, NULL,
159 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
160 CTLTYPE_STRING, "commandonenter",
161 SYSCTL_DESCR("Command to be executed on each ddb enter"),
162 NULL, 0, db_cmd_on_enter, DB_LINE_MAXLEN,
163 CTL_DDB, CTL_CREATE, CTL_EOL);
164}
165#endif /* _KERNEL */
166
167int
168db_find_variable(const struct db_variable **varp)
169{
170 int t;
171 const struct db_variable *vp;
172
173 t = db_read_token();
174 if (t == tIDENT) {
175 for (vp = db_vars; vp < db_evars; vp++) {
176 if (!strcmp(db_tok_string, vp->name)) {
177 *varp = vp;
178 return (1);
179 }
180 }
181 for (vp = db_regs; vp < db_eregs; vp++) {
182 if (!strcmp(db_tok_string, vp->name)) {
183 *varp = vp;
184 return (1);
185 }
186 }
187 }
188 db_error("Unknown variable\n");
189 /*NOTREACHED*/
190 return 0;
191}
192
193int
194db_get_variable(db_expr_t *valuep)
195{
196 const struct db_variable *vp;
197
198 if (!db_find_variable(&vp))
199 return (0);
200
201 db_read_variable(vp, valuep);
202
203 return (1);
204}
205
206int
207db_set_variable(db_expr_t value)
208{
209 const struct db_variable *vp;
210
211 if (!db_find_variable(&vp))
212 return (0);
213
214 db_write_variable(vp, &value);
215
216 return (1);
217}
218
219
220void
221db_read_variable(const struct db_variable *vp, db_expr_t *valuep)
222{
223 int (*func)(const struct db_variable *, db_expr_t *, int) = vp->fcn;
224
225 if (func == FCN_NULL)
226 *valuep = *(vp->valuep);
227 else
228 (*func)(vp, valuep, DB_VAR_GET);
229}
230
231void
232db_write_variable(const struct db_variable *vp, db_expr_t *valuep)
233{
234 int (*func)(const struct db_variable *, db_expr_t *, int) = vp->fcn;
235
236 if (func == FCN_NULL)
237 *(vp->valuep) = *valuep;
238 else
239 (*func)(vp, valuep, DB_VAR_SET);
240}
241
242/*ARGSUSED*/
243void
244db_set_cmd(db_expr_t addr, bool have_addr,
245 db_expr_t count, const char *modif)
246{
247 db_expr_t value;
248 db_expr_t old_value;
249 const struct db_variable *vp = NULL; /* XXX: GCC */
250 int t;
251
252 t = db_read_token();
253 if (t != tDOLLAR) {
254 db_error("Unknown variable\n");
255 /*NOTREACHED*/
256 }
257 if (!db_find_variable(&vp)) {
258 db_error("Unknown variable\n");
259 /*NOTREACHED*/
260 }
261
262 t = db_read_token();
263 if (t != tEQ)
264 db_unread_token(t);
265
266 if (!db_expression(&value)) {
267 db_error("No value\n");
268 /*NOTREACHED*/
269 }
270 if (db_read_token() != tEOL) {
271 db_error("?\n");
272 /*NOTREACHED*/
273 }
274
275 db_read_variable(vp, &old_value);
276 db_printf("$%s\t\t%s = ", vp->name, db_num_to_str(old_value));
277 db_printf("%s\n", db_num_to_str(value));
278 db_write_variable(vp, &value);
279}
280