1/* $NetBSD: db_command.c,v 1.136 2011/05/17 04:18:06 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.136 2011/05/17 04:18:06 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/malloc.h> 83#include <sys/mbuf.h> 84#include <sys/namei.h> 85#include <sys/pool.h> 86#include <sys/proc.h> 87#include <sys/vnode.h> 88#include <sys/vmem.h> 89#include <sys/lockdebug.h> 90#include <sys/cpu.h> 91#include <sys/buf.h> 92#include <sys/module.h> 93#include <sys/kernhist.h> 94 95/*include queue macros*/ 96#include <sys/queue.h> 97 98#include <ddb/ddb.h> 99 100#include <uvm/uvm_extern.h> 101#include <uvm/uvm_ddb.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 */ 114bool db_cmd_loop_done; 115label_t *db_recover; 116db_addr_t db_dot; 117db_addr_t db_last_addr; 118db_addr_t db_prev; 119db_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 133static const struct db_command db_command_table[]; 134static const struct db_command db_show_cmds[]; 135 136#ifdef DB_MACHINE_COMMANDS 137/* arch/<arch>/<arch>/db_interface.c */ 138extern const struct db_command db_machine_command_table[]; 139#endif 140 141/* the global queue of all command tables */ 142TAILQ_HEAD(db_cmd_tbl_en_head, db_cmd_tbl_en); 143 144/* TAILQ entry used to register command tables */ 145struct 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 */ 151static struct db_cmd_tbl_en_head db_base_cmd_list = 152 TAILQ_HEAD_INITIALIZER(db_base_cmd_list); 153static struct db_cmd_tbl_en db_base_cmd_builtins = 154 { .db_cmd = db_command_table }; 155 156/* head of show commands list */ 157static struct db_cmd_tbl_en_head db_show_cmd_list = 158 TAILQ_HEAD_INITIALIZER(db_show_cmd_list); 159static struct db_cmd_tbl_en db_show_cmd_builtins = 160 { .db_cmd = db_show_cmds }; 161 162/* head of machine commands list */ 163static struct db_cmd_tbl_en_head db_mach_cmd_list = 164 TAILQ_HEAD_INITIALIZER(db_mach_cmd_list); 165#ifdef DB_MACHINE_COMMANDS 166static 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 */ 175static bool db_ed_style = true; 176 177static void db_init_commands(void); 178static int db_register_tbl_entry(uint8_t type, 179 struct db_cmd_tbl_en *list_ent); 180static void db_cmd_list(const struct db_cmd_tbl_en_head *); 181static int db_cmd_search(const char *, struct db_cmd_tbl_en_head *, 182 const struct db_command **); 183static int db_cmd_search_table(const char *, const struct db_command *, 184 const struct db_command **); 185static void db_cmd_search_failed(char *, int); 186static const struct db_command *db_read_command(void); 187static void db_command(const struct db_command **); 188static void db_buf_print_cmd(db_expr_t, bool, db_expr_t, const char *); 189static void db_event_print_cmd(db_expr_t, bool, db_expr_t, const char *); 190static void db_fncall(db_expr_t, bool, db_expr_t, const char *); 191static void db_help_print_cmd(db_expr_t, bool, db_expr_t, const char *); 192static void db_lock_print_cmd(db_expr_t, bool, db_expr_t, const char *); 193static void db_mount_print_cmd(db_expr_t, bool, db_expr_t, const char *); 194static void db_mbuf_print_cmd(db_expr_t, bool, db_expr_t, const char *); 195static void db_malloc_print_cmd(db_expr_t, bool, db_expr_t, const char *); 196static void db_map_print_cmd(db_expr_t, bool, db_expr_t, const char *); 197static void db_namecache_print_cmd(db_expr_t, bool, db_expr_t, 198 const char *); 199static void db_object_print_cmd(db_expr_t, bool, db_expr_t, const char *); 200static void db_page_print_cmd(db_expr_t, bool, db_expr_t, const char *); 201static void db_show_all_pages(db_expr_t, bool, db_expr_t, const char *); 202static void db_pool_print_cmd(db_expr_t, bool, db_expr_t, const char *); 203static void db_reboot_cmd(db_expr_t, bool, db_expr_t, const char *); 204static void db_sifting_cmd(db_expr_t, bool, db_expr_t, const char *); 205static void db_stack_trace_cmd(db_expr_t, bool, db_expr_t, const char *); 206static void db_sync_cmd(db_expr_t, bool, db_expr_t, const char *); 207static void db_whatis_cmd(db_expr_t, bool, db_expr_t, const char *); 208static void db_uvmexp_print_cmd(db_expr_t, bool, db_expr_t, const char *); 209#ifdef KERNHIST 210static void db_kernhist_print_cmd(db_expr_t, bool, db_expr_t, const char *); 211#endif 212static void db_vnode_print_cmd(db_expr_t, bool, db_expr_t, const char *); 213static void db_vmem_print_cmd(db_expr_t, bool, db_expr_t, const char *); 214 215static const struct db_command db_show_cmds[] = { 216 /*added from all sub cmds*/ 217#ifdef _KERNEL /* XXX CRASH(8) */ 218 { DDB_ADD_CMD("callout", db_show_callout, 219 0 ,"List all used callout functions.",NULL,NULL) }, 220#endif 221 { DDB_ADD_CMD("pages", db_show_all_pages, 222 0 ,"List all used memory pages.",NULL,NULL) }, 223 { DDB_ADD_CMD("proc", db_show_proc, 224 0 ,"Print process information.",NULL,NULL) }, 225 { DDB_ADD_CMD("procs", db_show_all_procs, 226 0 ,"List all processes.",NULL,NULL) }, 227 { DDB_ADD_CMD("pools", db_show_all_pools, 228 0 ,"Show all pools",NULL,NULL) }, 229#ifdef AIO 230 /*added from all sub cmds*/ 231 { DDB_ADD_CMD("aio_jobs", db_show_aio_jobs, 0, 232 "Show aio jobs",NULL,NULL) }, 233#endif 234 { DDB_ADD_CMD("all", NULL, 235 CS_COMPAT, NULL,NULL,NULL) }, 236#if defined(INET) && (NARP > 0) 237 { DDB_ADD_CMD("arptab", db_show_arptab, 0,NULL,NULL,NULL) }, 238#endif 239#ifdef _KERNEL 240 { DDB_ADD_CMD("breaks", db_listbreak_cmd, 0, 241 "Display all breaks.",NULL,NULL) }, 242#endif 243 { DDB_ADD_CMD("buf", db_buf_print_cmd, 0, 244 "Print the struct buf at address.", "[/f] address",NULL) }, 245 { DDB_ADD_CMD("event", db_event_print_cmd, 0, 246 "Print all the non-zero evcnt(9) event counters.", "[/fitm]",NULL) }, 247 { DDB_ADD_CMD("files", db_show_files_cmd, 0, 248 "Print the files open by process at address", 249 "[/f] address", NULL) }, 250 { DDB_ADD_CMD("lock", db_lock_print_cmd, 0,NULL,NULL,NULL) }, 251 { DDB_ADD_CMD("malloc", db_malloc_print_cmd,0,NULL,NULL,NULL) }, 252 { DDB_ADD_CMD("map", db_map_print_cmd, 0, 253 "Print the vm_map at address.", "[/f] address",NULL) }, 254 { DDB_ADD_CMD("module", db_show_module_cmd, 0, 255 "Print kernel modules", NULL, NULL) }, 256 { DDB_ADD_CMD("mount", db_mount_print_cmd, 0, 257 "Print the mount structure at address.", "[/f] address",NULL) }, 258#ifdef MQUEUE 259 { DDB_ADD_CMD("mqueue", db_show_mqueue_cmd, 0, 260 "Print the message queues", NULL, NULL) }, 261#endif 262 { DDB_ADD_CMD("mbuf", db_mbuf_print_cmd, 0,NULL,NULL, 263 "-c prints all mbuf chains") }, 264 { DDB_ADD_CMD("ncache", db_namecache_print_cmd, 0, 265 "Dump the namecache list.", "address",NULL) }, 266 { DDB_ADD_CMD("object", db_object_print_cmd, 0, 267 "Print the vm_object at address.", "[/f] address",NULL) }, 268 { DDB_ADD_CMD("page", db_page_print_cmd, 0, 269 "Print the vm_page at address.", "[/f] address",NULL) }, 270 { DDB_ADD_CMD("pool", db_pool_print_cmd, 0, 271 "Print the pool at address.", "[/clp] address",NULL) }, 272 { DDB_ADD_CMD("registers", db_show_regs, 0, 273 "Display the register set.", "[/u]",NULL) }, 274 { DDB_ADD_CMD("sched_qs", db_show_sched_qs, 0, 275 "Print the state of the scheduler's run queues.", 276 NULL,NULL) }, 277 { DDB_ADD_CMD("uvmexp", db_uvmexp_print_cmd, 0, 278 "Print a selection of UVM counters and statistics.", 279 NULL,NULL) }, 280#ifdef KERNHIST 281 { DDB_ADD_CMD("kernhist", db_kernhist_print_cmd, 0, 282 "Print the UVM history logs.", 283 NULL,NULL) }, 284#endif 285 { DDB_ADD_CMD("vnode", db_vnode_print_cmd, 0, 286 "Print the vnode at address.", "[/f] address",NULL) }, 287 { DDB_ADD_CMD("vmem", db_vmem_print_cmd, 0, 288 "Print the vmem usage.", "[/a] address", NULL) }, 289 { DDB_ADD_CMD("vmems", db_show_all_vmems, 0, 290 "Show all vmems.", NULL, NULL) }, 291#ifdef _KERNEL 292 { DDB_ADD_CMD("watches", db_listwatch_cmd, 0, 293 "Display all watchpoints.", NULL,NULL) }, 294#endif 295 { DDB_ADD_CMD(NULL, NULL, 0,NULL,NULL,NULL) } 296}; 297 298static const struct db_command db_command_table[] = { 299 { DDB_ADD_CMD("b", db_breakpoint_cmd, 0, 300 "Set a breakpoint at address", "[/u] address[,count].",NULL) }, 301 { DDB_ADD_CMD("break", db_breakpoint_cmd, 0, 302 "Set a breakpoint at address", "[/u] address[,count].",NULL) }, 303 { DDB_ADD_CMD("bt", db_stack_trace_cmd, 0, 304 "Show backtrace.", "See help trace.",NULL) }, 305 { DDB_ADD_CMD("c", db_continue_cmd, 0, 306 "Continue execution.", "[/c]",NULL) }, 307 { DDB_ADD_CMD("call", db_fncall, CS_OWN, 308 "Call the function", "address[(expression[,...])]",NULL) }, 309#ifdef _KERNEL /* XXX CRASH(8) */ 310 { DDB_ADD_CMD("callout", db_show_callout, 0, NULL, 311 NULL,NULL ) }, 312#endif 313 { DDB_ADD_CMD("continue", db_continue_cmd, 0, 314 "Continue execution.", "[/c]",NULL) }, 315 { DDB_ADD_CMD("d", db_delete_cmd, 0, 316 "Delete a breakpoint.", "address | #number",NULL) }, 317 { DDB_ADD_CMD("delete", db_delete_cmd, 0, 318 "Delete a breakpoint.", "address | #number",NULL) }, 319 { DDB_ADD_CMD("dmesg", db_dmesg, 0, 320 "Show kernel message buffer.", "[count]",NULL) }, 321 { DDB_ADD_CMD("dwatch", db_deletewatch_cmd, 0, 322 "Delete the watchpoint.", "address",NULL) }, 323 { DDB_ADD_CMD("examine", db_examine_cmd, CS_SET_DOT, 324 "Display the address locations.", 325 "[/modifier] address[,count]",NULL) }, 326 { DDB_ADD_CMD("exit", db_continue_cmd, 0, 327 "Continue execution.", "[/c]",NULL) }, 328 { DDB_ADD_CMD("help", db_help_print_cmd, CS_OWN|CS_NOREPEAT, 329 "Display help about commands", 330 "Use other commands as arguments.",NULL) }, 331 { DDB_ADD_CMD("kill", db_kill_proc, CS_OWN, 332 "Send a signal to the process","pid[,signal_number]", 333 " pid:\t\t\tthe process id (may need 0t prefix for decimal)\n" 334 " signal_number:\tthe signal to send") }, 335#ifdef KGDB 336 { DDB_ADD_CMD("kgdb", db_kgdb_cmd, 0, NULL,NULL,NULL) }, 337#endif 338 { DDB_ADD_CMD("machine",NULL,CS_MACH, 339 "Architecture specific functions.",NULL,NULL) }, 340 { DDB_ADD_CMD("match", db_trace_until_matching_cmd,0, 341 "Stop at the matching return instruction.","See help next",NULL) }, 342 { DDB_ADD_CMD("next", db_trace_until_matching_cmd,0, 343 "Stop at the matching return instruction.","[/p]",NULL) }, 344 { DDB_ADD_CMD("p", db_print_cmd, 0, 345 "Print address according to the format.", 346 "[/axzodurc] address [address ...]",NULL) }, 347 { DDB_ADD_CMD("print", db_print_cmd, 0, 348 "Print address according to the format.", 349 "[/axzodurc] address [address ...]",NULL) }, 350 { DDB_ADD_CMD("ps", db_show_all_procs, 0, 351 "Print all processes.","See show all procs",NULL) }, 352 { DDB_ADD_CMD("quit", db_continue_cmd, 0, 353 "Continue execution.", "[/c]",NULL) }, 354 { DDB_ADD_CMD("reboot", db_reboot_cmd, CS_OWN, 355 "Reboot","0x1 RB_ASKNAME, 0x2 RB_SINGLE, 0x4 RB_NOSYNC, 0x8 RB_HALT," 356 "0x40 RB_KDB, 0x100 RB_DUMP, 0x808 RB_POWERDOWN",NULL) }, 357 { DDB_ADD_CMD("s", db_single_step_cmd, 0, 358 "Single-step count times.","[/p] [,count]",NULL) }, 359 { DDB_ADD_CMD("search", db_search_cmd, CS_OWN|CS_SET_DOT, 360 "Search memory from address for value.", 361 "[/bhl] address value [mask] [,count]",NULL) }, 362 { DDB_ADD_CMD("set", db_set_cmd, CS_OWN, 363 "Set the named variable","$variable [=] expression",NULL) }, 364 { DDB_ADD_CMD("show", NULL, CS_SHOW, 365 "Show kernel stats.", NULL,NULL) }, 366 { DDB_ADD_CMD("sifting", db_sifting_cmd, CS_OWN, 367 "Search the symbol tables ","[/F] string",NULL) }, 368 { DDB_ADD_CMD("step", db_single_step_cmd, 0, 369 "Single-step count times.","[/p] [,count]",NULL) }, 370 { DDB_ADD_CMD("sync", db_sync_cmd, CS_OWN, 371 "Force a crash dump, and then reboot.",NULL,NULL) }, 372 { DDB_ADD_CMD("trace", db_stack_trace_cmd, 0, 373 "Stack trace from frame-address.", 374 "[/u[l]] [frame-address][,count]",NULL) }, 375 { DDB_ADD_CMD("until", db_trace_until_call_cmd,0, 376 "Stop at the next call or return instruction.","[/p]",NULL) }, 377 { DDB_ADD_CMD("w", db_write_cmd, CS_MORE|CS_SET_DOT, 378 "Write the expressions at succeeding locations.", 379 "[/bhl] address expression [expression ...]",NULL) }, 380 { DDB_ADD_CMD("watch", db_watchpoint_cmd, CS_MORE, 381 "Set a watchpoint for a region. ","address[,size]",NULL) }, 382 { DDB_ADD_CMD("whatis", db_whatis_cmd, 0, 383 "Describe what an address is", "address", NULL) }, 384 { DDB_ADD_CMD("write", db_write_cmd, CS_MORE|CS_SET_DOT, 385 "Write the expressions at succeeding locations.", 386 "[/bhl] address expression [expression ...]",NULL) }, 387 { DDB_ADD_CMD("x", db_examine_cmd, CS_SET_DOT, 388 "Display the address locations.", 389 "[/modifier] address[,count]",NULL) }, 390 { DDB_ADD_CMD(NULL, NULL, 0, NULL, NULL, NULL) } 391}; 392 393static const struct db_command *db_last_command = NULL; 394#if defined(DDB_COMMANDONENTER) 395char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ___STRING(DDB_COMMANDONENTER); 396#else /* defined(DDB_COMMANDONENTER) */ 397char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ""; 398#endif /* defined(DDB_COMMANDONENTER) */ 399#define DB_LINE_SEP ';' 400 401/* 402 * Execute commandlist after ddb start 403 * This function goes through the command list created from commands and ';' 404 */ 405static void 406db_execute_commandlist(const char *cmdlist) 407{ 408 const char *cmd = cmdlist; 409 const struct db_command *dummy = NULL; 410 411 while (*cmd != '\0') { 412 const char *ep = cmd; 413 414 while (*ep != '\0' && *ep != DB_LINE_SEP) { 415 ep++; 416 } 417 db_set_line(cmd, ep); 418 db_command(&dummy); 419 cmd = ep; 420 if (*cmd == DB_LINE_SEP) { 421 cmd++; 422 } 423 } 424} 425 426/* Initialize ddb command tables */ 427void 428db_init_commands(void) 429{ 430 static bool done = false; 431 432 if (done) return; 433 done = true; 434 435 /* register command tables */ 436 (void)db_register_tbl_entry(DDB_BASE_CMD, &db_base_cmd_builtins); 437#ifdef DB_MACHINE_COMMANDS 438 (void)db_register_tbl_entry(DDB_MACH_CMD, &db_mach_cmd_builtins); 439#endif 440 (void)db_register_tbl_entry(DDB_SHOW_CMD, &db_show_cmd_builtins); 441} 442 443 444/* 445 * Add command table to the specified list 446 * Arg: 447 * int type specifies type of command table DDB_SHOW_CMD|DDB_BASE_CMD|DDB_MAC_CMD 448 * *cmd_tbl poiter to static allocated db_command table 449 * 450 * Command table must be NULL terminated array of struct db_command 451 */ 452int 453db_register_tbl(uint8_t type, const struct db_command *cmd_tbl) 454{ 455 struct db_cmd_tbl_en *list_ent; 456 457 /* empty list - ignore */ 458 if (cmd_tbl->name == 0) 459 return 0; 460 461 /* force builtin commands to be registered first */ 462 db_init_commands(); 463 464 /* now create a list entry for this table */ 465 list_ent = db_zalloc(sizeof(*list_ent)); 466 if (list_ent == NULL) 467 return ENOMEM; 468 list_ent->db_cmd=cmd_tbl; 469 470 /* and register it */ 471 return db_register_tbl_entry(type, list_ent); 472} 473 474static int 475db_register_tbl_entry(uint8_t type, struct db_cmd_tbl_en *list_ent) 476{ 477 struct db_cmd_tbl_en_head *list; 478 479 switch(type) { 480 case DDB_BASE_CMD: 481 list = &db_base_cmd_list; 482 break; 483 case DDB_SHOW_CMD: 484 list = &db_show_cmd_list; 485 break; 486 case DDB_MACH_CMD: 487 list = &db_mach_cmd_list; 488 break; 489 default: 490 return ENOENT; 491 } 492 493 TAILQ_INSERT_TAIL(list, list_ent, db_cmd_next); 494 495 return 0; 496} 497 498/* 499 * Remove command table specified with db_cmd address == cmd_tbl 500 */ 501int 502db_unregister_tbl(uint8_t type,const struct db_command *cmd_tbl) 503{ 504 struct db_cmd_tbl_en *list_ent; 505 struct db_cmd_tbl_en_head *list; 506 507 /* find list on which the entry should live */ 508 switch (type) { 509 case DDB_BASE_CMD: 510 list=&db_base_cmd_list; 511 break; 512 case DDB_SHOW_CMD: 513 list=&db_show_cmd_list; 514 break; 515 case DDB_MACH_CMD: 516 list=&db_mach_cmd_list; 517 break; 518 default: 519 return EINVAL; 520 } 521 522 TAILQ_FOREACH (list_ent, list, db_cmd_next) { 523 if (list_ent->db_cmd == cmd_tbl){ 524 TAILQ_REMOVE(list, 525 list_ent, db_cmd_next); 526 db_free(list_ent, sizeof(*list_ent)); 527 return 0; 528 } 529 } 530 return ENOENT; 531} 532 533/* This function is called from machine trap code. */ 534void 535db_command_loop(void) 536{ 537 label_t db_jmpbuf; 538 label_t *savejmp; 539 540 /* 541 * Initialize 'prev' and 'next' to dot. 542 */ 543 db_prev = db_dot; 544 db_next = db_dot; 545 546 db_cmd_loop_done = false; 547 548 /* Init default command tables add machine, base, 549 show command tables to the list */ 550 db_init_commands(); 551 552 /* save context for return from ddb */ 553 savejmp = db_recover; 554 db_recover = &db_jmpbuf; 555 (void) setjmp(&db_jmpbuf); 556 557 /* Execute default ddb start commands */ 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 */ 575static int 576db_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 */ 624static int 625db_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 681static void 682db_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 */ 694static void 695db_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 */ 753static const struct db_command * 754db_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 */ 794static void 795db_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 */ 932static void 933db_help_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 934const 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*/ 969static void 970db_map_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 971 const char *modif) 972{ 973 bool full = false; 974 975 if (modif[0] == 'f') 976 full = true; 977 978 if (have_addr == false) 979 addr = (db_expr_t)(uintptr_t)db_read_ptr("kernel_map"); 980 981#ifdef _KERNEL 982 uvm_map_printit((struct vm_map *)(uintptr_t) addr, full, db_printf); 983#endif /* XXX CRASH(8) */ 984} 985 986/*ARGSUSED*/ 987static void 988db_malloc_print_cmd(db_expr_t addr, bool have_addr, 989 db_expr_t count, const char *modif) 990{ 991 992#ifdef MALLOC_DEBUG 993 if (!have_addr) 994 addr = 0; 995 996 debug_malloc_printit(db_printf, (vaddr_t) addr); 997#else 998 db_printf("The kernel is not built with the MALLOC_DEBUG option.\n"); 999#endif /* MALLOC_DEBUG */ 1000} 1001 1002/*ARGSUSED*/ 1003static void 1004db_object_print_cmd(db_expr_t addr, bool have_addr, 1005 db_expr_t count, const char *modif) 1006{ 1007 bool full = false; 1008 1009 if (modif[0] == 'f') 1010 full = true; 1011 1012#ifdef _KERNEL /* XXX CRASH(8) */ 1013 uvm_object_printit((struct uvm_object *)(uintptr_t) addr, full, 1014 db_printf); 1015#endif 1016} 1017 1018/*ARGSUSED*/ 1019static void 1020db_page_print_cmd(db_expr_t addr, bool have_addr, 1021 db_expr_t count, const char *modif) 1022{ 1023 bool full = false; 1024 1025 if (modif[0] == 'f') 1026 full = true; 1027 1028#ifdef _KERNEL /* XXX CRASH(8) */ 1029 uvm_page_printit((struct vm_page *)(uintptr_t) addr, full, db_printf); 1030#endif 1031} 1032 1033/*ARGSUSED*/ 1034static void 1035db_show_all_pages(db_expr_t addr, bool have_addr, 1036 db_expr_t count, const char *modif) 1037{ 1038 1039#ifdef _KERNEL /* XXX CRASH(8) */ 1040 uvm_page_printall(db_printf); 1041#endif 1042} 1043 1044/*ARGSUSED*/ 1045static void 1046db_buf_print_cmd(db_expr_t addr, bool have_addr, 1047 db_expr_t count, const char *modif) 1048{ 1049 bool full = false; 1050 1051 if (modif[0] == 'f') 1052 full = true; 1053 1054#ifdef _KERNEL /* XXX CRASH(8) */ 1055 vfs_buf_print((struct buf *)(uintptr_t) addr, full, db_printf); 1056#endif 1057} 1058 1059/*ARGSUSED*/ 1060static void 1061db_event_print_cmd(db_expr_t addr, bool have_addr, 1062 db_expr_t count, const char *modif) 1063{ 1064 bool showzero = false; 1065 bool showall = true; 1066 bool showintr = false; 1067 bool showtrap = false; 1068 bool showmisc = false; 1069 struct evcnt ev, *evp; 1070 char buf[80]; 1071 int i; 1072 1073 i = 0; 1074 while (modif[i]) { 1075 switch (modif[i]) { 1076 case 'f': 1077 showzero = true; 1078 break; 1079 case 'i': 1080 showintr = true; 1081 showall = false; 1082 break; 1083 case 't': 1084 showtrap = true; 1085 showall = false; 1086 break; 1087 case 'm': 1088 showmisc = true; 1089 showall = false; 1090 break; 1091 } 1092 i++; 1093 } 1094 1095 if (showall) 1096 showmisc = showintr = showtrap = true; 1097 1098 evp = (struct evcnt *)db_read_ptr("allevents"); 1099 while (evp != NULL) { 1100 db_read_bytes((db_addr_t)evp, sizeof(ev), (char *)&ev); 1101 evp = ev.ev_list.tqe_next; 1102 if (ev.ev_count == 0 && !showzero) 1103 continue; 1104 if (ev.ev_type == EVCNT_TYPE_INTR && !showintr) 1105 continue; 1106 if (ev.ev_type == EVCNT_TYPE_TRAP && !showtrap) 1107 continue; 1108 if (ev.ev_type == EVCNT_TYPE_MISC && !showmisc) 1109 continue; 1110 db_read_bytes((db_addr_t)ev.ev_group, ev.ev_grouplen + 1, buf); 1111 db_printf("evcnt type %d: %s ", ev.ev_type, buf); 1112 db_read_bytes((db_addr_t)ev.ev_name, ev.ev_namelen + 1, buf); 1113 db_printf("%s = %lld\n", buf, (long long)ev.ev_count); 1114 } 1115} 1116 1117/*ARGSUSED*/ 1118static void 1119db_vnode_print_cmd(db_expr_t addr, bool have_addr, 1120 db_expr_t count, const char *modif) 1121{ 1122 bool full = false; 1123 1124 if (modif[0] == 'f') 1125 full = true; 1126 1127#ifdef _KERNEL /* XXX CRASH(8) */ 1128 vfs_vnode_print((struct vnode *)(uintptr_t) addr, full, db_printf); 1129#endif 1130} 1131 1132/*ARGSUSED*/ 1133static void 1134db_vmem_print_cmd(db_expr_t addr, bool have_addr, 1135 db_expr_t count, const char *modif) 1136{ 1137 1138#ifdef _KERNEL /* XXX CRASH(8) */ 1139 vmem_print((uintptr_t) addr, modif, db_printf); 1140#endif 1141} 1142 1143static void 1144db_mount_print_cmd(db_expr_t addr, bool have_addr, 1145 db_expr_t count, const char *modif) 1146{ 1147 bool full = false; 1148 1149 if (modif[0] == 'f') 1150 full = true; 1151 1152#ifdef _KERNEL /* XXX CRASH(8) */ 1153 vfs_mount_print((struct mount *)(uintptr_t) addr, full, db_printf); 1154#endif 1155} 1156 1157/*ARGSUSED*/ 1158static void 1159db_mbuf_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 m_print((const struct mbuf *)(uintptr_t) addr, modif, db_printf); 1165#endif 1166} 1167 1168/*ARGSUSED*/ 1169static void 1170db_pool_print_cmd(db_expr_t addr, bool have_addr, 1171 db_expr_t count, const char *modif) 1172{ 1173 1174#ifdef _KERNEL /* XXX CRASH(8) */ 1175 pool_printit((struct pool *)(uintptr_t) addr, modif, db_printf); 1176#endif 1177} 1178 1179/*ARGSUSED*/ 1180static void 1181db_namecache_print_cmd(db_expr_t addr, bool have_addr, 1182 db_expr_t count, const char *modif) 1183{ 1184 1185#ifdef _KERNEL /* XXX CRASH(8) */ 1186 namecache_print((struct vnode *)(uintptr_t) addr, db_printf); 1187#endif 1188} 1189 1190/*ARGSUSED*/ 1191static void 1192db_uvmexp_print_cmd(db_expr_t addr, bool have_addr, 1193 db_expr_t count, const char *modif) 1194{ 1195 1196#ifdef _KERNEL /* XXX CRASH(8) */ 1197 uvmexp_print(db_printf); 1198#endif 1199} 1200 1201#ifdef KERNHIST 1202/*ARGSUSED*/ 1203static void 1204db_kernhist_print_cmd(db_expr_t addr, bool have_addr, 1205 db_expr_t count, const char *modif) 1206{ 1207 1208 kernhist_print(db_printf); 1209} 1210#endif 1211 1212/*ARGSUSED*/ 1213static void 1214db_lock_print_cmd(db_expr_t addr, bool have_addr, 1215 db_expr_t count, const char *modif) 1216{ 1217 1218#ifdef _KERNEL /* XXX CRASH(8) */ 1219 lockdebug_lock_print((void *)(uintptr_t)addr, db_printf); 1220#endif 1221} 1222 1223/* 1224 * Call random function: 1225 * !expr(arg,arg,arg) 1226 */ 1227/*ARGSUSED*/ 1228static void 1229db_fncall(db_expr_t addr, bool have_addr, 1230 db_expr_t count, const char *modif) 1231{ 1232#ifdef _KERNEL 1233 db_expr_t fn_addr; 1234#define MAXARGS 11 1235 db_expr_t args[MAXARGS]; 1236 int nargs = 0; 1237 db_expr_t retval; 1238 db_expr_t (*func)(db_expr_t, ...); 1239 int t; 1240 1241 if (!db_expression(&fn_addr)) { 1242 db_printf("Bad function\n"); 1243 db_flush_lex(); 1244 return; 1245 } 1246 func = (db_expr_t (*)(db_expr_t, ...))(uintptr_t) fn_addr; 1247 1248 t = db_read_token(); 1249 if (t == tLPAREN) { 1250 if (db_expression(&args[0])) { 1251 nargs++; 1252 while ((t = db_read_token()) == tCOMMA) { 1253 if (nargs == MAXARGS) { 1254 db_printf("Too many arguments\n"); 1255 db_flush_lex(); 1256 return; 1257 } 1258 if (!db_expression(&args[nargs])) { 1259 db_printf("Argument missing\n"); 1260 db_flush_lex(); 1261 return; 1262 } 1263 nargs++; 1264 } 1265 db_unread_token(t); 1266 } 1267 if (db_read_token() != tRPAREN) { 1268 db_printf("?\n"); 1269 db_flush_lex(); 1270 return; 1271 } 1272 } 1273 db_skip_to_eol(); 1274 1275 while (nargs < MAXARGS) { 1276 args[nargs++] = 0; 1277 } 1278 1279 retval = (*func)(args[0], args[1], args[2], args[3], args[4], 1280 args[5], args[6], args[7], args[8], args[9]); 1281 db_printf("%s\n", db_num_to_str(retval)); 1282#else /* _KERNEL */ 1283 db_printf("This command can only be used in-kernel.\n"); 1284#endif /* _KERNEL */ 1285} 1286 1287static void 1288db_reboot_cmd(db_expr_t addr, bool have_addr, 1289 db_expr_t count, const char *modif) 1290{ 1291#ifdef _KERNEL 1292 db_expr_t bootflags; 1293 1294 /* Flags, default to RB_AUTOBOOT */ 1295 if (!db_expression(&bootflags)) 1296 bootflags = (db_expr_t)RB_AUTOBOOT; 1297 if (db_read_token() != tEOL) { 1298 db_error("?\n"); 1299 /*NOTREACHED*/ 1300 } 1301 /* 1302 * We are leaving DDB, never to return upward. 1303 * Clear db_recover so that we can debug faults in functions 1304 * called from cpu_reboot. 1305 */ 1306 db_recover = 0; 1307 panicstr = "reboot forced via kernel debugger"; 1308 cpu_reboot((int)bootflags, NULL); 1309#else /* _KERNEL */ 1310 db_printf("This command can only be used in-kernel.\n"); 1311#endif /* _KERNEL */ 1312} 1313 1314static void 1315db_sifting_cmd(db_expr_t addr, bool have_addr, 1316 db_expr_t count, const char *modif) 1317{ 1318 int mode, t; 1319 1320 t = db_read_token(); 1321 if (t == tSLASH) { 1322 t = db_read_token(); 1323 if (t != tIDENT) { 1324 bad_modifier: 1325 db_printf("Bad modifier\n"); 1326 db_flush_lex(); 1327 return; 1328 } 1329 if (!strcmp(db_tok_string, "F")) 1330 mode = 'F'; 1331 else 1332 goto bad_modifier; 1333 t = db_read_token(); 1334 } else 1335 mode = 0; 1336 1337 if (t == tIDENT) 1338 db_sifting(db_tok_string, mode); 1339 else { 1340 db_printf("Bad argument (non-string)\n"); 1341 db_flush_lex(); 1342 } 1343} 1344 1345static void 1346db_stack_trace_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 1347{ 1348 register const char *cp = modif; 1349 register char c; 1350 void (*pr)(const char *, ...); 1351 1352 pr = db_printf; 1353 while ((c = *cp++) != 0) 1354 if (c == 'l') 1355 pr = (void (*)(const char *, ...))printf; 1356 1357 if (count == -1) 1358 count = 65535; 1359 1360 db_stack_trace_print(addr, have_addr, count, modif, pr); 1361} 1362 1363static void 1364db_sync_cmd(db_expr_t addr, bool have_addr, 1365 db_expr_t count, const char *modif) 1366{ 1367#ifdef _KERNEL 1368 /* 1369 * We are leaving DDB, never to return upward. 1370 * Clear db_recover so that we can debug faults in functions 1371 * called from cpu_reboot. 1372 */ 1373 db_recover = 0; 1374 panicstr = "dump forced via kernel debugger"; 1375 cpu_reboot(RB_DUMP, NULL); 1376#else /* _KERNEL */ 1377 db_printf("This command can only be used in-kernel.\n"); 1378#endif /* _KERNEL */ 1379} 1380 1381/* 1382 * Describe what an address is 1383 */ 1384void 1385db_whatis_cmd(db_expr_t address, bool have_addr, 1386 db_expr_t count, const char *modif) 1387{ 1388 const uintptr_t addr = (uintptr_t)address; 1389 1390 db_lwp_whatis(addr, db_printf); 1391#ifdef _KERNEL /* XXX CRASH(8) */ 1392 pool_whatis(addr, db_printf); 1393 vmem_whatis(addr, db_printf); 1394 uvm_whatis(addr, db_printf); 1395 module_whatis(addr, db_printf); 1396#endif 1397} 1398