1 /* $NetBSD: db_command.c,v 1.76 2004/04/27 04:03:28 atatat Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1991,1990 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 */ 28 29 /* 30 * Command dispatcher. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: db_command.c,v 1.76 2004/04/27 04:03:28 atatat Exp $"); 35 36 #include "opt_ddb.h" 37 #include "opt_kgdb.h" 38 #include "opt_inet.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/reboot.h> 43 #include <sys/device.h> 44 #include <sys/malloc.h> 45 #include <sys/namei.h> 46 #include <sys/pool.h> 47 #include <sys/proc.h> 48 #include <sys/vnode.h> 49 50 #include <machine/db_machdep.h> /* type definitions */ 51 52 #if defined(_KERNEL_OPT) 53 #include "opt_multiprocessor.h" 54 #endif 55 #ifdef MULTIPROCESSOR 56 #include <machine/cpu.h> 57 #endif 58 59 #include <ddb/db_lex.h> 60 #include <ddb/db_output.h> 61 #include <ddb/db_command.h> 62 #include <ddb/db_break.h> 63 #include <ddb/db_watch.h> 64 #include <ddb/db_run.h> 65 #include <ddb/db_variables.h> 66 #include <ddb/db_interface.h> 67 #include <ddb/db_sym.h> 68 #include <ddb/db_extern.h> 69 70 #include <uvm/uvm_extern.h> 71 #include <uvm/uvm_ddb.h> 72 73 #include "arp.h" 74 75 /* 76 * Results of command search. 77 */ 78 #define CMD_UNIQUE 0 79 #define CMD_FOUND 1 80 #define CMD_NONE 2 81 #define CMD_AMBIGUOUS 3 82 #define CMD_HELP 4 83 84 /* 85 * Exported global variables 86 */ 87 boolean_t db_cmd_loop_done; 88 label_t *db_recover; 89 db_addr_t db_dot; 90 db_addr_t db_last_addr; 91 db_addr_t db_prev; 92 db_addr_t db_next; 93 94 /* 95 * if 'ed' style: 'dot' is set at start of last item printed, 96 * and '+' points to next line. 97 * Otherwise: 'dot' points to next item, '..' points to last. 98 */ 99 static boolean_t db_ed_style = TRUE; 100 101 static void db_buf_print_cmd(db_expr_t, int, db_expr_t, char *); 102 static void db_cmd_list(const struct db_command *); 103 static int db_cmd_search(const char *, const struct db_command *, 104 const struct db_command **); 105 static void db_command(const struct db_command **, 106 const struct db_command *); 107 static void db_event_print_cmd(db_expr_t, int, db_expr_t, char *); 108 static void db_fncall(db_expr_t, int, db_expr_t, char *); 109 static void db_malloc_print_cmd(db_expr_t, int, db_expr_t, char *); 110 static void db_map_print_cmd(db_expr_t, int, db_expr_t, char *); 111 static void db_namecache_print_cmd(db_expr_t, int, db_expr_t, char *); 112 static void db_object_print_cmd(db_expr_t, int, db_expr_t, char *); 113 static void db_page_print_cmd(db_expr_t, int, db_expr_t, char *); 114 static void db_pool_print_cmd(db_expr_t, int, db_expr_t, char *); 115 static void db_reboot_cmd(db_expr_t, int, db_expr_t, char *); 116 static void db_sifting_cmd(db_expr_t, int, db_expr_t, char *); 117 static void db_stack_trace_cmd(db_expr_t, int, db_expr_t, char *); 118 static void db_sync_cmd(db_expr_t, int, db_expr_t, char *); 119 static void db_uvmexp_print_cmd(db_expr_t, int, db_expr_t, char *); 120 static void db_vnode_print_cmd(db_expr_t, int, db_expr_t, char *); 121 static void db_mount_print_cmd(db_expr_t, int, db_expr_t, char *); 122 123 /* 124 * 'show' commands 125 */ 126 127 static const struct db_command db_show_all_cmds[] = { 128 { "callout", db_show_callout, 0, NULL }, 129 { "procs", db_show_all_procs, 0, NULL }, 130 { NULL, NULL, 0, NULL } 131 }; 132 133 static const struct db_command db_show_cmds[] = { 134 { "all", NULL, 0, db_show_all_cmds }, 135 #if defined(INET) && (NARP > 0) 136 { "arptab", db_show_arptab, 0, NULL }, 137 #endif 138 { "breaks", db_listbreak_cmd, 0, NULL }, 139 { "buf", db_buf_print_cmd, 0, NULL }, 140 { "event", db_event_print_cmd, 0, NULL }, 141 { "malloc", db_malloc_print_cmd, 0, NULL }, 142 { "map", db_map_print_cmd, 0, NULL }, 143 { "mount", db_mount_print_cmd, 0, NULL }, 144 { "ncache", db_namecache_print_cmd, 0, NULL }, 145 { "object", db_object_print_cmd, 0, NULL }, 146 { "page", db_page_print_cmd, 0, NULL }, 147 { "pool", db_pool_print_cmd, 0, NULL }, 148 { "registers", db_show_regs, 0, NULL }, 149 { "sched_qs", db_show_sched_qs, 0, NULL }, 150 { "uvmexp", db_uvmexp_print_cmd, 0, NULL }, 151 { "vnode", db_vnode_print_cmd, 0, NULL }, 152 { "watches", db_listwatch_cmd, 0, NULL }, 153 { NULL, NULL, 0, NULL } 154 }; 155 156 static const struct db_command db_command_table[] = { 157 { "b", db_breakpoint_cmd, 0, NULL }, 158 { "break", db_breakpoint_cmd, 0, NULL }, 159 { "bt", db_stack_trace_cmd, 0, NULL }, 160 { "c", db_continue_cmd, 0, NULL }, 161 { "call", db_fncall, CS_OWN, NULL }, 162 { "callout", db_show_callout, 0, NULL }, 163 { "continue", db_continue_cmd, 0, NULL }, 164 { "d", db_delete_cmd, 0, NULL }, 165 { "delete", db_delete_cmd, 0, NULL }, 166 { "dmesg", db_dmesg, 0, NULL }, 167 { "dwatch", db_deletewatch_cmd, 0, NULL }, 168 { "examine", db_examine_cmd, CS_SET_DOT, NULL }, 169 { "kill", db_kill_proc, CS_OWN, NULL }, 170 #ifdef KGDB 171 { "kgdb", db_kgdb_cmd, 0, NULL }, 172 #endif 173 #ifdef DB_MACHINE_COMMANDS 174 { "machine", NULL, 0, db_machine_command_table }, 175 #endif 176 { "match", db_trace_until_matching_cmd,0, NULL }, 177 { "next", db_trace_until_matching_cmd,0, NULL }, 178 { "p", db_print_cmd, 0, NULL }, 179 { "print", db_print_cmd, 0, NULL }, 180 { "ps", db_show_all_procs, 0, NULL }, 181 { "reboot", db_reboot_cmd, CS_OWN, NULL }, 182 { "s", db_single_step_cmd, 0, NULL }, 183 { "search", db_search_cmd, CS_OWN|CS_SET_DOT, NULL }, 184 { "set", db_set_cmd, CS_OWN, NULL }, 185 { "show", NULL, 0, db_show_cmds }, 186 { "sifting", db_sifting_cmd, CS_OWN, NULL }, 187 { "step", db_single_step_cmd, 0, NULL }, 188 { "sync", db_sync_cmd, CS_OWN, NULL }, 189 { "trace", db_stack_trace_cmd, 0, NULL }, 190 { "until", db_trace_until_call_cmd,0, NULL }, 191 { "w", db_write_cmd, CS_MORE|CS_SET_DOT, NULL }, 192 { "watch", db_watchpoint_cmd, CS_MORE, NULL }, 193 { "write", db_write_cmd, CS_MORE|CS_SET_DOT, NULL }, 194 { "x", db_examine_cmd, CS_SET_DOT, NULL }, 195 { NULL, NULL, 0, NULL } 196 }; 197 198 static const struct db_command *db_last_command = NULL; 199 200 /* 201 * Utility routine - discard tokens through end-of-line. 202 */ 203 void 204 db_skip_to_eol(void) 205 { 206 int t; 207 208 do { 209 t = db_read_token(); 210 } while (t != tEOL); 211 } 212 213 void 214 db_error(s) 215 char *s; 216 { 217 218 if (s) 219 db_printf("%s", s); 220 db_flush_lex(); 221 longjmp(db_recover); 222 } 223 224 void 225 db_command_loop(void) 226 { 227 label_t db_jmpbuf; 228 label_t *savejmp; 229 230 /* 231 * Initialize 'prev' and 'next' to dot. 232 */ 233 db_prev = db_dot; 234 db_next = db_dot; 235 236 db_cmd_loop_done = 0; 237 238 savejmp = db_recover; 239 db_recover = &db_jmpbuf; 240 (void) setjmp(&db_jmpbuf); 241 242 while (!db_cmd_loop_done) { 243 if (db_print_position() != 0) 244 db_printf("\n"); 245 db_output_line = 0; 246 247 248 #ifdef MULTIPROCESSOR 249 db_printf("db{%ld}> ", (long)cpu_number()); 250 #else 251 db_printf("db> "); 252 #endif 253 (void) db_read_line(); 254 255 db_command(&db_last_command, db_command_table); 256 } 257 258 db_recover = savejmp; 259 } 260 261 /* 262 * Search for command prefix. 263 */ 264 static int 265 db_cmd_search(const char *name, const struct db_command *table, 266 const struct db_command **cmdp) 267 { 268 const struct db_command *cmd; 269 int result = CMD_NONE; 270 271 for (cmd = table; cmd->name != 0; cmd++) { 272 const char *lp; 273 const char *rp; 274 int c; 275 276 lp = name; 277 rp = cmd->name; 278 while ((c = *lp) == *rp) { 279 if (c == 0) { 280 /* complete match */ 281 *cmdp = cmd; 282 return (CMD_UNIQUE); 283 } 284 lp++; 285 rp++; 286 } 287 if (c == 0) { 288 /* end of name, not end of command - 289 partial match */ 290 if (result == CMD_FOUND) { 291 result = CMD_AMBIGUOUS; 292 /* but keep looking for a full match - 293 this lets us match single letters */ 294 } else { 295 *cmdp = cmd; 296 result = CMD_FOUND; 297 } 298 } 299 } 300 if (result == CMD_NONE) { 301 /* check for 'help' */ 302 if (name[0] == 'h' && name[1] == 'e' 303 && name[2] == 'l' && name[3] == 'p') 304 result = CMD_HELP; 305 } 306 return (result); 307 } 308 309 static void 310 db_cmd_list(const struct db_command *table) 311 { 312 int i, j, w, columns, lines, width=0, numcmds; 313 const char *p; 314 315 for (numcmds = 0; table[numcmds].name != NULL; numcmds++) { 316 w = strlen(table[numcmds].name); 317 if (w > width) 318 width = w; 319 } 320 width = DB_NEXT_TAB(width); 321 322 columns = db_max_width / width; 323 if (columns == 0) 324 columns = 1; 325 lines = (numcmds + columns - 1) / columns; 326 for (i = 0; i < lines; i++) { 327 for (j = 0; j < columns; j++) { 328 p = table[j * lines + i].name; 329 if (p) 330 db_printf("%s", p); 331 if (j * lines + i + lines >= numcmds) { 332 db_putchar('\n'); 333 break; 334 } 335 w = strlen(p); 336 while (w < width) { 337 w = DB_NEXT_TAB(w); 338 db_putchar('\t'); 339 } 340 } 341 } 342 } 343 344 static void 345 db_command(const struct db_command **last_cmdp, 346 const struct db_command *cmd_table) 347 { 348 const struct db_command *cmd; 349 int t; 350 char modif[TOK_STRING_SIZE]; 351 db_expr_t addr, count; 352 boolean_t have_addr = FALSE; 353 int result; 354 355 static db_expr_t last_count = 0; 356 357 t = db_read_token(); 358 if ((t == tEOL) || (t == tCOMMA)) { 359 /* 360 * An empty line repeats last command, at 'next'. 361 * Only a count repeats the last command with the new count. 362 */ 363 cmd = *last_cmdp; 364 addr = (db_expr_t)db_next; 365 if (t == tCOMMA) { 366 if (!db_expression(&count)) { 367 db_printf("Count missing\n"); 368 db_flush_lex(); 369 return; 370 } 371 } else 372 count = last_count; 373 have_addr = FALSE; 374 modif[0] = '\0'; 375 db_skip_to_eol(); 376 } else if (t == tEXCL) { 377 db_fncall(0, 0, 0, NULL); 378 return; 379 } else if (t != tIDENT) { 380 db_printf("?\n"); 381 db_flush_lex(); 382 return; 383 } else { 384 /* 385 * Search for command 386 */ 387 while (cmd_table) { 388 result = db_cmd_search(db_tok_string, cmd_table, &cmd); 389 switch (result) { 390 case CMD_NONE: 391 db_printf("No such command\n"); 392 db_flush_lex(); 393 return; 394 case CMD_AMBIGUOUS: 395 db_printf("Ambiguous\n"); 396 db_flush_lex(); 397 return; 398 case CMD_HELP: 399 db_cmd_list(cmd_table); 400 db_flush_lex(); 401 return; 402 default: 403 break; 404 } 405 if ((cmd_table = cmd->more) != 0) { 406 t = db_read_token(); 407 if (t != tIDENT) { 408 db_cmd_list(cmd_table); 409 db_flush_lex(); 410 return; 411 } 412 } 413 } 414 415 if ((cmd->flag & CS_OWN) == 0) { 416 /* 417 * Standard syntax: 418 * command [/modifier] [addr] [,count] 419 */ 420 t = db_read_token(); 421 if (t == tSLASH) { 422 t = db_read_token(); 423 if (t != tIDENT) { 424 db_printf("Bad modifier\n"); 425 db_flush_lex(); 426 return; 427 } 428 strlcpy(modif, db_tok_string, sizeof(modif)); 429 } else { 430 db_unread_token(t); 431 modif[0] = '\0'; 432 } 433 434 if (db_expression(&addr)) { 435 db_dot = (db_addr_t) addr; 436 db_last_addr = db_dot; 437 have_addr = TRUE; 438 } else { 439 addr = (db_expr_t) db_dot; 440 have_addr = FALSE; 441 } 442 t = db_read_token(); 443 if (t == tCOMMA) { 444 if (!db_expression(&count)) { 445 db_printf("Count missing\n"); 446 db_flush_lex(); 447 return; 448 } 449 } else { 450 db_unread_token(t); 451 count = -1; 452 } 453 if ((cmd->flag & CS_MORE) == 0) { 454 db_skip_to_eol(); 455 } 456 } 457 } 458 *last_cmdp = cmd; 459 last_count = count; 460 if (cmd != 0) { 461 /* 462 * Execute the command. 463 */ 464 (*cmd->fcn)(addr, have_addr, count, modif); 465 466 if (cmd->flag & CS_SET_DOT) { 467 /* 468 * If command changes dot, set dot to 469 * previous address displayed (if 'ed' style). 470 */ 471 if (db_ed_style) 472 db_dot = db_prev; 473 else 474 db_dot = db_next; 475 } else { 476 /* 477 * If command does not change dot, 478 * set 'next' location to be the same. 479 */ 480 db_next = db_dot; 481 } 482 } 483 } 484 485 /*ARGSUSED*/ 486 static void 487 db_map_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 488 { 489 boolean_t full = FALSE; 490 491 if (modif[0] == 'f') 492 full = TRUE; 493 494 if (have_addr == FALSE) 495 addr = (db_expr_t)(intptr_t) kernel_map; 496 497 uvm_map_printit((struct vm_map *)(intptr_t) addr, full, db_printf); 498 } 499 500 /*ARGSUSED*/ 501 static void 502 db_malloc_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 503 { 504 505 #ifdef MALLOC_DEBUG 506 if (!have_addr) 507 addr = 0; 508 509 debug_malloc_printit(db_printf, (vaddr_t) addr); 510 #else 511 db_printf("The kernel is not built with the MALLOC_DEBUG option.\n"); 512 #endif /* MALLOC_DEBUG */ 513 } 514 515 /*ARGSUSED*/ 516 static void 517 db_object_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 518 { 519 boolean_t full = FALSE; 520 521 if (modif[0] == 'f') 522 full = TRUE; 523 524 uvm_object_printit((struct uvm_object *)(intptr_t) addr, full, 525 db_printf); 526 } 527 528 /*ARGSUSED*/ 529 static void 530 db_page_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 531 { 532 boolean_t full = FALSE; 533 534 if (modif[0] == 'f') 535 full = TRUE; 536 537 uvm_page_printit((struct vm_page *)(intptr_t) addr, full, db_printf); 538 } 539 540 /*ARGSUSED*/ 541 static void 542 db_buf_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 543 { 544 boolean_t full = FALSE; 545 546 if (modif[0] == 'f') 547 full = TRUE; 548 549 vfs_buf_print((struct buf *)(intptr_t) addr, full, db_printf); 550 } 551 552 /*ARGSUSED*/ 553 static void 554 db_event_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 555 { 556 boolean_t full = FALSE; 557 558 if (modif[0] == 'f') 559 full = TRUE; 560 561 event_print(full, db_printf); 562 } 563 564 /*ARGSUSED*/ 565 static void 566 db_vnode_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 567 { 568 boolean_t full = FALSE; 569 570 if (modif[0] == 'f') 571 full = TRUE; 572 573 vfs_vnode_print((struct vnode *)(intptr_t) addr, full, db_printf); 574 } 575 576 static void 577 db_mount_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 578 { 579 boolean_t full = FALSE; 580 581 if (modif[0] == 'f') 582 full = TRUE; 583 584 vfs_mount_print((struct mount *)(intptr_t) addr, full, db_printf); 585 } 586 587 /*ARGSUSED*/ 588 static void 589 db_pool_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 590 { 591 592 pool_printit((struct pool *)(intptr_t) addr, modif, db_printf); 593 } 594 595 /*ARGSUSED*/ 596 static void 597 db_namecache_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, 598 char *modif) 599 { 600 601 namecache_print((struct vnode *)(intptr_t) addr, db_printf); 602 } 603 604 /*ARGSUSED*/ 605 static void 606 db_uvmexp_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 607 { 608 609 uvmexp_print(db_printf); 610 } 611 612 /* 613 * Call random function: 614 * !expr(arg,arg,arg) 615 */ 616 /*ARGSUSED*/ 617 static void 618 db_fncall(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 619 { 620 db_expr_t fn_addr; 621 #define MAXARGS 11 622 db_expr_t args[MAXARGS]; 623 int nargs = 0; 624 db_expr_t retval; 625 db_expr_t (*func)(db_expr_t, ...); 626 int t; 627 628 if (!db_expression(&fn_addr)) { 629 db_printf("Bad function\n"); 630 db_flush_lex(); 631 return; 632 } 633 func = (db_expr_t (*)(db_expr_t, ...))(intptr_t) fn_addr; 634 635 t = db_read_token(); 636 if (t == tLPAREN) { 637 if (db_expression(&args[0])) { 638 nargs++; 639 while ((t = db_read_token()) == tCOMMA) { 640 if (nargs == MAXARGS) { 641 db_printf("Too many arguments\n"); 642 db_flush_lex(); 643 return; 644 } 645 if (!db_expression(&args[nargs])) { 646 db_printf("Argument missing\n"); 647 db_flush_lex(); 648 return; 649 } 650 nargs++; 651 } 652 db_unread_token(t); 653 } 654 if (db_read_token() != tRPAREN) { 655 db_printf("?\n"); 656 db_flush_lex(); 657 return; 658 } 659 } 660 db_skip_to_eol(); 661 662 while (nargs < MAXARGS) { 663 args[nargs++] = 0; 664 } 665 666 retval = (*func)(args[0], args[1], args[2], args[3], args[4], 667 args[5], args[6], args[7], args[8], args[9]); 668 db_printf("%s\n", db_num_to_str(retval)); 669 } 670 671 static void 672 db_reboot_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 673 { 674 db_expr_t bootflags; 675 676 /* Flags, default to RB_AUTOBOOT */ 677 if (!db_expression(&bootflags)) 678 bootflags = (db_expr_t)RB_AUTOBOOT; 679 if (db_read_token() != tEOL) { 680 db_error("?\n"); 681 /*NOTREACHED*/ 682 } 683 /* 684 * We are leaving DDB, never to return upward. 685 * Clear db_recover so that we can debug faults in functions 686 * called from cpu_reboot. 687 */ 688 db_recover = 0; 689 cpu_reboot((int)bootflags, NULL); 690 } 691 692 static void 693 db_sifting_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 694 { 695 int mode, t; 696 697 t = db_read_token(); 698 if (t == tSLASH) { 699 t = db_read_token(); 700 if (t != tIDENT) { 701 bad_modifier: 702 db_printf("Bad modifier\n"); 703 db_flush_lex(); 704 return; 705 } 706 if (!strcmp(db_tok_string, "F")) 707 mode = 'F'; 708 else 709 goto bad_modifier; 710 t = db_read_token(); 711 } else 712 mode = 0; 713 714 if (t == tIDENT) 715 db_sifting(db_tok_string, mode); 716 else { 717 db_printf("Bad argument (non-string)\n"); 718 db_flush_lex(); 719 } 720 } 721 722 static void 723 db_stack_trace_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 724 { 725 register char *cp = modif; 726 register char c; 727 void (*pr)(const char *, ...); 728 729 pr = db_printf; 730 while ((c = *cp++) != 0) 731 if (c == 'l') 732 pr = printf; 733 734 if (count == -1) 735 count = 65535; 736 737 db_stack_trace_print(addr, have_addr, count, modif, pr); 738 } 739 740 static void 741 db_sync_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 742 { 743 744 /* 745 * We are leaving DDB, never to return upward. 746 * Clear db_recover so that we can debug faults in functions 747 * called from cpu_reboot. 748 */ 749 db_recover = 0; 750 cpu_reboot(RB_DUMP, NULL); 751 } 752