xref: /netbsd-src/sys/ddb/db_command.c (revision c34236556bea94afcaca1782d7d228301edc3ea0)
1 /*	$NetBSD: db_command.c,v 1.147 2016/04/13 00:47:02 ozaki-r Exp $	*/
2 
3 /*
4  * Copyright (c) 1996, 1997, 1998, 1999, 2002, 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Adam Hamsik, and by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Mach Operating System
34  * Copyright (c) 1991,1990 Carnegie Mellon University
35  * All Rights Reserved.
36  *
37  * Permission to use, copy, modify and distribute this software and its
38  * documentation is hereby granted, provided that both the copyright
39  * notice and this permission notice appear in all copies of the
40  * software, derivative works or modified versions, and any portions
41  * thereof, and that both notices appear in supporting documentation.
42  *
43  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
44  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
45  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46  *
47  * Carnegie Mellon requests users of this software to return to
48  *
49  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
50  *  School of Computer Science
51  *  Carnegie Mellon University
52  *  Pittsburgh PA 15213-3890
53  *
54  * any improvements or extensions that they make and grant Carnegie the
55  * rights to redistribute these changes.
56  */
57 
58 /*
59  * Command dispatcher.
60  */
61 
62 #include <sys/cdefs.h>
63 __KERNEL_RCSID(0, "$NetBSD: db_command.c,v 1.147 2016/04/13 00:47:02 ozaki-r Exp $");
64 
65 #ifdef _KERNEL_OPT
66 #include "opt_aio.h"
67 #include "opt_ddb.h"
68 #include "opt_kgdb.h"
69 #include "opt_mqueue.h"
70 #include "opt_inet.h"
71 #include "opt_kernhist.h"
72 #include "opt_ddbparam.h"
73 #include "opt_multiprocessor.h"
74 #endif
75 
76 #include <sys/param.h>
77 #include <sys/systm.h>
78 #include <sys/reboot.h>
79 #include <sys/device.h>
80 #include <sys/lwp.h>
81 #include <sys/mbuf.h>
82 #include <sys/namei.h>
83 #include <sys/pool.h>
84 #include <sys/proc.h>
85 #include <sys/vnode.h>
86 #include <sys/vmem.h>
87 #include <sys/lockdebug.h>
88 #include <sys/cpu.h>
89 #include <sys/buf.h>
90 #include <sys/module.h>
91 #include <sys/kernhist.h>
92 
93 /*include queue macros*/
94 #include <sys/queue.h>
95 
96 #include <ddb/ddb.h>
97 
98 #include <uvm/uvm_extern.h>
99 #include <uvm/uvm_ddb.h>
100 
101 #include <net/route.h>
102 
103 /*
104  * Results of command search.
105  */
106 #define	CMD_EXACT		0
107 #define	CMD_PREFIX		1
108 #define	CMD_NONE		2
109 #define	CMD_AMBIGUOUS	3
110 
111 /*
112  * Exported global variables
113  */
114 bool		db_cmd_loop_done;
115 label_t		*db_recover;
116 db_addr_t	db_dot;
117 db_addr_t	db_last_addr;
118 db_addr_t	db_prev;
119 db_addr_t	db_next;
120 
121 
122 /*
123  * New DDB api for adding and removing commands uses three lists, because
124  * we use two types of commands
125  * a) standard commands without subcommands -> reboot
126  * b) show commands which are subcommands of show command -> show aio_jobs
127  * c) if defined machine specific commands
128  *
129  * ddb_add_cmd, ddb_rem_cmd use type (DDB_SHOW_CMD||DDB_BASE_CMD)argument to
130  * add them to representativ lists.
131  */
132 
133 static const struct db_command db_command_table[];
134 static const struct db_command db_show_cmds[];
135 
136 #ifdef DB_MACHINE_COMMANDS
137 /* arch/<arch>/<arch>/db_interface.c */
138 extern const struct db_command db_machine_command_table[];
139 #endif
140 
141 /* the global queue of all command tables */
142 TAILQ_HEAD(db_cmd_tbl_en_head, db_cmd_tbl_en);
143 
144 /* TAILQ entry used to register command tables */
145 struct db_cmd_tbl_en {
146 	const struct db_command *db_cmd;	/* cmd table */
147 	TAILQ_ENTRY(db_cmd_tbl_en) db_cmd_next;
148 };
149 
150 /* head of base commands list */
151 static struct db_cmd_tbl_en_head db_base_cmd_list =
152 	TAILQ_HEAD_INITIALIZER(db_base_cmd_list);
153 static struct db_cmd_tbl_en db_base_cmd_builtins =
154      { .db_cmd = db_command_table };
155 
156 /* head of show commands list */
157 static struct db_cmd_tbl_en_head db_show_cmd_list =
158 	TAILQ_HEAD_INITIALIZER(db_show_cmd_list);
159 static struct db_cmd_tbl_en db_show_cmd_builtins =
160      { .db_cmd = db_show_cmds };
161 
162 /* head of machine commands list */
163 static struct db_cmd_tbl_en_head db_mach_cmd_list =
164 	TAILQ_HEAD_INITIALIZER(db_mach_cmd_list);
165 #ifdef DB_MACHINE_COMMANDS
166 static struct db_cmd_tbl_en db_mach_cmd_builtins =
167      { .db_cmd = db_machine_command_table };
168 #endif
169 
170 /*
171  * if 'ed' style: 'dot' is set at start of last item printed,
172  * and '+' points to next line.
173  * Otherwise: 'dot' points to next item, '..' points to last.
174  */
175 static bool	 db_ed_style = true;
176 
177 static void	db_init_commands(void);
178 static int	db_register_tbl_entry(uint8_t type,
179     struct db_cmd_tbl_en *list_ent);
180 static void	db_cmd_list(const struct db_cmd_tbl_en_head *);
181 static int	db_cmd_search(const char *, struct db_cmd_tbl_en_head *,
182 			      const struct db_command **);
183 static int	db_cmd_search_table(const char *, const struct db_command *,
184 				    const struct db_command **);
185 static void	db_cmd_search_failed(char *, int);
186 static const struct db_command *db_read_command(void);
187 static void	db_command(const struct db_command **);
188 static void	db_buf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
189 static void	db_event_print_cmd(db_expr_t, bool, db_expr_t, const char *);
190 static void	db_fncall(db_expr_t, bool, db_expr_t, const char *);
191 static void     db_help_print_cmd(db_expr_t, bool, db_expr_t, const char *);
192 static void	db_lock_print_cmd(db_expr_t, bool, db_expr_t, const char *);
193 static void	db_mount_print_cmd(db_expr_t, bool, db_expr_t, const char *);
194 static void	db_mbuf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
195 static void	db_map_print_cmd(db_expr_t, bool, db_expr_t, const char *);
196 static void	db_namecache_print_cmd(db_expr_t, bool, db_expr_t,
197 		    const char *);
198 static void	db_object_print_cmd(db_expr_t, bool, db_expr_t, const char *);
199 static void	db_page_print_cmd(db_expr_t, bool, db_expr_t, const char *);
200 static void	db_show_all_pages(db_expr_t, bool, db_expr_t, const char *);
201 static void	db_pool_print_cmd(db_expr_t, bool, db_expr_t, const char *);
202 static void	db_reboot_cmd(db_expr_t, bool, db_expr_t, const char *);
203 static void	db_sifting_cmd(db_expr_t, bool, db_expr_t, const char *);
204 static void	db_stack_trace_cmd(db_expr_t, bool, db_expr_t, const char *);
205 static void	db_sync_cmd(db_expr_t, bool, db_expr_t, const char *);
206 static void	db_whatis_cmd(db_expr_t, bool, db_expr_t, const char *);
207 static void	db_uvmexp_print_cmd(db_expr_t, bool, db_expr_t, const char *);
208 #ifdef KERNHIST
209 static void	db_kernhist_print_cmd(db_expr_t, bool, db_expr_t, const char *);
210 #endif
211 static void	db_vnode_print_cmd(db_expr_t, bool, db_expr_t, const char *);
212 static void	db_vmem_print_cmd(db_expr_t, bool, db_expr_t, const char *);
213 
214 static const struct db_command db_show_cmds[] = {
215 	/*added from all sub cmds*/
216 	{ DDB_ADD_CMD("callout",  db_show_callout,
217 	    0 ,"List all used callout functions.",NULL,NULL) },
218 	{ DDB_ADD_CMD("pages",	db_show_all_pages,
219 	    0 ,"List all used memory pages.",NULL,NULL) },
220 	{ DDB_ADD_CMD("proc",	db_show_proc,
221 	    0 ,"Print process information.",NULL,NULL) },
222 	{ DDB_ADD_CMD("procs",	db_show_all_procs,
223 	    0 ,"List all processes.",NULL,NULL) },
224 	{ DDB_ADD_CMD("pools",	db_show_all_pools,
225 	    0 ,"Show all pools",NULL,NULL) },
226 #ifdef AIO
227 	/*added from all sub cmds*/
228 	{ DDB_ADD_CMD("aio_jobs",	db_show_aio_jobs,	0,
229 	    "Show aio jobs",NULL,NULL) },
230 #endif
231 	{ DDB_ADD_CMD("all",	NULL,
232 	    CS_COMPAT, NULL,NULL,NULL) },
233 #if defined(INET)
234 	{ DDB_ADD_CMD("routes",	db_show_routes,		0,NULL,NULL,NULL) },
235 #endif
236 #ifdef _KERNEL
237 	{ DDB_ADD_CMD("breaks",	db_listbreak_cmd, 	0,
238 	    "Display all breaks.",NULL,NULL) },
239 #endif
240 	{ DDB_ADD_CMD("buf",	db_buf_print_cmd,	0,
241 	    "Print the struct buf at address.", "[/f] address",NULL) },
242 	{ DDB_ADD_CMD("event",	db_event_print_cmd,	0,
243 	    "Print all the non-zero evcnt(9) event counters.", "[/fitm]",NULL) },
244 	{ DDB_ADD_CMD("files", db_show_files_cmd,	0,
245 	    "Print the files open by process at address",
246 	    "[/f] address", NULL) },
247 	{ DDB_ADD_CMD("lock",	db_lock_print_cmd,	0,NULL,NULL,NULL) },
248 	{ DDB_ADD_CMD("map",	db_map_print_cmd,	0,
249 	    "Print the vm_map at address.", "[/f] address",NULL) },
250 	{ DDB_ADD_CMD("module", db_show_module_cmd,	0,
251 	    "Print kernel modules", NULL, NULL) },
252 	{ DDB_ADD_CMD("mount",	db_mount_print_cmd,	0,
253 	    "Print the mount structure at address.", "[/f] address",NULL) },
254 #ifdef MQUEUE
255 	{ DDB_ADD_CMD("mqueue", db_show_mqueue_cmd,	0,
256 	    "Print the message queues", NULL, NULL) },
257 #endif
258 	{ DDB_ADD_CMD("mbuf",	db_mbuf_print_cmd,	0,NULL,NULL,
259 	    "-c prints all mbuf chains") },
260 	{ DDB_ADD_CMD("ncache",	db_namecache_print_cmd,	0,
261 	    "Dump the namecache list.", "address",NULL) },
262 	{ DDB_ADD_CMD("object",	db_object_print_cmd,	0,
263 	    "Print the vm_object at address.", "[/f] address",NULL) },
264 	{ DDB_ADD_CMD("page",	db_page_print_cmd,	0,
265 	    "Print the vm_page at address.", "[/f] address",NULL) },
266 	{ DDB_ADD_CMD("panic",	db_show_panic,	0,
267 	    "Print the current panic string",NULL,NULL) },
268 	{ DDB_ADD_CMD("pool",	db_pool_print_cmd,	0,
269 	    "Print the pool at address.", "[/clp] address",NULL) },
270 	{ DDB_ADD_CMD("registers",	db_show_regs,		0,
271 	    "Display the register set.", "[/u]",NULL) },
272 	{ DDB_ADD_CMD("sched_qs",	db_show_sched_qs,	0,
273 	    "Print the state of the scheduler's run queues.",
274 	    NULL,NULL) },
275 	{ DDB_ADD_CMD("uvmexp",	db_uvmexp_print_cmd, 0,
276 	    "Print a selection of UVM counters and statistics.",
277 	    NULL,NULL) },
278 #ifdef KERNHIST
279 	{ DDB_ADD_CMD("kernhist", db_kernhist_print_cmd, 0,
280 	    "Print the UVM history logs.",
281 	    NULL,NULL) },
282 #endif
283 	{ DDB_ADD_CMD("vnode",	db_vnode_print_cmd,	0,
284 	    "Print the vnode at address.", "[/f] address",NULL) },
285 	{ DDB_ADD_CMD("vmem", db_vmem_print_cmd,	0,
286 	    "Print the vmem usage.", "[/a] address", NULL) },
287 	{ DDB_ADD_CMD("vmems", db_show_all_vmems,	0,
288 	    "Show all vmems.", NULL, NULL) },
289 #ifdef _KERNEL
290 	{ DDB_ADD_CMD("watches",	db_listwatch_cmd, 	0,
291 	    "Display all watchpoints.", NULL,NULL) },
292 #endif
293 	{ DDB_ADD_CMD(NULL,		NULL,			0,NULL,NULL,NULL) }
294 };
295 
296 static const struct db_command db_command_table[] = {
297 	{ DDB_ADD_CMD("b",		db_breakpoint_cmd,	0,
298 	    "Set a breakpoint at address", "[/u] address[,count].",NULL) },
299 	{ DDB_ADD_CMD("break",	db_breakpoint_cmd,	0,
300 	    "Set a breakpoint at address", "[/u] address[,count].",NULL) },
301 	{ DDB_ADD_CMD("bt",		db_stack_trace_cmd,	0,
302 	    "Show backtrace.", "See help trace.",NULL) },
303 	{ DDB_ADD_CMD("c",		db_continue_cmd,	0,
304 	    "Continue execution.", "[/c]",NULL) },
305 	{ DDB_ADD_CMD("call",	db_fncall,		CS_OWN,
306 	    "Call the function", "address[(expression[,...])]",NULL) },
307 	{ DDB_ADD_CMD("callout",	db_show_callout,	0, NULL,
308 	    NULL,NULL ) },
309 	{ DDB_ADD_CMD("continue",	db_continue_cmd,	0,
310 	    "Continue execution.", "[/c]",NULL) },
311 	{ DDB_ADD_CMD("d",		db_delete_cmd,		0,
312 	    "Delete a breakpoint.", "address | #number",NULL) },
313 	{ DDB_ADD_CMD("delete",	db_delete_cmd,		0,
314 	    "Delete a breakpoint.", "address | #number",NULL) },
315 	{ DDB_ADD_CMD("dmesg",	db_dmesg,		0,
316 	    "Show kernel message buffer.", "[count]",NULL) },
317 	{ DDB_ADD_CMD("dwatch",	db_deletewatch_cmd,	0,
318 	    "Delete the watchpoint.", "address",NULL) },
319 	{ DDB_ADD_CMD("examine",	db_examine_cmd,		CS_SET_DOT,
320 	    "Display the address locations.",
321 	    "[/modifier] address[,count]",NULL) },
322 	{ DDB_ADD_CMD("exit",		db_continue_cmd,	0,
323 	    "Continue execution.", "[/c]",NULL) },
324 	{ DDB_ADD_CMD("help",   db_help_print_cmd, CS_OWN|CS_NOREPEAT,
325 	    "Display help about commands",
326 	    "Use other commands as arguments.",NULL) },
327 	{ DDB_ADD_CMD("kill",	db_kill_proc,		CS_OWN,
328 	    "Send a signal to the process","pid[,signal_number]",
329 	    "   pid:\t\t\tthe process id (may need 0t prefix for decimal)\n"
330 	    "   signal_number:\tthe signal to send") },
331 #ifdef KGDB
332 	{ DDB_ADD_CMD("kgdb",	db_kgdb_cmd,	0,	NULL,NULL,NULL) },
333 #endif
334 	{ DDB_ADD_CMD("machine",NULL,CS_MACH,
335 	    "Architecture specific functions.",NULL,NULL) },
336 	{ DDB_ADD_CMD("match",	db_trace_until_matching_cmd,0,
337 	    "Stop at the matching return instruction.","See help next",NULL) },
338 	{ DDB_ADD_CMD("next",	db_trace_until_matching_cmd,0,
339 	    "Stop at the matching return instruction.","[/p]",NULL) },
340 	{ DDB_ADD_CMD("p",		db_print_cmd,		0,
341 	    "Print address according to the format.",
342 	    "[/axzodurc] address [address ...]",NULL) },
343 	{ DDB_ADD_CMD("print",	db_print_cmd,		0,
344 	    "Print address according to the format.",
345 	    "[/axzodurc] address [address ...]",NULL) },
346 	{ DDB_ADD_CMD("ps",		db_show_all_procs,	0,
347 	    "Print all processes.","See show all procs",NULL) },
348 	{ DDB_ADD_CMD("quit",		db_continue_cmd,	0,
349 	    "Continue execution.", "[/c]",NULL) },
350 	{ DDB_ADD_CMD("reboot",	db_reboot_cmd,		CS_OWN,
351 	    "Reboot","0x1  RB_ASKNAME, 0x2 RB_SINGLE, 0x4 RB_NOSYNC, 0x8 RB_HALT,"
352 	    "0x40 RB_KDB, 0x100 RB_DUMP, 0x808 RB_POWERDOWN",NULL) },
353 	{ DDB_ADD_CMD("s",		db_single_step_cmd,	0,
354 	    "Single-step count times.","[/p] [,count]",NULL) },
355 	{ DDB_ADD_CMD("search",	db_search_cmd,		CS_OWN|CS_SET_DOT,
356 	    "Search memory from address for value.",
357 	    "[/bhl] address value [mask] [,count]",NULL) },
358 	{ DDB_ADD_CMD("set",	db_set_cmd,		CS_OWN,
359 	    "Set the named variable","$variable [=] expression",NULL) },
360 	{ DDB_ADD_CMD("show",	NULL, CS_SHOW,
361 	    "Show kernel stats.", NULL,NULL) },
362 	{ DDB_ADD_CMD("sifting",	db_sifting_cmd,		CS_OWN,
363 	    "Search the symbol tables ","[/F] string",NULL) },
364 	{ DDB_ADD_CMD("step",	db_single_step_cmd,	0,
365 	    "Single-step count times.","[/p] [,count]",NULL) },
366 	{ DDB_ADD_CMD("sync",	db_sync_cmd,		CS_OWN,
367 	    "Force a crash dump, and then reboot.",NULL,NULL) },
368 	{ DDB_ADD_CMD("trace",	db_stack_trace_cmd,	0,
369 	    "Stack trace from frame-address.",
370 	    "[/u[l]] [frame-address][,count]",NULL) },
371 	{ DDB_ADD_CMD("until",	db_trace_until_call_cmd,0,
372 	    "Stop at the next call or return instruction.","[/p]",NULL) },
373 	{ DDB_ADD_CMD("w",		db_write_cmd,		CS_MORE|CS_SET_DOT,
374 	    "Write the expressions at succeeding locations.",
375 	    "[/bhl] address expression [expression ...]",NULL) },
376 	{ DDB_ADD_CMD("watch",	db_watchpoint_cmd,	CS_MORE,
377 	    "Set a watchpoint for a region. ","address[,size]",NULL) },
378 	{ DDB_ADD_CMD("whatis",	db_whatis_cmd, 0,
379 	    "Describe what an address is", "address", NULL) },
380 	{ DDB_ADD_CMD("write",	db_write_cmd,		CS_MORE|CS_SET_DOT,
381 	    "Write the expressions at succeeding locations.",
382 	    "[/bhl] address expression [expression ...]",NULL) },
383 	{ DDB_ADD_CMD("x",		db_examine_cmd,		CS_SET_DOT,
384 	    "Display the address locations.",
385 	    "[/modifier] address[,count]",NULL) },
386 	{ DDB_ADD_CMD(NULL, 	NULL,		   0, NULL, NULL, NULL) }
387 };
388 
389 static const struct db_command	*db_last_command = NULL;
390 #if defined(DDB_COMMANDONENTER)
391 char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ___STRING(DDB_COMMANDONENTER);
392 #else /* defined(DDB_COMMANDONENTER) */
393 char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = "";
394 #endif /* defined(DDB_COMMANDONENTER) */
395 #define	DB_LINE_SEP	';'
396 
397 /*
398  * Execute commandlist after ddb start
399  * This function goes through the command list created from commands and ';'
400  */
401 static void
402 db_execute_commandlist(const char *cmdlist)
403 {
404 	const char *cmd = cmdlist;
405 	const struct db_command	*dummy = NULL;
406 
407 	while (*cmd != '\0') {
408 		const char *ep = cmd;
409 
410 		while (*ep != '\0' && *ep != DB_LINE_SEP) {
411 			ep++;
412 		}
413 		db_set_line(cmd, ep);
414 		db_command(&dummy);
415 		cmd = ep;
416 		if (*cmd == DB_LINE_SEP) {
417 			cmd++;
418 		}
419 	}
420 }
421 
422 /* Initialize ddb command tables */
423 void
424 db_init_commands(void)
425 {
426 	static bool done = false;
427 
428 	if (done) return;
429 	done = true;
430 
431 	/* register command tables */
432 	(void)db_register_tbl_entry(DDB_BASE_CMD, &db_base_cmd_builtins);
433 #ifdef DB_MACHINE_COMMANDS
434 	(void)db_register_tbl_entry(DDB_MACH_CMD, &db_mach_cmd_builtins);
435 #endif
436 	(void)db_register_tbl_entry(DDB_SHOW_CMD, &db_show_cmd_builtins);
437 }
438 
439 
440 /*
441  * Add command table to the specified list
442  * Arg:
443  * int type specifies type of command table DDB_SHOW_CMD|DDB_BASE_CMD|DDB_MAC_CMD
444  * *cmd_tbl poiter to static allocated db_command table
445  *
446  * Command table must be NULL terminated array of struct db_command
447  */
448 int
449 db_register_tbl(uint8_t type, const struct db_command *cmd_tbl)
450 {
451 	struct db_cmd_tbl_en *list_ent;
452 
453 	/* empty list - ignore */
454 	if (cmd_tbl->name == 0)
455 		return 0;
456 
457 	/* force builtin commands to be registered first */
458 	db_init_commands();
459 
460 	/* now create a list entry for this table */
461 	list_ent = db_zalloc(sizeof(*list_ent));
462 	if (list_ent == NULL)
463 		return ENOMEM;
464 	list_ent->db_cmd=cmd_tbl;
465 
466 	/* and register it */
467 	return db_register_tbl_entry(type, list_ent);
468 }
469 
470 static int
471 db_register_tbl_entry(uint8_t type, struct db_cmd_tbl_en *list_ent)
472 {
473 	struct db_cmd_tbl_en_head *list;
474 
475 	switch(type) {
476 	case DDB_BASE_CMD:
477 		list = &db_base_cmd_list;
478 		break;
479 	case DDB_SHOW_CMD:
480 		list = &db_show_cmd_list;
481 		break;
482 	case DDB_MACH_CMD:
483 		list = &db_mach_cmd_list;
484 		break;
485 	default:
486 		return ENOENT;
487 	}
488 
489 	TAILQ_INSERT_TAIL(list, list_ent, db_cmd_next);
490 
491 	return 0;
492 }
493 
494 /*
495  * Remove command table specified with db_cmd address == cmd_tbl
496  */
497 int
498 db_unregister_tbl(uint8_t type,const struct db_command *cmd_tbl)
499 {
500 	struct db_cmd_tbl_en *list_ent;
501 	struct db_cmd_tbl_en_head *list;
502 
503 	/* find list on which the entry should live */
504 	switch (type) {
505 	case DDB_BASE_CMD:
506 		list=&db_base_cmd_list;
507 		break;
508 	case DDB_SHOW_CMD:
509 		list=&db_show_cmd_list;
510 		break;
511 	case DDB_MACH_CMD:
512 		list=&db_mach_cmd_list;
513 		break;
514 	default:
515 		return EINVAL;
516 	}
517 
518 	TAILQ_FOREACH (list_ent, list, db_cmd_next) {
519 		if (list_ent->db_cmd == cmd_tbl){
520 			TAILQ_REMOVE(list,
521 			    list_ent, db_cmd_next);
522 			db_free(list_ent, sizeof(*list_ent));
523 			return 0;
524 		}
525 	}
526 	return ENOENT;
527 }
528 
529 /* This function is called from machine trap code. */
530 void
531 db_command_loop(void)
532 {
533 	label_t	db_jmpbuf;
534 	label_t	*savejmp;
535 
536 	/*
537 	 * Initialize 'prev' and 'next' to dot.
538 	 */
539 	db_prev = db_dot;
540 	db_next = db_dot;
541 
542 	db_cmd_loop_done = false;
543 
544 	/* Init default command tables add machine, base,
545 	   show command tables to the list */
546 	db_init_commands();
547 
548 	/* save context for return from ddb */
549 	savejmp = db_recover;
550 	db_recover = &db_jmpbuf;
551 	(void) setjmp(&db_jmpbuf);
552 
553 	/*
554 	 * Execute default ddb start commands only if this is the
555 	 * first entry into DDB, in case the start commands fault
556 	 * and we recurse into here.
557 	 */
558 	if (!savejmp)
559 		db_execute_commandlist(db_cmd_on_enter);
560 
561 	(void) setjmp(&db_jmpbuf);
562 	while (!db_cmd_loop_done) {
563 		if (db_print_position() != 0)
564 			db_printf("\n");
565 		db_output_line = 0;
566 		(void) db_read_line();
567 		db_command(&db_last_command);
568 	}
569 
570 	db_recover = savejmp;
571 }
572 
573 /*
574  * Search command table for command prefix
575  */
576 static int
577 db_cmd_search_table(const char *name,
578 		    const struct db_command *table,
579 		    const struct db_command **cmdp)
580 {
581 
582 	const struct db_command	*cmd;
583 	int result;
584 
585 	result = CMD_NONE;
586 	*cmdp = NULL;
587 
588 	for (cmd = table; cmd->name != 0; cmd++) {
589 		const char *lp;
590 		const char *rp;
591 
592 		lp = name;
593 		rp = cmd->name;
594 		while (*lp != '\0' && *lp == *rp) {
595 			rp++;
596 			lp++;
597 		}
598 
599 		if (*lp != '\0') /* mismatch or extra chars in name */
600 			continue;
601 
602 		if (*rp == '\0') { /* exact match */
603 			*cmdp = cmd;
604 			return (CMD_EXACT);
605 		}
606 
607 		/* prefix match: end of name, not end of command */
608 		if (result == CMD_NONE) {
609 			result = CMD_PREFIX;
610 			*cmdp = cmd;
611 		}
612 		else if (result == CMD_PREFIX) {
613 			result = CMD_AMBIGUOUS;
614 			*cmdp = NULL;
615 		}
616 	}
617 
618 	return (result);
619 }
620 
621 
622 /*
623  * Search list of command tables for command
624  */
625 static int
626 db_cmd_search(const char *name,
627 	      struct db_cmd_tbl_en_head *list_head,
628 	      const struct db_command **cmdp)
629 {
630 	struct db_cmd_tbl_en *list_ent;
631 	const struct db_command *found_command;
632 	bool accept_prefix_match;
633 	int result;
634 
635 	result = CMD_NONE;
636 	found_command = NULL;
637 	accept_prefix_match = true;
638 
639 	TAILQ_FOREACH(list_ent, list_head, db_cmd_next) {
640 		const struct db_command *cmd;
641 		int found;
642 
643 		found = db_cmd_search_table(name, list_ent->db_cmd, &cmd);
644 		if (found == CMD_EXACT) {
645 			result = CMD_EXACT;
646 			found_command = cmd;
647 			break;
648 		}
649 
650 		if (found == CMD_PREFIX) {
651 			if (accept_prefix_match) {
652 				/*
653 				 * Continue search, but note current result
654 				 * in case we won't find anything else.
655 				 */
656 				accept_prefix_match = false;
657 				result = CMD_PREFIX;
658 				found_command = cmd;
659 			} else {
660 				/*
661 				 * Watch out for globally ambiguous
662 				 * prefix match that is not locally
663 				 * ambiguous - with one match in one
664 				 * table and another match(es) in
665 				 * another table.
666 				 */
667 				result = CMD_AMBIGUOUS;
668 				found_command = NULL;
669 			}
670 		}
671 		else if (found == CMD_AMBIGUOUS) {
672 			accept_prefix_match = false;
673 			result = CMD_AMBIGUOUS;
674 			found_command = NULL;
675 		}
676 	}
677 
678 	*cmdp = found_command;
679 	return result;
680 }
681 
682 static void
683 db_cmd_search_failed(char *name, int search_result)
684 {
685 	if (search_result == CMD_NONE)
686 		db_printf("No such command: %s\n", name);
687 	else
688 		db_printf("Ambiguous command: %s\n", name);
689 }
690 
691 
692 /*
693  * List commands to the console.
694  */
695 static void
696 db_cmd_list(const struct db_cmd_tbl_en_head *list)
697 {
698 
699 	struct db_cmd_tbl_en *list_ent;
700 	const struct db_command *table;
701 	size_t		i, j, w, columns, lines, numcmds, width=0;
702 	const char	*p;
703 
704 	TAILQ_FOREACH(list_ent,list,db_cmd_next) {
705 		table = list_ent->db_cmd;
706 		for (i = 0; table[i].name != NULL; i++) {
707 			w = strlen(table[i].name);
708 			if (w > width)
709 				width = w;
710 		}
711 	}
712 
713 	width = DB_NEXT_TAB(width);
714 
715 	columns = db_max_width / width;
716 	if (columns == 0)
717 		columns = 1;
718 
719 	TAILQ_FOREACH(list_ent,list,db_cmd_next) {
720 		table = list_ent->db_cmd;
721 
722 		for (numcmds = 0; table[numcmds].name != NULL; numcmds++)
723 			;
724 		lines = (numcmds + columns - 1) / columns;
725 
726 		for (i = 0; i < lines; i++) {
727 			for (j = 0; j < columns; j++) {
728 				p = table[j * lines + i].name;
729 				if (p)
730 					db_printf("%s", p);
731 				if (j * lines + i + lines >= numcmds) {
732 					db_putchar('\n');
733 					break;
734 				}
735 				if (p) {
736 					w = strlen(p);
737 					while (w < width) {
738 						w = DB_NEXT_TAB(w);
739 						db_putchar('\t');
740 					}
741 				}
742 			}
743 		}
744 	}
745 	return;
746 }
747 
748 /*
749  * Read complete command with all subcommands, starting with current
750  * db_tok_string. If subcommand is missing, print the list of all
751  * subcommands.  If command/subcommand is not found, print an error
752  * message.  Returns pointer to "leaf" command or NULL.
753  */
754 static const struct db_command *
755 db_read_command(void)
756 {
757 	const struct db_command *command;
758 	struct db_cmd_tbl_en_head *list;
759 	int found;
760 	int t;
761 
762 	list = &db_base_cmd_list;
763 	do {
764 		found = db_cmd_search(db_tok_string, list, &command);
765 		if (command == NULL) {
766 			db_cmd_search_failed(db_tok_string, found);
767 			db_flush_lex();
768 			return NULL;
769 		}
770 
771 		if (command->flag == CS_SHOW)
772 			list = &db_show_cmd_list;
773 		else if (command->flag == CS_MACH)
774 			list = &db_mach_cmd_list;
775 		else if (command->flag == CS_COMPAT)
776 			/* same list */;
777 		else
778 			break; /* expect no more subcommands */
779 
780 		t = db_read_token(); /* read subcommand */
781 		if (t != tIDENT) {
782 			/* if none given - just print all of them */
783 			db_cmd_list(list);
784 			db_flush_lex();
785 			return NULL;
786 		}
787 	} while (list != NULL);
788 
789 	return command;
790 }
791 
792 /*
793  * Parse command line and execute apropriate function.
794  */
795 static void
796 db_command(const struct db_command **last_cmdp)
797 {
798 	const struct db_command *command;
799 	static db_expr_t last_count = 0;
800 	db_expr_t	addr, count;
801 	char		modif[TOK_STRING_SIZE];
802 
803 	int			t;
804 	bool		have_addr = false;
805 
806 	command = NULL;
807 
808 	t = db_read_token();
809 	if ((t == tEOL) || (t == tCOMMA)) {
810 		/*
811 		 * An empty line repeats last command, at 'next'.
812 		 * Only a count repeats the last command with the new count.
813 		 */
814 		command = *last_cmdp;
815 
816 		if (!command)
817 			return;
818 
819 		addr = (db_expr_t)db_next;
820 		if (t == tCOMMA) {
821 			if (!db_expression(&count)) {
822 				db_printf("Count missing\n");
823 				db_flush_lex();
824 				return;
825 			}
826 		} else
827 			count = last_count;
828 		have_addr = false;
829 		modif[0] = '\0';
830 		db_skip_to_eol();
831 
832 	} else if (t == tEXCL) {
833 		db_fncall(0, 0, 0, NULL);
834 		return;
835 
836 	} else if (t != tIDENT) {
837 		db_printf("?\n");
838 		db_flush_lex();
839 		return;
840 
841 	} else {
842 
843 		command = db_read_command();
844 		if (command == NULL)
845 			return;
846 
847 		if ((command->flag & CS_OWN) == 0) {
848 
849 			/*
850 			 * Standard syntax:
851 			 * command [/modifier] [addr] [,count]
852 			 */
853 			t = db_read_token(); /* get modifier */
854 			if (t == tSLASH) {
855 				t = db_read_token();
856 				if (t != tIDENT) {
857 					db_printf("Bad modifier\n");
858 					db_flush_lex();
859 					return;
860 				}
861 				/* save modifier */
862 				strlcpy(modif, db_tok_string, sizeof(modif));
863 
864 			} else {
865 				db_unread_token(t);
866 				modif[0] = '\0';
867 			}
868 
869 			if (db_expression(&addr)) { /*get address*/
870 				db_dot = (db_addr_t) addr;
871 				db_last_addr = db_dot;
872 				have_addr = true;
873 			} else {
874 				addr = (db_expr_t) db_dot;
875 				have_addr = false;
876 			}
877 
878 			t = db_read_token();
879 			if (t == tCOMMA) { /*Get count*/
880 				if (!db_expression(&count)) {
881 					db_printf("Count missing\n");
882 					db_flush_lex();
883 					return;
884 				}
885 			} else {
886 				db_unread_token(t);
887 				count = -1;
888 			}
889 			if ((command->flag & CS_MORE) == 0) {
890 				db_skip_to_eol();
891 			}
892 		}
893 	}
894 
895 	if (command != NULL && command->flag & CS_NOREPEAT) {
896 		*last_cmdp = NULL;
897 		last_count = 0;
898 	} else {
899 		*last_cmdp = command;
900 		last_count = count;
901 	}
902 
903 
904 	if (command != NULL) {
905 		/*
906 		 * Execute the command.
907 		 */
908 		if (command->fcn != NULL)
909 			(*command->fcn)(addr, have_addr, count, modif);
910 
911 		if (command->flag & CS_SET_DOT) {
912 			/*
913 			 * If command changes dot, set dot to
914 			 * previous address displayed (if 'ed' style).
915 			 */
916 			if (db_ed_style)
917 				db_dot = db_prev;
918 			else
919 				db_dot = db_next;
920 		} else {
921 			/*
922 			 * If command does not change dot,
923 			 * set 'next' location to be the same.
924 			 */
925 			db_next = db_dot;
926 		}
927 	}
928 }
929 
930 /*
931  * Print help for commands
932  */
933 static void
934 db_help_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
935 const char *modif)
936 {
937 	const struct db_command *command;
938 	int t;
939 
940 	t = db_read_token();
941 
942 	/* is there another command after the "help"? */
943 	if (t != tIDENT) {
944 		/* print base commands */
945 		db_cmd_list(&db_base_cmd_list);
946 		return;
947 	}
948 
949 	command = db_read_command();
950 	if (command == NULL)
951 		return;
952 
953 #ifdef DDB_VERBOSE_HELP
954 	db_printf("Command: %s\n", command->name);
955 	if (command->cmd_descr != NULL)
956 		db_printf(" Description: %s\n", command->cmd_descr);
957 	if (command->cmd_arg != NULL)
958 		db_printf(" Arguments: %s\n", command->cmd_arg);
959 	if (command->cmd_arg_help != NULL)
960 		db_printf(" Arguments description:\n%s\n",
961 			  command->cmd_arg_help);
962 	if ((command->cmd_arg == NULL) && (command->cmd_descr == NULL))
963 		db_printf(" No help message.\n");
964 #endif
965 
966 	db_skip_to_eol();
967 }
968 
969 /*ARGSUSED*/
970 static void
971 db_map_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
972     const char *modif)
973 {
974 #ifdef _KERNEL
975 	bool full = false;
976 
977 	if (modif[0] == 'f')
978 		full = true;
979 
980 	if (have_addr == false)
981 		addr = (db_expr_t)(uintptr_t)db_read_ptr("kernel_map");
982 
983 	uvm_map_printit((struct vm_map *)(uintptr_t) addr, full, db_printf);
984 #endif	/* XXX CRASH(8) */
985 }
986 
987 /*ARGSUSED*/
988 static void
989 db_object_print_cmd(db_expr_t addr, bool have_addr,
990     db_expr_t count, const char *modif)
991 {
992 #ifdef _KERNEL /* XXX CRASH(8) */
993 	bool full = false;
994 
995 	if (modif[0] == 'f')
996 		full = true;
997 
998 	uvm_object_printit((struct uvm_object *)(uintptr_t) addr, full,
999 	    db_printf);
1000 #endif
1001 }
1002 
1003 /*ARGSUSED*/
1004 static void
1005 db_page_print_cmd(db_expr_t addr, bool have_addr,
1006     db_expr_t count, const char *modif)
1007 {
1008 #ifdef _KERNEL /* XXX CRASH(8) */
1009 	bool full = false;
1010 
1011 	if (modif[0] == 'f')
1012 		full = true;
1013 
1014 	uvm_page_printit((struct vm_page *)(uintptr_t) addr, full, db_printf);
1015 #endif
1016 }
1017 
1018 /*ARGSUSED*/
1019 static void
1020 db_show_all_pages(db_expr_t addr, bool have_addr,
1021     db_expr_t count, const char *modif)
1022 {
1023 
1024 #ifdef _KERNEL /* XXX CRASH(8) */
1025 	uvm_page_printall(db_printf);
1026 #endif
1027 }
1028 
1029 /*ARGSUSED*/
1030 static void
1031 db_buf_print_cmd(db_expr_t addr, bool have_addr,
1032     db_expr_t count, const char *modif)
1033 {
1034 #ifdef _KERNEL /* XXX CRASH(8) */
1035 	bool full = false;
1036 
1037 	if (modif[0] == 'f')
1038 		full = true;
1039 
1040 	vfs_buf_print((struct buf *)(uintptr_t) addr, full, db_printf);
1041 #endif
1042 }
1043 
1044 /*ARGSUSED*/
1045 static void
1046 db_event_print_cmd(db_expr_t addr, bool have_addr,
1047     db_expr_t count, const char *modif)
1048 {
1049 	bool showzero = false;
1050 	bool showall = true;
1051 	bool showintr = false;
1052 	bool showtrap = false;
1053 	bool showmisc = false;
1054 	struct evcnt ev, *evp;
1055 	char buf[80];
1056 	int i;
1057 
1058 	i = 0;
1059 	while (modif[i]) {
1060 		switch (modif[i]) {
1061 		case 'f':
1062 			showzero = true;
1063 			break;
1064 		case 'i':
1065 			showintr = true;
1066 			showall = false;
1067 			break;
1068 		case 't':
1069 			showtrap = true;
1070 			showall = false;
1071 			break;
1072 		case 'm':
1073 			showmisc = true;
1074 			showall = false;
1075 			break;
1076 		}
1077 		i++;
1078 	}
1079 
1080 	if (showall)
1081 		showmisc = showintr = showtrap = true;
1082 
1083 	evp = (struct evcnt *)db_read_ptr("allevents");
1084 	while (evp != NULL) {
1085 		db_read_bytes((db_addr_t)evp, sizeof(ev), (char *)&ev);
1086 		evp = ev.ev_list.tqe_next;
1087 		if (ev.ev_count == 0 && !showzero)
1088 			continue;
1089 		if (ev.ev_type == EVCNT_TYPE_INTR && !showintr)
1090 			continue;
1091 		if (ev.ev_type == EVCNT_TYPE_TRAP && !showtrap)
1092 			continue;
1093 		if (ev.ev_type == EVCNT_TYPE_MISC && !showmisc)
1094 			continue;
1095 		db_read_bytes((db_addr_t)ev.ev_group, ev.ev_grouplen + 1, buf);
1096 		db_printf("evcnt type %d: %s ", ev.ev_type, buf);
1097 		db_read_bytes((db_addr_t)ev.ev_name, ev.ev_namelen + 1, buf);
1098 		db_printf("%s = %lld\n", buf, (long long)ev.ev_count);
1099 	}
1100 }
1101 
1102 /*ARGSUSED*/
1103 static void
1104 db_vnode_print_cmd(db_expr_t addr, bool have_addr,
1105     db_expr_t count, const char *modif)
1106 {
1107 #ifdef _KERNEL /* XXX CRASH(8) */
1108 	bool full = false;
1109 
1110 	if (modif[0] == 'f')
1111 		full = true;
1112 
1113 	vfs_vnode_print((struct vnode *)(uintptr_t) addr, full, db_printf);
1114 #endif
1115 }
1116 
1117 /*ARGSUSED*/
1118 static void
1119 db_vmem_print_cmd(db_expr_t addr, bool have_addr,
1120     db_expr_t count, const char *modif)
1121 {
1122 
1123 #ifdef _KERNEL /* XXX CRASH(8) */
1124 	vmem_print((uintptr_t) addr, modif, db_printf);
1125 #endif
1126 }
1127 
1128 static void
1129 db_mount_print_cmd(db_expr_t addr, bool have_addr,
1130     db_expr_t count, const char *modif)
1131 {
1132 #ifdef _KERNEL	/* XXX CRASH(8) */
1133 	bool full = false;
1134 
1135 	if (modif[0] == 'f')
1136 		full = true;
1137 
1138 	vfs_mount_print((struct mount *)(uintptr_t) addr, full, db_printf);
1139 #endif
1140 }
1141 
1142 /*ARGSUSED*/
1143 static void
1144 db_mbuf_print_cmd(db_expr_t addr, bool have_addr,
1145     db_expr_t count, const char *modif)
1146 {
1147 
1148 #ifdef _KERNEL /* XXX CRASH(8) */
1149 	m_print((const struct mbuf *)(uintptr_t) addr, modif, db_printf);
1150 #endif
1151 }
1152 
1153 /*ARGSUSED*/
1154 static void
1155 db_pool_print_cmd(db_expr_t addr, bool have_addr,
1156     db_expr_t count, const char *modif)
1157 {
1158 
1159 #ifdef _KERNEL /* XXX CRASH(8) */
1160 	pool_printit((struct pool *)(uintptr_t) addr, modif, db_printf);
1161 #endif
1162 }
1163 
1164 /*ARGSUSED*/
1165 static void
1166 db_namecache_print_cmd(db_expr_t addr, bool have_addr,
1167     db_expr_t count, const char *modif)
1168 {
1169 
1170 #ifdef _KERNEL /* XXX CRASH(8) */
1171 	namecache_print((struct vnode *)(uintptr_t) addr, db_printf);
1172 #endif
1173 }
1174 
1175 /*ARGSUSED*/
1176 static void
1177 db_uvmexp_print_cmd(db_expr_t addr, bool have_addr,
1178     db_expr_t count, const char *modif)
1179 {
1180 
1181 #ifdef _KERNEL	/* XXX CRASH(8) */
1182 	uvmexp_print(db_printf);
1183 #endif
1184 }
1185 
1186 #ifdef KERNHIST
1187 /*ARGSUSED*/
1188 static void
1189 db_kernhist_print_cmd(db_expr_t addr, bool have_addr,
1190     db_expr_t count, const char *modif)
1191 {
1192 
1193 	kernhist_print((void *)(uintptr_t)addr, db_printf);
1194 }
1195 #endif
1196 
1197 /*ARGSUSED*/
1198 static void
1199 db_lock_print_cmd(db_expr_t addr, bool have_addr,
1200     db_expr_t count, const char *modif)
1201 {
1202 
1203 #ifdef _KERNEL	/* XXX CRASH(8) */
1204 	lockdebug_lock_print((void *)(uintptr_t)addr, db_printf);
1205 #endif
1206 }
1207 
1208 /*
1209  * Call random function:
1210  * !expr(arg,arg,arg)
1211  */
1212 /*ARGSUSED*/
1213 static void
1214 db_fncall(db_expr_t addr, bool have_addr,
1215     db_expr_t count, const char *modif)
1216 {
1217 #ifdef _KERNEL
1218 	db_expr_t	fn_addr;
1219 #define	MAXARGS		11
1220 	db_expr_t	args[MAXARGS];
1221 	int		nargs = 0;
1222 	db_expr_t	retval;
1223 	db_expr_t	(*func)(db_expr_t, ...);
1224 	int		t;
1225 
1226 	if (!db_expression(&fn_addr)) {
1227 		db_printf("Bad function\n");
1228 		db_flush_lex();
1229 		return;
1230 	}
1231 	func = (db_expr_t (*)(db_expr_t, ...))(uintptr_t) fn_addr;
1232 
1233 	t = db_read_token();
1234 	if (t == tLPAREN) {
1235 		if (db_expression(&args[0])) {
1236 			nargs++;
1237 			while ((t = db_read_token()) == tCOMMA) {
1238 				if (nargs == MAXARGS) {
1239 					db_printf("Too many arguments\n");
1240 					db_flush_lex();
1241 					return;
1242 				}
1243 				if (!db_expression(&args[nargs])) {
1244 					db_printf("Argument missing\n");
1245 					db_flush_lex();
1246 					return;
1247 				}
1248 				nargs++;
1249 			}
1250 			db_unread_token(t);
1251 		}
1252 		if (db_read_token() != tRPAREN) {
1253 			db_printf("?\n");
1254 			db_flush_lex();
1255 			return;
1256 		}
1257 	}
1258 	db_skip_to_eol();
1259 
1260 	while (nargs < MAXARGS) {
1261 		args[nargs++] = 0;
1262 	}
1263 
1264 	retval = (*func)(args[0], args[1], args[2], args[3], args[4],
1265 			 args[5], args[6], args[7], args[8], args[9]);
1266 	db_printf("%s\n", db_num_to_str(retval));
1267 #else	/* _KERNEL */
1268 	db_printf("This command can only be used in-kernel.\n");
1269 #endif	/* _KERNEL */
1270 }
1271 
1272 static void
1273 db_reboot_cmd(db_expr_t addr, bool have_addr,
1274     db_expr_t count, const char *modif)
1275 {
1276 #ifdef _KERNEL
1277 	db_expr_t bootflags;
1278 
1279 	/* Flags, default to RB_AUTOBOOT */
1280 	if (!db_expression(&bootflags))
1281 		bootflags = (db_expr_t)RB_AUTOBOOT;
1282 	if (db_read_token() != tEOL) {
1283 		db_error("?\n");
1284 		/*NOTREACHED*/
1285 	}
1286 	/*
1287 	 * We are leaving DDB, never to return upward.
1288 	 * Clear db_recover so that we can debug faults in functions
1289 	 * called from cpu_reboot.
1290 	 */
1291 	db_recover = 0;
1292 	panicstr = "reboot forced via kernel debugger";
1293 	cpu_reboot((int)bootflags, NULL);
1294 #else	/* _KERNEL */
1295 	db_printf("This command can only be used in-kernel.\n");
1296 #endif	/* _KERNEL */
1297 }
1298 
1299 static void
1300 db_sifting_cmd(db_expr_t addr, bool have_addr,
1301     db_expr_t count, const char *modif)
1302 {
1303 	int	mode, t;
1304 
1305 	t = db_read_token();
1306 	if (t == tSLASH) {
1307 		t = db_read_token();
1308 		if (t != tIDENT) {
1309 			bad_modifier:
1310 			db_printf("Bad modifier\n");
1311 			db_flush_lex();
1312 			return;
1313 		}
1314 		if (!strcmp(db_tok_string, "F"))
1315 			mode = 'F';
1316 		else
1317 			goto bad_modifier;
1318 		t = db_read_token();
1319 	} else
1320 		mode = 0;
1321 
1322 	if (t == tIDENT)
1323 		db_sifting(db_tok_string, mode);
1324 	else {
1325 		db_printf("Bad argument (non-string)\n");
1326 		db_flush_lex();
1327 	}
1328 }
1329 
1330 static void
1331 db_stack_trace_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
1332 {
1333 	register const char *cp = modif;
1334 	register char c;
1335 	void (*pr)(const char *, ...);
1336 
1337 	pr = db_printf;
1338 	while ((c = *cp++) != 0)
1339 		if (c == 'l')
1340 			pr = (void (*)(const char *, ...))printf;
1341 
1342 	if (count == -1)
1343 		count = 65535;
1344 
1345 	db_stack_trace_print(addr, have_addr, count, modif, pr);
1346 }
1347 
1348 static void
1349 db_sync_cmd(db_expr_t addr, bool have_addr,
1350     db_expr_t count, const char *modif)
1351 {
1352 #ifdef _KERNEL
1353 	/*
1354 	 * We are leaving DDB, never to return upward.
1355 	 * Clear db_recover so that we can debug faults in functions
1356 	 * called from cpu_reboot.
1357 	 */
1358 	db_recover = 0;
1359 	panicstr = "dump forced via kernel debugger";
1360 	cpu_reboot(RB_DUMP, NULL);
1361 #else	/* _KERNEL */
1362 	db_printf("This command can only be used in-kernel.\n");
1363 #endif	/* _KERNEL */
1364 }
1365 
1366 /*
1367  * Describe what an address is
1368  */
1369 void
1370 db_whatis_cmd(db_expr_t address, bool have_addr,
1371     db_expr_t count, const char *modif)
1372 {
1373 	const uintptr_t addr = (uintptr_t)address;
1374 
1375 	db_lwp_whatis(addr, db_printf);
1376 #ifdef _KERNEL	/* XXX CRASH(8) */
1377 	pool_whatis(addr, db_printf);
1378 	vmem_whatis(addr, db_printf);
1379 	uvm_whatis(addr, db_printf);
1380 	module_whatis(addr, db_printf);
1381 #endif
1382 }
1383