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