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