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