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