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