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