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