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