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