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