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