1*5a464645Schristos /* $NetBSD: db_variables.c,v 1.47 2020/03/10 15:58:37 christos Exp $ */
2cf92afd6Scgd
361f28255Scgd /*
461f28255Scgd * Mach Operating System
561f28255Scgd * Copyright (c) 1991,1990 Carnegie Mellon University
661f28255Scgd * All Rights Reserved.
761f28255Scgd *
861f28255Scgd * Permission to use, copy, modify and distribute this software and its
961f28255Scgd * documentation is hereby granted, provided that both the copyright
1061f28255Scgd * notice and this permission notice appear in all copies of the
1161f28255Scgd * software, derivative works or modified versions, and any portions
1261f28255Scgd * thereof, and that both notices appear in supporting documentation.
1361f28255Scgd *
14b13e5d14Spk * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1561f28255Scgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1661f28255Scgd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1761f28255Scgd *
1861f28255Scgd * Carnegie Mellon requests users of this software to return to
1961f28255Scgd *
2061f28255Scgd * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
2161f28255Scgd * School of Computer Science
2261f28255Scgd * Carnegie Mellon University
2361f28255Scgd * Pittsburgh PA 15213-3890
2461f28255Scgd *
2561f28255Scgd * any improvements or extensions that they make and grant Carnegie the
2661f28255Scgd * rights to redistribute these changes.
2761f28255Scgd */
2861f28255Scgd
291ac69d9cSlukem #include <sys/cdefs.h>
30*5a464645Schristos __KERNEL_RCSID(0, "$NetBSD: db_variables.c,v 1.47 2020/03/10 15:58:37 christos Exp $");
311ac69d9cSlukem
32cd6b1c8fSad #ifdef _KERNEL_OPT
3394b2e6e6Sitohy #include "opt_ddbparam.h"
34cd6b1c8fSad #endif
35466e784eSjonathan
36f1a5c330Smycroft #include <sys/param.h>
37f1a5c330Smycroft #include <sys/proc.h>
38f324eef2Smrg #include <uvm/uvm_extern.h>
39c14ce368Sthorpej #include <sys/sysctl.h>
40f1a5c330Smycroft
41cd6b1c8fSad #include <ddb/ddb.h>
42466e784eSjonathan #include <ddb/ddbvar.h>
43466e784eSjonathan
44c14ce368Sthorpej /*
45c14ce368Sthorpej * If this is non-zero, the DDB will be entered when the system
46c14ce368Sthorpej * panics. Initialize it so that it's patchable.
47c14ce368Sthorpej */
48c14ce368Sthorpej #ifndef DDB_ONPANIC
497d537978Smartin #define DDB_ONPANIC 1
50c14ce368Sthorpej #endif
51c14ce368Sthorpej int db_onpanic = DDB_ONPANIC;
52c14ce368Sthorpej
533ac3cbcfSjonathan /*
543ac3cbcfSjonathan * Can DDB can be entered from the console?
553ac3cbcfSjonathan */
563ac3cbcfSjonathan #ifndef DDB_FROMCONSOLE
573ac3cbcfSjonathan #define DDB_FROMCONSOLE 1
583ac3cbcfSjonathan #endif
593ac3cbcfSjonathan int db_fromconsole = DDB_FROMCONSOLE;
603ac3cbcfSjonathan
6122f11328Sreinoud /*
6222f11328Sreinoud * Output DDB output to the message buffer?
6322f11328Sreinoud */
6422f11328Sreinoud #ifndef DDB_TEE_MSGBUF
6522f11328Sreinoud #define DDB_TEE_MSGBUF 0
6622f11328Sreinoud #endif
6722f11328Sreinoud int db_tee_msgbuf = DDB_TEE_MSGBUF;
6822f11328Sreinoud
69bba31073Schristos #ifndef DDB_PANICSTACKFRAMES
70bba31073Schristos #define DDB_PANICSTACKFRAMES 65535
71bba31073Schristos #endif
72bba31073Schristos int db_panicstackframes = DDB_PANICSTACKFRAMES;
73bba31073Schristos
74ef017746Ssevan #ifndef DDB_DUMPSTACK
75ef017746Ssevan #define DDB_DUMPSTACK 1
76ef017746Ssevan #endif
77ef017746Ssevan int db_dumpstack = DDB_DUMPSTACK;
7822f11328Sreinoud
794eaa4d66Ssimonb static int db_rw_internal_variable(const struct db_variable *, db_expr_t *,
804eaa4d66Ssimonb int);
814eaa4d66Ssimonb static int db_find_variable(const struct db_variable **);
82a9295bf8Scgd
83a9295bf8Scgd /* XXX must all be ints for sysctl. */
849aa0a018Sjdolecek const struct db_variable db_vars[] = {
85bba31073Schristos {
86bba31073Schristos .name = "fromconsole",
87bba31073Schristos .valuep = &db_fromconsole,
88bba31073Schristos .fcn = db_rw_internal_variable,
89bba31073Schristos .modif = NULL,
90bba31073Schristos },
91bba31073Schristos {
92bba31073Schristos .name = "maxoff",
93bba31073Schristos .valuep = &db_maxoff,
94bba31073Schristos .fcn = db_rw_internal_variable,
95bba31073Schristos .modif = NULL,
96bba31073Schristos },
97bba31073Schristos {
98bba31073Schristos .name = "maxwidth",
99bba31073Schristos .valuep = &db_max_width,
100bba31073Schristos .fcn = db_rw_internal_variable,
101bba31073Schristos .modif = NULL,
102bba31073Schristos },
103bba31073Schristos {
104bba31073Schristos .name = "lines",
105bba31073Schristos .valuep = &db_max_line,
106bba31073Schristos .fcn = db_rw_internal_variable,
107bba31073Schristos .modif = NULL,
108bba31073Schristos },
109bba31073Schristos {
110bba31073Schristos .name = "onpanic",
111bba31073Schristos .valuep = &db_onpanic,
112bba31073Schristos .fcn = db_rw_internal_variable,
113bba31073Schristos .modif = NULL,
114bba31073Schristos },
115bba31073Schristos {
116bba31073Schristos .name = "panicstackframes",
117bba31073Schristos .valuep = &db_panicstackframes,
118bba31073Schristos .fcn = db_rw_internal_variable,
119bba31073Schristos .modif = NULL,
120bba31073Schristos },
121bba31073Schristos {
122ef017746Ssevan .name = "dumpstack",
123ef017746Ssevan .valuep = &db_dumpstack,
124ef017746Ssevan .fcn = db_rw_internal_variable,
125ef017746Ssevan .modif = NULL,
126ef017746Ssevan },
127ef017746Ssevan {
128bba31073Schristos .name = "radix",
129bba31073Schristos .valuep = &db_radix,
130bba31073Schristos .fcn = db_rw_internal_variable,
131bba31073Schristos .modif = NULL,
132bba31073Schristos },
133bba31073Schristos {
134bba31073Schristos .name = "tabstops",
135bba31073Schristos .valuep = &db_tab_stop_width,
136bba31073Schristos .fcn = db_rw_internal_variable,
137bba31073Schristos .modif = NULL,
138bba31073Schristos },
139bba31073Schristos {
140bba31073Schristos .name = "tee_msgbuf",
141bba31073Schristos .valuep = &db_tee_msgbuf,
142bba31073Schristos .fcn = db_rw_internal_variable,
143bba31073Schristos .modif = NULL,
144bba31073Schristos },
14561f28255Scgd };
146bba31073Schristos const struct db_variable * const db_evars = db_vars + __arraycount(db_vars);
14761f28255Scgd
148c14ce368Sthorpej /*
149a9295bf8Scgd * ddb command line access to the DDB variables defined above.
150a9295bf8Scgd */
151a9295bf8Scgd static int
db_rw_internal_variable(const struct db_variable * vp,db_expr_t * valp,int rw)1524eaa4d66Ssimonb db_rw_internal_variable(const struct db_variable *vp, db_expr_t *valp, int rw)
153a9295bf8Scgd {
154a9295bf8Scgd
1554eaa4d66Ssimonb if (rw == DB_VAR_GET)
156a9295bf8Scgd *valp = *(int *)vp->valuep;
1574eaa4d66Ssimonb else
158a9295bf8Scgd *(int *)vp->valuep = *valp;
159a9295bf8Scgd return (0);
160a9295bf8Scgd }
161a9295bf8Scgd
162a9295bf8Scgd /*
163c14ce368Sthorpej * sysctl(3) access to the DDB variables defined above.
164c14ce368Sthorpej */
165cd6b1c8fSad #ifdef _KERNEL
16613f8d2ceSatatat SYSCTL_SETUP(sysctl_ddb_setup, "sysctl ddb subtree setup")
167c14ce368Sthorpej {
168c14ce368Sthorpej
16919af35fdSatatat sysctl_createv(clog, 0, NULL, NULL,
17019af35fdSatatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
171d37080bcSatatat CTLTYPE_INT, "radix",
172d37080bcSatatat SYSCTL_DESCR("Input and output radix"),
17313f8d2ceSatatat NULL, 0, &db_radix, 0,
17413f8d2ceSatatat CTL_DDB, DDBCTL_RADIX, CTL_EOL);
17519af35fdSatatat sysctl_createv(clog, 0, NULL, NULL,
17619af35fdSatatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
177d37080bcSatatat CTLTYPE_INT, "maxoff",
178d37080bcSatatat SYSCTL_DESCR("Maximum symbol offset"),
17913f8d2ceSatatat NULL, 0, &db_maxoff, 0,
18013f8d2ceSatatat CTL_DDB, DDBCTL_MAXOFF, CTL_EOL);
18119af35fdSatatat sysctl_createv(clog, 0, NULL, NULL,
18219af35fdSatatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
183d37080bcSatatat CTLTYPE_INT, "maxwidth",
184d37080bcSatatat SYSCTL_DESCR("Maximum output line width"),
18513f8d2ceSatatat NULL, 0, &db_max_width, 0,
18613f8d2ceSatatat CTL_DDB, DDBCTL_MAXWIDTH, CTL_EOL);
18719af35fdSatatat sysctl_createv(clog, 0, NULL, NULL,
18819af35fdSatatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
189d37080bcSatatat CTLTYPE_INT, "lines",
190d37080bcSatatat SYSCTL_DESCR("Number of display lines"),
19113f8d2ceSatatat NULL, 0, &db_max_line, 0,
19213f8d2ceSatatat CTL_DDB, DDBCTL_LINES, CTL_EOL);
19319af35fdSatatat sysctl_createv(clog, 0, NULL, NULL,
19419af35fdSatatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
195d37080bcSatatat CTLTYPE_INT, "tabstops",
196d37080bcSatatat SYSCTL_DESCR("Output tab width"),
19713f8d2ceSatatat NULL, 0, &db_tab_stop_width, 0,
19813f8d2ceSatatat CTL_DDB, DDBCTL_TABSTOPS, CTL_EOL);
19919af35fdSatatat sysctl_createv(clog, 0, NULL, NULL,
20019af35fdSatatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
201d37080bcSatatat CTLTYPE_INT, "onpanic",
202d37080bcSatatat SYSCTL_DESCR("Whether to enter ddb on a kernel panic"),
20313f8d2ceSatatat NULL, 0, &db_onpanic, 0,
20413f8d2ceSatatat CTL_DDB, DDBCTL_ONPANIC, CTL_EOL);
20519af35fdSatatat sysctl_createv(clog, 0, NULL, NULL,
20619af35fdSatatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
207d37080bcSatatat CTLTYPE_INT, "fromconsole",
208d37080bcSatatat SYSCTL_DESCR("Whether ddb can be entered from the "
209d37080bcSatatat "console"),
21013f8d2ceSatatat NULL, 0, &db_fromconsole, 0,
21113f8d2ceSatatat CTL_DDB, DDBCTL_FROMCONSOLE, CTL_EOL);
21222f11328Sreinoud sysctl_createv(clog, 0, NULL, NULL,
21322f11328Sreinoud CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
21422f11328Sreinoud CTLTYPE_INT, "tee_msgbuf",
21522f11328Sreinoud SYSCTL_DESCR("Whether to tee ddb output to the msgbuf"),
21622f11328Sreinoud NULL, 0, &db_tee_msgbuf, 0,
21722f11328Sreinoud CTL_DDB, CTL_CREATE, CTL_EOL);
2183afdabd8Syamt sysctl_createv(clog, 0, NULL, NULL,
2193afdabd8Syamt CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
2203afdabd8Syamt CTLTYPE_STRING, "commandonenter",
2213afdabd8Syamt SYSCTL_DESCR("Command to be executed on each ddb enter"),
222e21a34c2Sdsl NULL, 0, db_cmd_on_enter, DB_LINE_MAXLEN,
2233afdabd8Syamt CTL_DDB, CTL_CREATE, CTL_EOL);
224bba31073Schristos sysctl_createv(clog, 0, NULL, NULL,
225bba31073Schristos CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
226bba31073Schristos CTLTYPE_INT, "panicstackframes",
227bba31073Schristos SYSCTL_DESCR("Number of stack frames to print on panic"),
228bba31073Schristos NULL, 0, &db_panicstackframes, 0,
229bba31073Schristos CTL_DDB, CTL_CREATE, CTL_EOL);
230ef017746Ssevan sysctl_createv(clog, 0, NULL, NULL,
231ef017746Ssevan CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
232ef017746Ssevan CTLTYPE_INT, "dumpstack",
233ef017746Ssevan SYSCTL_DESCR("On panic print stack trace"),
234ef017746Ssevan NULL, 0, &db_dumpstack, 0,
235ef017746Ssevan CTL_DDB, CTL_CREATE, CTL_EOL);
236c14ce368Sthorpej }
237cd6b1c8fSad #endif /* _KERNEL */
238c14ce368Sthorpej
23961f28255Scgd int
db_find_variable(const struct db_variable ** varp)2404eaa4d66Ssimonb db_find_variable(const struct db_variable **varp)
24161f28255Scgd {
24261f28255Scgd int t;
2439aa0a018Sjdolecek const struct db_variable *vp;
24461f28255Scgd
24561f28255Scgd t = db_read_token();
24661f28255Scgd if (t == tIDENT) {
24761f28255Scgd for (vp = db_vars; vp < db_evars; vp++) {
24861f28255Scgd if (!strcmp(db_tok_string, vp->name)) {
24961f28255Scgd *varp = vp;
25061f28255Scgd return (1);
25161f28255Scgd }
25261f28255Scgd }
253*5a464645Schristos #ifdef _KERNEL
25461f28255Scgd for (vp = db_regs; vp < db_eregs; vp++) {
25561f28255Scgd if (!strcmp(db_tok_string, vp->name)) {
25661f28255Scgd *varp = vp;
25761f28255Scgd return (1);
25861f28255Scgd }
25961f28255Scgd }
260*5a464645Schristos #endif
26161f28255Scgd }
26261f28255Scgd db_error("Unknown variable\n");
2634f0f8fdfSmycroft /*NOTREACHED*/
2648c2e3b4bSchristos return 0;
26561f28255Scgd }
26661f28255Scgd
26761f28255Scgd int
db_get_variable(db_expr_t * valuep)2684eaa4d66Ssimonb db_get_variable(db_expr_t *valuep)
26961f28255Scgd {
2709aa0a018Sjdolecek const struct db_variable *vp;
27161f28255Scgd
27261f28255Scgd if (!db_find_variable(&vp))
27361f28255Scgd return (0);
27461f28255Scgd
27561f28255Scgd db_read_variable(vp, valuep);
27661f28255Scgd
27761f28255Scgd return (1);
27861f28255Scgd }
27961f28255Scgd
28061f28255Scgd int
db_set_variable(db_expr_t value)2814eaa4d66Ssimonb db_set_variable(db_expr_t value)
28261f28255Scgd {
2839aa0a018Sjdolecek const struct db_variable *vp;
28461f28255Scgd
28561f28255Scgd if (!db_find_variable(&vp))
28661f28255Scgd return (0);
28761f28255Scgd
28861f28255Scgd db_write_variable(vp, &value);
28961f28255Scgd
29061f28255Scgd return (1);
29161f28255Scgd }
29261f28255Scgd
29361f28255Scgd
2948c2e3b4bSchristos void
db_read_variable(const struct db_variable * vp,db_expr_t * valuep)2954eaa4d66Ssimonb db_read_variable(const struct db_variable *vp, db_expr_t *valuep)
29661f28255Scgd {
2974eaa4d66Ssimonb int (*func)(const struct db_variable *, db_expr_t *, int) = vp->fcn;
29861f28255Scgd
29961f28255Scgd if (func == FCN_NULL)
300bba31073Schristos *valuep = *(db_expr_t *)vp->valuep;
30161f28255Scgd else
30261f28255Scgd (*func)(vp, valuep, DB_VAR_GET);
30361f28255Scgd }
30461f28255Scgd
3058c2e3b4bSchristos void
db_write_variable(const struct db_variable * vp,db_expr_t * valuep)3064eaa4d66Ssimonb db_write_variable(const struct db_variable *vp, db_expr_t *valuep)
30761f28255Scgd {
3084eaa4d66Ssimonb int (*func)(const struct db_variable *, db_expr_t *, int) = vp->fcn;
30961f28255Scgd
31061f28255Scgd if (func == FCN_NULL)
311bba31073Schristos *(db_expr_t *)vp->valuep = *valuep;
31261f28255Scgd else
31361f28255Scgd (*func)(vp, valuep, DB_VAR_SET);
31461f28255Scgd }
31561f28255Scgd
3168c2e3b4bSchristos /*ARGSUSED*/
31761f28255Scgd void
db_set_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)31893feeb12Smatt db_set_cmd(db_expr_t addr, bool have_addr,
319168cd830Schristos db_expr_t count, const char *modif)
32061f28255Scgd {
32161f28255Scgd db_expr_t value;
32292276a6cSjhawk db_expr_t old_value;
323103d2f52Schristos const struct db_variable *vp = NULL; /* XXX: GCC */
32461f28255Scgd int t;
32561f28255Scgd
32661f28255Scgd t = db_read_token();
32761f28255Scgd if (t != tDOLLAR) {
32861f28255Scgd db_error("Unknown variable\n");
3294f0f8fdfSmycroft /*NOTREACHED*/
33061f28255Scgd }
33161f28255Scgd if (!db_find_variable(&vp)) {
33261f28255Scgd db_error("Unknown variable\n");
3334f0f8fdfSmycroft /*NOTREACHED*/
33461f28255Scgd }
33561f28255Scgd
33661f28255Scgd t = db_read_token();
33761f28255Scgd if (t != tEQ)
33861f28255Scgd db_unread_token(t);
33961f28255Scgd
34061f28255Scgd if (!db_expression(&value)) {
34161f28255Scgd db_error("No value\n");
3424f0f8fdfSmycroft /*NOTREACHED*/
34361f28255Scgd }
34461f28255Scgd if (db_read_token() != tEOL) {
34561f28255Scgd db_error("?\n");
3464f0f8fdfSmycroft /*NOTREACHED*/
34761f28255Scgd }
34861f28255Scgd
34992276a6cSjhawk db_read_variable(vp, &old_value);
35092276a6cSjhawk db_printf("$%s\t\t%s = ", vp->name, db_num_to_str(old_value));
35192276a6cSjhawk db_printf("%s\n", db_num_to_str(value));
35261f28255Scgd db_write_variable(vp, &value);
35361f28255Scgd }
354