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