xref: /netbsd-src/sys/ddb/db_command.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: db_command.c,v 1.133 2009/07/19 02:37:33 rmind 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.133 2009/07/19 02:37:33 rmind 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_uvmhist.h"
72 #include "opt_ddbparam.h"
73 #include "opt_multiprocessor.h"
74 #include "arp.h"
75 #endif
76 
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/reboot.h>
80 #include <sys/device.h>
81 #include <sys/lwp.h>
82 #include <sys/malloc.h>
83 #include <sys/mbuf.h>
84 #include <sys/namei.h>
85 #include <sys/pool.h>
86 #include <sys/proc.h>
87 #include <sys/vnode.h>
88 #include <sys/vmem.h>
89 #include <sys/lockdebug.h>
90 #include <sys/cpu.h>
91 #include <sys/buf.h>
92 #include <sys/module.h>
93 
94 /*include queue macros*/
95 #include <sys/queue.h>
96 
97 #include <ddb/ddb.h>
98 
99 #include <uvm/uvm_extern.h>
100 #include <uvm/uvm_ddb.h>
101 
102 /*
103  * Results of command search.
104  */
105 #define	CMD_EXACT		0
106 #define	CMD_PREFIX		1
107 #define	CMD_NONE		2
108 #define	CMD_AMBIGUOUS	3
109 
110 /*
111  * Exported global variables
112  */
113 bool		db_cmd_loop_done;
114 label_t		*db_recover;
115 db_addr_t	db_dot;
116 db_addr_t	db_last_addr;
117 db_addr_t	db_prev;
118 db_addr_t	db_next;
119 
120 
121 /*
122  * New DDB api for adding and removing commands uses three lists, because
123  * we use two types of commands
124  * a) standard commands without subcommands -> reboot
125  * b) show commands which are subcommands of show command -> show aio_jobs
126  * c) if defined machine specific commands
127  *
128  * ddb_add_cmd, ddb_rem_cmd use type (DDB_SHOW_CMD||DDB_BASE_CMD)argument to
129  * add them to representativ lists.
130  */
131 
132 static const struct db_command db_command_table[];
133 static const struct db_command db_show_cmds[];
134 
135 #ifdef DB_MACHINE_COMMANDS
136 static const struct db_command db_machine_command_table[];
137 #endif
138 
139 /* the global queue of all command tables */
140 TAILQ_HEAD(db_cmd_tbl_en_head, db_cmd_tbl_en);
141 
142 /* TAILQ entry used to register command tables */
143 struct db_cmd_tbl_en {
144 	const struct db_command *db_cmd;	/* cmd table */
145 	TAILQ_ENTRY(db_cmd_tbl_en) db_cmd_next;
146 };
147 
148 /* head of base commands list */
149 static struct db_cmd_tbl_en_head db_base_cmd_list =
150 	TAILQ_HEAD_INITIALIZER(db_base_cmd_list);
151 static struct db_cmd_tbl_en db_base_cmd_builtins =
152      { .db_cmd = db_command_table };
153 
154 /* head of show commands list */
155 static struct db_cmd_tbl_en_head db_show_cmd_list =
156 	TAILQ_HEAD_INITIALIZER(db_show_cmd_list);
157 static struct db_cmd_tbl_en db_show_cmd_builtins =
158      { .db_cmd = db_show_cmds };
159 
160 /* head of machine commands list */
161 static struct db_cmd_tbl_en_head db_mach_cmd_list =
162 	TAILQ_HEAD_INITIALIZER(db_mach_cmd_list);
163 #ifdef DB_MACHINE_COMMANDS
164 static struct db_cmd_tbl_en db_mach_cmd_builtins =
165      { .db_cmd = db_machine_command_table };
166 #endif
167 
168 /*
169  * if 'ed' style: 'dot' is set at start of last item printed,
170  * and '+' points to next line.
171  * Otherwise: 'dot' points to next item, '..' points to last.
172  */
173 static bool	 db_ed_style = true;
174 
175 static void	db_init_commands(void);
176 static int	db_register_tbl_entry(uint8_t type,
177     struct db_cmd_tbl_en *list_ent);
178 static void	db_cmd_list(const struct db_cmd_tbl_en_head *);
179 static int	db_cmd_search(const char *, struct db_cmd_tbl_en_head *,
180 			      const struct db_command **);
181 static int	db_cmd_search_table(const char *, const struct db_command *,
182 				    const struct db_command **);
183 static void	db_cmd_search_failed(char *, int);
184 static const struct db_command *db_read_command(void);
185 static void	db_command(const struct db_command **);
186 static void	db_buf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
187 static void	db_event_print_cmd(db_expr_t, bool, db_expr_t, const char *);
188 static void	db_fncall(db_expr_t, bool, db_expr_t, const char *);
189 static void     db_help_print_cmd(db_expr_t, bool, db_expr_t, const char *);
190 static void	db_lock_print_cmd(db_expr_t, bool, db_expr_t, const char *);
191 static void	db_mount_print_cmd(db_expr_t, bool, db_expr_t, const char *);
192 static void	db_mbuf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
193 static void	db_malloc_print_cmd(db_expr_t, bool, db_expr_t, const char *);
194 static void	db_map_print_cmd(db_expr_t, bool, db_expr_t, const char *);
195 static void	db_namecache_print_cmd(db_expr_t, bool, db_expr_t,
196 		    const char *);
197 static void	db_object_print_cmd(db_expr_t, bool, db_expr_t, const char *);
198 static void	db_page_print_cmd(db_expr_t, bool, db_expr_t, const char *);
199 static void	db_show_all_pages(db_expr_t, bool, db_expr_t, const char *);
200 static void	db_pool_print_cmd(db_expr_t, bool, db_expr_t, const char *);
201 static void	db_reboot_cmd(db_expr_t, bool, db_expr_t, const char *);
202 static void	db_sifting_cmd(db_expr_t, bool, db_expr_t, const char *);
203 static void	db_stack_trace_cmd(db_expr_t, bool, db_expr_t, const char *);
204 static void	db_sync_cmd(db_expr_t, bool, db_expr_t, const char *);
205 static void	db_whatis_cmd(db_expr_t, bool, db_expr_t, const char *);
206 static void	db_uvmexp_print_cmd(db_expr_t, bool, db_expr_t, const char *);
207 #ifdef UVMHIST
208 static void	db_uvmhist_print_cmd(db_expr_t, bool, db_expr_t, const char *);
209 #endif
210 static void	db_vnode_print_cmd(db_expr_t, bool, db_expr_t, const char *);
211 static void	db_vmem_print_cmd(db_expr_t, bool, db_expr_t, const char *);
212 
213 static const struct db_command db_show_cmds[] = {
214 	/*added from all sub cmds*/
215 #ifdef _KERNEL	/* XXX CRASH(8) */
216 	{ DDB_ADD_CMD("callout",  db_show_callout,
217 	    0 ,"List all used callout functions.",NULL,NULL) },
218 #endif
219 	{ DDB_ADD_CMD("pages",	db_show_all_pages,
220 	    0 ,"List all used memory pages.",NULL,NULL) },
221 	{ DDB_ADD_CMD("procs",	db_show_all_procs,
222 	    0 ,"List all processes.",NULL,NULL) },
223 	{ DDB_ADD_CMD("pools",	db_show_all_pools,
224 	    0 ,"Show all poolS",NULL,NULL) },
225 #ifdef AIO
226 	/*added from all sub cmds*/
227 	{ DDB_ADD_CMD("aio_jobs",	db_show_aio_jobs,	0,
228 	    "Show aio jobs",NULL,NULL) },
229 #endif
230 	{ DDB_ADD_CMD("all",	NULL,
231 	    CS_COMPAT, NULL,NULL,NULL) },
232 #if defined(INET) && (NARP > 0)
233 	{ DDB_ADD_CMD("arptab",	db_show_arptab,		0,NULL,NULL,NULL) },
234 #endif
235 #ifdef _KERNEL
236 	{ DDB_ADD_CMD("breaks",	db_listbreak_cmd, 	0,
237 	    "Display all breaks.",NULL,NULL) },
238 #endif
239 	{ DDB_ADD_CMD("buf",	db_buf_print_cmd,	0,
240 	    "Print the struct buf at address.", "[/f] address",NULL) },
241 	{ DDB_ADD_CMD("event",	db_event_print_cmd,	0,
242 	    "Print all the non-zero evcnt(9) event counters.", "[/fitm]",NULL) },
243 	{ DDB_ADD_CMD("files", db_show_files_cmd,	0,
244 	    "Print the files open by process at address",
245 	    "[/f] address", NULL) },
246 	{ DDB_ADD_CMD("lock",	db_lock_print_cmd,	0,NULL,NULL,NULL) },
247 	{ DDB_ADD_CMD("malloc",	db_malloc_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("pool",	db_pool_print_cmd,	0,
267 	    "Print the pool at address.", "[/clp] address",NULL) },
268 	{ DDB_ADD_CMD("registers",	db_show_regs,		0,
269 	    "Display the register set.", "[/u]",NULL) },
270 	{ DDB_ADD_CMD("sched_qs",	db_show_sched_qs,	0,
271 	    "Print the state of the scheduler's run queues.",
272 	    NULL,NULL) },
273 	{ DDB_ADD_CMD("uvmexp",	db_uvmexp_print_cmd, 0,
274 	    "Print a selection of UVM counters and statistics.",
275 	    NULL,NULL) },
276 #ifdef UVMHIST
277 	{ DDB_ADD_CMD("uvmhist", db_uvmhist_print_cmd, 0,
278 	    "Print the UVM history logs.",
279 	    NULL,NULL) },
280 #endif
281 	{ DDB_ADD_CMD("vnode",	db_vnode_print_cmd,	0,
282 	    "Print the vnode at address.", "[/f] address",NULL) },
283 	{ DDB_ADD_CMD("vmem", db_vmem_print_cmd,	0,
284 	    "Print the vmem usage.", "[/a] address", NULL) },
285 	{ DDB_ADD_CMD("vmems", db_show_all_vmems,	0,
286 	    "Show all vmems.", NULL, NULL) },
287 #ifdef _KERNEL
288 	{ DDB_ADD_CMD("watches",	db_listwatch_cmd, 	0,
289 	    "Display all watchpoints.", NULL,NULL) },
290 #endif
291 	{ DDB_ADD_CMD(NULL,		NULL,			0,NULL,NULL,NULL) }
292 };
293 
294 /* arch/<arch>/<arch>/db_interface.c */
295 #ifdef DB_MACHINE_COMMANDS
296 extern const struct db_command db_machine_command_table[];
297 #endif
298 
299 static const struct db_command db_command_table[] = {
300 	{ DDB_ADD_CMD("b",		db_breakpoint_cmd,	0,
301 	    "Set a breakpoint at address", "[/u] address[,count].",NULL) },
302 	{ DDB_ADD_CMD("break",	db_breakpoint_cmd,	0,
303 	    "Set a breakpoint at address", "[/u] address[,count].",NULL) },
304 	{ DDB_ADD_CMD("bt",		db_stack_trace_cmd,	0,
305 	    "Show backtrace.", "See help trace.",NULL) },
306 	{ DDB_ADD_CMD("c",		db_continue_cmd,	0,
307 	    "Continue execution.", "[/c]",NULL) },
308 	{ DDB_ADD_CMD("call",	db_fncall,		CS_OWN,
309 	    "Call the function", "address[(expression[,...])]",NULL) },
310 #ifdef _KERNEL	/* XXX CRASH(8) */
311 	{ DDB_ADD_CMD("callout",	db_show_callout,	0, NULL,
312 	    NULL,NULL ) },
313 #endif
314 	{ DDB_ADD_CMD("continue",	db_continue_cmd,	0,
315 	    "Continue execution.", "[/c]",NULL) },
316 	{ DDB_ADD_CMD("d",		db_delete_cmd,		0,
317 	    "Delete a breakpoint.", "address | #number",NULL) },
318 	{ DDB_ADD_CMD("delete",	db_delete_cmd,		0,
319 	    "Delete a breakpoint.", "address | #number",NULL) },
320 	{ DDB_ADD_CMD("dmesg",	db_dmesg,		0,
321 	    "Show kernel message buffer.", "[count]",NULL) },
322 	{ DDB_ADD_CMD("dwatch",	db_deletewatch_cmd,	0,
323 	    "Delete the watchpoint.", "address",NULL) },
324 	{ DDB_ADD_CMD("examine",	db_examine_cmd,		CS_SET_DOT,
325 	    "Display the address locations.",
326 	    "[/modifier] address[,count]",NULL) },
327 	{ DDB_ADD_CMD("exit",		db_continue_cmd,	0,
328 	    "Continue execution.", "[/c]",NULL) },
329 	{ DDB_ADD_CMD("help",   db_help_print_cmd, CS_OWN|CS_NOREPEAT,
330 	    "Display help about commands",
331 	    "Use other commands as arguments.",NULL) },
332 	{ DDB_ADD_CMD("kill",	db_kill_proc,		CS_OWN,
333 	    "Send a signal to the process","pid[,signal_number]",
334 	    "   pid:\t\t\tthe process id (may need 0t prefix for decimal)\n"
335 	    "   signal_number:\tthe signal to send") },
336 #ifdef KGDB
337 	{ DDB_ADD_CMD("kgdb",	db_kgdb_cmd,	0,	NULL,NULL,NULL) },
338 #endif
339 	{ DDB_ADD_CMD("machine",NULL,CS_MACH,
340 	    "Architecture specific functions.",NULL,NULL) },
341 	{ DDB_ADD_CMD("match",	db_trace_until_matching_cmd,0,
342 	    "Stop at the matching return instruction.","See help next",NULL) },
343 	{ DDB_ADD_CMD("next",	db_trace_until_matching_cmd,0,
344 	    "Stop at the matching return instruction.","[/p]",NULL) },
345 	{ DDB_ADD_CMD("p",		db_print_cmd,		0,
346 	    "Print address according to the format.",
347 	    "[/axzodurc] address [address ...]",NULL) },
348 	{ DDB_ADD_CMD("print",	db_print_cmd,		0,
349 	    "Print address according to the format.",
350 	    "[/axzodurc] address [address ...]",NULL) },
351 	{ DDB_ADD_CMD("ps",		db_show_all_procs,	0,
352 	    "Print all processes.","See show all procs",NULL) },
353 	{ DDB_ADD_CMD("quit",		db_continue_cmd,	0,
354 	    "Continue execution.", "[/c]",NULL) },
355 	{ DDB_ADD_CMD("reboot",	db_reboot_cmd,		CS_OWN,
356 	    "Reboot","0x1  RB_ASKNAME, 0x2 RB_SINGLE, 0x4 RB_NOSYNC, 0x8 RB_HALT,"
357 	    "0x40 RB_KDB, 0x100 RB_DUMP, 0x808 RB_POWERDOWN",NULL) },
358 	{ DDB_ADD_CMD("s",		db_single_step_cmd,	0,
359 	    "Single-step count times.","[/p] [,count]",NULL) },
360 	{ DDB_ADD_CMD("search",	db_search_cmd,		CS_OWN|CS_SET_DOT,
361 	    "Search memory from address for value.",
362 	    "[/bhl] address value [mask] [,count]",NULL) },
363 	{ DDB_ADD_CMD("set",	db_set_cmd,		CS_OWN,
364 	    "Set the named variable","$variable [=] expression",NULL) },
365 	{ DDB_ADD_CMD("show",	NULL, CS_SHOW,
366 	    "Show kernel stats.", NULL,NULL) },
367 	{ DDB_ADD_CMD("sifting",	db_sifting_cmd,		CS_OWN,
368 	    "Search the symbol tables ","[/F] string",NULL) },
369 	{ DDB_ADD_CMD("step",	db_single_step_cmd,	0,
370 	    "Single-step count times.","[/p] [,count]",NULL) },
371 	{ DDB_ADD_CMD("sync",	db_sync_cmd,		CS_OWN,
372 	    "Force a crash dump, and then reboot.",NULL,NULL) },
373 	{ DDB_ADD_CMD("trace",	db_stack_trace_cmd,	0,
374 	    "Stack trace from frame-address.",
375 	    "[/u[l]] [frame-address][,count]",NULL) },
376 	{ DDB_ADD_CMD("until",	db_trace_until_call_cmd,0,
377 	    "Stop at the next call or return instruction.","[/p]",NULL) },
378 	{ DDB_ADD_CMD("w",		db_write_cmd,		CS_MORE|CS_SET_DOT,
379 	    "Write the expressions at succeeding locations.",
380 	    "[/bhl] address expression [expression ...]",NULL) },
381 	{ DDB_ADD_CMD("watch",	db_watchpoint_cmd,	CS_MORE,
382 	    "Set a watchpoint for a region. ","address[,size]",NULL) },
383 	{ DDB_ADD_CMD("whatis",	db_whatis_cmd, 0,
384 	    "Describe what an address is", "address", NULL) },
385 	{ DDB_ADD_CMD("write",	db_write_cmd,		CS_MORE|CS_SET_DOT,
386 	    "Write the expressions at succeeding locations.",
387 	    "[/bhl] address expression [expression ...]",NULL) },
388 	{ DDB_ADD_CMD("x",		db_examine_cmd,		CS_SET_DOT,
389 	    "Display the address locations.",
390 	    "[/modifier] address[,count]",NULL) },
391 	{ DDB_ADD_CMD(NULL, 	NULL,		   0, NULL, NULL, NULL) }
392 };
393 
394 static const struct db_command	*db_last_command = NULL;
395 #if defined(DDB_COMMANDONENTER)
396 char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ___STRING(DDB_COMMANDONENTER);
397 #else /* defined(DDB_COMMANDONENTER) */
398 char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = "";
399 #endif /* defined(DDB_COMMANDONENTER) */
400 #define	DB_LINE_SEP	';'
401 
402 /*
403  * Execute commandlist after ddb start
404  * This function goes through the command list created from commands and ';'
405  */
406 static void
407 db_execute_commandlist(const char *cmdlist)
408 {
409 	const char *cmd = cmdlist;
410 	const struct db_command	*dummy = NULL;
411 
412 	while (*cmd != '\0') {
413 		const char *ep = cmd;
414 
415 		while (*ep != '\0' && *ep != DB_LINE_SEP) {
416 			ep++;
417 		}
418 		db_set_line(cmd, ep);
419 		db_command(&dummy);
420 		cmd = ep;
421 		if (*cmd == DB_LINE_SEP) {
422 			cmd++;
423 		}
424 	}
425 }
426 
427 /* Initialize ddb command tables */
428 void
429 db_init_commands(void)
430 {
431 	static bool done = false;
432 
433 	if (done) return;
434 	done = true;
435 
436 	/* register command tables */
437 	(void)db_register_tbl_entry(DDB_BASE_CMD, &db_base_cmd_builtins);
438 #ifdef DB_MACHINE_COMMANDS
439 	(void)db_register_tbl_entry(DDB_MACH_CMD, &db_mach_cmd_builtins);
440 #endif
441 	(void)db_register_tbl_entry(DDB_SHOW_CMD, &db_show_cmd_builtins);
442 }
443 
444 
445 /*
446  * Add command table to the specified list
447  * Arg:
448  * int type specifies type of command table DDB_SHOW_CMD|DDB_BASE_CMD|DDB_MAC_CMD
449  * *cmd_tbl poiter to static allocated db_command table
450  *
451  * Command table must be NULL terminated array of struct db_command
452  */
453 int
454 db_register_tbl(uint8_t type, const struct db_command *cmd_tbl)
455 {
456 	struct db_cmd_tbl_en *list_ent;
457 
458 	/* empty list - ignore */
459 	if (cmd_tbl->name == 0)
460 		return 0;
461 
462 	/* force builtin commands to be registered first */
463 	db_init_commands();
464 
465 	/* now create a list entry for this table */
466 	list_ent = db_zalloc(sizeof(*list_ent));
467 	if (list_ent == NULL)
468 		return ENOMEM;
469 	list_ent->db_cmd=cmd_tbl;
470 
471 	/* and register it */
472 	return db_register_tbl_entry(type, list_ent);
473 }
474 
475 static int
476 db_register_tbl_entry(uint8_t type, struct db_cmd_tbl_en *list_ent)
477 {
478 	struct db_cmd_tbl_en_head *list;
479 
480 	switch(type) {
481 	case DDB_BASE_CMD:
482 		list = &db_base_cmd_list;
483 		break;
484 	case DDB_SHOW_CMD:
485 		list = &db_show_cmd_list;
486 		break;
487 	case DDB_MACH_CMD:
488 		list = &db_mach_cmd_list;
489 		break;
490 	default:
491 		return ENOENT;
492 	}
493 
494 	TAILQ_INSERT_TAIL(list, list_ent, db_cmd_next);
495 
496 	return 0;
497 }
498 
499 /*
500  * Remove command table specified with db_cmd address == cmd_tbl
501  */
502 int
503 db_unregister_tbl(uint8_t type,const struct db_command *cmd_tbl)
504 {
505 	struct db_cmd_tbl_en *list_ent;
506 	struct db_cmd_tbl_en_head *list;
507 
508 	/* find list on which the entry should live */
509 	switch (type) {
510 	case DDB_BASE_CMD:
511 		list=&db_base_cmd_list;
512 		break;
513 	case DDB_SHOW_CMD:
514 		list=&db_show_cmd_list;
515 		break;
516 	case DDB_MACH_CMD:
517 		list=&db_mach_cmd_list;
518 		break;
519 	default:
520 		return EINVAL;
521 	}
522 
523 	TAILQ_FOREACH (list_ent, list, db_cmd_next) {
524 		if (list_ent->db_cmd == cmd_tbl){
525 			TAILQ_REMOVE(list,
526 			    list_ent, db_cmd_next);
527 			db_free(list_ent, sizeof(*list_ent));
528 			return 0;
529 		}
530 	}
531 	return ENOENT;
532 }
533 
534 /* This function is called from machine trap code. */
535 void
536 db_command_loop(void)
537 {
538 	label_t	db_jmpbuf;
539 	label_t	*savejmp;
540 
541 	/*
542 	 * Initialize 'prev' and 'next' to dot.
543 	 */
544 	db_prev = db_dot;
545 	db_next = db_dot;
546 
547 	db_cmd_loop_done = false;
548 
549 	/* Init default command tables add machine, base,
550 	   show command tables to the list */
551 	db_init_commands();
552 
553 	/* save context for return from ddb */
554 	savejmp = db_recover;
555 	db_recover = &db_jmpbuf;
556 	(void) setjmp(&db_jmpbuf);
557 
558 	/* Execute default ddb start commands */
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 	bool full = false;
975 
976 	if (modif[0] == 'f')
977 		full = true;
978 
979 	if (have_addr == false)
980 		addr = (db_expr_t)(uintptr_t)db_read_ptr("kernel_map");
981 
982 #ifdef _KERNEL
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_malloc_print_cmd(db_expr_t addr, bool have_addr,
990     db_expr_t count, const char *modif)
991 {
992 
993 #ifdef MALLOC_DEBUG
994 	if (!have_addr)
995 		addr = 0;
996 
997 	debug_malloc_printit(db_printf, (vaddr_t) addr);
998 #else
999 	db_printf("The kernel is not built with the MALLOC_DEBUG option.\n");
1000 #endif /* MALLOC_DEBUG */
1001 }
1002 
1003 /*ARGSUSED*/
1004 static void
1005 db_object_print_cmd(db_expr_t addr, bool have_addr,
1006     db_expr_t count, const char *modif)
1007 {
1008 	bool full = false;
1009 
1010 	if (modif[0] == 'f')
1011 		full = true;
1012 
1013 #ifdef _KERNEL /* XXX CRASH(8) */
1014 	uvm_object_printit((struct uvm_object *)(uintptr_t) addr, full,
1015 	    db_printf);
1016 #endif
1017 }
1018 
1019 /*ARGSUSED*/
1020 static void
1021 db_page_print_cmd(db_expr_t addr, bool have_addr,
1022     db_expr_t count, const char *modif)
1023 {
1024 	bool full = false;
1025 
1026 	if (modif[0] == 'f')
1027 		full = true;
1028 
1029 #ifdef _KERNEL /* XXX CRASH(8) */
1030 	uvm_page_printit((struct vm_page *)(uintptr_t) addr, full, db_printf);
1031 #endif
1032 }
1033 
1034 /*ARGSUSED*/
1035 static void
1036 db_show_all_pages(db_expr_t addr, bool have_addr,
1037     db_expr_t count, const char *modif)
1038 {
1039 
1040 #ifdef _KERNEL /* XXX CRASH(8) */
1041 	uvm_page_printall(db_printf);
1042 #endif
1043 }
1044 
1045 /*ARGSUSED*/
1046 static void
1047 db_buf_print_cmd(db_expr_t addr, bool have_addr,
1048     db_expr_t count, const char *modif)
1049 {
1050 	bool full = false;
1051 
1052 	if (modif[0] == 'f')
1053 		full = true;
1054 
1055 #ifdef _KERNEL /* XXX CRASH(8) */
1056 	vfs_buf_print((struct buf *)(uintptr_t) addr, full, db_printf);
1057 #endif
1058 }
1059 
1060 /*ARGSUSED*/
1061 static void
1062 db_event_print_cmd(db_expr_t addr, bool have_addr,
1063     db_expr_t count, const char *modif)
1064 {
1065 	bool showzero = false;
1066 	bool showall = true;
1067 	bool showintr = false;
1068 	bool showtrap = false;
1069 	bool showmisc = false;
1070 	struct evcnt ev, *evp;
1071 	char buf[80];
1072 	int i;
1073 
1074 	i = 0;
1075 	while (modif[i]) {
1076 		switch (modif[i]) {
1077 		case 'f':
1078 			showzero = true;
1079 			break;
1080 		case 'i':
1081 			showintr = true;
1082 			showall = false;
1083 			break;
1084 		case 't':
1085 			showtrap = true;
1086 			showall = false;
1087 			break;
1088 		case 'm':
1089 			showmisc = true;
1090 			showall = false;
1091 			break;
1092 		}
1093 		i++;
1094 	}
1095 
1096 	if (showall)
1097 		showmisc = showintr = showtrap = true;
1098 
1099 	evp = (struct evcnt *)db_read_ptr("allevents");
1100 	while (evp != NULL) {
1101 		db_read_bytes((db_addr_t)evp, sizeof(ev), (char *)&ev);
1102 		evp = ev.ev_list.tqe_next;
1103 		if (ev.ev_count == 0 && !showzero)
1104 			continue;
1105 		if (ev.ev_type == EVCNT_TYPE_INTR && !showintr)
1106 			continue;
1107 		if (ev.ev_type == EVCNT_TYPE_TRAP && !showtrap)
1108 			continue;
1109 		if (ev.ev_type == EVCNT_TYPE_MISC && !showmisc)
1110 			continue;
1111 		db_read_bytes((db_addr_t)ev.ev_group, ev.ev_grouplen + 1, buf);
1112 		db_printf("evcnt type %d: %s ", ev.ev_type, buf);
1113 		db_read_bytes((db_addr_t)ev.ev_name, ev.ev_namelen + 1, buf);
1114 		db_printf("%s = %lld\n", buf, (long long)ev.ev_count);
1115 	}
1116 }
1117 
1118 /*ARGSUSED*/
1119 static void
1120 db_vnode_print_cmd(db_expr_t addr, bool have_addr,
1121     db_expr_t count, const char *modif)
1122 {
1123 	bool full = false;
1124 
1125 	if (modif[0] == 'f')
1126 		full = true;
1127 
1128 #ifdef _KERNEL /* XXX CRASH(8) */
1129 	vfs_vnode_print((struct vnode *)(uintptr_t) addr, full, db_printf);
1130 #endif
1131 }
1132 
1133 /*ARGSUSED*/
1134 static void
1135 db_vmem_print_cmd(db_expr_t addr, bool have_addr,
1136     db_expr_t count, const char *modif)
1137 {
1138 
1139 #ifdef _KERNEL /* XXX CRASH(8) */
1140 	vmem_print((uintptr_t) addr, modif, db_printf);
1141 #endif
1142 }
1143 
1144 static void
1145 db_mount_print_cmd(db_expr_t addr, bool have_addr,
1146     db_expr_t count, const char *modif)
1147 {
1148 	bool full = false;
1149 
1150 	if (modif[0] == 'f')
1151 		full = true;
1152 
1153 #ifdef _KERNEL	/* XXX CRASH(8) */
1154 	vfs_mount_print((struct mount *)(uintptr_t) addr, full, db_printf);
1155 #endif
1156 }
1157 
1158 /*ARGSUSED*/
1159 static void
1160 db_mbuf_print_cmd(db_expr_t addr, bool have_addr,
1161     db_expr_t count, const char *modif)
1162 {
1163 
1164 #ifdef _KERNEL /* XXX CRASH(8) */
1165 	m_print((const struct mbuf *)(uintptr_t) addr, modif, db_printf);
1166 #endif
1167 }
1168 
1169 /*ARGSUSED*/
1170 static void
1171 db_pool_print_cmd(db_expr_t addr, bool have_addr,
1172     db_expr_t count, const char *modif)
1173 {
1174 
1175 #ifdef _KERNEL /* XXX CRASH(8) */
1176 	pool_printit((struct pool *)(uintptr_t) addr, modif, db_printf);
1177 #endif
1178 }
1179 
1180 /*ARGSUSED*/
1181 static void
1182 db_namecache_print_cmd(db_expr_t addr, bool have_addr,
1183     db_expr_t count, const char *modif)
1184 {
1185 
1186 #ifdef _KERNEL /* XXX CRASH(8) */
1187 	namecache_print((struct vnode *)(uintptr_t) addr, db_printf);
1188 #endif
1189 }
1190 
1191 /*ARGSUSED*/
1192 static void
1193 db_uvmexp_print_cmd(db_expr_t addr, bool have_addr,
1194     db_expr_t count, const char *modif)
1195 {
1196 
1197 #ifdef _KERNEL	/* XXX CRASH(8) */
1198 	uvmexp_print(db_printf);
1199 #endif
1200 }
1201 
1202 #ifdef UVMHIST
1203 /*ARGSUSED*/
1204 static void
1205 db_uvmhist_print_cmd(db_expr_t addr, bool have_addr,
1206     db_expr_t count, const char *modif)
1207 {
1208 
1209 	uvmhist_print(db_printf);
1210 }
1211 #endif
1212 
1213 /*ARGSUSED*/
1214 static void
1215 db_lock_print_cmd(db_expr_t addr, bool have_addr,
1216     db_expr_t count, const char *modif)
1217 {
1218 
1219 #ifdef _KERNEL	/* XXX CRASH(8) */
1220 	lockdebug_lock_print((void *)(uintptr_t)addr, db_printf);
1221 #endif
1222 }
1223 
1224 /*
1225  * Call random function:
1226  * !expr(arg,arg,arg)
1227  */
1228 /*ARGSUSED*/
1229 static void
1230 db_fncall(db_expr_t addr, bool have_addr,
1231     db_expr_t count, const char *modif)
1232 {
1233 #ifdef _KERNEL
1234 	db_expr_t	fn_addr;
1235 #define	MAXARGS		11
1236 	db_expr_t	args[MAXARGS];
1237 	int		nargs = 0;
1238 	db_expr_t	retval;
1239 	db_expr_t	(*func)(db_expr_t, ...);
1240 	int		t;
1241 
1242 	if (!db_expression(&fn_addr)) {
1243 		db_printf("Bad function\n");
1244 		db_flush_lex();
1245 		return;
1246 	}
1247 	func = (db_expr_t (*)(db_expr_t, ...))(uintptr_t) fn_addr;
1248 
1249 	t = db_read_token();
1250 	if (t == tLPAREN) {
1251 		if (db_expression(&args[0])) {
1252 			nargs++;
1253 			while ((t = db_read_token()) == tCOMMA) {
1254 				if (nargs == MAXARGS) {
1255 					db_printf("Too many arguments\n");
1256 					db_flush_lex();
1257 					return;
1258 				}
1259 				if (!db_expression(&args[nargs])) {
1260 					db_printf("Argument missing\n");
1261 					db_flush_lex();
1262 					return;
1263 				}
1264 				nargs++;
1265 			}
1266 			db_unread_token(t);
1267 		}
1268 		if (db_read_token() != tRPAREN) {
1269 			db_printf("?\n");
1270 			db_flush_lex();
1271 			return;
1272 		}
1273 	}
1274 	db_skip_to_eol();
1275 
1276 	while (nargs < MAXARGS) {
1277 		args[nargs++] = 0;
1278 	}
1279 
1280 	retval = (*func)(args[0], args[1], args[2], args[3], args[4],
1281 			 args[5], args[6], args[7], args[8], args[9]);
1282 	db_printf("%s\n", db_num_to_str(retval));
1283 #else	/* _KERNEL */
1284 	db_printf("This command can only be used in-kernel.\n");
1285 #endif	/* _KERNEL */
1286 }
1287 
1288 static void
1289 db_reboot_cmd(db_expr_t addr, bool have_addr,
1290     db_expr_t count, const char *modif)
1291 {
1292 #ifdef _KERNEL
1293 	db_expr_t bootflags;
1294 
1295 	/* Flags, default to RB_AUTOBOOT */
1296 	if (!db_expression(&bootflags))
1297 		bootflags = (db_expr_t)RB_AUTOBOOT;
1298 	if (db_read_token() != tEOL) {
1299 		db_error("?\n");
1300 		/*NOTREACHED*/
1301 	}
1302 	/*
1303 	 * We are leaving DDB, never to return upward.
1304 	 * Clear db_recover so that we can debug faults in functions
1305 	 * called from cpu_reboot.
1306 	 */
1307 	db_recover = 0;
1308 	cpu_reboot((int)bootflags, NULL);
1309 #else	/* _KERNEL */
1310 	db_printf("This command can only be used in-kernel.\n");
1311 #endif	/* _KERNEL */
1312 }
1313 
1314 static void
1315 db_sifting_cmd(db_expr_t addr, bool have_addr,
1316     db_expr_t count, const char *modif)
1317 {
1318 	int	mode, t;
1319 
1320 	t = db_read_token();
1321 	if (t == tSLASH) {
1322 		t = db_read_token();
1323 		if (t != tIDENT) {
1324 			bad_modifier:
1325 			db_printf("Bad modifier\n");
1326 			db_flush_lex();
1327 			return;
1328 		}
1329 		if (!strcmp(db_tok_string, "F"))
1330 			mode = 'F';
1331 		else
1332 			goto bad_modifier;
1333 		t = db_read_token();
1334 	} else
1335 		mode = 0;
1336 
1337 	if (t == tIDENT)
1338 		db_sifting(db_tok_string, mode);
1339 	else {
1340 		db_printf("Bad argument (non-string)\n");
1341 		db_flush_lex();
1342 	}
1343 }
1344 
1345 static void
1346 db_stack_trace_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
1347 {
1348 	register const char *cp = modif;
1349 	register char c;
1350 	void (*pr)(const char *, ...);
1351 
1352 	pr = db_printf;
1353 	while ((c = *cp++) != 0)
1354 		if (c == 'l')
1355 			pr = (void (*)(const char *, ...))printf;
1356 
1357 	if (count == -1)
1358 		count = 65535;
1359 
1360 	db_stack_trace_print(addr, have_addr, count, modif, pr);
1361 }
1362 
1363 static void
1364 db_sync_cmd(db_expr_t addr, bool have_addr,
1365     db_expr_t count, const char *modif)
1366 {
1367 #ifdef _KERNEL
1368 	/*
1369 	 * We are leaving DDB, never to return upward.
1370 	 * Clear db_recover so that we can debug faults in functions
1371 	 * called from cpu_reboot.
1372 	 */
1373 	db_recover = 0;
1374 	panicstr = "dump forced via kernel debugger";
1375 	cpu_reboot(RB_DUMP, NULL);
1376 #else	/* _KERNEL */
1377 	db_printf("This command can only be used in-kernel.\n");
1378 #endif	/* _KERNEL */
1379 }
1380 
1381 /*
1382  * Describe what an address is
1383  */
1384 void
1385 db_whatis_cmd(db_expr_t address, bool have_addr,
1386     db_expr_t count, const char *modif)
1387 {
1388 	const uintptr_t addr = (uintptr_t)address;
1389 
1390 	db_lwp_whatis(addr, db_printf);
1391 #ifdef _KERNEL	/* XXX CRASH(8) */
1392 	pool_whatis(addr, db_printf);
1393 	vmem_whatis(addr, db_printf);
1394 	uvm_whatis(addr, db_printf);
1395 	module_whatis(addr, db_printf);
1396 #endif
1397 }
1398