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