xref: /openbsd-src/sys/ddb/db_command.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: db_command.c,v 1.71 2016/04/19 12:23:25 mpi Exp $	*/
2 /*	$NetBSD: db_command.c,v 1.20 1996/03/30 22:30:05 christos Exp $	*/
3 
4 /*
5  * Mach Operating System
6  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7  * All Rights Reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie Mellon
27  * the rights to redistribute these changes.
28  */
29 
30 /*
31  * Command dispatcher.
32  */
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/proc.h>
36 #include <sys/reboot.h>
37 #include <sys/extent.h>
38 #include <sys/pool.h>
39 #include <sys/msgbuf.h>
40 #include <sys/malloc.h>
41 #include <sys/mount.h>
42 
43 #include <uvm/uvm_extern.h>
44 #include <machine/db_machdep.h>		/* type definitions */
45 
46 #include <ddb/db_access.h>
47 #include <ddb/db_lex.h>
48 #include <ddb/db_output.h>
49 #include <ddb/db_command.h>
50 #include <ddb/db_break.h>
51 #include <ddb/db_watch.h>
52 #include <ddb/db_run.h>
53 #include <ddb/db_sym.h>
54 #include <ddb/db_variables.h>
55 #include <ddb/db_interface.h>
56 #include <ddb/db_extern.h>
57 
58 #include <uvm/uvm_ddb.h>
59 
60 /*
61  * Exported global variables
62  */
63 int		db_cmd_loop_done;
64 label_t		*db_recover;
65 
66 /*
67  * if 'ed' style: 'dot' is set at start of last item printed,
68  * and '+' points to next line.
69  * Otherwise: 'dot' points to next item, '..' points to last.
70  */
71 boolean_t	db_ed_style = TRUE;
72 
73 db_addr_t	db_dot;		/* current location */
74 db_addr_t	db_last_addr;	/* last explicit address typed */
75 db_addr_t	db_prev;	/* last address examined
76 				   or written */
77 db_addr_t	db_next;	/* next address to be examined
78 				   or written */
79 
80 int	db_cmd_search(char *, struct db_command *, struct db_command **);
81 void	db_cmd_list(struct db_command *);
82 void	db_map_print_cmd(db_expr_t, int, db_expr_t, char *);
83 void	db_buf_print_cmd(db_expr_t, int, db_expr_t, char *);
84 void	db_malloc_print_cmd(db_expr_t, int, db_expr_t, char *);
85 void	db_mbuf_print_cmd(db_expr_t, int, db_expr_t, char *);
86 void	db_mount_print_cmd(db_expr_t, int, db_expr_t, char *);
87 void	db_show_all_mounts(db_expr_t, int, db_expr_t, char *);
88 void	db_show_all_vnodes(db_expr_t, int, db_expr_t, char *);
89 void	db_show_all_bufs(db_expr_t, int, db_expr_t, char *);
90 void	db_object_print_cmd(db_expr_t, int, db_expr_t, char *);
91 void	db_page_print_cmd(db_expr_t, int, db_expr_t, char *);
92 void	db_extent_print_cmd(db_expr_t, int, db_expr_t, char *);
93 void	db_pool_print_cmd(db_expr_t, int, db_expr_t, char *);
94 void	db_proc_print_cmd(db_expr_t, int, db_expr_t, char *);
95 void	db_uvmexp_print_cmd(db_expr_t, int, db_expr_t, char *);
96 void	db_vnode_print_cmd(db_expr_t, int, db_expr_t, char *);
97 void	db_nfsreq_print_cmd(db_expr_t, int, db_expr_t, char *);
98 void	db_nfsnode_print_cmd(db_expr_t, int, db_expr_t, char *);
99 void	db_help_cmd(db_expr_t, int, db_expr_t, char *);
100 void	db_fncall(db_expr_t, int, db_expr_t, char *);
101 void	db_boot_sync_cmd(db_expr_t, int, db_expr_t, char *);
102 void	db_boot_crash_cmd(db_expr_t, int, db_expr_t, char *);
103 void	db_boot_dump_cmd(db_expr_t, int, db_expr_t, char *);
104 void	db_boot_halt_cmd(db_expr_t, int, db_expr_t, char *);
105 void	db_boot_reboot_cmd(db_expr_t, int, db_expr_t, char *);
106 void	db_boot_poweroff_cmd(db_expr_t, int, db_expr_t, char *);
107 void	db_stack_trace_cmd(db_expr_t, int, db_expr_t, char *);
108 void	db_dmesg_cmd(db_expr_t, int, db_expr_t, char *);
109 void	db_show_panic_cmd(db_expr_t, int, db_expr_t, char *);
110 void	db_bcstats_print_cmd(db_expr_t, int, db_expr_t, char *);
111 void	db_struct_offset_cmd(db_expr_t, int, db_expr_t, char *);
112 void	db_struct_layout_cmd(db_expr_t, int, db_expr_t, char *);
113 void	db_show_regs(db_expr_t, boolean_t, db_expr_t, char *);
114 void	db_write_cmd(db_expr_t, boolean_t, db_expr_t, char *);
115 
116 
117 /*
118  * Utility routine - discard tokens through end-of-line.
119  */
120 void
121 db_skip_to_eol(void)
122 {
123 	int	t;
124 	do {
125 	    t = db_read_token();
126 	} while (t != tEOL);
127 }
128 
129 /*
130  * Results of command search.
131  */
132 #define	CMD_UNIQUE	0
133 #define	CMD_FOUND	1
134 #define	CMD_NONE	2
135 #define	CMD_AMBIGUOUS	3
136 
137 /*
138  * Search for command prefix.
139  */
140 int
141 db_cmd_search(char *name, struct db_command *table, struct db_command **cmdp)
142 {
143 	struct db_command	*cmd;
144 	int			result = CMD_NONE;
145 
146 	for (cmd = table; cmd->name != 0; cmd++) {
147 	    char *lp;
148 	    char *rp;
149 	    int  c;
150 
151 	    lp = name;
152 	    rp = cmd->name;
153 	    while ((c = *lp) == *rp) {
154 		if (c == 0) {
155 		    /* complete match */
156 		    *cmdp = cmd;
157 		    return (CMD_UNIQUE);
158 		}
159 		lp++;
160 		rp++;
161 	    }
162 	    if (c == 0) {
163 		/* end of name, not end of command -
164 		   partial match */
165 		if (result == CMD_FOUND) {
166 		    result = CMD_AMBIGUOUS;
167 		    /* but keep looking for a full match -
168 		       this lets us match single letters */
169 		}
170 		else {
171 		    *cmdp = cmd;
172 		    result = CMD_FOUND;
173 		}
174 	    }
175 	}
176 	return (result);
177 }
178 
179 void
180 db_cmd_list(struct db_command *table)
181 {
182 	struct db_command *cmd;
183 
184 	for (cmd = table; cmd->name != 0; cmd++) {
185 	    db_printf("%-12s", cmd->name);
186 	    db_end_line(12);
187 	}
188 }
189 
190 void
191 db_command(struct db_command **last_cmdp, struct db_command *cmd_table)
192 {
193 	struct db_command	*cmd;
194 	int		t;
195 	char		modif[TOK_STRING_SIZE];
196 	db_expr_t	addr, count;
197 	boolean_t	have_addr = FALSE;
198 	int		result;
199 
200 	t = db_read_token();
201 	if (t == tEOL) {
202 	    /* empty line repeats last command, at 'next' */
203 	    cmd = *last_cmdp;
204 	    addr = (db_expr_t)db_next;
205 	    have_addr = FALSE;
206 	    count = 1;
207 	    modif[0] = '\0';
208 	}
209 	else if (t == tEXCL) {
210 	    db_fncall(0, 0, 0, NULL);
211 	    return;
212 	}
213 	else if (t != tIDENT) {
214 	    db_printf("?\n");
215 	    db_flush_lex();
216 	    return;
217 	}
218 	else {
219 	    /*
220 	     * Search for command
221 	     */
222 	    while (cmd_table) {
223 		result = db_cmd_search(db_tok_string,
224 				       cmd_table,
225 				       &cmd);
226 		switch (result) {
227 		    case CMD_NONE:
228 			db_printf("No such command\n");
229 			db_flush_lex();
230 			return;
231 		    case CMD_AMBIGUOUS:
232 			db_printf("Ambiguous\n");
233 			db_flush_lex();
234 			return;
235 		    default:
236 			break;
237 		}
238 		if ((cmd_table = cmd->more) != 0) {
239 		    t = db_read_token();
240 		    if (t != tIDENT) {
241 			db_cmd_list(cmd_table);
242 			db_flush_lex();
243 			return;
244 		    }
245 		}
246 	    }
247 
248 	    if ((cmd->flag & CS_OWN) == 0) {
249 		/*
250 		 * Standard syntax:
251 		 * command [/modifier] [addr] [,count]
252 		 */
253 		t = db_read_token();
254 		if (t == tSLASH) {
255 		    t = db_read_token();
256 		    if (t != tIDENT) {
257 			db_printf("Bad modifier\n");
258 			db_flush_lex();
259 			return;
260 		    }
261 		    db_strlcpy(modif, db_tok_string, sizeof(modif));
262 		}
263 		else {
264 		    db_unread_token(t);
265 		    modif[0] = '\0';
266 		}
267 
268 		if (db_expression(&addr)) {
269 		    db_dot = (db_addr_t) addr;
270 		    db_last_addr = db_dot;
271 		    have_addr = TRUE;
272 		}
273 		else {
274 		    addr = (db_expr_t) db_dot;
275 		    have_addr = FALSE;
276 		}
277 		t = db_read_token();
278 		if (t == tCOMMA) {
279 		    if (!db_expression(&count)) {
280 			db_printf("Count missing\n");
281 			db_flush_lex();
282 			return;
283 		    }
284 		}
285 		else {
286 		    db_unread_token(t);
287 		    count = -1;
288 		}
289 		if ((cmd->flag & CS_MORE) == 0) {
290 		    db_skip_to_eol();
291 		}
292 	    }
293 	}
294 	*last_cmdp = cmd;
295 	if (cmd != 0) {
296 	    /*
297 	     * Execute the command.
298 	     */
299 	    (*cmd->fcn)(addr, have_addr, count, modif);
300 
301 	    if (cmd->flag & CS_SET_DOT) {
302 		/*
303 		 * If command changes dot, set dot to
304 		 * previous address displayed (if 'ed' style).
305 		 */
306 		if (db_ed_style) {
307 		    db_dot = db_prev;
308 		}
309 		else {
310 		    db_dot = db_next;
311 		}
312 	    }
313 	    else {
314 		/*
315 		 * If command does not change dot,
316 		 * set 'next' location to be the same.
317 		 */
318 		db_next = db_dot;
319 	    }
320 	}
321 }
322 
323 /*ARGSUSED*/
324 void
325 db_buf_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
326 {
327 	boolean_t full = FALSE;
328 
329 	if (modif[0] == 'f')
330 		full = TRUE;
331 
332 	vfs_buf_print((void *) addr, full, db_printf);
333 }
334 
335 /*ARGSUSED*/
336 void
337 db_map_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
338 {
339         boolean_t full = FALSE;
340 
341         if (modif[0] == 'f')
342                 full = TRUE;
343 
344         uvm_map_printit((struct vm_map *) addr, full, db_printf);
345 }
346 
347 /*ARGSUSED*/
348 void
349 db_malloc_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
350 {
351 #if defined(MALLOC_DEBUG)
352 	extern void debug_malloc_printit(int (*)(const char *, ...), vaddr_t);
353 
354 	if (!have_addr)
355 		addr = 0;
356 
357 	debug_malloc_printit(db_printf, (vaddr_t)addr);
358 #else
359 	malloc_printit(db_printf);
360 #endif
361 }
362 
363 /*ARGSUSED*/
364 void
365 db_mbuf_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
366 {
367 	m_print((void *)addr, db_printf);
368 }
369 
370 /*ARGSUSED*/
371 void
372 db_socket_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
373 {
374 	so_print((void *)addr, db_printf);
375 }
376 
377 /*ARGSUSED*/
378 void
379 db_mount_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
380 {
381 	boolean_t full = FALSE;
382 
383 	if (modif[0] == 'f')
384 		full = TRUE;
385 
386 	vfs_mount_print((struct mount *) addr, full, db_printf);
387 }
388 
389 void
390 db_show_all_mounts(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
391 {
392 	boolean_t full = FALSE;
393 	struct mount *mp;
394 
395 	if (modif[0] == 'f')
396 		full = TRUE;
397 
398 	TAILQ_FOREACH(mp, &mountlist, mnt_list)
399 		vfs_mount_print(mp, full, db_printf);
400 }
401 
402 extern struct pool vnode_pool;
403 void
404 db_show_all_vnodes(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
405 {
406 	boolean_t full = FALSE;
407 
408 	if (modif[0] == 'f')
409 		full = TRUE;
410 
411 	pool_walk(&vnode_pool, full, db_printf, vfs_vnode_print);
412 }
413 
414 extern struct pool bufpool;
415 void
416 db_show_all_bufs(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
417 {
418 	boolean_t full = FALSE;
419 
420 	if (modif[0] == 'f')
421 		full = TRUE;
422 
423 	pool_walk(&bufpool, full, db_printf, vfs_buf_print);
424 }
425 
426 /*ARGSUSED*/
427 void
428 db_object_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
429 {
430         boolean_t full = FALSE;
431 
432         if (modif[0] == 'f')
433                 full = TRUE;
434 
435 	uvm_object_printit((struct uvm_object *) addr, full, db_printf);
436 }
437 
438 /*ARGSUSED*/
439 void
440 db_page_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
441 {
442         boolean_t full = FALSE;
443 
444         if (modif[0] == 'f')
445                 full = TRUE;
446 
447 	uvm_page_printit((struct vm_page *) addr, full, db_printf);
448 }
449 
450 /*ARGSUSED*/
451 void
452 db_vnode_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
453 {
454 	boolean_t full = FALSE;
455 
456 	if (modif[0] == 'f')
457 		full = TRUE;
458 
459 	vfs_vnode_print((void *)addr, full, db_printf);
460 }
461 
462 #ifdef NFSCLIENT
463 /*ARGSUSED*/
464 void
465 db_nfsreq_print_cmd(db_expr_t addr, int have_addr, db_expr_t count,
466     char *modif)
467 {
468 	boolean_t full = FALSE;
469 
470 	if (modif[0] == 'f')
471 		full = TRUE;
472 
473 	nfs_request_print((void *)addr, full, db_printf);
474 }
475 
476 /*ARGSUSED*/
477 void
478 db_nfsnode_print_cmd(db_expr_t addr, int have_addr, db_expr_t count,
479     char *modif)
480 {
481 	boolean_t full = FALSE;
482 
483 	if (modif[0] == 'f')
484 		full = TRUE;
485 
486 	nfs_node_print((void *)addr, full, db_printf);
487 }
488 #endif
489 
490 
491 /*ARGSUSED*/
492 void
493 db_show_panic_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
494 {
495 	if (panicstr)
496 		db_printf("%s\n", panicstr);
497 	else
498 		db_printf("the kernel did not panic\n");	/* yet */
499 }
500 
501 /*ARGSUSED*/
502 void
503 db_extent_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
504 {
505 	extent_print_all();
506 }
507 
508 /*ARGSUSED*/
509 void
510 db_pool_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
511 {
512 	pool_printit((struct pool *)addr, modif, db_printf);
513 }
514 
515 /*ARGSUSED*/
516 void
517 db_proc_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
518 {
519 	if (!have_addr)
520 		addr = (db_expr_t)curproc;
521 
522 	proc_printit((struct proc *)addr, modif, db_printf);
523 }
524 
525 /*ARGSUSED*/
526 void
527 db_uvmexp_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
528 {
529 	uvmexp_print(db_printf);
530 }
531 
532 void	bcstats_print(int (*)(const char *, ...));
533 
534 /*ARGSUSED*/
535 void
536 db_bcstats_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
537 {
538 	bcstats_print(db_printf);
539 }
540 
541 /*
542  * 'show' commands
543  */
544 
545 struct db_command db_show_all_cmds[] = {
546 	{ "procs",	db_show_all_procs,	0, NULL },
547 	{ "callout",	db_show_callout,	0, NULL },
548 	{ "pools",	db_show_all_pools,	0, NULL },
549 	{ "mounts",	db_show_all_mounts,	0, NULL },
550 	{ "vnodes",	db_show_all_vnodes,	0, NULL },
551 	{ "bufs",	db_show_all_bufs,	0, NULL },
552 #ifdef NFSCLIENT
553 	{ "nfsreqs",	db_show_all_nfsreqs,	0, NULL },
554 	{ "nfsnodes",	db_show_all_nfsnodes,	0, NULL },
555 #endif
556 	{ NULL, 	NULL, 			0, NULL }
557 };
558 
559 struct db_command db_show_cmds[] = {
560 	{ "all",	NULL,			0,	db_show_all_cmds },
561 	{ "bcstats",	db_bcstats_print_cmd,	0,	NULL },
562 	{ "breaks",	db_listbreak_cmd, 	0,	NULL },
563 	{ "buf",	db_buf_print_cmd,	0,	NULL },
564 	{ "extents",	db_extent_print_cmd,	0,	NULL },
565 	{ "malloc",	db_malloc_print_cmd,	0,	NULL },
566 	{ "map",	db_map_print_cmd,	0,	NULL },
567 	{ "mbuf",	db_mbuf_print_cmd,	0,	NULL },
568 	{ "mount",	db_mount_print_cmd,	0,	NULL },
569 #ifdef NFSCLIENT
570 	{ "nfsreq",	db_nfsreq_print_cmd,	0,	NULL },
571 	{ "nfsnode",	db_nfsnode_print_cmd,	0,	NULL },
572 #endif
573 	{ "object",	db_object_print_cmd,	0,	NULL },
574 #ifdef DDB_STRUCT
575 	{ "offset",	db_struct_offset_cmd,	CS_OWN,	NULL },
576 #endif
577 	{ "page",	db_page_print_cmd,	0,	NULL },
578 	{ "panic",	db_show_panic_cmd,	0,	NULL },
579 	{ "pool",	db_pool_print_cmd,	0,	NULL },
580 	{ "proc",	db_proc_print_cmd,	0,	NULL },
581 	{ "registers",	db_show_regs,		0,	NULL },
582 	{ "socket",	db_socket_print_cmd,	0,	NULL },
583 #ifdef DDB_STRUCT
584 	{ "struct",	db_struct_layout_cmd,	CS_OWN,	NULL },
585 #endif
586 	{ "uvmexp",	db_uvmexp_print_cmd,	0,	NULL },
587 	{ "vnode",	db_vnode_print_cmd,	0,	NULL },
588 	{ "watches",	db_listwatch_cmd, 	0,	NULL },
589 	{ NULL,		NULL,			0,	NULL }
590 };
591 
592 struct db_command db_boot_cmds[] = {
593 	{ "sync",	db_boot_sync_cmd,	0,	0 },
594 	{ "crash",	db_boot_crash_cmd,	0,	0 },
595 	{ "dump",	db_boot_dump_cmd,	0,	0 },
596 	{ "halt",	db_boot_halt_cmd,	0,	0 },
597 	{ "reboot",	db_boot_reboot_cmd,	0,	0 },
598 	{ "poweroff",	db_boot_poweroff_cmd,	0,	0 },
599 	{ NULL, }
600 };
601 
602 struct db_command db_command_table[] = {
603 #ifdef DB_MACHINE_COMMANDS
604   /* this must be the first entry, if it exists */
605 	{ "machine",    NULL,                   0,     		NULL},
606 #endif
607 	{ "print",	db_print_cmd,		0,		NULL },
608 	{ "examine",	db_examine_cmd,		CS_SET_DOT, 	NULL },
609 	{ "x",		db_examine_cmd,		CS_SET_DOT, 	NULL },
610 	{ "search",	db_search_cmd,		CS_OWN|CS_SET_DOT, NULL },
611 	{ "set",	db_set_cmd,		CS_OWN,		NULL },
612 	{ "write",	db_write_cmd,		CS_MORE|CS_SET_DOT, NULL },
613 	{ "w",		db_write_cmd,		CS_MORE|CS_SET_DOT, NULL },
614 	{ "delete",	db_delete_cmd,		0,		NULL },
615 	{ "d",		db_delete_cmd,		0,		NULL },
616 	{ "break",	db_breakpoint_cmd,	0,		NULL },
617 	{ "dwatch",	db_deletewatch_cmd,	0,		NULL },
618 	{ "watch",	db_watchpoint_cmd,	CS_MORE,	NULL },
619 	{ "step",	db_single_step_cmd,	0,		NULL },
620 	{ "s",		db_single_step_cmd,	0,		NULL },
621 	{ "continue",	db_continue_cmd,	0,		NULL },
622 	{ "c",		db_continue_cmd,	0,		NULL },
623 	{ "until",	db_trace_until_call_cmd,0,		NULL },
624 	{ "next",	db_trace_until_matching_cmd,0,		NULL },
625 	{ "match",	db_trace_until_matching_cmd,0,		NULL },
626 	{ "trace",	db_stack_trace_cmd,	0,		NULL },
627 	{ "call",	db_fncall,		CS_OWN,		NULL },
628 	{ "ps",		db_show_all_procs,	0,		NULL },
629 	{ "callout",	db_show_callout,	0,		NULL },
630 	{ "show",	NULL,			0,		db_show_cmds },
631 	{ "boot",	NULL,			0,		db_boot_cmds },
632 	{ "help",	db_help_cmd,		0,		NULL },
633 	{ "hangman",	db_hangman,		0,		NULL },
634 	{ "dmesg",	db_dmesg_cmd,		0,		NULL },
635 	{ NULL, 	NULL,			0,		NULL }
636 };
637 
638 #ifdef DB_MACHINE_COMMANDS
639 
640 /* this function should be called to install the machine dependent
641    commands. It should be called before the debugger is enabled  */
642 void db_machine_commands_install(struct db_command *ptr)
643 {
644   db_command_table[0].more = ptr;
645   return;
646 }
647 
648 #endif
649 
650 struct db_command	*db_last_command = NULL;
651 
652 void
653 db_help_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
654 {
655 	db_cmd_list(db_command_table);
656 }
657 
658 void
659 db_command_loop(void)
660 {
661 	label_t		db_jmpbuf;
662 	label_t		*savejmp;
663 	extern int	db_output_line;
664 
665 	/*
666 	 * Initialize 'prev' and 'next' to dot.
667 	 */
668 	db_prev = db_dot;
669 	db_next = db_dot;
670 
671 	db_cmd_loop_done = 0;
672 
673 	savejmp = db_recover;
674 	db_recover = &db_jmpbuf;
675 	(void) setjmp(&db_jmpbuf);
676 
677 	while (!db_cmd_loop_done) {
678 
679 		if (db_print_position() != 0)
680 			db_printf("\n");
681 		db_output_line = 0;
682 
683 #ifdef MULTIPROCESSOR
684 		db_printf("ddb{%d}> ", CPU_INFO_UNIT(curcpu()));
685 #else
686 		db_printf("ddb> ");
687 #endif
688 		(void) db_read_line();
689 
690 		db_command(&db_last_command, db_command_table);
691 	}
692 
693 	db_recover = savejmp;
694 }
695 
696 void
697 db_error(char *s)
698 {
699 	if (s)
700 		db_printf("%s", s);
701 	db_flush_lex();
702 	if (db_recover != NULL)
703 		longjmp(db_recover);
704 }
705 
706 
707 /*
708  * Call random function:
709  * !expr(arg,arg,arg)
710  */
711 /*ARGSUSED*/
712 void
713 db_fncall(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
714 {
715 	db_expr_t	fn_addr;
716 #define	MAXARGS		11
717 	db_expr_t	args[MAXARGS];
718 	int		nargs = 0;
719 	db_expr_t	retval;
720 	db_expr_t	(*func)(db_expr_t, ...);
721 	int		t;
722 	char		tmpfmt[28];
723 
724 	if (!db_expression(&fn_addr)) {
725 	    db_printf("Bad function\n");
726 	    db_flush_lex();
727 	    return;
728 	}
729 	func = (db_expr_t (*)(db_expr_t, ...)) fn_addr;
730 
731 	t = db_read_token();
732 	if (t == tLPAREN) {
733 	    if (db_expression(&args[0])) {
734 		nargs++;
735 		while ((t = db_read_token()) == tCOMMA) {
736 		    if (nargs == MAXARGS) {
737 			db_printf("Too many arguments\n");
738 			db_flush_lex();
739 			return;
740 		    }
741 		    if (!db_expression(&args[nargs])) {
742 			db_printf("Argument missing\n");
743 			db_flush_lex();
744 			return;
745 		    }
746 		    nargs++;
747 		}
748 		db_unread_token(t);
749 	    }
750 	    if (db_read_token() != tRPAREN) {
751 		db_printf("?\n");
752 		db_flush_lex();
753 		return;
754 	    }
755 	}
756 	db_skip_to_eol();
757 
758 	while (nargs < MAXARGS) {
759 	    args[nargs++] = 0;
760 	}
761 
762 	retval = (*func)(args[0], args[1], args[2], args[3], args[4],
763 			 args[5], args[6], args[7], args[8], args[9]);
764 	db_printf("%s\n", db_format(tmpfmt, sizeof tmpfmt, retval,
765 	    DB_FORMAT_N, 1, 0));
766 }
767 
768 void
769 db_boot_sync_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
770 {
771 	reboot(RB_AUTOBOOT | RB_TIMEBAD | RB_USERREQ);
772 }
773 
774 void
775 db_boot_crash_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
776 {
777 	reboot(RB_NOSYNC | RB_DUMP | RB_TIMEBAD | RB_USERREQ);
778 }
779 
780 void
781 db_boot_dump_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
782 {
783 	reboot(RB_DUMP | RB_TIMEBAD | RB_USERREQ);
784 }
785 
786 void
787 db_boot_halt_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
788 {
789 	reboot(RB_NOSYNC | RB_HALT | RB_TIMEBAD | RB_USERREQ);
790 }
791 
792 void
793 db_boot_reboot_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
794 {
795 	reboot(RB_AUTOBOOT | RB_NOSYNC | RB_TIMEBAD | RB_USERREQ);
796 }
797 
798 void
799 db_boot_poweroff_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
800 {
801 	reboot(RB_NOSYNC | RB_HALT | RB_POWERDOWN | RB_TIMEBAD | RB_USERREQ);
802 }
803 
804 void
805 db_dmesg_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
806 {
807 	int i, off;
808 	char *p;
809 
810 	if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC)
811 		return;
812 	off = msgbufp->msg_bufx;
813 	if (off > msgbufp->msg_bufs)
814 		off = 0;
815 	for (i = 0, p = msgbufp->msg_bufc + off;
816 	    i < msgbufp->msg_bufs; i++, p++) {
817 		if (p >= msgbufp->msg_bufc + msgbufp->msg_bufs)
818 			p = msgbufp->msg_bufc;
819 		if (*p != '\0')
820 			db_putchar(*p);
821 	}
822 	db_putchar('\n');
823 }
824 
825 void
826 db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
827     char *modif)
828 {
829 	db_stack_trace_print(addr, have_addr, count, modif, db_printf);
830 }
831 
832 void
833 db_show_regs(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
834 {
835 	struct db_variable *regp;
836 	db_expr_t	value, offset;
837 	char *		name;
838 	char		tmpfmt[28];
839 
840 	for (regp = db_regs; regp < db_eregs; regp++) {
841 	    db_read_variable(regp, &value);
842 	    db_printf("%-12s%s", regp->name, db_format(tmpfmt, sizeof tmpfmt,
843 	      (long)value, DB_FORMAT_N, 1, sizeof(long) * 3));
844 	    db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset);
845 	    if (name != 0 && offset <= db_maxoff && offset != value) {
846 		db_printf("\t%s", name);
847 		if (offset != 0)
848 		    db_printf("+%s", db_format(tmpfmt, sizeof tmpfmt,
849 		      (long)offset, DB_FORMAT_R, 1, 0));
850 	    }
851 	    db_printf("\n");
852 	}
853 	db_print_loc_and_inst(PC_REGS(&ddb_regs));
854 }
855 
856 /*
857  * Write to file.
858  */
859 /*ARGSUSED*/
860 void
861 db_write_cmd(db_expr_t	address, boolean_t have_addr, db_expr_t count,
862     char *modif)
863 {
864 	db_addr_t	addr;
865 	db_expr_t	old_value;
866 	db_expr_t	new_value;
867 	int		size;
868 	boolean_t	wrote_one = FALSE;
869 	char		tmpfmt[28];
870 
871 	addr = (db_addr_t) address;
872 
873 	switch (modif[0]) {
874 	case 'b':
875 		size = 1;
876 		break;
877 	case 'h':
878 		size = 2;
879 		break;
880 	case 'l':
881 	case '\0':
882 		size = 4;
883 		break;
884 #ifdef __LP64__
885 	case 'q':
886 		size = 8;
887 		break;
888 #endif
889 	default:
890 		size = -1;
891 		db_error("Unknown size\n");
892 		/*NOTREACHED*/
893 	}
894 
895 	while (db_expression(&new_value)) {
896 		old_value = db_get_value(addr, size, FALSE);
897 		db_printsym(addr, DB_STGY_ANY, db_printf);
898 		db_printf("\t\t%s\t", db_format(tmpfmt, sizeof tmpfmt,
899 		    old_value, DB_FORMAT_N, 0, 8));
900 		db_printf("=\t%s\n",  db_format(tmpfmt, sizeof tmpfmt,
901 		    new_value, DB_FORMAT_N, 0, 8));
902 		db_put_value(addr, size, new_value);
903 		addr += size;
904 
905 		wrote_one = TRUE;
906 	}
907 
908 	if (!wrote_one) {
909 		db_error("Nothing written.\n");
910 		/*NOTREACHED*/
911 	}
912 
913 	db_next = addr;
914 	db_prev = addr - size;
915 
916 	db_skip_to_eol();
917 }
918