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