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