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