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