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