xref: /openbsd-src/sys/ddb/db_command.c (revision 3a3fbb3f2e2521ab7c4a56b7ff7462ebd9095ec5)
1 /*	$OpenBSD: db_command.c,v 1.25 2002/01/02 22:22:00 miod 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 
40 #include <uvm/uvm_extern.h>
41 #include <machine/db_machdep.h>		/* type definitions */
42 
43 #include <ddb/db_lex.h>
44 #include <ddb/db_output.h>
45 #include <ddb/db_command.h>
46 #include <ddb/db_break.h>
47 #include <ddb/db_watch.h>
48 #include <ddb/db_run.h>
49 #include <ddb/db_variables.h>
50 #include <ddb/db_interface.h>
51 #include <ddb/db_sym.h>
52 #include <ddb/db_extern.h>
53 
54 #include <uvm/uvm_ddb.h>
55 
56 /*
57  * Exported global variables
58  */
59 boolean_t	db_cmd_loop_done;
60 label_t		*db_recover;
61 
62 /*
63  * if 'ed' style: 'dot' is set at start of last item printed,
64  * and '+' points to next line.
65  * Otherwise: 'dot' points to next item, '..' points to last.
66  */
67 boolean_t	db_ed_style = TRUE;
68 
69 /*
70  * Utility routine - discard tokens through end-of-line.
71  */
72 void
73 db_skip_to_eol()
74 {
75 	int	t;
76 	do {
77 	    t = db_read_token();
78 	} while (t != tEOL);
79 }
80 
81 /*
82  * Results of command search.
83  */
84 #define	CMD_UNIQUE	0
85 #define	CMD_FOUND	1
86 #define	CMD_NONE	2
87 #define	CMD_AMBIGUOUS	3
88 
89 /*
90  * Search for command prefix.
91  */
92 int
93 db_cmd_search(name, table, cmdp)
94 	char			*name;
95 	struct db_command	*table;
96 	struct db_command	**cmdp;	/* out */
97 {
98 	struct db_command	*cmd;
99 	int			result = CMD_NONE;
100 
101 	for (cmd = table; cmd->name != 0; cmd++) {
102 	    register char *lp;
103 	    register char *rp;
104 	    register int  c;
105 
106 	    lp = name;
107 	    rp = cmd->name;
108 	    while ((c = *lp) == *rp) {
109 		if (c == 0) {
110 		    /* complete match */
111 		    *cmdp = cmd;
112 		    return (CMD_UNIQUE);
113 		}
114 		lp++;
115 		rp++;
116 	    }
117 	    if (c == 0) {
118 		/* end of name, not end of command -
119 		   partial match */
120 		if (result == CMD_FOUND) {
121 		    result = CMD_AMBIGUOUS;
122 		    /* but keep looking for a full match -
123 		       this lets us match single letters */
124 		}
125 		else {
126 		    *cmdp = cmd;
127 		    result = CMD_FOUND;
128 		}
129 	    }
130 	}
131 	return (result);
132 }
133 
134 void
135 db_cmd_list(table)
136 	struct db_command *table;
137 {
138 	register struct db_command *cmd;
139 
140 	for (cmd = table; cmd->name != 0; cmd++) {
141 	    db_printf("%-12s", cmd->name);
142 	    db_end_line(12);
143 	}
144 }
145 
146 void
147 db_command(last_cmdp, cmd_table)
148 	struct db_command	**last_cmdp;	/* IN_OUT */
149 	struct db_command	*cmd_table;
150 {
151 	struct db_command	*cmd;
152 	int		t;
153 	char		modif[TOK_STRING_SIZE];
154 	db_expr_t	addr, count;
155 	boolean_t	have_addr = FALSE;
156 	int		result;
157 
158 	t = db_read_token();
159 	if (t == tEOL) {
160 	    /* empty line repeats last command, at 'next' */
161 	    cmd = *last_cmdp;
162 	    addr = (db_expr_t)db_next;
163 	    have_addr = FALSE;
164 	    count = 1;
165 	    modif[0] = '\0';
166 	}
167 	else if (t == tEXCL) {
168 	    db_fncall(0, 0, 0, NULL);
169 	    return;
170 	}
171 	else if (t != tIDENT) {
172 	    db_printf("?\n");
173 	    db_flush_lex();
174 	    return;
175 	}
176 	else {
177 	    /*
178 	     * Search for command
179 	     */
180 	    while (cmd_table) {
181 		result = db_cmd_search(db_tok_string,
182 				       cmd_table,
183 				       &cmd);
184 		switch (result) {
185 		    case CMD_NONE:
186 			db_printf("No such command\n");
187 			db_flush_lex();
188 			return;
189 		    case CMD_AMBIGUOUS:
190 			db_printf("Ambiguous\n");
191 			db_flush_lex();
192 			return;
193 		    default:
194 			break;
195 		}
196 		if ((cmd_table = cmd->more) != 0) {
197 		    t = db_read_token();
198 		    if (t != tIDENT) {
199 			db_cmd_list(cmd_table);
200 			db_flush_lex();
201 			return;
202 		    }
203 		}
204 	    }
205 
206 	    if ((cmd->flag & CS_OWN) == 0) {
207 		/*
208 		 * Standard syntax:
209 		 * command [/modifier] [addr] [,count]
210 		 */
211 		t = db_read_token();
212 		if (t == tSLASH) {
213 		    t = db_read_token();
214 		    if (t != tIDENT) {
215 			db_printf("Bad modifier\n");
216 			db_flush_lex();
217 			return;
218 		    }
219 		    db_strcpy(modif, db_tok_string);
220 		}
221 		else {
222 		    db_unread_token(t);
223 		    modif[0] = '\0';
224 		}
225 
226 		if (db_expression(&addr)) {
227 		    db_dot = (db_addr_t) addr;
228 		    db_last_addr = db_dot;
229 		    have_addr = TRUE;
230 		}
231 		else {
232 		    addr = (db_expr_t) db_dot;
233 		    have_addr = FALSE;
234 		}
235 		t = db_read_token();
236 		if (t == tCOMMA) {
237 		    if (!db_expression(&count)) {
238 			db_printf("Count missing\n");
239 			db_flush_lex();
240 			return;
241 		    }
242 		}
243 		else {
244 		    db_unread_token(t);
245 		    count = -1;
246 		}
247 		if ((cmd->flag & CS_MORE) == 0) {
248 		    db_skip_to_eol();
249 		}
250 	    }
251 	}
252 	*last_cmdp = cmd;
253 	if (cmd != 0) {
254 	    /*
255 	     * Execute the command.
256 	     */
257 	    (*cmd->fcn)(addr, have_addr, count, modif);
258 
259 	    if (cmd->flag & CS_SET_DOT) {
260 		/*
261 		 * If command changes dot, set dot to
262 		 * previous address displayed (if 'ed' style).
263 		 */
264 		if (db_ed_style) {
265 		    db_dot = db_prev;
266 		}
267 		else {
268 		    db_dot = db_next;
269 		}
270 	    }
271 	    else {
272 		/*
273 		 * If command does not change dot,
274 		 * set 'next' location to be the same.
275 		 */
276 		db_next = db_dot;
277 	    }
278 	}
279 }
280 
281 /*ARGSUSED*/
282 void
283 db_map_print_cmd(addr, have_addr, count, modif)
284 	db_expr_t	addr;
285 	int		have_addr;
286 	db_expr_t	count;
287 	char *		modif;
288 {
289         boolean_t full = FALSE;
290 
291         if (modif[0] == 'f')
292                 full = TRUE;
293 
294         uvm_map_printit((struct vm_map *) addr, full, db_printf);
295 }
296 /*ARGSUSED*/
297 void
298 db_malloc_print_cmd(addr, have_addr, count, modif)
299 	db_expr_t	addr;
300 	int		have_addr;
301 	db_expr_t	count;
302 	char *		modif;
303 {
304 #if defined(MALLOC_DEBUG)
305 	extern void debug_malloc_printit __P((int (*) __P((const char *, ...)), vaddr_t));
306 
307 	if (!have_addr)
308 		addr = 0;
309 
310 	debug_malloc_printit(db_printf, (vaddr_t)addr);
311 #else
312 	db_printf("Malloc debugging not enabled.\n");
313 #endif
314 }
315 
316 /*ARGSUSED*/
317 void
318 db_object_print_cmd(addr, have_addr, count, modif)
319 	db_expr_t	addr;
320 	int		have_addr;
321 	db_expr_t	count;
322 	char *		modif;
323 {
324         boolean_t full = FALSE;
325 
326         if (modif[0] == 'f')
327                 full = TRUE;
328 
329 	uvm_object_printit((struct uvm_object *) addr, full, db_printf);
330 }
331 
332 /*ARGSUSED*/
333 void
334 db_page_print_cmd(addr, have_addr, count, modif)
335 	db_expr_t	addr;
336 	int		have_addr;
337 	db_expr_t	count;
338 	char *		modif;
339 {
340         boolean_t full = FALSE;
341 
342         if (modif[0] == 'f')
343                 full = TRUE;
344 
345 	uvm_page_printit((struct vm_page *) addr, full, db_printf);
346 }
347 
348 /*ARGSUSED*/
349 void
350 db_extent_print_cmd(addr, have_addr, count, modif)
351 	db_expr_t	addr;
352 	int		have_addr;
353 	db_expr_t	count;
354 	char *		modif;
355 {
356 	extent_print_all();
357 }
358 
359 /*ARGSUSED*/
360 void
361 db_pool_print_cmd(addr, have_addr, count, modif)
362 	db_expr_t	addr;
363 	int		have_addr;
364 	db_expr_t	count;
365 	char *		modif;
366 {
367 	pool_printit((struct pool *)addr, modif, db_printf);
368 }
369 
370 /*ARGSUSED*/
371 void
372 db_uvmexp_print_cmd(addr, have_addr, count, modif)
373 	db_expr_t	addr;
374 	int		have_addr;
375 	db_expr_t	count;
376 	char *		modif;
377 {
378 	uvmexp_print(db_printf);
379 }
380 
381 /*
382  * 'show' commands
383  */
384 
385 struct db_command db_show_all_cmds[] = {
386 	{ "procs",	db_show_all_procs,	0, NULL },
387 	{ "callout",	db_show_callout,	0, NULL },
388 	{ NULL, 	NULL, 			0, NULL }
389 };
390 
391 struct db_command db_show_cmds[] = {
392 	{ "all",	NULL,			0,	db_show_all_cmds },
393 	{ "breaks",	db_listbreak_cmd, 	0,	NULL },
394 	{ "extents",	db_extent_print_cmd,	0,	NULL },
395 	{ "malloc",	db_malloc_print_cmd,	0,	NULL },
396 	{ "map",	db_map_print_cmd,	0,	NULL },
397 	{ "object",	db_object_print_cmd,	0,	NULL },
398 	{ "page",	db_page_print_cmd,	0,	NULL },
399 	{ "pool",	db_pool_print_cmd,	0,	NULL },
400 	{ "registers",	db_show_regs,		0,	NULL },
401 	{ "uvmexp",	db_uvmexp_print_cmd,	0,	NULL },
402 	{ "watches",	db_listwatch_cmd, 	0,	NULL },
403 	{ NULL,		NULL,			0,	NULL }
404 };
405 
406 struct db_command db_boot_cmds[] = {
407 	{ "sync",	db_boot_sync_cmd,	0,	0 },
408 	{ "crash",	db_boot_crash_cmd,	0,	0 },
409 	{ "dump",	db_boot_dump_cmd,	0,	0 },
410 	{ "halt",	db_boot_halt_cmd,	0,	0 },
411 	{ NULL, }
412 };
413 
414 struct db_command db_command_table[] = {
415 #ifdef DB_MACHINE_COMMANDS
416   /* this must be the first entry, if it exists */
417 	{ "machine",    NULL,                   0,     		NULL},
418 #endif
419 	{ "print",	db_print_cmd,		0,		NULL },
420 	{ "examine",	db_examine_cmd,		CS_SET_DOT, 	NULL },
421 	{ "x",		db_examine_cmd,		CS_SET_DOT, 	NULL },
422 	{ "search",	db_search_cmd,		CS_OWN|CS_SET_DOT, NULL },
423 	{ "set",	db_set_cmd,		CS_OWN,		NULL },
424 	{ "write",	db_write_cmd,		CS_MORE|CS_SET_DOT, NULL },
425 	{ "w",		db_write_cmd,		CS_MORE|CS_SET_DOT, NULL },
426 	{ "delete",	db_delete_cmd,		0,		NULL },
427 	{ "d",		db_delete_cmd,		0,		NULL },
428 	{ "break",	db_breakpoint_cmd,	0,		NULL },
429 	{ "dwatch",	db_deletewatch_cmd,	0,		NULL },
430 	{ "watch",	db_watchpoint_cmd,	CS_MORE,	NULL },
431 	{ "step",	db_single_step_cmd,	0,		NULL },
432 	{ "s",		db_single_step_cmd,	0,		NULL },
433 	{ "continue",	db_continue_cmd,	0,		NULL },
434 	{ "c",		db_continue_cmd,	0,		NULL },
435 	{ "until",	db_trace_until_call_cmd,0,		NULL },
436 	{ "next",	db_trace_until_matching_cmd,0,		NULL },
437 	{ "match",	db_trace_until_matching_cmd,0,		NULL },
438 	{ "trace",	db_stack_trace_cmd,	0,		NULL },
439 	{ "call",	db_fncall,		CS_OWN,		NULL },
440 	{ "ps",		db_show_all_procs,	0,		NULL },
441 	{ "callout",	db_show_callout,	0,		NULL },
442 	{ "show",	NULL,			0,		db_show_cmds },
443 	{ "boot",	NULL,			0,		db_boot_cmds },
444 	{ "help",	db_help_cmd,		0,		NULL },
445 	{ "hangman",	db_hangman,		0,		NULL },
446 	{ NULL, 	NULL,			0,		NULL }
447 };
448 
449 #ifdef DB_MACHINE_COMMANDS
450 
451 /* this function should be called to install the machine dependent
452    commands. It should be called before the debugger is enabled  */
453 void db_machine_commands_install(ptr)
454 struct db_command *ptr;
455 {
456   db_command_table[0].more = ptr;
457   return;
458 }
459 
460 #endif
461 
462 struct db_command	*db_last_command = 0;
463 
464 void
465 db_help_cmd(addr, haddr, count, modif)
466 	db_expr_t addr;
467 	int	haddr;
468 	db_expr_t count;
469 	char	*modif;
470 {
471 	db_cmd_list(db_command_table);
472 }
473 
474 void
475 db_command_loop()
476 {
477 	label_t		db_jmpbuf;
478 	label_t		*savejmp;
479 	extern int	db_output_line;
480 
481 	/*
482 	 * Initialize 'prev' and 'next' to dot.
483 	 */
484 	db_prev = db_dot;
485 	db_next = db_dot;
486 
487 	db_cmd_loop_done = 0;
488 
489 	savejmp = db_recover;
490 	db_recover = &db_jmpbuf;
491 	(void) setjmp(&db_jmpbuf);
492 
493 	while (!db_cmd_loop_done) {
494 		if (db_print_position() != 0)
495 			db_printf("\n");
496 		db_output_line = 0;
497 
498 		db_printf("ddb> ");
499 		(void) db_read_line();
500 
501 		db_command(&db_last_command, db_command_table);
502 	}
503 
504 	db_recover = savejmp;
505 }
506 
507 void
508 db_error(s)
509 	char *s;
510 {
511 	if (s)
512 	    db_printf(s);
513 	db_flush_lex();
514 	longjmp(db_recover);
515 }
516 
517 
518 /*
519  * Call random function:
520  * !expr(arg,arg,arg)
521  */
522 /*ARGSUSED*/
523 void
524 db_fncall(addr, have_addr, count, modif)
525 	db_expr_t	addr;
526 	int		have_addr;
527 	db_expr_t	count;
528 	char *		modif;
529 {
530 	db_expr_t	fn_addr;
531 #define	MAXARGS		11
532 	db_expr_t	args[MAXARGS];
533 	int		nargs = 0;
534 	db_expr_t	retval;
535 	db_expr_t	(*func) __P((db_expr_t, ...));
536 	int		t;
537 
538 	if (!db_expression(&fn_addr)) {
539 	    db_printf("Bad function\n");
540 	    db_flush_lex();
541 	    return;
542 	}
543 	func = (db_expr_t (*) __P((db_expr_t, ...))) fn_addr;
544 
545 	t = db_read_token();
546 	if (t == tLPAREN) {
547 	    if (db_expression(&args[0])) {
548 		nargs++;
549 		while ((t = db_read_token()) == tCOMMA) {
550 		    if (nargs == MAXARGS) {
551 			db_printf("Too many arguments\n");
552 			db_flush_lex();
553 			return;
554 		    }
555 		    if (!db_expression(&args[nargs])) {
556 			db_printf("Argument missing\n");
557 			db_flush_lex();
558 			return;
559 		    }
560 		    nargs++;
561 		}
562 		db_unread_token(t);
563 	    }
564 	    if (db_read_token() != tRPAREN) {
565 		db_printf("?\n");
566 		db_flush_lex();
567 		return;
568 	    }
569 	}
570 	db_skip_to_eol();
571 
572 	while (nargs < MAXARGS) {
573 	    args[nargs++] = 0;
574 	}
575 
576 	retval = (*func)(args[0], args[1], args[2], args[3], args[4],
577 			 args[5], args[6], args[7], args[8], args[9]);
578 	db_printf("%#n\n", retval);
579 }
580 
581 void
582 db_boot_sync_cmd(addr, haddr, count, modif)
583 	db_expr_t addr;
584 	int haddr;
585 	db_expr_t count;
586 	char *modif;
587 {
588 	boot(RB_AUTOBOOT | RB_TIMEBAD);
589 }
590 
591 void
592 db_boot_crash_cmd(addr, haddr, count, modif)
593 	db_expr_t addr;
594 	int haddr;
595 	db_expr_t count;
596 	char *modif;
597 {
598 	boot(RB_NOSYNC | RB_DUMP | RB_TIMEBAD);
599 }
600 
601 void
602 db_boot_dump_cmd(addr, haddr, count, modif)
603 	db_expr_t addr;
604 	int haddr;
605 	db_expr_t count;
606 	char *modif;
607 {
608 	boot(RB_DUMP | RB_TIMEBAD);
609 }
610 
611 void
612 db_boot_halt_cmd(addr, haddr, count, modif)
613 	db_expr_t addr;
614 	int haddr;
615 	db_expr_t count;
616 	char *modif;
617 {
618 	boot(RB_NOSYNC | RB_HALT | RB_TIMEBAD);
619 }
620