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