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