1 /* $NetBSD: db_command.c,v 1.181 2022/04/28 07:08:38 msaitoh Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 1997, 1998, 1999, 2002, 2009, 2019 5 * The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Adam Hamsik, and by Andrew Doran. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Mach Operating System 35 * Copyright (c) 1991,1990 Carnegie Mellon University 36 * All Rights Reserved. 37 * 38 * Permission to use, copy, modify and distribute this software and its 39 * documentation is hereby granted, provided that both the copyright 40 * notice and this permission notice appear in all copies of the 41 * software, derivative works or modified versions, and any portions 42 * thereof, and that both notices appear in supporting documentation. 43 * 44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 47 * 48 * Carnegie Mellon requests users of this software to return to 49 * 50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 51 * School of Computer Science 52 * Carnegie Mellon University 53 * Pittsburgh PA 15213-3890 54 * 55 * any improvements or extensions that they make and grant Carnegie the 56 * rights to redistribute these changes. 57 */ 58 59 /* 60 * Command dispatcher. 61 */ 62 63 #include <sys/cdefs.h> 64 __KERNEL_RCSID(0, "$NetBSD: db_command.c,v 1.181 2022/04/28 07:08:38 msaitoh Exp $"); 65 66 #ifdef _KERNEL_OPT 67 #include "opt_aio.h" 68 #include "opt_ddb.h" 69 #include "opt_fdt.h" 70 #include "opt_kgdb.h" 71 #include "opt_mqueue.h" 72 #include "opt_inet.h" 73 #include "opt_kernhist.h" 74 #include "opt_ddbparam.h" 75 #include "opt_multiprocessor.h" 76 #endif 77 78 #include <sys/param.h> 79 #include <sys/systm.h> 80 #include <sys/reboot.h> 81 #include <sys/device.h> 82 #include <sys/eventvar.h> 83 #include <sys/lwp.h> 84 #include <sys/mbuf.h> 85 #include <sys/namei.h> 86 #include <sys/pool.h> 87 #include <sys/proc.h> 88 #include <sys/vnode.h> 89 #include <sys/vmem.h> 90 #include <sys/lockdebug.h> 91 #include <sys/cpu.h> 92 #include <sys/buf.h> 93 #include <sys/module.h> 94 #include <sys/kernhist.h> 95 #include <sys/socketvar.h> 96 #include <sys/queue.h> 97 98 #include <dev/cons.h> 99 100 #include <ddb/ddb.h> 101 102 #include <uvm/uvm_extern.h> 103 #include <uvm/uvm_ddb.h> 104 105 #include <net/route.h> 106 107 #ifdef FDT 108 #include <dev/fdt/fdtvar.h> 109 #include <dev/fdt/fdt_ddb.h> 110 #endif 111 112 /* 113 * Results of command search. 114 */ 115 #define CMD_EXACT 0 116 #define CMD_PREFIX 1 117 #define CMD_NONE 2 118 #define CMD_AMBIGUOUS 3 119 120 /* 121 * Exported global variables 122 */ 123 bool db_cmd_loop_done; 124 label_t *db_recover; 125 db_addr_t db_dot; 126 db_addr_t db_last_addr; 127 db_addr_t db_prev; 128 db_addr_t db_next; 129 130 131 /* 132 * New DDB api for adding and removing commands uses three lists, because 133 * we use two types of commands 134 * a) standard commands without subcommands -> reboot 135 * b) show commands which are subcommands of show command -> show aio_jobs 136 * c) if defined machine specific commands 137 * 138 * ddb_add_cmd, ddb_rem_cmd use type (DDB_SHOW_CMD||DDB_BASE_CMD)argument to 139 * add them to representativ lists. 140 */ 141 142 static const struct db_command db_command_table[]; 143 static const struct db_command db_show_cmds[]; 144 145 #ifdef DB_MACHINE_COMMANDS 146 /* arch/<arch>/<arch>/db_interface.c */ 147 extern const struct db_command db_machine_command_table[]; 148 #endif 149 150 /* the global queue of all command tables */ 151 TAILQ_HEAD(db_cmd_tbl_en_head, db_cmd_tbl_en); 152 153 /* TAILQ entry used to register command tables */ 154 struct db_cmd_tbl_en { 155 const struct db_command *db_cmd; /* cmd table */ 156 TAILQ_ENTRY(db_cmd_tbl_en) db_cmd_next; 157 }; 158 159 /* head of base commands list */ 160 static struct db_cmd_tbl_en_head db_base_cmd_list = 161 TAILQ_HEAD_INITIALIZER(db_base_cmd_list); 162 static struct db_cmd_tbl_en db_base_cmd_builtins = 163 { .db_cmd = db_command_table }; 164 165 /* head of show commands list */ 166 static struct db_cmd_tbl_en_head db_show_cmd_list = 167 TAILQ_HEAD_INITIALIZER(db_show_cmd_list); 168 static struct db_cmd_tbl_en db_show_cmd_builtins = 169 { .db_cmd = db_show_cmds }; 170 171 /* head of machine commands list */ 172 static struct db_cmd_tbl_en_head db_mach_cmd_list = 173 TAILQ_HEAD_INITIALIZER(db_mach_cmd_list); 174 #ifdef DB_MACHINE_COMMANDS 175 static struct db_cmd_tbl_en db_mach_cmd_builtins = 176 { .db_cmd = db_machine_command_table }; 177 #endif 178 179 /* 180 * if 'ed' style: 'dot' is set at start of last item printed, 181 * and '+' points to next line. 182 * Otherwise: 'dot' points to next item, '..' points to last. 183 */ 184 static bool db_ed_style = true; 185 186 static void db_init_commands(void); 187 static int db_register_tbl_entry(uint8_t type, 188 struct db_cmd_tbl_en *list_ent); 189 static void db_cmd_list(const struct db_cmd_tbl_en_head *); 190 static int db_cmd_search(const char *, struct db_cmd_tbl_en_head *, 191 const struct db_command **); 192 static int db_cmd_search_table(const char *, const struct db_command *, 193 const struct db_command **); 194 static void db_cmd_search_failed(char *, int); 195 static const struct db_command *db_read_command(void); 196 static void db_command(const struct db_command **); 197 static void db_buf_print_cmd(db_expr_t, bool, db_expr_t, const char *); 198 static void db_event_print_cmd(db_expr_t, bool, db_expr_t, const char *); 199 static void db_fncall(db_expr_t, bool, db_expr_t, const char *); 200 static void db_help_print_cmd(db_expr_t, bool, db_expr_t, const char *); 201 static void db_lock_print_cmd(db_expr_t, bool, db_expr_t, const char *); 202 static void db_show_all_locks(db_expr_t, bool, db_expr_t, const char *); 203 static void db_show_lockstats(db_expr_t, bool, db_expr_t, const char *); 204 static void db_show_all_freelists(db_expr_t, bool, db_expr_t, const char *); 205 static void db_mount_print_cmd(db_expr_t, bool, db_expr_t, const char *); 206 static void db_show_all_mount(db_expr_t, bool, db_expr_t, const char *); 207 static void db_mbuf_print_cmd(db_expr_t, bool, db_expr_t, const char *); 208 static void db_kqueue_print_cmd(db_expr_t, bool, db_expr_t, const char *); 209 static void db_map_print_cmd(db_expr_t, bool, db_expr_t, const char *); 210 static void db_namecache_print_cmd(db_expr_t, bool, db_expr_t, 211 const char *); 212 static void db_object_print_cmd(db_expr_t, bool, db_expr_t, const char *); 213 static void db_page_print_cmd(db_expr_t, bool, db_expr_t, const char *); 214 static void db_show_all_pages(db_expr_t, bool, db_expr_t, const char *); 215 static void db_pool_print_cmd(db_expr_t, bool, db_expr_t, const char *); 216 static void db_reboot_cmd(db_expr_t, bool, db_expr_t, const char *); 217 static void db_sifting_cmd(db_expr_t, bool, db_expr_t, const char *); 218 static void db_socket_print_cmd(db_expr_t, bool, db_expr_t, const char *); 219 static void db_stack_trace_cmd(db_expr_t, bool, db_expr_t, const char *); 220 static void db_sync_cmd(db_expr_t, bool, db_expr_t, const char *); 221 static void db_whatis_cmd(db_expr_t, bool, db_expr_t, const char *); 222 static void db_uvmexp_print_cmd(db_expr_t, bool, db_expr_t, const char *); 223 #ifdef KERNHIST 224 static void db_kernhist_print_cmd(db_expr_t, bool, db_expr_t, const char *); 225 #endif 226 static void db_vnode_print_cmd(db_expr_t, bool, db_expr_t, const char *); 227 static void db_vnode_lock_print_cmd(db_expr_t, bool, db_expr_t, 228 const char *); 229 static void db_vmem_print_cmd(db_expr_t, bool, db_expr_t, const char *); 230 #ifdef FDT 231 static void db_fdt_print_cmd(db_expr_t, bool, db_expr_t, const char *); 232 #endif 233 234 static const struct db_command db_show_cmds[] = { 235 { DDB_ADD_CMD("all", NULL, 236 CS_COMPAT, NULL,NULL,NULL) }, 237 #ifdef AIO 238 { DDB_ADD_CMD("aio_jobs", db_show_aio_jobs, 0, 239 "Show aio jobs",NULL,NULL) }, 240 #endif 241 #ifdef _KERNEL 242 { DDB_ADD_CMD("breaks", db_listbreak_cmd, 0, 243 "Display all breaks.",NULL,NULL) }, 244 #endif 245 { DDB_ADD_CMD("buf", db_buf_print_cmd, 0, 246 "Print the struct buf at address.", "[/f] address",NULL) }, 247 /* added from all sub cmds */ 248 { DDB_ADD_CMD("callout", db_show_callout, 249 0 ,"List all used callout functions.",NULL,NULL) }, 250 { DDB_ADD_CMD("devices", db_show_all_devices, 0,NULL,NULL,NULL) }, 251 { DDB_ADD_CMD("event", db_event_print_cmd, 0, 252 "Print all the non-zero evcnt(9) event counters.", "[/fitm]",NULL) }, 253 #ifdef FDT 254 { DDB_ADD_CMD("fdt", db_fdt_print_cmd, 0, 255 "Show FDT information", NULL, NULL) }, 256 #endif 257 { DDB_ADD_CMD("files", db_show_files_cmd, 0, 258 "Print the files open by process at address", 259 "[/f] address", NULL) }, 260 { DDB_ADD_CMD("freelists", db_show_all_freelists, 261 0 ,"Show all freelists", NULL, NULL) }, 262 #ifdef KERNHIST 263 { DDB_ADD_CMD("kernhist", db_kernhist_print_cmd, 0, 264 "Print the UVM history logs.", 265 NULL,NULL) }, 266 #endif 267 /* added from all sub cmds */ 268 { DDB_ADD_CMD("locks", db_show_all_locks, 269 0 ,"Show all held locks", "[/t]", NULL) }, 270 { DDB_ADD_CMD("lock", db_lock_print_cmd, 0,NULL,NULL,NULL) }, 271 { DDB_ADD_CMD("lockstats", 272 db_show_lockstats, 0, 273 "Print statistics of locks", NULL, NULL) }, 274 { DDB_ADD_CMD("kqueue", db_kqueue_print_cmd, 0, 275 "Print the kqueue at address.", "[/f] address",NULL) }, 276 { DDB_ADD_CMD("map", db_map_print_cmd, 0, 277 "Print the vm_map at address.", "[/f] address",NULL) }, 278 { DDB_ADD_CMD("mbuf", db_mbuf_print_cmd, 0,NULL,NULL, 279 "-c prints all mbuf chains") }, 280 { DDB_ADD_CMD("module", db_show_module_cmd, 0, 281 "Print kernel modules", NULL, NULL) }, 282 { DDB_ADD_CMD("mount", db_show_all_mount, 0, 283 "Print all mount structures.", "[/f]", NULL) }, 284 { DDB_ADD_CMD("mount", db_mount_print_cmd, 0, 285 "Print the mount structure at address.", "[/f] address",NULL) }, 286 #ifdef MQUEUE 287 { DDB_ADD_CMD("mqueue", db_show_mqueue_cmd, 0, 288 "Print the message queues", NULL, NULL) }, 289 #endif 290 { DDB_ADD_CMD("ncache", db_namecache_print_cmd, 0, 291 "Dump the namecache list.", "address",NULL) }, 292 { DDB_ADD_CMD("object", db_object_print_cmd, 0, 293 "Print the vm_object at address.", "[/f] address",NULL) }, 294 { DDB_ADD_CMD("page", db_page_print_cmd, 0, 295 "Print the vm_page at address.", "[/f] address",NULL) }, 296 { DDB_ADD_CMD("pages", db_show_all_pages, 297 0 ,"List all used memory pages.",NULL,NULL) }, 298 { DDB_ADD_CMD("panic", db_show_panic, 0, 299 "Print the current panic string",NULL,NULL) }, 300 { DDB_ADD_CMD("pool", db_pool_print_cmd, 0, 301 "Print the pool at address.", "[/clp] address",NULL) }, 302 /* added from all sub cmds */ 303 { DDB_ADD_CMD("pools", db_show_all_pools, 304 0 ,"Show all pools",NULL,NULL) }, 305 { DDB_ADD_CMD("proc", db_show_proc, 306 0 ,"Print process information.",NULL,NULL) }, 307 /* added from all sub cmds */ 308 { DDB_ADD_CMD("procs", db_show_all_procs, 309 0 ,"List all processes.",NULL,NULL) }, 310 { DDB_ADD_CMD("registers", db_show_regs, 0, 311 "Display the register set.", "[/u]",NULL) }, 312 #if defined(INET) 313 { DDB_ADD_CMD("routes", db_show_routes, 0,NULL,NULL,NULL) }, 314 #endif 315 { DDB_ADD_CMD("sched_qs", db_show_sched_qs, 0, 316 "Print the state of the scheduler's run queues.", 317 NULL,NULL) }, 318 { DDB_ADD_CMD("socket", db_socket_print_cmd, 0,NULL,NULL,NULL) }, 319 { DDB_ADD_CMD("uvmexp", db_uvmexp_print_cmd, 0, 320 "Print a selection of UVM counters and statistics.", 321 NULL,NULL) }, 322 { DDB_ADD_CMD("vmem", db_vmem_print_cmd, 0, 323 "Print the vmem usage.", "address", NULL) }, 324 { DDB_ADD_CMD("vmems", db_show_all_vmems, 0, 325 "Show all vmems.", NULL, NULL) }, 326 { DDB_ADD_CMD("vnode", db_vnode_print_cmd, 0, 327 "Print the vnode at address.", "[/f] address",NULL) }, 328 { DDB_ADD_CMD("vnode_lock", db_vnode_lock_print_cmd, 0, 329 "Print the vnode having that address as v_lock.", 330 "[/f] address",NULL) }, 331 #ifdef _KERNEL 332 { DDB_ADD_CMD("watches", db_listwatch_cmd, 0, 333 "Display all watchpoints.", NULL,NULL) }, 334 #endif 335 { DDB_END_CMD }, 336 }; 337 338 static const struct db_command db_command_table[] = { 339 { DDB_ADD_CMD("b", db_breakpoint_cmd, 0, 340 "Set a breakpoint at address", "[/u] address[,count].",NULL) }, 341 { DDB_ADD_CMD("break", db_breakpoint_cmd, 0, 342 "Set a breakpoint at address", "[/u] address[,count].",NULL) }, 343 { DDB_ADD_CMD("bt", db_stack_trace_cmd, 0, 344 "Show backtrace.", "See help trace.",NULL) }, 345 { DDB_ADD_CMD("c", db_continue_cmd, 0, 346 "Continue execution.", "[/c]",NULL) }, 347 { DDB_ADD_CMD("call", db_fncall, CS_OWN, 348 "Call the function", "address[(expression[,...])]",NULL) }, 349 { DDB_ADD_CMD("callout", db_show_callout, 0, NULL, 350 NULL,NULL ) }, 351 { DDB_ADD_CMD("continue", db_continue_cmd, 0, 352 "Continue execution.", "[/c]",NULL) }, 353 { DDB_ADD_CMD("d", db_delete_cmd, 0, 354 "Delete a breakpoint.", "address | #number",NULL) }, 355 { DDB_ADD_CMD("delete", db_delete_cmd, 0, 356 "Delete a breakpoint.", "address | #number",NULL) }, 357 { DDB_ADD_CMD("dmesg", db_dmesg, 0, 358 "Show kernel message buffer.", "[count]",NULL) }, 359 { DDB_ADD_CMD("dwatch", db_deletewatch_cmd, 0, 360 "Delete the watchpoint.", "address",NULL) }, 361 { DDB_ADD_CMD("examine", db_examine_cmd, CS_SET_DOT, 362 "Display the address locations.", 363 "[/modifier] address[,count]",NULL) }, 364 { DDB_ADD_CMD("exit", db_continue_cmd, 0, 365 "Continue execution.", "[/c]",NULL) }, 366 { DDB_ADD_CMD("help", db_help_print_cmd, CS_OWN|CS_NOREPEAT, 367 "Display help about commands", 368 "Use other commands as arguments.",NULL) }, 369 { DDB_ADD_CMD("kill", db_kill_proc, CS_OWN, 370 "Send a signal to the process","pid[,signal_number]", 371 " pid:\t\t\tthe process id (may need 0t prefix for decimal)\n" 372 " signal_number:\tthe signal to send") }, 373 #ifdef KGDB 374 { DDB_ADD_CMD("kgdb", db_kgdb_cmd, 0, NULL,NULL,NULL) }, 375 #endif 376 { DDB_ADD_CMD("machine",NULL,CS_MACH, 377 "Architecture specific functions.",NULL,NULL) }, 378 { DDB_ADD_CMD("match", db_trace_until_matching_cmd,0, 379 "Stop at the matching return instruction.","See help next",NULL) }, 380 { DDB_ADD_CMD("next", db_trace_until_matching_cmd,0, 381 "Stop at the matching return instruction.","[/p]",NULL) }, 382 { DDB_ADD_CMD("p", db_print_cmd, 0, 383 "Print address according to the format.", 384 "[/axzodurc] address [address ...]",NULL) }, 385 { DDB_ADD_CMD("print", db_print_cmd, 0, 386 "Print address according to the format.", 387 "[/axzodurc] address [address ...]",NULL) }, 388 { DDB_ADD_CMD("ps", db_show_all_procs, 0, 389 "Print all processes.","See show all procs",NULL) }, 390 { DDB_ADD_CMD("quit", db_continue_cmd, 0, 391 "Continue execution.", "[/c]",NULL) }, 392 { DDB_ADD_CMD("reboot", db_reboot_cmd, CS_OWN, 393 "Reboot","0x1 RB_ASKNAME, 0x2 RB_SINGLE, 0x4 RB_NOSYNC, 0x8 RB_HALT," 394 "0x40 RB_KDB, 0x100 RB_DUMP, 0x808 RB_POWERDOWN",NULL) }, 395 { DDB_ADD_CMD("s", db_single_step_cmd, 0, 396 "Single-step count times.","[/p] [,count]",NULL) }, 397 { DDB_ADD_CMD("search", db_search_cmd, CS_OWN|CS_SET_DOT, 398 "Search memory from address for value.", 399 "[/bhl] address value [mask] [,count]",NULL) }, 400 { DDB_ADD_CMD("set", db_set_cmd, CS_OWN, 401 "Set the named variable","$variable [=] expression",NULL) }, 402 { DDB_ADD_CMD("show", NULL, CS_SHOW, 403 "Show kernel stats.", NULL,NULL) }, 404 { DDB_ADD_CMD("sifting", db_sifting_cmd, CS_OWN, 405 "Search the symbol tables ","[/F] string",NULL) }, 406 { DDB_ADD_CMD("step", db_single_step_cmd, 0, 407 "Single-step count times.","[/p] [,count]",NULL) }, 408 { DDB_ADD_CMD("sync", db_sync_cmd, CS_OWN, 409 "Force a crash dump, and then reboot.",NULL,NULL) }, 410 { DDB_ADD_CMD("trace", db_stack_trace_cmd, 0, 411 "Stack trace from frame-address.", 412 "[/u[l]] [frame-address][,count]",NULL) }, 413 { DDB_ADD_CMD("until", db_trace_until_call_cmd,0, 414 "Stop at the next call or return instruction.","[/p]",NULL) }, 415 { DDB_ADD_CMD("w", db_write_cmd, CS_MORE|CS_SET_DOT, 416 "Write the expressions at succeeding locations.", 417 "[/bhl] address expression [expression ...]",NULL) }, 418 { DDB_ADD_CMD("watch", db_watchpoint_cmd, CS_MORE, 419 "Set a watchpoint for a region. ","address[,size]",NULL) }, 420 { DDB_ADD_CMD("whatis", db_whatis_cmd, 0, 421 "Describe what an address is", "address", NULL) }, 422 { DDB_ADD_CMD("write", db_write_cmd, CS_MORE|CS_SET_DOT, 423 "Write the expressions at succeeding locations.", 424 "[/bhl] address expression [expression ...]",NULL) }, 425 { DDB_ADD_CMD("x", db_examine_cmd, CS_SET_DOT, 426 "Display the address locations.", 427 "[/modifier] address[,count]",NULL) }, 428 { DDB_END_CMD }, 429 }; 430 431 static const struct db_command *db_last_command = NULL; 432 #if defined(DDB_COMMANDONENTER) 433 char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ___STRING(DDB_COMMANDONENTER); 434 #else /* defined(DDB_COMMANDONENTER) */ 435 char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ""; 436 #endif /* defined(DDB_COMMANDONENTER) */ 437 #define DB_LINE_SEP ';' 438 439 /* 440 * Execute commandlist after ddb start 441 * This function goes through the command list created from commands and ';' 442 */ 443 static void 444 db_execute_commandlist(const char *cmdlist) 445 { 446 const char *cmd = cmdlist; 447 const struct db_command *dummy = NULL; 448 449 while (*cmd != '\0') { 450 const char *ep = cmd; 451 452 while (*ep != '\0' && *ep != DB_LINE_SEP) { 453 ep++; 454 } 455 db_set_line(cmd, ep); 456 db_command(&dummy); 457 cmd = ep; 458 if (*cmd == DB_LINE_SEP) { 459 cmd++; 460 } 461 } 462 } 463 464 /* Initialize ddb command tables */ 465 void 466 db_init_commands(void) 467 { 468 static bool done = false; 469 470 if (done) return; 471 done = true; 472 473 /* register command tables */ 474 (void)db_register_tbl_entry(DDB_BASE_CMD, &db_base_cmd_builtins); 475 #ifdef DB_MACHINE_COMMANDS 476 (void)db_register_tbl_entry(DDB_MACH_CMD, &db_mach_cmd_builtins); 477 #endif 478 (void)db_register_tbl_entry(DDB_SHOW_CMD, &db_show_cmd_builtins); 479 } 480 481 482 /* 483 * Add command table to the specified list 484 * Arg: 485 * int type specifies type of command table DDB_SHOW_CMD|DDB_BASE_CMD|DDB_MAC_CMD 486 * *cmd_tbl pointer to static allocated db_command table 487 * 488 * Command table must be NULL terminated array of struct db_command 489 */ 490 int 491 db_register_tbl(uint8_t type, const struct db_command *cmd_tbl) 492 { 493 struct db_cmd_tbl_en *list_ent; 494 495 /* empty list - ignore */ 496 if (cmd_tbl->name == 0) 497 return 0; 498 499 /* force builtin commands to be registered first */ 500 db_init_commands(); 501 502 /* now create a list entry for this table */ 503 list_ent = db_zalloc(sizeof(*list_ent)); 504 if (list_ent == NULL) 505 return ENOMEM; 506 list_ent->db_cmd=cmd_tbl; 507 508 /* and register it */ 509 return db_register_tbl_entry(type, list_ent); 510 } 511 512 static int 513 db_register_tbl_entry(uint8_t type, struct db_cmd_tbl_en *list_ent) 514 { 515 struct db_cmd_tbl_en_head *list; 516 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 ENOENT; 529 } 530 531 TAILQ_INSERT_TAIL(list, list_ent, db_cmd_next); 532 533 return 0; 534 } 535 536 /* 537 * Remove command table specified with db_cmd address == cmd_tbl 538 */ 539 int 540 db_unregister_tbl(uint8_t type,const struct db_command *cmd_tbl) 541 { 542 struct db_cmd_tbl_en *list_ent; 543 struct db_cmd_tbl_en_head *list; 544 545 /* find list on which the entry should live */ 546 switch (type) { 547 case DDB_BASE_CMD: 548 list=&db_base_cmd_list; 549 break; 550 case DDB_SHOW_CMD: 551 list=&db_show_cmd_list; 552 break; 553 case DDB_MACH_CMD: 554 list=&db_mach_cmd_list; 555 break; 556 default: 557 return EINVAL; 558 } 559 560 TAILQ_FOREACH (list_ent, list, db_cmd_next) { 561 if (list_ent->db_cmd == cmd_tbl){ 562 TAILQ_REMOVE(list, 563 list_ent, db_cmd_next); 564 db_free(list_ent, sizeof(*list_ent)); 565 return 0; 566 } 567 } 568 return ENOENT; 569 } 570 571 #ifndef _KERNEL 572 #define cnpollc(c) __nothing 573 #endif 574 575 /* 576 * This function is called via db_trap() or directly from 577 * machine trap code. 578 */ 579 void 580 db_command_loop(void) 581 { 582 label_t db_jmpbuf; 583 label_t *savejmp; 584 585 /* 586 * Initialize 'prev' and 'next' to dot. 587 */ 588 db_prev = db_dot; 589 db_next = db_dot; 590 591 db_cmd_loop_done = false; 592 593 /* Init default command tables add machine, base, 594 show command tables to the list */ 595 db_init_commands(); 596 597 /* save context for return from ddb */ 598 savejmp = db_recover; 599 db_recover = &db_jmpbuf; 600 601 /* 602 * Execute default ddb start commands only if this is the 603 * first entry into DDB, in case the start commands fault 604 * and we recurse into here. 605 */ 606 if (savejmp == NULL && db_cmd_on_enter[0] != '\0') { 607 if (setjmp(&db_jmpbuf) == 0) 608 db_execute_commandlist(db_cmd_on_enter); 609 } 610 611 (void) setjmp(&db_jmpbuf); 612 while (!db_cmd_loop_done) { 613 if (db_print_position() != 0) 614 db_printf("\n"); 615 db_output_line = 0; 616 cnpollc(1); 617 (void) db_read_line(); 618 cnpollc(0); 619 db_command(&db_last_command); 620 } 621 622 db_recover = savejmp; 623 } 624 625 /* 626 * Search command table for command prefix 627 */ 628 static int 629 db_cmd_search_table(const char *name, 630 const struct db_command *table, 631 const struct db_command **cmdp) 632 { 633 634 const struct db_command *cmd; 635 int result; 636 637 result = CMD_NONE; 638 *cmdp = NULL; 639 640 for (cmd = table; cmd->name != 0; cmd++) { 641 const char *lp; 642 const char *rp; 643 644 lp = name; 645 rp = cmd->name; 646 while (*lp != '\0' && *lp == *rp) { 647 rp++; 648 lp++; 649 } 650 651 if (*lp != '\0') /* mismatch or extra chars in name */ 652 continue; 653 654 if (*rp == '\0') { /* exact match */ 655 *cmdp = cmd; 656 return (CMD_EXACT); 657 } 658 659 /* prefix match: end of name, not end of command */ 660 if (result == CMD_NONE) { 661 result = CMD_PREFIX; 662 *cmdp = cmd; 663 } 664 else if (result == CMD_PREFIX) { 665 result = CMD_AMBIGUOUS; 666 *cmdp = NULL; 667 } 668 } 669 670 return (result); 671 } 672 673 674 /* 675 * Search list of command tables for command 676 */ 677 static int 678 db_cmd_search(const char *name, 679 struct db_cmd_tbl_en_head *list_head, 680 const struct db_command **cmdp) 681 { 682 struct db_cmd_tbl_en *list_ent; 683 const struct db_command *found_command; 684 bool accept_prefix_match; 685 int result; 686 687 result = CMD_NONE; 688 found_command = NULL; 689 accept_prefix_match = true; 690 691 TAILQ_FOREACH(list_ent, list_head, db_cmd_next) { 692 const struct db_command *cmd; 693 int found; 694 695 found = db_cmd_search_table(name, list_ent->db_cmd, &cmd); 696 if (found == CMD_EXACT) { 697 result = CMD_EXACT; 698 found_command = cmd; 699 break; 700 } 701 702 if (found == CMD_PREFIX) { 703 if (accept_prefix_match) { 704 /* 705 * Continue search, but note current result 706 * in case we won't find anything else. 707 */ 708 accept_prefix_match = false; 709 result = CMD_PREFIX; 710 found_command = cmd; 711 } else { 712 /* 713 * Watch out for globally ambiguous 714 * prefix match that is not locally 715 * ambiguous - with one match in one 716 * table and another match(es) in 717 * another table. 718 */ 719 result = CMD_AMBIGUOUS; 720 found_command = NULL; 721 } 722 } 723 else if (found == CMD_AMBIGUOUS) { 724 accept_prefix_match = false; 725 result = CMD_AMBIGUOUS; 726 found_command = NULL; 727 } 728 } 729 730 *cmdp = found_command; 731 return result; 732 } 733 734 static void 735 db_cmd_search_failed(char *name, int search_result) 736 { 737 if (search_result == CMD_NONE) 738 db_printf("No such command: %s\n", name); 739 else 740 db_printf("Ambiguous command: %s\n", name); 741 } 742 743 744 /* 745 * List commands to the console. 746 */ 747 static void 748 db_cmd_list(const struct db_cmd_tbl_en_head *list) 749 { 750 751 struct db_cmd_tbl_en *list_ent; 752 const struct db_command *table; 753 size_t i, j, w, columns, lines, numcmds, width=0; 754 const char *p; 755 756 TAILQ_FOREACH(list_ent,list,db_cmd_next) { 757 table = list_ent->db_cmd; 758 for (i = 0; table[i].name != NULL; i++) { 759 w = strlen(table[i].name); 760 if (w > width) 761 width = w; 762 } 763 } 764 765 width = DB_NEXT_TAB(width); 766 767 columns = db_max_width / width; 768 if (columns == 0) 769 columns = 1; 770 771 TAILQ_FOREACH(list_ent,list,db_cmd_next) { 772 table = list_ent->db_cmd; 773 774 for (numcmds = 0; table[numcmds].name != NULL; numcmds++) 775 ; 776 lines = (numcmds + columns - 1) / columns; 777 778 for (i = 0; i < lines; i++) { 779 for (j = 0; j < columns; j++) { 780 p = table[j * lines + i].name; 781 if (p) 782 db_printf("%s", p); 783 if (j * lines + i + lines >= numcmds) { 784 db_putchar('\n'); 785 break; 786 } 787 if (p) { 788 w = strlen(p); 789 while (w < width) { 790 w = DB_NEXT_TAB(w); 791 db_putchar('\t'); 792 } 793 } 794 } 795 } 796 } 797 return; 798 } 799 800 /* 801 * Read complete command with all subcommands, starting with current 802 * db_tok_string. If subcommand is missing, print the list of all 803 * subcommands. If command/subcommand is not found, print an error 804 * message. Returns pointer to "leaf" command or NULL. 805 */ 806 static const struct db_command * 807 db_read_command(void) 808 { 809 const struct db_command *command; 810 struct db_cmd_tbl_en_head *list; 811 int found; 812 int t; 813 814 list = &db_base_cmd_list; 815 do { 816 found = db_cmd_search(db_tok_string, list, &command); 817 if (command == NULL) { 818 db_cmd_search_failed(db_tok_string, found); 819 db_flush_lex(); 820 return NULL; 821 } 822 823 if (command->flag == CS_SHOW) 824 list = &db_show_cmd_list; 825 else if (command->flag == CS_MACH) 826 list = &db_mach_cmd_list; 827 else if (command->flag == CS_COMPAT) 828 /* same list */; 829 else 830 break; /* expect no more subcommands */ 831 832 t = db_read_token(); /* read subcommand */ 833 if (t != tIDENT) { 834 /* if none given - just print all of them */ 835 db_cmd_list(list); 836 db_flush_lex(); 837 return NULL; 838 } 839 } while (list != NULL); 840 841 return command; 842 } 843 844 /* 845 * Parse command line and execute appropriate function. 846 */ 847 static void 848 db_command(const struct db_command **last_cmdp) 849 { 850 static db_expr_t last_count = 0; 851 852 int t; 853 const struct db_command *command; 854 db_expr_t addr, count; 855 bool have_addr; 856 char modif[TOK_STRING_SIZE]; 857 858 command = NULL; 859 have_addr = false; 860 count = -1; 861 862 t = db_read_token(); 863 if ((t == tEOL) || (t == tCOMMA)) { 864 /* 865 * An empty line repeats last command, at 'next'. 866 * Only a count repeats the last command with the new count. 867 */ 868 command = *last_cmdp; 869 870 if (!command) 871 return; 872 873 addr = (db_expr_t)db_next; 874 if (t == tCOMMA) { 875 if (!db_expression(&count)) { 876 db_printf("Count missing\n"); 877 db_flush_lex(); 878 return; 879 } 880 } else 881 count = last_count; 882 modif[0] = '\0'; 883 db_skip_to_eol(); 884 885 } else if (t == tEXCL) { 886 db_fncall(0, 0, 0, NULL); 887 return; 888 889 } else if (t != tIDENT) { 890 db_printf("?\n"); 891 db_flush_lex(); 892 return; 893 894 } else { 895 896 command = db_read_command(); 897 if (command == NULL) 898 return; 899 900 if ((command->flag & CS_OWN) == 0) { 901 902 /* 903 * Standard syntax: 904 * command [/modifier] [addr] [,count] 905 */ 906 t = db_read_token(); /* get modifier */ 907 if (t == tSLASH) { 908 t = db_read_token(); 909 if (t != tIDENT) { 910 db_printf("Bad modifier\n"); 911 db_flush_lex(); 912 return; 913 } 914 /* save modifier */ 915 strlcpy(modif, db_tok_string, sizeof(modif)); 916 917 } else { 918 db_unread_token(t); 919 modif[0] = '\0'; 920 } 921 922 if (db_expression(&addr)) { /*get address*/ 923 db_dot = (db_addr_t) addr; 924 db_last_addr = db_dot; 925 have_addr = true; 926 } else { 927 addr = (db_expr_t) db_dot; 928 } 929 930 t = db_read_token(); 931 if (t == tCOMMA) { /*Get count*/ 932 if (!db_expression(&count)) { 933 db_printf("Count missing\n"); 934 db_flush_lex(); 935 return; 936 } 937 } else { 938 db_unread_token(t); 939 } 940 if ((command->flag & CS_MORE) == 0) { 941 db_skip_to_eol(); 942 } 943 } 944 } 945 946 if (command != NULL && command->flag & CS_NOREPEAT) { 947 *last_cmdp = NULL; 948 last_count = 0; 949 } else { 950 *last_cmdp = command; 951 last_count = count; 952 } 953 954 955 if (command != NULL) { 956 /* 957 * Execute the command. 958 */ 959 if (command->fcn != NULL) 960 (*command->fcn)(addr, have_addr, count, modif); 961 962 if (command->flag & CS_SET_DOT) { 963 /* 964 * If command changes dot, set dot to 965 * previous address displayed (if 'ed' style). 966 */ 967 if (db_ed_style) 968 db_dot = db_prev; 969 else 970 db_dot = db_next; 971 } else { 972 /* 973 * If command does not change dot, 974 * set 'next' location to be the same. 975 */ 976 db_next = db_dot; 977 } 978 } 979 } 980 981 /* 982 * Print help for commands 983 */ 984 static void 985 db_help_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 986 const char *modif) 987 { 988 const struct db_command *command; 989 int t; 990 991 t = db_read_token(); 992 993 /* is there another command after the "help"? */ 994 if (t != tIDENT) { 995 /* print base commands */ 996 db_cmd_list(&db_base_cmd_list); 997 return; 998 } 999 1000 command = db_read_command(); 1001 if (command == NULL) 1002 return; 1003 1004 #ifdef DDB_VERBOSE_HELP 1005 db_printf("Command: %s\n", command->name); 1006 if (command->cmd_descr != NULL) 1007 db_printf(" Description: %s\n", command->cmd_descr); 1008 if (command->cmd_arg != NULL) 1009 db_printf(" Arguments: %s\n", command->cmd_arg); 1010 if (command->cmd_arg_help != NULL) 1011 db_printf(" Arguments description:\n%s\n", 1012 command->cmd_arg_help); 1013 if ((command->cmd_arg == NULL) && (command->cmd_descr == NULL)) 1014 db_printf(" No help message.\n"); 1015 #endif 1016 1017 db_skip_to_eol(); 1018 } 1019 1020 /*ARGSUSED*/ 1021 static void 1022 db_kqueue_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 1023 const char *modif) 1024 { 1025 #ifdef _KERNEL 1026 bool full = false; 1027 1028 if (modif[0] == 'f') 1029 full = true; 1030 1031 if (have_addr == false) { 1032 db_printf("%s: must specify kqueue address\n", __func__); 1033 return; 1034 } 1035 1036 kqueue_printit((struct kqueue *)(uintptr_t) addr, full, db_printf); 1037 #else 1038 db_kernelonly(); 1039 #endif /* XXX CRASH(8) */ 1040 } 1041 1042 /*ARGSUSED*/ 1043 static void 1044 db_map_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 1045 const char *modif) 1046 { 1047 #ifdef _KERNEL 1048 bool full = false; 1049 1050 if (modif[0] == 'f') 1051 full = true; 1052 1053 if (have_addr == false) 1054 addr = (db_expr_t)(uintptr_t)db_read_ptr("kernel_map"); 1055 1056 uvm_map_printit((struct vm_map *)(uintptr_t) addr, full, db_printf); 1057 #else 1058 db_kernelonly(); 1059 #endif /* XXX CRASH(8) */ 1060 } 1061 1062 /*ARGSUSED*/ 1063 static void 1064 db_object_print_cmd(db_expr_t addr, bool have_addr, 1065 db_expr_t count, const char *modif) 1066 { 1067 #ifdef _KERNEL /* XXX CRASH(8) */ 1068 bool full = false; 1069 1070 if (modif[0] == 'f') 1071 full = true; 1072 1073 uvm_object_printit((struct uvm_object *)(uintptr_t) addr, full, 1074 db_printf); 1075 #else 1076 db_kernelonly(); 1077 #endif 1078 } 1079 1080 /*ARGSUSED*/ 1081 static void 1082 db_page_print_cmd(db_expr_t addr, bool have_addr, 1083 db_expr_t count, const char *modif) 1084 { 1085 #ifdef _KERNEL /* XXX CRASH(8) */ 1086 bool full = false; 1087 1088 if (modif[0] == 'f') 1089 full = true; 1090 1091 uvm_page_printit((struct vm_page *)(uintptr_t) addr, full, db_printf); 1092 #else 1093 db_kernelonly(); 1094 #endif 1095 } 1096 1097 /*ARGSUSED*/ 1098 static void 1099 db_show_all_pages(db_expr_t addr, bool have_addr, 1100 db_expr_t count, const char *modif) 1101 { 1102 1103 #ifdef _KERNEL /* XXX CRASH(8) */ 1104 uvm_page_printall(db_printf); 1105 #else 1106 db_kernelonly(); 1107 #endif 1108 } 1109 1110 /*ARGSUSED*/ 1111 static void 1112 db_buf_print_cmd(db_expr_t addr, bool have_addr, 1113 db_expr_t count, const char *modif) 1114 { 1115 #ifdef _KERNEL /* XXX CRASH(8) */ 1116 bool full = false; 1117 1118 if (modif[0] == 'f') 1119 full = true; 1120 1121 vfs_buf_print((struct buf *)(uintptr_t) addr, full, db_printf); 1122 #else 1123 db_kernelonly(); 1124 #endif 1125 } 1126 1127 /*ARGSUSED*/ 1128 static void 1129 db_event_print_cmd(db_expr_t addr, bool have_addr, 1130 db_expr_t count, const char *modif) 1131 { 1132 bool showzero = false; 1133 bool showall = true; 1134 bool showintr = false; 1135 bool showtrap = false; 1136 bool showmisc = false; 1137 struct evcnt ev, *evp; 1138 char buf[80]; 1139 int i; 1140 1141 i = 0; 1142 while (modif[i]) { 1143 switch (modif[i]) { 1144 case 'f': 1145 showzero = true; 1146 break; 1147 case 'i': 1148 showintr = true; 1149 showall = false; 1150 break; 1151 case 't': 1152 showtrap = true; 1153 showall = false; 1154 break; 1155 case 'm': 1156 showmisc = true; 1157 showall = false; 1158 break; 1159 } 1160 i++; 1161 } 1162 1163 if (showall) 1164 showmisc = showintr = showtrap = true; 1165 1166 evp = (struct evcnt *)db_read_ptr("allevents"); 1167 while (evp != NULL) { 1168 db_read_bytes((db_addr_t)evp, sizeof(ev), (char *)&ev); 1169 evp = ev.ev_list.tqe_next; 1170 if (ev.ev_count == 0 && !showzero) 1171 continue; 1172 if (ev.ev_type == EVCNT_TYPE_INTR && !showintr) 1173 continue; 1174 if (ev.ev_type == EVCNT_TYPE_TRAP && !showtrap) 1175 continue; 1176 if (ev.ev_type == EVCNT_TYPE_MISC && !showmisc) 1177 continue; 1178 db_read_bytes((db_addr_t)ev.ev_group, ev.ev_grouplen + 1, buf); 1179 db_printf("evcnt type %d: %s ", ev.ev_type, buf); 1180 db_read_bytes((db_addr_t)ev.ev_name, ev.ev_namelen + 1, buf); 1181 db_printf("%s = %lld\n", buf, (long long)ev.ev_count); 1182 } 1183 } 1184 1185 /*ARGSUSED*/ 1186 static void 1187 db_vnode_print_cmd(db_expr_t addr, bool have_addr, 1188 db_expr_t count, const char *modif) 1189 { 1190 #ifdef _KERNEL /* XXX CRASH(8) */ 1191 bool full = false; 1192 1193 if (modif[0] == 'f') 1194 full = true; 1195 1196 vfs_vnode_print((struct vnode *)(uintptr_t) addr, full, db_printf); 1197 #else 1198 db_kernelonly(); 1199 #endif 1200 } 1201 1202 /*ARGSUSED*/ 1203 static void 1204 db_vnode_lock_print_cmd(db_expr_t addr, bool have_addr, 1205 db_expr_t count, const char *modif) 1206 { 1207 #ifdef _KERNEL /* XXX CRASH(8) */ 1208 bool full = false; 1209 1210 if (modif[0] == 'f') 1211 full = true; 1212 1213 vfs_vnode_lock_print((struct vnode *)(uintptr_t) addr, full, db_printf); 1214 #else 1215 db_kernelonly(); 1216 #endif 1217 } 1218 1219 /*ARGSUSED*/ 1220 static void 1221 db_vmem_print_cmd(db_expr_t addr, bool have_addr, 1222 db_expr_t count, const char *modif) 1223 { 1224 1225 #ifdef _KERNEL /* XXX CRASH(8) */ 1226 vmem_print((uintptr_t) addr, modif, db_printf); 1227 #else 1228 db_kernelonly(); 1229 #endif 1230 } 1231 1232 static void 1233 db_mount_print_cmd(db_expr_t addr, bool have_addr, 1234 db_expr_t count, const char *modif) 1235 { 1236 #ifdef _KERNEL /* XXX CRASH(8) */ 1237 bool full = false; 1238 1239 if (modif[0] == 'f') 1240 full = true; 1241 1242 vfs_mount_print((struct mount *)(uintptr_t) addr, full, db_printf); 1243 #endif 1244 } 1245 1246 static void 1247 db_show_all_mount(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 1248 { 1249 #ifdef _KERNEL /* XXX CRASH(8) */ 1250 bool full = false; 1251 1252 if (modif[0] == 'f') 1253 full = true; 1254 1255 vfs_mount_print_all(full, db_printf); 1256 #else 1257 db_kernelonly(); 1258 #endif 1259 } 1260 1261 /*ARGSUSED*/ 1262 static void 1263 db_mbuf_print_cmd(db_expr_t addr, bool have_addr, 1264 db_expr_t count, const char *modif) 1265 { 1266 1267 #ifdef _KERNEL /* XXX CRASH(8) */ 1268 m_print((const struct mbuf *)(uintptr_t) addr, modif, db_printf); 1269 #else 1270 db_kernelonly(); 1271 #endif 1272 } 1273 1274 /*ARGSUSED*/ 1275 static void 1276 db_pool_print_cmd(db_expr_t addr, bool have_addr, 1277 db_expr_t count, const char *modif) 1278 { 1279 1280 #ifdef _KERNEL /* XXX CRASH(8) */ 1281 pool_printit((struct pool *)(uintptr_t) addr, modif, db_printf); 1282 #else 1283 db_kernelonly(); 1284 #endif 1285 } 1286 1287 /*ARGSUSED*/ 1288 static void 1289 db_namecache_print_cmd(db_expr_t addr, bool have_addr, 1290 db_expr_t count, const char *modif) 1291 { 1292 1293 #ifdef _KERNEL /* XXX CRASH(8) */ 1294 namecache_print((struct vnode *)(uintptr_t) addr, db_printf); 1295 #else 1296 db_kernelonly(); 1297 #endif 1298 } 1299 1300 /*ARGSUSED*/ 1301 static void 1302 db_uvmexp_print_cmd(db_expr_t addr, bool have_addr, 1303 db_expr_t count, const char *modif) 1304 { 1305 1306 #ifdef _KERNEL /* XXX CRASH(8) */ 1307 uvmexp_print(db_printf); 1308 #else 1309 db_kernelonly(); 1310 #endif 1311 } 1312 1313 /*ARGSUSED */ 1314 static void 1315 db_socket_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 1316 const char *modif) 1317 { 1318 1319 #ifdef _KERNEL /* XXX CRASH(8) */ 1320 socket_print(modif, db_printf); 1321 #else 1322 db_kernelonly(); 1323 #endif 1324 } 1325 1326 #ifdef KERNHIST 1327 /*ARGSUSED*/ 1328 static void 1329 db_kernhist_print_cmd(db_expr_t addr, bool have_addr, 1330 db_expr_t count, const char *modif) 1331 { 1332 1333 if (!have_addr) 1334 addr = 0; 1335 1336 if (count == -1) 1337 count = 0; 1338 1339 kernhist_print((void *)(uintptr_t)addr, count, modif, db_printf); 1340 } 1341 #endif 1342 1343 /*ARGSUSED*/ 1344 static void 1345 db_lock_print_cmd(db_expr_t addr, bool have_addr, 1346 db_expr_t count, const char *modif) 1347 { 1348 1349 lockdebug_lock_print(have_addr ? (void *)(uintptr_t)addr : NULL, 1350 db_printf); 1351 } 1352 1353 static void 1354 db_show_all_locks(db_expr_t addr, bool have_addr, 1355 db_expr_t count, const char *modif) 1356 { 1357 1358 #ifdef _KERNEL /* XXX CRASH(8) */ 1359 lockdebug_show_all_locks(db_printf, modif); 1360 #else 1361 db_kernelonly(); 1362 #endif 1363 } 1364 1365 static void 1366 db_show_all_freelists(db_expr_t addr, bool have_addr, 1367 db_expr_t count, const char *modif) 1368 { 1369 1370 #ifdef _KERNEL /* XXX CRASH(8) */ 1371 uvm_page_print_freelists(db_printf); 1372 #else 1373 db_kernelonly(); 1374 #endif 1375 } 1376 1377 static void 1378 db_show_lockstats(db_expr_t addr, bool have_addr, 1379 db_expr_t count, const char *modif) 1380 { 1381 1382 #ifdef _KERNEL /* XXX CRASH(8) */ 1383 lockdebug_show_lockstats(db_printf); 1384 #else 1385 db_kernelonly(); 1386 #endif 1387 } 1388 1389 #ifdef FDT 1390 /*ARGSUSED*/ 1391 static void 1392 db_fdt_print_cmd(db_expr_t addr, bool have_addr, 1393 db_expr_t count, const char *modif) 1394 { 1395 #ifdef _KERNEL /* XXX CRASH(8) */ 1396 bool full = false; 1397 1398 if (modif[0] == 'f') 1399 full = true; 1400 1401 fdt_print(have_addr ? (void *)(uintptr_t)addr : fdtbus_get_data(), 1402 full, db_printf); 1403 #else 1404 db_kernelonly(); 1405 #endif 1406 } 1407 #endif 1408 1409 /* 1410 * Call random function: 1411 * !expr(arg,arg,arg) 1412 */ 1413 /*ARGSUSED*/ 1414 static void 1415 db_fncall(db_expr_t addr, bool have_addr, 1416 db_expr_t count, const char *modif) 1417 { 1418 #ifdef _KERNEL 1419 db_expr_t fn_addr; 1420 #define MAXARGS 11 1421 db_expr_t args[MAXARGS]; 1422 int nargs = 0; 1423 db_expr_t retval; 1424 db_expr_t (*func)(db_expr_t, ...); 1425 int t; 1426 1427 if (!db_expression(&fn_addr)) { 1428 db_printf("Bad function\n"); 1429 db_flush_lex(); 1430 return; 1431 } 1432 func = (db_expr_t (*)(db_expr_t, ...))(uintptr_t) fn_addr; 1433 1434 t = db_read_token(); 1435 if (t == tLPAREN) { 1436 if (db_expression(&args[0])) { 1437 nargs++; 1438 while ((t = db_read_token()) == tCOMMA) { 1439 if (nargs == MAXARGS) { 1440 db_printf("Too many arguments\n"); 1441 db_flush_lex(); 1442 return; 1443 } 1444 if (!db_expression(&args[nargs])) { 1445 db_printf("Argument missing\n"); 1446 db_flush_lex(); 1447 return; 1448 } 1449 nargs++; 1450 } 1451 db_unread_token(t); 1452 } 1453 if (db_read_token() != tRPAREN) { 1454 db_printf("?\n"); 1455 db_flush_lex(); 1456 return; 1457 } 1458 } 1459 db_skip_to_eol(); 1460 1461 while (nargs < MAXARGS) { 1462 args[nargs++] = 0; 1463 } 1464 1465 retval = (*func)(args[0], args[1], args[2], args[3], args[4], 1466 args[5], args[6], args[7], args[8], args[9]); 1467 db_printf("%s\n", db_num_to_str(retval)); 1468 #else /* _KERNEL */ 1469 db_kernelonly(); 1470 #endif /* _KERNEL */ 1471 } 1472 1473 static void 1474 db_reboot_cmd(db_expr_t addr, bool have_addr, 1475 db_expr_t count, const char *modif) 1476 { 1477 #ifdef _KERNEL 1478 db_expr_t bootflags; 1479 1480 /* Flags, default to RB_AUTOBOOT */ 1481 if (!db_expression(&bootflags)) 1482 bootflags = (db_expr_t)RB_AUTOBOOT; 1483 if (db_read_token() != tEOL) { 1484 db_error("?\n"); 1485 /*NOTREACHED*/ 1486 } 1487 /* 1488 * We are leaving DDB, never to return upward. 1489 * Clear db_recover so that we can debug faults in functions 1490 * called from cpu_reboot. 1491 */ 1492 db_recover = 0; 1493 /* Avoid all mutex errors */ 1494 lockdebug_dismiss(); 1495 panicstr = "reboot forced via kernel debugger"; 1496 /* Make it possible to break into the debugger again */ 1497 spl0(); 1498 kern_reboot((int)bootflags, NULL); 1499 #else /* _KERNEL */ 1500 db_kernelonly(); 1501 #endif /* _KERNEL */ 1502 } 1503 1504 static void 1505 db_sifting_cmd(db_expr_t addr, bool have_addr, 1506 db_expr_t count, const char *modif) 1507 { 1508 int mode, t; 1509 1510 t = db_read_token(); 1511 if (t == tSLASH) { 1512 t = db_read_token(); 1513 if (t != tIDENT) { 1514 bad_modifier: 1515 db_printf("Bad modifier\n"); 1516 db_flush_lex(); 1517 return; 1518 } 1519 if (!strcmp(db_tok_string, "F")) 1520 mode = 'F'; 1521 else 1522 goto bad_modifier; 1523 t = db_read_token(); 1524 } else 1525 mode = 0; 1526 1527 if (t == tIDENT) 1528 db_sifting(db_tok_string, mode); 1529 else { 1530 db_printf("Bad argument (non-string)\n"); 1531 db_flush_lex(); 1532 } 1533 } 1534 1535 static void 1536 db_stack_trace_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 1537 { 1538 register const char *cp = modif; 1539 register char c; 1540 void (*pr)(const char *, ...); 1541 1542 pr = db_printf; 1543 while ((c = *cp++) != 0) 1544 if (c == 'l') 1545 pr = (void (*)(const char *, ...))printf; 1546 1547 if (count == -1) 1548 count = 65535; 1549 1550 db_stack_trace_print(addr, have_addr, count, modif, pr); 1551 } 1552 1553 static void 1554 db_sync_cmd(db_expr_t addr, bool have_addr, 1555 db_expr_t count, const char *modif) 1556 { 1557 #ifdef _KERNEL 1558 /* 1559 * We are leaving DDB, never to return upward. 1560 * Clear db_recover so that we can debug faults in functions 1561 * called from cpu_reboot. 1562 */ 1563 db_recover = 0; 1564 panicstr = "dump forced via kernel debugger"; 1565 kern_reboot(RB_DUMP, NULL); 1566 #else /* _KERNEL */ 1567 db_kernelonly(); 1568 #endif /* _KERNEL */ 1569 } 1570 1571 /* 1572 * Describe what an address is 1573 */ 1574 void 1575 db_whatis_cmd(db_expr_t address, bool have_addr, 1576 db_expr_t count, const char *modif) 1577 { 1578 const uintptr_t addr = (uintptr_t)address; 1579 1580 db_lwp_whatis(addr, db_printf); 1581 #ifdef _KERNEL /* XXX CRASH(8) */ 1582 pool_whatis(addr, db_printf); 1583 vmem_whatis(addr, db_printf); 1584 uvm_whatis(addr, db_printf); 1585 module_whatis(addr, db_printf); 1586 #else 1587 db_kernelonly(); 1588 #endif 1589 } 1590