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