1/*	$NetBSD: db_command.c,v 1.136 2011/05/17 04:18:06 mrg 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.136 2011/05/17 04:18:06 mrg 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#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#include <sys/kernhist.h>
94
95/*include queue macros*/
96#include <sys/queue.h>
97
98#include <ddb/ddb.h>
99
100#include <uvm/uvm_extern.h>
101#include <uvm/uvm_ddb.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 */
114bool		db_cmd_loop_done;
115label_t		*db_recover;
116db_addr_t	db_dot;
117db_addr_t	db_last_addr;
118db_addr_t	db_prev;
119db_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
133static const struct db_command db_command_table[];
134static const struct db_command db_show_cmds[];
135
136#ifdef DB_MACHINE_COMMANDS
137/* arch/<arch>/<arch>/db_interface.c */
138extern const struct db_command db_machine_command_table[];
139#endif
140
141/* the global queue of all command tables */
142TAILQ_HEAD(db_cmd_tbl_en_head, db_cmd_tbl_en);
143
144/* TAILQ entry used to register command tables */
145struct 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 */
151static struct db_cmd_tbl_en_head db_base_cmd_list =
152	TAILQ_HEAD_INITIALIZER(db_base_cmd_list);
153static struct db_cmd_tbl_en db_base_cmd_builtins =
154     { .db_cmd = db_command_table };
155
156/* head of show commands list */
157static struct db_cmd_tbl_en_head db_show_cmd_list =
158	TAILQ_HEAD_INITIALIZER(db_show_cmd_list);
159static struct db_cmd_tbl_en db_show_cmd_builtins =
160     { .db_cmd = db_show_cmds };
161
162/* head of machine commands list */
163static struct db_cmd_tbl_en_head db_mach_cmd_list =
164	TAILQ_HEAD_INITIALIZER(db_mach_cmd_list);
165#ifdef DB_MACHINE_COMMANDS
166static 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 */
175static bool	 db_ed_style = true;
176
177static void	db_init_commands(void);
178static int	db_register_tbl_entry(uint8_t type,
179    struct db_cmd_tbl_en *list_ent);
180static void	db_cmd_list(const struct db_cmd_tbl_en_head *);
181static int	db_cmd_search(const char *, struct db_cmd_tbl_en_head *,
182			      const struct db_command **);
183static int	db_cmd_search_table(const char *, const struct db_command *,
184				    const struct db_command **);
185static void	db_cmd_search_failed(char *, int);
186static const struct db_command *db_read_command(void);
187static void	db_command(const struct db_command **);
188static void	db_buf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
189static void	db_event_print_cmd(db_expr_t, bool, db_expr_t, const char *);
190static void	db_fncall(db_expr_t, bool, db_expr_t, const char *);
191static void     db_help_print_cmd(db_expr_t, bool, db_expr_t, const char *);
192static void	db_lock_print_cmd(db_expr_t, bool, db_expr_t, const char *);
193static void	db_mount_print_cmd(db_expr_t, bool, db_expr_t, const char *);
194static void	db_mbuf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
195static void	db_malloc_print_cmd(db_expr_t, bool, db_expr_t, const char *);
196static void	db_map_print_cmd(db_expr_t, bool, db_expr_t, const char *);
197static void	db_namecache_print_cmd(db_expr_t, bool, db_expr_t,
198		    const char *);
199static void	db_object_print_cmd(db_expr_t, bool, db_expr_t, const char *);
200static void	db_page_print_cmd(db_expr_t, bool, db_expr_t, const char *);
201static void	db_show_all_pages(db_expr_t, bool, db_expr_t, const char *);
202static void	db_pool_print_cmd(db_expr_t, bool, db_expr_t, const char *);
203static void	db_reboot_cmd(db_expr_t, bool, db_expr_t, const char *);
204static void	db_sifting_cmd(db_expr_t, bool, db_expr_t, const char *);
205static void	db_stack_trace_cmd(db_expr_t, bool, db_expr_t, const char *);
206static void	db_sync_cmd(db_expr_t, bool, db_expr_t, const char *);
207static void	db_whatis_cmd(db_expr_t, bool, db_expr_t, const char *);
208static void	db_uvmexp_print_cmd(db_expr_t, bool, db_expr_t, const char *);
209#ifdef KERNHIST
210static void	db_kernhist_print_cmd(db_expr_t, bool, db_expr_t, const char *);
211#endif
212static void	db_vnode_print_cmd(db_expr_t, bool, db_expr_t, const char *);
213static void	db_vmem_print_cmd(db_expr_t, bool, db_expr_t, const char *);
214
215static const struct db_command db_show_cmds[] = {
216	/*added from all sub cmds*/
217#ifdef _KERNEL	/* XXX CRASH(8) */
218	{ DDB_ADD_CMD("callout",  db_show_callout,
219	    0 ,"List all used callout functions.",NULL,NULL) },
220#endif
221	{ DDB_ADD_CMD("pages",	db_show_all_pages,
222	    0 ,"List all used memory pages.",NULL,NULL) },
223	{ DDB_ADD_CMD("proc",	db_show_proc,
224	    0 ,"Print process information.",NULL,NULL) },
225	{ DDB_ADD_CMD("procs",	db_show_all_procs,
226	    0 ,"List all processes.",NULL,NULL) },
227	{ DDB_ADD_CMD("pools",	db_show_all_pools,
228	    0 ,"Show all pools",NULL,NULL) },
229#ifdef AIO
230	/*added from all sub cmds*/
231	{ DDB_ADD_CMD("aio_jobs",	db_show_aio_jobs,	0,
232	    "Show aio jobs",NULL,NULL) },
233#endif
234	{ DDB_ADD_CMD("all",	NULL,
235	    CS_COMPAT, NULL,NULL,NULL) },
236#if defined(INET) && (NARP > 0)
237	{ DDB_ADD_CMD("arptab",	db_show_arptab,		0,NULL,NULL,NULL) },
238#endif
239#ifdef _KERNEL
240	{ DDB_ADD_CMD("breaks",	db_listbreak_cmd, 	0,
241	    "Display all breaks.",NULL,NULL) },
242#endif
243	{ DDB_ADD_CMD("buf",	db_buf_print_cmd,	0,
244	    "Print the struct buf at address.", "[/f] address",NULL) },
245	{ DDB_ADD_CMD("event",	db_event_print_cmd,	0,
246	    "Print all the non-zero evcnt(9) event counters.", "[/fitm]",NULL) },
247	{ DDB_ADD_CMD("files", db_show_files_cmd,	0,
248	    "Print the files open by process at address",
249	    "[/f] address", NULL) },
250	{ DDB_ADD_CMD("lock",	db_lock_print_cmd,	0,NULL,NULL,NULL) },
251	{ DDB_ADD_CMD("malloc",	db_malloc_print_cmd,0,NULL,NULL,NULL) },
252	{ DDB_ADD_CMD("map",	db_map_print_cmd,	0,
253	    "Print the vm_map at address.", "[/f] address",NULL) },
254	{ DDB_ADD_CMD("module", db_show_module_cmd,	0,
255	    "Print kernel modules", NULL, NULL) },
256	{ DDB_ADD_CMD("mount",	db_mount_print_cmd,	0,
257	    "Print the mount structure at address.", "[/f] address",NULL) },
258#ifdef MQUEUE
259	{ DDB_ADD_CMD("mqueue", db_show_mqueue_cmd,	0,
260	    "Print the message queues", NULL, NULL) },
261#endif
262	{ DDB_ADD_CMD("mbuf",	db_mbuf_print_cmd,	0,NULL,NULL,
263	    "-c prints all mbuf chains") },
264	{ DDB_ADD_CMD("ncache",	db_namecache_print_cmd,	0,
265	    "Dump the namecache list.", "address",NULL) },
266	{ DDB_ADD_CMD("object",	db_object_print_cmd,	0,
267	    "Print the vm_object at address.", "[/f] address",NULL) },
268	{ DDB_ADD_CMD("page",	db_page_print_cmd,	0,
269	    "Print the vm_page at address.", "[/f] address",NULL) },
270	{ DDB_ADD_CMD("pool",	db_pool_print_cmd,	0,
271	    "Print the pool at address.", "[/clp] address",NULL) },
272	{ DDB_ADD_CMD("registers",	db_show_regs,		0,
273	    "Display the register set.", "[/u]",NULL) },
274	{ DDB_ADD_CMD("sched_qs",	db_show_sched_qs,	0,
275	    "Print the state of the scheduler's run queues.",
276	    NULL,NULL) },
277	{ DDB_ADD_CMD("uvmexp",	db_uvmexp_print_cmd, 0,
278	    "Print a selection of UVM counters and statistics.",
279	    NULL,NULL) },
280#ifdef KERNHIST
281	{ DDB_ADD_CMD("kernhist", db_kernhist_print_cmd, 0,
282	    "Print the UVM history logs.",
283	    NULL,NULL) },
284#endif
285	{ DDB_ADD_CMD("vnode",	db_vnode_print_cmd,	0,
286	    "Print the vnode at address.", "[/f] address",NULL) },
287	{ DDB_ADD_CMD("vmem", db_vmem_print_cmd,	0,
288	    "Print the vmem usage.", "[/a] address", NULL) },
289	{ DDB_ADD_CMD("vmems", db_show_all_vmems,	0,
290	    "Show all vmems.", NULL, NULL) },
291#ifdef _KERNEL
292	{ DDB_ADD_CMD("watches",	db_listwatch_cmd, 	0,
293	    "Display all watchpoints.", NULL,NULL) },
294#endif
295	{ DDB_ADD_CMD(NULL,		NULL,			0,NULL,NULL,NULL) }
296};
297
298static const struct db_command db_command_table[] = {
299	{ DDB_ADD_CMD("b",		db_breakpoint_cmd,	0,
300	    "Set a breakpoint at address", "[/u] address[,count].",NULL) },
301	{ DDB_ADD_CMD("break",	db_breakpoint_cmd,	0,
302	    "Set a breakpoint at address", "[/u] address[,count].",NULL) },
303	{ DDB_ADD_CMD("bt",		db_stack_trace_cmd,	0,
304	    "Show backtrace.", "See help trace.",NULL) },
305	{ DDB_ADD_CMD("c",		db_continue_cmd,	0,
306	    "Continue execution.", "[/c]",NULL) },
307	{ DDB_ADD_CMD("call",	db_fncall,		CS_OWN,
308	    "Call the function", "address[(expression[,...])]",NULL) },
309#ifdef _KERNEL	/* XXX CRASH(8) */
310	{ DDB_ADD_CMD("callout",	db_show_callout,	0, NULL,
311	    NULL,NULL ) },
312#endif
313	{ DDB_ADD_CMD("continue",	db_continue_cmd,	0,
314	    "Continue execution.", "[/c]",NULL) },
315	{ DDB_ADD_CMD("d",		db_delete_cmd,		0,
316	    "Delete a breakpoint.", "address | #number",NULL) },
317	{ DDB_ADD_CMD("delete",	db_delete_cmd,		0,
318	    "Delete a breakpoint.", "address | #number",NULL) },
319	{ DDB_ADD_CMD("dmesg",	db_dmesg,		0,
320	    "Show kernel message buffer.", "[count]",NULL) },
321	{ DDB_ADD_CMD("dwatch",	db_deletewatch_cmd,	0,
322	    "Delete the watchpoint.", "address",NULL) },
323	{ DDB_ADD_CMD("examine",	db_examine_cmd,		CS_SET_DOT,
324	    "Display the address locations.",
325	    "[/modifier] address[,count]",NULL) },
326	{ DDB_ADD_CMD("exit",		db_continue_cmd,	0,
327	    "Continue execution.", "[/c]",NULL) },
328	{ DDB_ADD_CMD("help",   db_help_print_cmd, CS_OWN|CS_NOREPEAT,
329	    "Display help about commands",
330	    "Use other commands as arguments.",NULL) },
331	{ DDB_ADD_CMD("kill",	db_kill_proc,		CS_OWN,
332	    "Send a signal to the process","pid[,signal_number]",
333	    "   pid:\t\t\tthe process id (may need 0t prefix for decimal)\n"
334	    "   signal_number:\tthe signal to send") },
335#ifdef KGDB
336	{ DDB_ADD_CMD("kgdb",	db_kgdb_cmd,	0,	NULL,NULL,NULL) },
337#endif
338	{ DDB_ADD_CMD("machine",NULL,CS_MACH,
339	    "Architecture specific functions.",NULL,NULL) },
340	{ DDB_ADD_CMD("match",	db_trace_until_matching_cmd,0,
341	    "Stop at the matching return instruction.","See help next",NULL) },
342	{ DDB_ADD_CMD("next",	db_trace_until_matching_cmd,0,
343	    "Stop at the matching return instruction.","[/p]",NULL) },
344	{ DDB_ADD_CMD("p",		db_print_cmd,		0,
345	    "Print address according to the format.",
346	    "[/axzodurc] address [address ...]",NULL) },
347	{ DDB_ADD_CMD("print",	db_print_cmd,		0,
348	    "Print address according to the format.",
349	    "[/axzodurc] address [address ...]",NULL) },
350	{ DDB_ADD_CMD("ps",		db_show_all_procs,	0,
351	    "Print all processes.","See show all procs",NULL) },
352	{ DDB_ADD_CMD("quit",		db_continue_cmd,	0,
353	    "Continue execution.", "[/c]",NULL) },
354	{ DDB_ADD_CMD("reboot",	db_reboot_cmd,		CS_OWN,
355	    "Reboot","0x1  RB_ASKNAME, 0x2 RB_SINGLE, 0x4 RB_NOSYNC, 0x8 RB_HALT,"
356	    "0x40 RB_KDB, 0x100 RB_DUMP, 0x808 RB_POWERDOWN",NULL) },
357	{ DDB_ADD_CMD("s",		db_single_step_cmd,	0,
358	    "Single-step count times.","[/p] [,count]",NULL) },
359	{ DDB_ADD_CMD("search",	db_search_cmd,		CS_OWN|CS_SET_DOT,
360	    "Search memory from address for value.",
361	    "[/bhl] address value [mask] [,count]",NULL) },
362	{ DDB_ADD_CMD("set",	db_set_cmd,		CS_OWN,
363	    "Set the named variable","$variable [=] expression",NULL) },
364	{ DDB_ADD_CMD("show",	NULL, CS_SHOW,
365	    "Show kernel stats.", NULL,NULL) },
366	{ DDB_ADD_CMD("sifting",	db_sifting_cmd,		CS_OWN,
367	    "Search the symbol tables ","[/F] string",NULL) },
368	{ DDB_ADD_CMD("step",	db_single_step_cmd,	0,
369	    "Single-step count times.","[/p] [,count]",NULL) },
370	{ DDB_ADD_CMD("sync",	db_sync_cmd,		CS_OWN,
371	    "Force a crash dump, and then reboot.",NULL,NULL) },
372	{ DDB_ADD_CMD("trace",	db_stack_trace_cmd,	0,
373	    "Stack trace from frame-address.",
374	    "[/u[l]] [frame-address][,count]",NULL) },
375	{ DDB_ADD_CMD("until",	db_trace_until_call_cmd,0,
376	    "Stop at the next call or return instruction.","[/p]",NULL) },
377	{ DDB_ADD_CMD("w",		db_write_cmd,		CS_MORE|CS_SET_DOT,
378	    "Write the expressions at succeeding locations.",
379	    "[/bhl] address expression [expression ...]",NULL) },
380	{ DDB_ADD_CMD("watch",	db_watchpoint_cmd,	CS_MORE,
381	    "Set a watchpoint for a region. ","address[,size]",NULL) },
382	{ DDB_ADD_CMD("whatis",	db_whatis_cmd, 0,
383	    "Describe what an address is", "address", NULL) },
384	{ DDB_ADD_CMD("write",	db_write_cmd,		CS_MORE|CS_SET_DOT,
385	    "Write the expressions at succeeding locations.",
386	    "[/bhl] address expression [expression ...]",NULL) },
387	{ DDB_ADD_CMD("x",		db_examine_cmd,		CS_SET_DOT,
388	    "Display the address locations.",
389	    "[/modifier] address[,count]",NULL) },
390	{ DDB_ADD_CMD(NULL, 	NULL,		   0, NULL, NULL, NULL) }
391};
392
393static const struct db_command	*db_last_command = NULL;
394#if defined(DDB_COMMANDONENTER)
395char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ___STRING(DDB_COMMANDONENTER);
396#else /* defined(DDB_COMMANDONENTER) */
397char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = "";
398#endif /* defined(DDB_COMMANDONENTER) */
399#define	DB_LINE_SEP	';'
400
401/*
402 * Execute commandlist after ddb start
403 * This function goes through the command list created from commands and ';'
404 */
405static void
406db_execute_commandlist(const char *cmdlist)
407{
408	const char *cmd = cmdlist;
409	const struct db_command	*dummy = NULL;
410
411	while (*cmd != '\0') {
412		const char *ep = cmd;
413
414		while (*ep != '\0' && *ep != DB_LINE_SEP) {
415			ep++;
416		}
417		db_set_line(cmd, ep);
418		db_command(&dummy);
419		cmd = ep;
420		if (*cmd == DB_LINE_SEP) {
421			cmd++;
422		}
423	}
424}
425
426/* Initialize ddb command tables */
427void
428db_init_commands(void)
429{
430	static bool done = false;
431
432	if (done) return;
433	done = true;
434
435	/* register command tables */
436	(void)db_register_tbl_entry(DDB_BASE_CMD, &db_base_cmd_builtins);
437#ifdef DB_MACHINE_COMMANDS
438	(void)db_register_tbl_entry(DDB_MACH_CMD, &db_mach_cmd_builtins);
439#endif
440	(void)db_register_tbl_entry(DDB_SHOW_CMD, &db_show_cmd_builtins);
441}
442
443
444/*
445 * Add command table to the specified list
446 * Arg:
447 * int type specifies type of command table DDB_SHOW_CMD|DDB_BASE_CMD|DDB_MAC_CMD
448 * *cmd_tbl poiter to static allocated db_command table
449 *
450 * Command table must be NULL terminated array of struct db_command
451 */
452int
453db_register_tbl(uint8_t type, const struct db_command *cmd_tbl)
454{
455	struct db_cmd_tbl_en *list_ent;
456
457	/* empty list - ignore */
458	if (cmd_tbl->name == 0)
459		return 0;
460
461	/* force builtin commands to be registered first */
462	db_init_commands();
463
464	/* now create a list entry for this table */
465	list_ent = db_zalloc(sizeof(*list_ent));
466	if (list_ent == NULL)
467		return ENOMEM;
468	list_ent->db_cmd=cmd_tbl;
469
470	/* and register it */
471	return db_register_tbl_entry(type, list_ent);
472}
473
474static int
475db_register_tbl_entry(uint8_t type, struct db_cmd_tbl_en *list_ent)
476{
477	struct db_cmd_tbl_en_head *list;
478
479	switch(type) {
480	case DDB_BASE_CMD:
481		list = &db_base_cmd_list;
482		break;
483	case DDB_SHOW_CMD:
484		list = &db_show_cmd_list;
485		break;
486	case DDB_MACH_CMD:
487		list = &db_mach_cmd_list;
488		break;
489	default:
490		return ENOENT;
491	}
492
493	TAILQ_INSERT_TAIL(list, list_ent, db_cmd_next);
494
495	return 0;
496}
497
498/*
499 * Remove command table specified with db_cmd address == cmd_tbl
500 */
501int
502db_unregister_tbl(uint8_t type,const struct db_command *cmd_tbl)
503{
504	struct db_cmd_tbl_en *list_ent;
505	struct db_cmd_tbl_en_head *list;
506
507	/* find list on which the entry should live */
508	switch (type) {
509	case DDB_BASE_CMD:
510		list=&db_base_cmd_list;
511		break;
512	case DDB_SHOW_CMD:
513		list=&db_show_cmd_list;
514		break;
515	case DDB_MACH_CMD:
516		list=&db_mach_cmd_list;
517		break;
518	default:
519		return EINVAL;
520	}
521
522	TAILQ_FOREACH (list_ent, list, db_cmd_next) {
523		if (list_ent->db_cmd == cmd_tbl){
524			TAILQ_REMOVE(list,
525			    list_ent, db_cmd_next);
526			db_free(list_ent, sizeof(*list_ent));
527			return 0;
528		}
529	}
530	return ENOENT;
531}
532
533/* This function is called from machine trap code. */
534void
535db_command_loop(void)
536{
537	label_t	db_jmpbuf;
538	label_t	*savejmp;
539
540	/*
541	 * Initialize 'prev' and 'next' to dot.
542	 */
543	db_prev = db_dot;
544	db_next = db_dot;
545
546	db_cmd_loop_done = false;
547
548	/* Init default command tables add machine, base,
549	   show command tables to the list */
550	db_init_commands();
551
552	/* save context for return from ddb */
553	savejmp = db_recover;
554	db_recover = &db_jmpbuf;
555	(void) setjmp(&db_jmpbuf);
556
557	/* Execute default ddb start commands */
558	db_execute_commandlist(db_cmd_on_enter);
559
560	(void) setjmp(&db_jmpbuf);
561	while (!db_cmd_loop_done) {
562		if (db_print_position() != 0)
563			db_printf("\n");
564		db_output_line = 0;
565		(void) db_read_line();
566		db_command(&db_last_command);
567	}
568
569	db_recover = savejmp;
570}
571
572/*
573 * Search command table for command prefix
574 */
575static int
576db_cmd_search_table(const char *name,
577		    const struct db_command *table,
578		    const struct db_command **cmdp)
579{
580
581	const struct db_command	*cmd;
582	int result;
583
584	result = CMD_NONE;
585	*cmdp = NULL;
586
587	for (cmd = table; cmd->name != 0; cmd++) {
588		const char *lp;
589		const char *rp;
590
591		lp = name;
592		rp = cmd->name;
593		while (*lp != '\0' && *lp == *rp) {
594			rp++;
595			lp++;
596		}
597
598		if (*lp != '\0') /* mismatch or extra chars in name */
599			continue;
600
601		if (*rp == '\0') { /* exact match */
602			*cmdp = cmd;
603			return (CMD_EXACT);
604		}
605
606		/* prefix match: end of name, not end of command */
607		if (result == CMD_NONE) {
608			result = CMD_PREFIX;
609			*cmdp = cmd;
610		}
611		else if (result == CMD_PREFIX) {
612			result = CMD_AMBIGUOUS;
613			*cmdp = NULL;
614		}
615	}
616
617	return (result);
618}
619
620
621/*
622 * Search list of command tables for command
623 */
624static int
625db_cmd_search(const char *name,
626	      struct db_cmd_tbl_en_head *list_head,
627	      const struct db_command **cmdp)
628{
629	struct db_cmd_tbl_en *list_ent;
630	const struct db_command *found_command;
631	bool accept_prefix_match;
632	int result;
633
634	result = CMD_NONE;
635	found_command = NULL;
636	accept_prefix_match = true;
637
638	TAILQ_FOREACH(list_ent, list_head, db_cmd_next) {
639		const struct db_command *cmd;
640		int found;
641
642		found = db_cmd_search_table(name, list_ent->db_cmd, &cmd);
643		if (found == CMD_EXACT) {
644			result = CMD_EXACT;
645			found_command = cmd;
646			break;
647		}
648
649		if (found == CMD_PREFIX) {
650			if (accept_prefix_match) {
651				/*
652				 * Continue search, but note current result
653				 * in case we won't find anything else.
654				 */
655				accept_prefix_match = false;
656				result = CMD_PREFIX;
657				found_command = cmd;
658			} else {
659				/*
660				 * Watch out for globally ambiguous
661				 * prefix match that is not locally
662				 * ambiguous - with one match in one
663				 * table and another match(es) in
664				 * another table.
665				 */
666				result = CMD_AMBIGUOUS;
667				found_command = NULL;
668			}
669		}
670		else if (found == CMD_AMBIGUOUS) {
671			accept_prefix_match = false;
672			result = CMD_AMBIGUOUS;
673			found_command = NULL;
674		}
675	}
676
677	*cmdp = found_command;
678	return result;
679}
680
681static void
682db_cmd_search_failed(char *name, int search_result)
683{
684	if (search_result == CMD_NONE)
685		db_printf("No such command: %s\n", name);
686	else
687		db_printf("Ambiguous command: %s\n", name);
688}
689
690
691/*
692 * List commands to the console.
693 */
694static void
695db_cmd_list(const struct db_cmd_tbl_en_head *list)
696{
697
698	struct db_cmd_tbl_en *list_ent;
699	const struct db_command *table;
700	size_t		i, j, w, columns, lines, numcmds, width=0;
701	const char	*p;
702
703	TAILQ_FOREACH(list_ent,list,db_cmd_next) {
704		table = list_ent->db_cmd;
705		for (i = 0; table[i].name != NULL; i++) {
706			w = strlen(table[i].name);
707			if (w > width)
708				width = w;
709		}
710	}
711
712	width = DB_NEXT_TAB(width);
713
714	columns = db_max_width / width;
715	if (columns == 0)
716		columns = 1;
717
718	TAILQ_FOREACH(list_ent,list,db_cmd_next) {
719		table = list_ent->db_cmd;
720
721		for (numcmds = 0; table[numcmds].name != NULL; numcmds++)
722			;
723		lines = (numcmds + columns - 1) / columns;
724
725		for (i = 0; i < lines; i++) {
726			for (j = 0; j < columns; j++) {
727				p = table[j * lines + i].name;
728				if (p)
729					db_printf("%s", p);
730				if (j * lines + i + lines >= numcmds) {
731					db_putchar('\n');
732					break;
733				}
734				if (p) {
735					w = strlen(p);
736					while (w < width) {
737						w = DB_NEXT_TAB(w);
738						db_putchar('\t');
739					}
740				}
741			}
742		}
743	}
744	return;
745}
746
747/*
748 * Read complete command with all subcommands, starting with current
749 * db_tok_string. If subcommand is missing, print the list of all
750 * subcommands.  If command/subcommand is not found, print an error
751 * message.  Returns pointer to "leaf" command or NULL.
752 */
753static const struct db_command *
754db_read_command(void)
755{
756	const struct db_command *command;
757	struct db_cmd_tbl_en_head *list;
758	int found;
759	int t;
760
761	list = &db_base_cmd_list;
762	do {
763		found = db_cmd_search(db_tok_string, list, &command);
764		if (command == NULL) {
765			db_cmd_search_failed(db_tok_string, found);
766			db_flush_lex();
767			return NULL;
768		}
769
770		if (command->flag == CS_SHOW)
771			list = &db_show_cmd_list;
772		else if (command->flag == CS_MACH)
773			list = &db_mach_cmd_list;
774		else if (command->flag == CS_COMPAT)
775			/* same list */;
776		else
777			break; /* expect no more subcommands */
778
779		t = db_read_token(); /* read subcommand */
780		if (t != tIDENT) {
781			/* if none given - just print all of them */
782			db_cmd_list(list);
783			db_flush_lex();
784			return NULL;
785		}
786	} while (list != NULL);
787
788	return command;
789}
790
791/*
792 * Parse command line and execute apropriate function.
793 */
794static void
795db_command(const struct db_command **last_cmdp)
796{
797	const struct db_command *command;
798	static db_expr_t last_count = 0;
799	db_expr_t	addr, count;
800	char		modif[TOK_STRING_SIZE];
801
802	int			t;
803	bool		have_addr = false;
804
805	command = NULL;
806
807	t = db_read_token();
808	if ((t == tEOL) || (t == tCOMMA)) {
809		/*
810		 * An empty line repeats last command, at 'next'.
811		 * Only a count repeats the last command with the new count.
812		 */
813		command = *last_cmdp;
814
815		if (!command)
816			return;
817
818		addr = (db_expr_t)db_next;
819		if (t == tCOMMA) {
820			if (!db_expression(&count)) {
821				db_printf("Count missing\n");
822				db_flush_lex();
823				return;
824			}
825		} else
826			count = last_count;
827		have_addr = false;
828		modif[0] = '\0';
829		db_skip_to_eol();
830
831	} else if (t == tEXCL) {
832		db_fncall(0, 0, 0, NULL);
833		return;
834
835	} else if (t != tIDENT) {
836		db_printf("?\n");
837		db_flush_lex();
838		return;
839
840	} else {
841
842		command = db_read_command();
843		if (command == NULL)
844			return;
845
846		if ((command->flag & CS_OWN) == 0) {
847
848			/*
849			 * Standard syntax:
850			 * command [/modifier] [addr] [,count]
851			 */
852			t = db_read_token(); /* get modifier */
853			if (t == tSLASH) {
854				t = db_read_token();
855				if (t != tIDENT) {
856					db_printf("Bad modifier\n");
857					db_flush_lex();
858					return;
859				}
860				/* save modifier */
861				strlcpy(modif, db_tok_string, sizeof(modif));
862
863			} else {
864				db_unread_token(t);
865				modif[0] = '\0';
866			}
867
868			if (db_expression(&addr)) { /*get address*/
869				db_dot = (db_addr_t) addr;
870				db_last_addr = db_dot;
871				have_addr = true;
872			} else {
873				addr = (db_expr_t) db_dot;
874				have_addr = false;
875			}
876
877			t = db_read_token();
878			if (t == tCOMMA) { /*Get count*/
879				if (!db_expression(&count)) {
880					db_printf("Count missing\n");
881					db_flush_lex();
882					return;
883				}
884			} else {
885				db_unread_token(t);
886				count = -1;
887			}
888			if ((command->flag & CS_MORE) == 0) {
889				db_skip_to_eol();
890			}
891		}
892	}
893
894	if (command != NULL && command->flag & CS_NOREPEAT) {
895		*last_cmdp = NULL;
896		last_count = 0;
897	} else {
898		*last_cmdp = command;
899		last_count = count;
900	}
901
902
903	if (command != NULL) {
904		/*
905		 * Execute the command.
906		 */
907		if (command->fcn != NULL)
908			(*command->fcn)(addr, have_addr, count, modif);
909
910		if (command->flag & CS_SET_DOT) {
911			/*
912			 * If command changes dot, set dot to
913			 * previous address displayed (if 'ed' style).
914			 */
915			if (db_ed_style)
916				db_dot = db_prev;
917			else
918				db_dot = db_next;
919		} else {
920			/*
921			 * If command does not change dot,
922			 * set 'next' location to be the same.
923			 */
924			db_next = db_dot;
925		}
926	}
927}
928
929/*
930 * Print help for commands
931 */
932static void
933db_help_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
934const char *modif)
935{
936	const struct db_command *command;
937	int t;
938
939	t = db_read_token();
940
941	/* is there another command after the "help"? */
942	if (t != tIDENT) {
943		/* print base commands */
944		db_cmd_list(&db_base_cmd_list);
945		return;
946	}
947
948	command = db_read_command();
949	if (command == NULL)
950		return;
951
952#ifdef DDB_VERBOSE_HELP
953	db_printf("Command: %s\n", command->name);
954	if (command->cmd_descr != NULL)
955		db_printf(" Description: %s\n", command->cmd_descr);
956	if (command->cmd_arg != NULL)
957		db_printf(" Arguments: %s\n", command->cmd_arg);
958	if (command->cmd_arg_help != NULL)
959		db_printf(" Arguments description:\n%s\n",
960			  command->cmd_arg_help);
961	if ((command->cmd_arg == NULL) && (command->cmd_descr == NULL))
962		db_printf(" No help message.\n");
963#endif
964
965	db_skip_to_eol();
966}
967
968/*ARGSUSED*/
969static void
970db_map_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
971    const char *modif)
972{
973	bool full = false;
974
975	if (modif[0] == 'f')
976		full = true;
977
978	if (have_addr == false)
979		addr = (db_expr_t)(uintptr_t)db_read_ptr("kernel_map");
980
981#ifdef _KERNEL
982	uvm_map_printit((struct vm_map *)(uintptr_t) addr, full, db_printf);
983#endif	/* XXX CRASH(8) */
984}
985
986/*ARGSUSED*/
987static void
988db_malloc_print_cmd(db_expr_t addr, bool have_addr,
989    db_expr_t count, const char *modif)
990{
991
992#ifdef MALLOC_DEBUG
993	if (!have_addr)
994		addr = 0;
995
996	debug_malloc_printit(db_printf, (vaddr_t) addr);
997#else
998	db_printf("The kernel is not built with the MALLOC_DEBUG option.\n");
999#endif /* MALLOC_DEBUG */
1000}
1001
1002/*ARGSUSED*/
1003static void
1004db_object_print_cmd(db_expr_t addr, bool have_addr,
1005    db_expr_t count, const char *modif)
1006{
1007	bool full = false;
1008
1009	if (modif[0] == 'f')
1010		full = true;
1011
1012#ifdef _KERNEL /* XXX CRASH(8) */
1013	uvm_object_printit((struct uvm_object *)(uintptr_t) addr, full,
1014	    db_printf);
1015#endif
1016}
1017
1018/*ARGSUSED*/
1019static void
1020db_page_print_cmd(db_expr_t addr, bool have_addr,
1021    db_expr_t count, const char *modif)
1022{
1023	bool full = false;
1024
1025	if (modif[0] == 'f')
1026		full = true;
1027
1028#ifdef _KERNEL /* XXX CRASH(8) */
1029	uvm_page_printit((struct vm_page *)(uintptr_t) addr, full, db_printf);
1030#endif
1031}
1032
1033/*ARGSUSED*/
1034static void
1035db_show_all_pages(db_expr_t addr, bool have_addr,
1036    db_expr_t count, const char *modif)
1037{
1038
1039#ifdef _KERNEL /* XXX CRASH(8) */
1040	uvm_page_printall(db_printf);
1041#endif
1042}
1043
1044/*ARGSUSED*/
1045static void
1046db_buf_print_cmd(db_expr_t addr, bool have_addr,
1047    db_expr_t count, const char *modif)
1048{
1049	bool full = false;
1050
1051	if (modif[0] == 'f')
1052		full = true;
1053
1054#ifdef _KERNEL /* XXX CRASH(8) */
1055	vfs_buf_print((struct buf *)(uintptr_t) addr, full, db_printf);
1056#endif
1057}
1058
1059/*ARGSUSED*/
1060static void
1061db_event_print_cmd(db_expr_t addr, bool have_addr,
1062    db_expr_t count, const char *modif)
1063{
1064	bool showzero = false;
1065	bool showall = true;
1066	bool showintr = false;
1067	bool showtrap = false;
1068	bool showmisc = false;
1069	struct evcnt ev, *evp;
1070	char buf[80];
1071	int i;
1072
1073	i = 0;
1074	while (modif[i]) {
1075		switch (modif[i]) {
1076		case 'f':
1077			showzero = true;
1078			break;
1079		case 'i':
1080			showintr = true;
1081			showall = false;
1082			break;
1083		case 't':
1084			showtrap = true;
1085			showall = false;
1086			break;
1087		case 'm':
1088			showmisc = true;
1089			showall = false;
1090			break;
1091		}
1092		i++;
1093	}
1094
1095	if (showall)
1096		showmisc = showintr = showtrap = true;
1097
1098	evp = (struct evcnt *)db_read_ptr("allevents");
1099	while (evp != NULL) {
1100		db_read_bytes((db_addr_t)evp, sizeof(ev), (char *)&ev);
1101		evp = ev.ev_list.tqe_next;
1102		if (ev.ev_count == 0 && !showzero)
1103			continue;
1104		if (ev.ev_type == EVCNT_TYPE_INTR && !showintr)
1105			continue;
1106		if (ev.ev_type == EVCNT_TYPE_TRAP && !showtrap)
1107			continue;
1108		if (ev.ev_type == EVCNT_TYPE_MISC && !showmisc)
1109			continue;
1110		db_read_bytes((db_addr_t)ev.ev_group, ev.ev_grouplen + 1, buf);
1111		db_printf("evcnt type %d: %s ", ev.ev_type, buf);
1112		db_read_bytes((db_addr_t)ev.ev_name, ev.ev_namelen + 1, buf);
1113		db_printf("%s = %lld\n", buf, (long long)ev.ev_count);
1114	}
1115}
1116
1117/*ARGSUSED*/
1118static void
1119db_vnode_print_cmd(db_expr_t addr, bool have_addr,
1120    db_expr_t count, const char *modif)
1121{
1122	bool full = false;
1123
1124	if (modif[0] == 'f')
1125		full = true;
1126
1127#ifdef _KERNEL /* XXX CRASH(8) */
1128	vfs_vnode_print((struct vnode *)(uintptr_t) addr, full, db_printf);
1129#endif
1130}
1131
1132/*ARGSUSED*/
1133static void
1134db_vmem_print_cmd(db_expr_t addr, bool have_addr,
1135    db_expr_t count, const char *modif)
1136{
1137
1138#ifdef _KERNEL /* XXX CRASH(8) */
1139	vmem_print((uintptr_t) addr, modif, db_printf);
1140#endif
1141}
1142
1143static void
1144db_mount_print_cmd(db_expr_t addr, bool have_addr,
1145    db_expr_t count, const char *modif)
1146{
1147	bool full = false;
1148
1149	if (modif[0] == 'f')
1150		full = true;
1151
1152#ifdef _KERNEL	/* XXX CRASH(8) */
1153	vfs_mount_print((struct mount *)(uintptr_t) addr, full, db_printf);
1154#endif
1155}
1156
1157/*ARGSUSED*/
1158static void
1159db_mbuf_print_cmd(db_expr_t addr, bool have_addr,
1160    db_expr_t count, const char *modif)
1161{
1162
1163#ifdef _KERNEL /* XXX CRASH(8) */
1164	m_print((const struct mbuf *)(uintptr_t) addr, modif, db_printf);
1165#endif
1166}
1167
1168/*ARGSUSED*/
1169static void
1170db_pool_print_cmd(db_expr_t addr, bool have_addr,
1171    db_expr_t count, const char *modif)
1172{
1173
1174#ifdef _KERNEL /* XXX CRASH(8) */
1175	pool_printit((struct pool *)(uintptr_t) addr, modif, db_printf);
1176#endif
1177}
1178
1179/*ARGSUSED*/
1180static void
1181db_namecache_print_cmd(db_expr_t addr, bool have_addr,
1182    db_expr_t count, const char *modif)
1183{
1184
1185#ifdef _KERNEL /* XXX CRASH(8) */
1186	namecache_print((struct vnode *)(uintptr_t) addr, db_printf);
1187#endif
1188}
1189
1190/*ARGSUSED*/
1191static void
1192db_uvmexp_print_cmd(db_expr_t addr, bool have_addr,
1193    db_expr_t count, const char *modif)
1194{
1195
1196#ifdef _KERNEL	/* XXX CRASH(8) */
1197	uvmexp_print(db_printf);
1198#endif
1199}
1200
1201#ifdef KERNHIST
1202/*ARGSUSED*/
1203static void
1204db_kernhist_print_cmd(db_expr_t addr, bool have_addr,
1205    db_expr_t count, const char *modif)
1206{
1207
1208	kernhist_print(db_printf);
1209}
1210#endif
1211
1212/*ARGSUSED*/
1213static void
1214db_lock_print_cmd(db_expr_t addr, bool have_addr,
1215    db_expr_t count, const char *modif)
1216{
1217
1218#ifdef _KERNEL	/* XXX CRASH(8) */
1219	lockdebug_lock_print((void *)(uintptr_t)addr, db_printf);
1220#endif
1221}
1222
1223/*
1224 * Call random function:
1225 * !expr(arg,arg,arg)
1226 */
1227/*ARGSUSED*/
1228static void
1229db_fncall(db_expr_t addr, bool have_addr,
1230    db_expr_t count, const char *modif)
1231{
1232#ifdef _KERNEL
1233	db_expr_t	fn_addr;
1234#define	MAXARGS		11
1235	db_expr_t	args[MAXARGS];
1236	int		nargs = 0;
1237	db_expr_t	retval;
1238	db_expr_t	(*func)(db_expr_t, ...);
1239	int		t;
1240
1241	if (!db_expression(&fn_addr)) {
1242		db_printf("Bad function\n");
1243		db_flush_lex();
1244		return;
1245	}
1246	func = (db_expr_t (*)(db_expr_t, ...))(uintptr_t) fn_addr;
1247
1248	t = db_read_token();
1249	if (t == tLPAREN) {
1250		if (db_expression(&args[0])) {
1251			nargs++;
1252			while ((t = db_read_token()) == tCOMMA) {
1253				if (nargs == MAXARGS) {
1254					db_printf("Too many arguments\n");
1255					db_flush_lex();
1256					return;
1257				}
1258				if (!db_expression(&args[nargs])) {
1259					db_printf("Argument missing\n");
1260					db_flush_lex();
1261					return;
1262				}
1263				nargs++;
1264			}
1265			db_unread_token(t);
1266		}
1267		if (db_read_token() != tRPAREN) {
1268			db_printf("?\n");
1269			db_flush_lex();
1270			return;
1271		}
1272	}
1273	db_skip_to_eol();
1274
1275	while (nargs < MAXARGS) {
1276		args[nargs++] = 0;
1277	}
1278
1279	retval = (*func)(args[0], args[1], args[2], args[3], args[4],
1280			 args[5], args[6], args[7], args[8], args[9]);
1281	db_printf("%s\n", db_num_to_str(retval));
1282#else	/* _KERNEL */
1283	db_printf("This command can only be used in-kernel.\n");
1284#endif	/* _KERNEL */
1285}
1286
1287static void
1288db_reboot_cmd(db_expr_t addr, bool have_addr,
1289    db_expr_t count, const char *modif)
1290{
1291#ifdef _KERNEL
1292	db_expr_t bootflags;
1293
1294	/* Flags, default to RB_AUTOBOOT */
1295	if (!db_expression(&bootflags))
1296		bootflags = (db_expr_t)RB_AUTOBOOT;
1297	if (db_read_token() != tEOL) {
1298		db_error("?\n");
1299		/*NOTREACHED*/
1300	}
1301	/*
1302	 * We are leaving DDB, never to return upward.
1303	 * Clear db_recover so that we can debug faults in functions
1304	 * called from cpu_reboot.
1305	 */
1306	db_recover = 0;
1307	panicstr = "reboot forced via kernel debugger";
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
1314static void
1315db_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
1345static void
1346db_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
1363static void
1364db_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 */
1384void
1385db_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