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