1 /* $NetBSD: db_command.c,v 1.112 2007/12/13 02:45:11 yamt Exp $ */ 2 /* 3 * Mach Operating System 4 * Copyright (c) 1991,1990 Carnegie Mellon University 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify and distribute this software and its 8 * documentation is hereby granted, provided that both the copyright 9 * notice and this permission notice appear in all copies of the 10 * software, derivative works or modified versions, and any portions 11 * thereof, and that both notices appear in supporting documentation. 12 * 13 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 14 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 15 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 16 * 17 * Carnegie Mellon requests users of this software to return to 18 * 19 * Software Distribution Coordinator or Software.Distribution@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.112 2007/12/13 02:45:11 yamt 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 "Set a watchpoint for a region. ","address[,size]",NULL) }, 354 { DDB_ADD_CMD("watch", db_watchpoint_cmd, CS_MORE, 355 "Set a watchpoint for a region. ","address[,size]",NULL) }, 356 { DDB_ADD_CMD("whatis", db_whatis_cmd, 0, 357 "Describe what an address is", "address", NULL) }, 358 { DDB_ADD_CMD("write", db_write_cmd, CS_MORE|CS_SET_DOT, 359 "Write the expressions at succeeding locations.", 360 "[/bhl] address expression [expression ...]",NULL) }, 361 { DDB_ADD_CMD("x", db_examine_cmd, CS_SET_DOT, 362 "Display the address locations.", 363 "[/modifier] address[,count]",NULL) }, 364 { DDB_ADD_CMD(NULL, NULL, 0, NULL, NULL, NULL) } 365 }; 366 367 static const struct db_command *db_last_command = NULL; 368 #if defined(DDB_COMMANDONENTER) 369 char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ___STRING(DDB_COMMANDONENTER); 370 #else /* defined(DDB_COMMANDONENTER) */ 371 char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ""; 372 #endif /* defined(DDB_COMMANDONENTER) */ 373 #define DB_LINE_SEP ';' 374 375 /* 376 * Utility routine - discard tokens through end-of-line. 377 */ 378 void 379 db_skip_to_eol(void) 380 { 381 int t; 382 383 do { 384 t = db_read_token(); 385 } while (t != tEOL); 386 } 387 388 void 389 db_error(const char *s) 390 { 391 392 if (s) 393 db_printf("%s", s); 394 db_flush_lex(); 395 longjmp(db_recover); 396 } 397 398 /*Execute commandlist after ddb start 399 *This function goes through the command list created from commands and ';' 400 */ 401 402 static void 403 db_execute_commandlist(const char *cmdlist) 404 { 405 const char *cmd = cmdlist; 406 const struct db_command *dummy = NULL; 407 408 while (*cmd != '\0') { 409 const char *ep = cmd; 410 411 while (*ep != '\0' && *ep != DB_LINE_SEP) { 412 ep++; 413 } 414 db_set_line(cmd, ep); 415 db_command(&dummy); 416 cmd = ep; 417 if (*cmd == DB_LINE_SEP) { 418 cmd++; 419 } 420 } 421 } 422 423 /*Initialize ddb command tables*/ 424 void 425 db_init_commands(void) 426 { 427 static bool done = false; 428 429 if (done) return; 430 done = true; 431 432 /* register command tables */ 433 (void)db_register_tbl_entry(DDB_BASE_CMD, &db_base_cmd_builtins); 434 #ifdef DB_MACHINE_COMMANDS 435 (void)db_register_tbl_entry(DDB_MACH_CMD, &db_mach_cmd_builtins); 436 #endif 437 (void)db_register_tbl_entry(DDB_SHOW_CMD, &db_show_cmd_builtins); 438 } 439 440 441 /* 442 * Add command table to the specified list 443 * Arg: 444 * int type specifies type of command table DDB_SHOW_CMD|DDB_BASE_CMD|DDB_MAC_CMD 445 * *cmd_tbl poiter to static allocated db_command table 446 * 447 *Command table must be NULL terminated array of struct db_command 448 */ 449 int 450 db_register_tbl(uint8_t type, const struct db_command *cmd_tbl) 451 { 452 struct db_cmd_tbl_en *list_ent; 453 454 if (cmd_tbl->name == 0) 455 /* empty list - ignore */ 456 return 0; 457 458 /* force builtin commands to be registered first */ 459 db_init_commands(); 460 461 /* now create a list entry for this table */ 462 list_ent = malloc(sizeof(struct db_cmd_tbl_en), M_TEMP, M_ZERO); 463 if (list_ent == NULL) 464 return ENOMEM; 465 list_ent->db_cmd=cmd_tbl; 466 467 /* and register it */ 468 return db_register_tbl_entry(type, list_ent); 469 } 470 471 static int 472 db_register_tbl_entry(uint8_t type, struct db_cmd_tbl_en *list_ent) 473 { 474 struct db_cmd_tbl_en_head *list; 475 476 switch(type) { 477 case DDB_BASE_CMD: 478 list = &db_base_cmd_list; 479 break; 480 case DDB_SHOW_CMD: 481 list = &db_show_cmd_list; 482 break; 483 case DDB_MACH_CMD: 484 list = &db_mach_cmd_list; 485 break; 486 default: 487 return ENOENT; 488 } 489 490 TAILQ_INSERT_TAIL(list, list_ent, db_cmd_next); 491 492 return 0; 493 } 494 495 /* 496 * Remove command table specified with db_cmd address == cmd_tbl 497 */ 498 int 499 db_unregister_tbl(uint8_t type,const struct db_command *cmd_tbl) 500 { 501 struct db_cmd_tbl_en *list_ent; 502 struct db_cmd_tbl_en_head *list; 503 504 /* find list on which the entry should live */ 505 switch (type) { 506 case DDB_BASE_CMD: 507 list=&db_base_cmd_list; 508 break; 509 case DDB_SHOW_CMD: 510 list=&db_show_cmd_list; 511 break; 512 case DDB_MACH_CMD: 513 list=&db_mach_cmd_list; 514 break; 515 default: 516 return EINVAL; 517 } 518 519 TAILQ_FOREACH (list_ent,list,db_cmd_next) { 520 if (list_ent->db_cmd == cmd_tbl){ 521 TAILQ_REMOVE(list, 522 list_ent,db_cmd_next); 523 free(list_ent,M_TEMP); 524 return 0; 525 } 526 } 527 return ENOENT; 528 } 529 530 /*This function is called from machine trap code.*/ 531 void 532 db_command_loop(void) 533 { 534 535 label_t db_jmpbuf; 536 label_t *savejmp; 537 538 /* 539 * Initialize 'prev' and 'next' to dot. 540 */ 541 db_prev = db_dot; 542 db_next = db_dot; 543 544 db_cmd_loop_done = false; 545 546 /*Init default command tables add machine, base, 547 show command tables to the list*/ 548 db_init_commands(); 549 550 /*save context for return from ddb*/ 551 savejmp = db_recover; 552 db_recover = &db_jmpbuf; 553 (void) setjmp(&db_jmpbuf); 554 555 /*Execute default ddb start commands*/ 556 db_execute_commandlist(db_cmd_on_enter); 557 558 (void) setjmp(&db_jmpbuf); 559 while (!db_cmd_loop_done) { 560 if (db_print_position() != 0) 561 db_printf("\n"); 562 db_output_line = 0; 563 564 565 #ifdef MULTIPROCESSOR 566 db_printf("db{%ld}> ", (long)cpu_number()); 567 #else 568 db_printf("db> "); 569 #endif 570 (void) db_read_line(); 571 572 db_command(&db_last_command); 573 } 574 575 db_recover = savejmp; 576 } 577 578 /* 579 * Search for command table for command prefix 580 * ret: CMD_UNIQUE -> completely matches command 581 * CMD_FOUND -> matches prefix of single command 582 * CMD_AMBIGIOUS -> matches prefix of more than one command 583 * CMD_NONE -> command not found 584 */ 585 static int 586 db_cmd_search(const char *name,const struct db_command *table, 587 const struct db_command **cmdp) 588 { 589 590 const struct db_command *cmd; 591 int result; 592 593 result = CMD_NONE; 594 *cmdp = NULL; 595 for (cmd = table; cmd->name != 0; cmd++) { 596 const char *lp; 597 const char *rp; 598 599 lp = name; 600 rp = cmd->name; 601 while (*lp != '\0' && *lp == *rp) { 602 rp++; 603 lp++; 604 } 605 606 if (*lp != '\0') /* mismatch or extra chars in name */ 607 continue; 608 609 if (*rp == '\0') { /* complete match */ 610 *cmdp = cmd; 611 return (CMD_UNIQUE); 612 } 613 614 /* prefix match: end of name, not end of command */ 615 if (result == CMD_NONE) { 616 result = CMD_FOUND; 617 *cmdp = cmd; 618 } 619 else if (result == CMD_FOUND) { 620 result = CMD_AMBIGUOUS; 621 *cmdp = NULL; 622 } 623 } 624 625 return (result); 626 } 627 628 /* 629 *List commands to the console. 630 */ 631 static void 632 db_cmd_list(const struct db_cmd_tbl_en_head *list) 633 { 634 635 struct db_cmd_tbl_en *list_ent; 636 const struct db_command *table; 637 size_t i, j, w, columns, lines, numcmds, width=0; 638 const char *p; 639 640 TAILQ_FOREACH(list_ent,list,db_cmd_next) { 641 table = list_ent->db_cmd; 642 for (i = 0; table[i].name != NULL; i++) { 643 w = strlen(table[i].name); 644 if (w > width) 645 width = w; 646 } 647 } 648 649 width = DB_NEXT_TAB(width); 650 651 columns = db_max_width / width; 652 if (columns == 0) 653 columns = 1; 654 655 TAILQ_FOREACH(list_ent,list,db_cmd_next) { 656 table = list_ent->db_cmd; 657 658 for (numcmds = 0; table[numcmds].name != NULL; numcmds++) 659 ; 660 lines = (numcmds + columns - 1) / columns; 661 662 for (i = 0; i < lines; i++) { 663 for (j = 0; j < columns; j++) { 664 p = table[j * lines + i].name; 665 if (p) 666 db_printf("%s", p); 667 if (j * lines + i + lines >= numcmds) { 668 db_putchar('\n'); 669 break; 670 } 671 if (p) { 672 w = strlen(p); 673 while (w < width) { 674 w = DB_NEXT_TAB(w); 675 db_putchar('\t'); 676 } 677 } 678 } 679 } 680 } 681 return; 682 } 683 684 /* 685 *Returns type of list for command with name *name. 686 */ 687 static int 688 db_get_list_type(const char *name) 689 { 690 691 const struct db_command *cmd; 692 struct db_cmd_tbl_en *list_ent; 693 int error,ret=-1; 694 695 /* search for the command name */ 696 TAILQ_FOREACH(list_ent,&db_base_cmd_list,db_cmd_next) { 697 /* 698 * cmd_search returns CMD_UNIQUE, CMD_FOUND ... 699 * CMD_UNIQUE when name was completly matched to cmd->name 700 * CMD_FOUND when name was only partially matched to cmd->name 701 * CMD_NONE command not found in a list 702 * CMD_AMBIGIOUS ->more partialy matches 703 */ 704 705 error = db_cmd_search(name, list_ent->db_cmd, &cmd); 706 707 if (error == CMD_UNIQUE) { 708 /* exact match found */ 709 if (cmd->flag == CS_SHOW) { 710 ret = DDB_SHOW_CMD; 711 break; 712 } 713 if (cmd->flag == CS_MACH) { 714 ret = DDB_MACH_CMD; 715 break; 716 } else { 717 ret = DDB_BASE_CMD; 718 break; 719 } 720 721 } else if (error == CMD_FOUND) { 722 /* 723 * partial match, search will continue, but 724 * note current result in case we won't 725 * find anything better. 726 */ 727 if (cmd->flag == CS_SHOW) 728 ret = DDB_SHOW_CMD; 729 else if (cmd->flag == CS_MACH) 730 ret = DDB_MACH_CMD; 731 else 732 ret = DDB_BASE_CMD; 733 } 734 } 735 736 return ret; 737 } 738 739 /* 740 *Parse command line and execute apropriate function. 741 */ 742 static void 743 db_command(const struct db_command **last_cmdp) 744 { 745 const struct db_command *command; 746 struct db_cmd_tbl_en *list_ent; 747 struct db_cmd_tbl_en_head *list; 748 749 int t; 750 int result; 751 752 char modif[TOK_STRING_SIZE]; 753 db_expr_t addr, count; 754 bool have_addr = false; 755 756 static db_expr_t last_count = 0; 757 758 command = NULL; /* XXX gcc */ 759 760 t = db_read_token(); 761 if ((t == tEOL) || (t == tCOMMA)) { 762 /* 763 * An empty line repeats last command, at 'next'. 764 * Only a count repeats the last command with the new count. 765 */ 766 command = *last_cmdp; 767 768 if (!command) 769 return; 770 771 addr = (db_expr_t)db_next; 772 if (t == tCOMMA) { 773 if (!db_expression(&count)) { 774 db_printf("Count missing\n"); 775 db_flush_lex(); 776 return; 777 } 778 } else 779 count = last_count; 780 have_addr = false; 781 modif[0] = '\0'; 782 db_skip_to_eol(); 783 784 } else if (t == tEXCL) { 785 db_fncall(0, 0, 0, NULL); 786 return; 787 788 } else if (t != tIDENT) { 789 db_printf("?\n"); 790 db_flush_lex(); 791 return; 792 793 } else { 794 795 switch(db_get_list_type(db_tok_string)) { 796 797 case DDB_BASE_CMD: 798 list = &db_base_cmd_list; 799 break; 800 801 case DDB_SHOW_CMD: 802 list = &db_show_cmd_list; 803 /* need to read show subcommand if show command list 804 is used. */ 805 t = db_read_token(); 806 807 if (t != tIDENT) { 808 /* if only show command is executed, print 809 all subcommands */ 810 db_cmd_list(list); 811 db_flush_lex(); 812 return; 813 } 814 break; 815 case DDB_MACH_CMD: 816 list = &db_mach_cmd_list; 817 /* need to read machine subcommand if 818 machine level 2 command list is used. */ 819 t = db_read_token(); 820 821 if (t != tIDENT) { 822 /* if only show command is executed, print 823 all subcommands */ 824 db_cmd_list(list); 825 db_flush_lex(); 826 return; 827 } 828 break; 829 default: 830 db_printf("No such command\n"); 831 db_flush_lex(); 832 return; 833 } 834 835 COMPAT_RET: 836 TAILQ_FOREACH(list_ent, list, db_cmd_next) { 837 result = db_cmd_search(db_tok_string, list_ent->db_cmd, 838 &command); 839 840 /* after CMD_UNIQUE in cmd_list only a single command 841 name is possible */ 842 if (result == CMD_UNIQUE) 843 break; 844 845 } 846 847 /* check compatibility flag */ 848 if (command && command->flag & CS_COMPAT){ 849 t = db_read_token(); 850 if (t != tIDENT) { 851 db_cmd_list(list); 852 db_flush_lex(); 853 return; 854 } 855 856 /* support only level 2 commands here */ 857 goto COMPAT_RET; 858 } 859 860 if (!command) { 861 db_printf("No such command\n"); 862 db_flush_lex(); 863 return; 864 } 865 866 if ((command->flag & CS_OWN) == 0) { 867 868 /* 869 * Standard syntax: 870 * command [/modifier] [addr] [,count] 871 */ 872 t = db_read_token(); /* get modifier */ 873 if (t == tSLASH) { 874 t = db_read_token(); 875 if (t != tIDENT) { 876 db_printf("Bad modifier\n"); 877 db_flush_lex(); 878 return; 879 } 880 /* save modifier */ 881 strlcpy(modif, db_tok_string, sizeof(modif)); 882 883 } else { 884 db_unread_token(t); 885 modif[0] = '\0'; 886 } 887 888 if (db_expression(&addr)) { /*get address*/ 889 db_dot = (db_addr_t) addr; 890 db_last_addr = db_dot; 891 have_addr = true; 892 } else { 893 addr = (db_expr_t) db_dot; 894 have_addr = false; 895 } 896 897 t = db_read_token(); 898 if (t == tCOMMA) { /*Get count*/ 899 if (!db_expression(&count)) { 900 db_printf("Count missing\n"); 901 db_flush_lex(); 902 return; 903 } 904 } else { 905 db_unread_token(t); 906 count = -1; 907 } 908 if ((command->flag & CS_MORE) == 0) { 909 db_skip_to_eol(); 910 } 911 } 912 } 913 914 if (command->flag & CS_NOREPEAT) { 915 *last_cmdp = NULL; 916 last_count = 0; 917 } else { 918 *last_cmdp = command; 919 last_count = count; 920 } 921 922 if (command != NULL) { 923 /* 924 * Execute the command. 925 */ 926 if (command->fcn != NULL) 927 (*command->fcn)(addr, have_addr, count, modif); 928 929 if (command->flag & CS_SET_DOT) { 930 /* 931 * If command changes dot, set dot to 932 * previous address displayed (if 'ed' style). 933 */ 934 if (db_ed_style) 935 db_dot = db_prev; 936 else 937 db_dot = db_next; 938 } else { 939 /* 940 * If command does not change dot, 941 * set 'next' location to be the same. 942 */ 943 db_next = db_dot; 944 } 945 } 946 } 947 948 /* 949 * Print help for commands 950 */ 951 static void 952 db_help_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 953 const char *modif) 954 { 955 956 const struct db_cmd_tbl_en_head *list; 957 const struct db_cmd_tbl_en *list_ent; 958 const struct db_command *help = NULL; 959 int t, result; 960 961 t = db_read_token(); 962 /* is there another command after the "help"? */ 963 if (t == tIDENT){ 964 965 switch(db_get_list_type(db_tok_string)) { 966 967 case DDB_BASE_CMD: 968 list=&db_base_cmd_list; 969 break; 970 case DDB_SHOW_CMD: 971 list=&db_show_cmd_list; 972 /* read the show subcommand */ 973 t = db_read_token(); 974 975 if (t != tIDENT) { 976 /* no subcommand, print the list */ 977 db_cmd_list(list); 978 db_flush_lex(); 979 return; 980 } 981 982 break; 983 case DDB_MACH_CMD: 984 list=&db_mach_cmd_list; 985 /* read machine subcommand */ 986 t = db_read_token(); 987 988 if (t != tIDENT) { 989 /* no subcommand - just print the list */ 990 db_cmd_list(list); 991 db_flush_lex(); 992 return; 993 } 994 break; 995 996 default: 997 db_printf("No such command\n"); 998 db_flush_lex(); 999 return; 1000 } 1001 COMPAT_RET: 1002 TAILQ_FOREACH(list_ent,list,db_cmd_next){ 1003 result = db_cmd_search(db_tok_string, list_ent->db_cmd, 1004 &help); 1005 /* after CMD_UNIQUE only a single command 1006 name is possible */ 1007 if (result == CMD_UNIQUE) 1008 break; 1009 } 1010 #ifdef DDB_VERBOSE_HELP 1011 /*print help*/ 1012 1013 db_printf("Command: %s\n",help->name); 1014 1015 if (help->cmd_descr != NULL) 1016 db_printf(" Description: %s\n",help->cmd_descr); 1017 1018 if (help->cmd_arg != NULL) 1019 db_printf(" Arguments: %s\n",help->cmd_arg); 1020 1021 if (help->cmd_arg_help != NULL) 1022 db_printf(" Arguments description:\n%s\n", 1023 help->cmd_arg_help); 1024 1025 if ((help->cmd_arg == NULL) && (help->cmd_descr == NULL)) 1026 db_printf("%s Doesn't have any help message included.\n", 1027 help->name); 1028 #endif 1029 /* check compatibility flag */ 1030 /* 1031 * The "show all" command table has been merged with the 1032 * "show" command table - but we want to keep the old UI 1033 * available. So if we find a CS_COMPAT entry, we read 1034 * the next token and try again. 1035 */ 1036 if (help->flag == CS_COMPAT){ 1037 t = db_read_token(); 1038 1039 if (t != tIDENT){ 1040 db_cmd_list(list); 1041 db_flush_lex(); 1042 return; 1043 } 1044 1045 goto COMPAT_RET; 1046 /* support only level 2 commands here */ 1047 } else { 1048 db_skip_to_eol(); 1049 } 1050 1051 } else /* t != tIDENT */ 1052 /* print base commands */ 1053 db_cmd_list(&db_base_cmd_list); 1054 1055 return; 1056 } 1057 1058 /*ARGSUSED*/ 1059 static void 1060 db_map_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 1061 const char *modif) 1062 { 1063 bool full = false; 1064 1065 if (modif[0] == 'f') 1066 full = true; 1067 1068 if (have_addr == false) 1069 addr = (db_expr_t)(intptr_t) kernel_map; 1070 1071 uvm_map_printit((struct vm_map *)(intptr_t) addr, full, db_printf); 1072 } 1073 1074 /*ARGSUSED*/ 1075 static void 1076 db_malloc_print_cmd(db_expr_t addr, bool have_addr, 1077 db_expr_t count, const char *modif) 1078 { 1079 1080 #ifdef MALLOC_DEBUG 1081 if (!have_addr) 1082 addr = 0; 1083 1084 debug_malloc_printit(db_printf, (vaddr_t) addr); 1085 #else 1086 db_printf("The kernel is not built with the MALLOC_DEBUG option.\n"); 1087 #endif /* MALLOC_DEBUG */ 1088 } 1089 1090 /*ARGSUSED*/ 1091 static void 1092 db_object_print_cmd(db_expr_t addr, bool have_addr, 1093 db_expr_t count, const char *modif) 1094 { 1095 bool full = false; 1096 1097 if (modif[0] == 'f') 1098 full = true; 1099 1100 uvm_object_printit((struct uvm_object *)(intptr_t) addr, full, 1101 db_printf); 1102 } 1103 1104 /*ARGSUSED*/ 1105 static void 1106 db_page_print_cmd(db_expr_t addr, bool have_addr, 1107 db_expr_t count, const char *modif) 1108 { 1109 bool full = false; 1110 1111 if (modif[0] == 'f') 1112 full = true; 1113 1114 uvm_page_printit((struct vm_page *)(intptr_t) addr, full, db_printf); 1115 } 1116 1117 /*ARGSUSED*/ 1118 static void 1119 db_show_all_pages(db_expr_t addr, bool have_addr, 1120 db_expr_t count, const char *modif) 1121 { 1122 1123 uvm_page_printall(db_printf); 1124 } 1125 1126 /*ARGSUSED*/ 1127 static void 1128 db_buf_print_cmd(db_expr_t addr, bool have_addr, 1129 db_expr_t count, const char *modif) 1130 { 1131 bool full = false; 1132 1133 if (modif[0] == 'f') 1134 full = true; 1135 1136 vfs_buf_print((struct buf *)(intptr_t) addr, full, db_printf); 1137 } 1138 1139 /*ARGSUSED*/ 1140 static void 1141 db_event_print_cmd(db_expr_t addr, bool have_addr, 1142 db_expr_t count, const char *modif) 1143 { 1144 bool full = false; 1145 1146 if (modif[0] == 'f') 1147 full = true; 1148 1149 event_print(full, db_printf); 1150 } 1151 1152 /*ARGSUSED*/ 1153 static void 1154 db_vnode_print_cmd(db_expr_t addr, bool have_addr, 1155 db_expr_t count, const char *modif) 1156 { 1157 bool full = false; 1158 1159 if (modif[0] == 'f') 1160 full = true; 1161 1162 vfs_vnode_print((struct vnode *)(intptr_t) addr, full, db_printf); 1163 } 1164 1165 static void 1166 db_mount_print_cmd(db_expr_t addr, bool have_addr, 1167 db_expr_t count, const char *modif) 1168 { 1169 bool full = false; 1170 1171 if (modif[0] == 'f') 1172 full = true; 1173 1174 vfs_mount_print((struct mount *)(intptr_t) addr, full, db_printf); 1175 } 1176 1177 /*ARGSUSED*/ 1178 static void 1179 db_mbuf_print_cmd(db_expr_t addr, bool have_addr, 1180 db_expr_t count, const char *modif) 1181 { 1182 1183 m_print((const struct mbuf *)(intptr_t) addr, modif, db_printf); 1184 } 1185 1186 /*ARGSUSED*/ 1187 static void 1188 db_pool_print_cmd(db_expr_t addr, bool have_addr, 1189 db_expr_t count, const char *modif) 1190 { 1191 1192 pool_printit((struct pool *)(intptr_t) addr, modif, db_printf); 1193 } 1194 1195 /*ARGSUSED*/ 1196 static void 1197 db_namecache_print_cmd(db_expr_t addr, bool have_addr, 1198 db_expr_t count, const char *modif) 1199 { 1200 1201 namecache_print((struct vnode *)(intptr_t) addr, db_printf); 1202 } 1203 1204 /*ARGSUSED*/ 1205 static void 1206 db_uvmexp_print_cmd(db_expr_t addr, bool have_addr, 1207 db_expr_t count, const char *modif) 1208 { 1209 1210 uvmexp_print(db_printf); 1211 } 1212 1213 /*ARGSUSED*/ 1214 static void 1215 db_lock_print_cmd(db_expr_t addr, bool have_addr, 1216 db_expr_t count, const char *modif) 1217 { 1218 1219 lockdebug_lock_print((void *)addr, db_printf); 1220 } 1221 1222 /* 1223 * Call random function: 1224 * !expr(arg,arg,arg) 1225 */ 1226 /*ARGSUSED*/ 1227 static void 1228 db_fncall(db_expr_t addr, bool have_addr, 1229 db_expr_t count, const char *modif) 1230 { 1231 db_expr_t fn_addr; 1232 #define MAXARGS 11 1233 db_expr_t args[MAXARGS]; 1234 int nargs = 0; 1235 db_expr_t retval; 1236 db_expr_t (*func)(db_expr_t, ...); 1237 int t; 1238 1239 if (!db_expression(&fn_addr)) { 1240 db_printf("Bad function\n"); 1241 db_flush_lex(); 1242 return; 1243 } 1244 func = (db_expr_t (*)(db_expr_t, ...))(intptr_t) fn_addr; 1245 1246 t = db_read_token(); 1247 if (t == tLPAREN) { 1248 if (db_expression(&args[0])) { 1249 nargs++; 1250 while ((t = db_read_token()) == tCOMMA) { 1251 if (nargs == MAXARGS) { 1252 db_printf("Too many arguments\n"); 1253 db_flush_lex(); 1254 return; 1255 } 1256 if (!db_expression(&args[nargs])) { 1257 db_printf("Argument missing\n"); 1258 db_flush_lex(); 1259 return; 1260 } 1261 nargs++; 1262 } 1263 db_unread_token(t); 1264 } 1265 if (db_read_token() != tRPAREN) { 1266 db_printf("?\n"); 1267 db_flush_lex(); 1268 return; 1269 } 1270 } 1271 db_skip_to_eol(); 1272 1273 while (nargs < MAXARGS) { 1274 args[nargs++] = 0; 1275 } 1276 1277 retval = (*func)(args[0], args[1], args[2], args[3], args[4], 1278 args[5], args[6], args[7], args[8], args[9]); 1279 db_printf("%s\n", db_num_to_str(retval)); 1280 } 1281 1282 static void 1283 db_reboot_cmd(db_expr_t addr, bool have_addr, 1284 db_expr_t count, const char *modif) 1285 { 1286 db_expr_t bootflags; 1287 1288 /* Flags, default to RB_AUTOBOOT */ 1289 if (!db_expression(&bootflags)) 1290 bootflags = (db_expr_t)RB_AUTOBOOT; 1291 if (db_read_token() != tEOL) { 1292 db_error("?\n"); 1293 /*NOTREACHED*/ 1294 } 1295 /* 1296 * We are leaving DDB, never to return upward. 1297 * Clear db_recover so that we can debug faults in functions 1298 * called from cpu_reboot. 1299 */ 1300 db_recover = 0; 1301 cpu_reboot((int)bootflags, NULL); 1302 } 1303 1304 static void 1305 db_sifting_cmd(db_expr_t addr, bool have_addr, 1306 db_expr_t count, const char *modif) 1307 { 1308 int mode, t; 1309 1310 t = db_read_token(); 1311 if (t == tSLASH) { 1312 t = db_read_token(); 1313 if (t != tIDENT) { 1314 bad_modifier: 1315 db_printf("Bad modifier\n"); 1316 db_flush_lex(); 1317 return; 1318 } 1319 if (!strcmp(db_tok_string, "F")) 1320 mode = 'F'; 1321 else 1322 goto bad_modifier; 1323 t = db_read_token(); 1324 } else 1325 mode = 0; 1326 1327 if (t == tIDENT) 1328 db_sifting(db_tok_string, mode); 1329 else { 1330 db_printf("Bad argument (non-string)\n"); 1331 db_flush_lex(); 1332 } 1333 } 1334 1335 static void 1336 db_stack_trace_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 1337 { 1338 register const char *cp = modif; 1339 register char c; 1340 void (*pr)(const char *, ...); 1341 1342 pr = db_printf; 1343 while ((c = *cp++) != 0) 1344 if (c == 'l') 1345 pr = printf; 1346 1347 if (count == -1) 1348 count = 65535; 1349 1350 db_stack_trace_print(addr, have_addr, count, modif, pr); 1351 } 1352 1353 static void 1354 db_sync_cmd(db_expr_t addr, bool have_addr, 1355 db_expr_t count, const char *modif) 1356 { 1357 1358 /* 1359 * We are leaving DDB, never to return upward. 1360 * Clear db_recover so that we can debug faults in functions 1361 * called from cpu_reboot. 1362 */ 1363 db_recover = 0; 1364 cpu_reboot(RB_DUMP, NULL); 1365 } 1366 1367 /* 1368 * Describe what an address is 1369 */ 1370 void 1371 db_whatis_cmd(db_expr_t address, bool have_addr, 1372 db_expr_t count, const char *modif) 1373 { 1374 const uintptr_t addr = (uintptr_t)address; 1375 1376 lwp_whatis(addr, db_printf); 1377 pool_whatis(addr, db_printf); 1378 vmem_whatis(addr, db_printf); 1379 uvm_whatis(addr, db_printf); 1380 } 1381