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