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