1 /* $OpenBSD: db_command.c,v 1.88 2019/11/07 13:16:25 mpi 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 #include <sys/msgbuf.h> 40 #include <sys/malloc.h> 41 #include <sys/mount.h> 42 43 #include <uvm/uvm_extern.h> 44 #include <machine/db_machdep.h> /* type definitions */ 45 46 #include <ddb/db_access.h> 47 #include <ddb/db_lex.h> 48 #include <ddb/db_output.h> 49 #include <ddb/db_command.h> 50 #include <ddb/db_break.h> 51 #include <ddb/db_watch.h> 52 #include <ddb/db_run.h> 53 #include <ddb/db_sym.h> 54 #include <ddb/db_var.h> 55 #include <ddb/db_variables.h> 56 #include <ddb/db_interface.h> 57 #include <ddb/db_extern.h> 58 59 #include <uvm/uvm_ddb.h> 60 61 /* 62 * Exported global variables 63 */ 64 int db_cmd_loop_done; 65 label_t *db_recover; 66 67 /* 68 * if 'ed' style: 'dot' is set at start of last item printed, 69 * and '+' points to next line. 70 * Otherwise: 'dot' points to next item, '..' points to last. 71 */ 72 int db_ed_style = 1; 73 74 vaddr_t db_dot; /* current location */ 75 vaddr_t db_last_addr; /* last explicit address typed */ 76 vaddr_t db_prev; /* last address examined 77 or written */ 78 vaddr_t db_next; /* next address to be examined 79 or written */ 80 81 int db_cmd_search(char *, struct db_command *, struct db_command **); 82 void db_cmd_list(struct db_command *); 83 void db_ctf_pprint_cmd(db_expr_t, int, db_expr_t,char *); 84 void db_map_print_cmd(db_expr_t, int, db_expr_t, char *); 85 void db_buf_print_cmd(db_expr_t, int, db_expr_t, char *); 86 void db_malloc_print_cmd(db_expr_t, int, db_expr_t, char *); 87 void db_mbuf_print_cmd(db_expr_t, int, db_expr_t, char *); 88 void db_mount_print_cmd(db_expr_t, int, db_expr_t, char *); 89 void db_show_all_mounts(db_expr_t, int, db_expr_t, char *); 90 void db_show_all_vnodes(db_expr_t, int, db_expr_t, char *); 91 void db_show_all_bufs(db_expr_t, int, db_expr_t, char *); 92 void db_object_print_cmd(db_expr_t, int, db_expr_t, char *); 93 void db_page_print_cmd(db_expr_t, int, db_expr_t, char *); 94 void db_extent_print_cmd(db_expr_t, int, db_expr_t, char *); 95 void db_pool_print_cmd(db_expr_t, int, db_expr_t, char *); 96 void db_proc_print_cmd(db_expr_t, int, db_expr_t, char *); 97 void db_uvmexp_print_cmd(db_expr_t, int, db_expr_t, char *); 98 void db_vnode_print_cmd(db_expr_t, int, db_expr_t, char *); 99 void db_nfsreq_print_cmd(db_expr_t, int, db_expr_t, char *); 100 void db_nfsnode_print_cmd(db_expr_t, int, db_expr_t, char *); 101 void db_help_cmd(db_expr_t, int, db_expr_t, char *); 102 void db_fncall(db_expr_t, int, db_expr_t, char *); 103 void db_boot_sync_cmd(db_expr_t, int, db_expr_t, char *); 104 void db_boot_crash_cmd(db_expr_t, int, db_expr_t, char *); 105 void db_boot_dump_cmd(db_expr_t, int, db_expr_t, char *); 106 void db_boot_halt_cmd(db_expr_t, int, db_expr_t, char *); 107 void db_boot_reboot_cmd(db_expr_t, int, db_expr_t, char *); 108 void db_boot_poweroff_cmd(db_expr_t, int, db_expr_t, char *); 109 void db_stack_trace_cmd(db_expr_t, int, db_expr_t, char *); 110 void db_dmesg_cmd(db_expr_t, int, db_expr_t, char *); 111 void db_show_panic_cmd(db_expr_t, int, db_expr_t, char *); 112 void db_bcstats_print_cmd(db_expr_t, int, db_expr_t, char *); 113 void db_struct_offset_cmd(db_expr_t, int, db_expr_t, char *); 114 void db_ctf_show_struct(db_expr_t, int, db_expr_t, char *); 115 void db_show_regs(db_expr_t, int, db_expr_t, char *); 116 void db_write_cmd(db_expr_t, int, db_expr_t, char *); 117 void db_witness_display(db_expr_t, int, db_expr_t, char *); 118 void db_witness_list(db_expr_t, int, db_expr_t, char *); 119 void db_witness_list_all(db_expr_t, int, db_expr_t, char *); 120 121 122 /* 123 * Utility routine - discard tokens through end-of-line. 124 */ 125 void 126 db_skip_to_eol(void) 127 { 128 int t; 129 do { 130 t = db_read_token(); 131 } while (t != tEOL); 132 } 133 134 /* 135 * Results of command search. 136 */ 137 #define CMD_UNIQUE 0 138 #define CMD_FOUND 1 139 #define CMD_NONE 2 140 #define CMD_AMBIGUOUS 3 141 142 /* 143 * Search for command prefix. 144 */ 145 int 146 db_cmd_search(char *name, struct db_command *table, struct db_command **cmdp) 147 { 148 struct db_command *cmd; 149 int result = CMD_NONE; 150 151 for (cmd = table; cmd->name != 0; cmd++) { 152 char *lp; 153 char *rp; 154 int c; 155 156 lp = name; 157 rp = cmd->name; 158 while ((c = *lp) == *rp) { 159 if (c == 0) { 160 /* complete match */ 161 *cmdp = cmd; 162 return (CMD_UNIQUE); 163 } 164 lp++; 165 rp++; 166 } 167 if (c == 0) { 168 /* end of name, not end of command - 169 partial match */ 170 if (result == CMD_FOUND) { 171 result = CMD_AMBIGUOUS; 172 /* but keep looking for a full match - 173 this lets us match single letters */ 174 } 175 else { 176 *cmdp = cmd; 177 result = CMD_FOUND; 178 } 179 } 180 } 181 return (result); 182 } 183 184 void 185 db_cmd_list(struct db_command *table) 186 { 187 struct db_command *cmd; 188 189 for (cmd = table; cmd->name != 0; cmd++) { 190 db_printf("%-12s", cmd->name); 191 db_end_line(12); 192 } 193 } 194 195 void 196 db_command(struct db_command **last_cmdp, struct db_command *cmd_table) 197 { 198 struct db_command *cmd; 199 char modif[TOK_STRING_SIZE]; 200 db_expr_t addr, count; 201 int t, result, have_addr = 0; 202 203 t = db_read_token(); 204 if (t == tEOL) { 205 /* empty line repeats last command, at 'next' */ 206 cmd = *last_cmdp; 207 addr = (db_expr_t)db_next; 208 have_addr = 0; 209 count = 1; 210 modif[0] = '\0'; 211 } 212 else if (t == tEXCL) { 213 db_fncall(0, 0, 0, NULL); 214 return; 215 } 216 else if (t != tIDENT) { 217 db_printf("?\n"); 218 db_flush_lex(); 219 return; 220 } 221 else { 222 /* 223 * Search for command 224 */ 225 while (cmd_table) { 226 result = db_cmd_search(db_tok_string, 227 cmd_table, 228 &cmd); 229 switch (result) { 230 case CMD_NONE: 231 db_printf("No such command\n"); 232 db_flush_lex(); 233 return; 234 case CMD_AMBIGUOUS: 235 db_printf("Ambiguous\n"); 236 db_flush_lex(); 237 return; 238 default: 239 break; 240 } 241 if ((cmd_table = cmd->more) != 0) { 242 t = db_read_token(); 243 if (t != tIDENT) { 244 db_cmd_list(cmd_table); 245 db_flush_lex(); 246 return; 247 } 248 } 249 } 250 251 if ((cmd->flag & CS_OWN) == 0) { 252 /* 253 * Standard syntax: 254 * command [/modifier] [addr] [,count] 255 */ 256 t = db_read_token(); 257 if (t == tSLASH) { 258 t = db_read_token(); 259 if (t != tIDENT) { 260 db_printf("Bad modifier\n"); 261 db_flush_lex(); 262 return; 263 } 264 db_strlcpy(modif, db_tok_string, sizeof(modif)); 265 } 266 else { 267 db_unread_token(t); 268 modif[0] = '\0'; 269 } 270 271 if (db_expression(&addr)) { 272 db_dot = (vaddr_t) addr; 273 db_last_addr = db_dot; 274 have_addr = 1; 275 } 276 else { 277 addr = (db_expr_t) db_dot; 278 have_addr = 0; 279 } 280 t = db_read_token(); 281 if (t == tCOMMA) { 282 if (!db_expression(&count)) { 283 db_printf("Count missing\n"); 284 db_flush_lex(); 285 return; 286 } 287 } 288 else { 289 db_unread_token(t); 290 count = -1; 291 } 292 if ((cmd->flag & CS_MORE) == 0) { 293 db_skip_to_eol(); 294 } 295 } 296 } 297 *last_cmdp = cmd; 298 if (cmd != 0) { 299 /* 300 * Execute the command. 301 */ 302 (*cmd->fcn)(addr, have_addr, count, modif); 303 304 if (cmd->flag & CS_SET_DOT) { 305 /* 306 * If command changes dot, set dot to 307 * previous address displayed (if 'ed' style). 308 */ 309 if (db_ed_style) { 310 db_dot = db_prev; 311 } 312 else { 313 db_dot = db_next; 314 } 315 } 316 else { 317 /* 318 * If command does not change dot, 319 * set 'next' location to be the same. 320 */ 321 db_next = db_dot; 322 } 323 } 324 } 325 326 /*ARGSUSED*/ 327 void 328 db_buf_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 329 { 330 int full = 0; 331 332 if (modif[0] == 'f') 333 full = 1; 334 335 vfs_buf_print((void *) addr, full, db_printf); 336 } 337 338 /*ARGSUSED*/ 339 void 340 db_map_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 341 { 342 int full = 0; 343 344 if (modif[0] == 'f') 345 full = 1; 346 347 uvm_map_printit((struct vm_map *) addr, full, db_printf); 348 } 349 350 /*ARGSUSED*/ 351 void 352 db_malloc_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 353 { 354 malloc_printit(db_printf); 355 } 356 357 /*ARGSUSED*/ 358 void 359 db_mbuf_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 360 { 361 m_print((void *)addr, db_printf); 362 } 363 364 /*ARGSUSED*/ 365 void 366 db_socket_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 367 { 368 so_print((void *)addr, db_printf); 369 } 370 371 /*ARGSUSED*/ 372 void 373 db_mount_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 374 { 375 int full = 0; 376 377 if (modif[0] == 'f') 378 full = 1; 379 380 vfs_mount_print((struct mount *) addr, full, db_printf); 381 } 382 383 void 384 db_show_all_mounts(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 385 { 386 int full = 0; 387 struct mount *mp; 388 389 if (modif[0] == 'f') 390 full = 1; 391 392 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 393 db_printf("mountpoint %p\n", mp); 394 vfs_mount_print(mp, full, db_printf); 395 } 396 } 397 398 extern struct pool vnode_pool; 399 void 400 db_show_all_vnodes(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 401 { 402 int full = 0; 403 404 if (modif[0] == 'f') 405 full = 1; 406 407 pool_walk(&vnode_pool, full, db_printf, vfs_vnode_print); 408 } 409 410 extern struct pool bufpool; 411 void 412 db_show_all_bufs(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 413 { 414 int full = 0; 415 416 if (modif[0] == 'f') 417 full = 1; 418 419 pool_walk(&bufpool, full, db_printf, vfs_buf_print); 420 } 421 422 /*ARGSUSED*/ 423 void 424 db_object_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 425 { 426 int full = 0; 427 428 if (modif[0] == 'f') 429 full = 1; 430 431 uvm_object_printit((struct uvm_object *) addr, full, db_printf); 432 } 433 434 /*ARGSUSED*/ 435 void 436 db_page_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 437 { 438 int full = 0; 439 440 if (modif[0] == 'f') 441 full = 1; 442 443 uvm_page_printit((struct vm_page *) addr, full, db_printf); 444 } 445 446 /*ARGSUSED*/ 447 void 448 db_vnode_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 449 { 450 int full = 0; 451 452 if (modif[0] == 'f') 453 full = 1; 454 455 vfs_vnode_print((void *)addr, full, db_printf); 456 } 457 458 #ifdef NFSCLIENT 459 /*ARGSUSED*/ 460 void 461 db_nfsreq_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, 462 char *modif) 463 { 464 int full = 0; 465 466 if (modif[0] == 'f') 467 full = 1; 468 469 nfs_request_print((void *)addr, full, db_printf); 470 } 471 472 /*ARGSUSED*/ 473 void 474 db_nfsnode_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, 475 char *modif) 476 { 477 int full = 0; 478 479 if (modif[0] == 'f') 480 full = 1; 481 482 nfs_node_print((void *)addr, full, db_printf); 483 } 484 #endif 485 486 487 /*ARGSUSED*/ 488 void 489 db_show_panic_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 490 { 491 if (panicstr) 492 db_printf("%s\n", panicstr); 493 else if (faultstr) { 494 db_printf("kernel page fault\n"); 495 db_printf("%s\n", faultstr); 496 db_stack_trace_print(addr, have_addr, 1, modif, db_printf); 497 } 498 else 499 db_printf("the kernel did not panic\n"); /* yet */ 500 } 501 502 /*ARGSUSED*/ 503 void 504 db_extent_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 505 { 506 extent_print_all(); 507 } 508 509 /*ARGSUSED*/ 510 void 511 db_pool_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 512 { 513 pool_printit((struct pool *)addr, modif, db_printf); 514 } 515 516 /*ARGSUSED*/ 517 void 518 db_proc_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 519 { 520 if (!have_addr) 521 addr = (db_expr_t)curproc; 522 523 proc_printit((struct proc *)addr, modif, db_printf); 524 } 525 526 /*ARGSUSED*/ 527 void 528 db_uvmexp_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 529 { 530 uvmexp_print(db_printf); 531 } 532 533 void bcstats_print(int (*)(const char *, ...)); 534 535 /*ARGSUSED*/ 536 void 537 db_bcstats_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 538 { 539 bcstats_print(db_printf); 540 } 541 542 /* 543 * 'show' commands 544 */ 545 546 struct db_command db_show_all_cmds[] = { 547 { "procs", db_show_all_procs, 0, NULL }, 548 { "callout", db_show_callout, 0, NULL }, 549 { "pools", db_show_all_pools, 0, NULL }, 550 { "mounts", db_show_all_mounts, 0, NULL }, 551 { "vnodes", db_show_all_vnodes, 0, NULL }, 552 { "bufs", db_show_all_bufs, 0, NULL }, 553 #ifdef NFSCLIENT 554 { "nfsreqs", db_show_all_nfsreqs, 0, NULL }, 555 { "nfsnodes", db_show_all_nfsnodes, 0, NULL }, 556 #endif 557 #ifdef WITNESS 558 { "locks", db_witness_list_all, 0, NULL }, 559 #endif 560 { NULL, NULL, 0, NULL } 561 }; 562 563 struct db_command db_show_cmds[] = { 564 { "all", NULL, 0, db_show_all_cmds }, 565 { "bcstats", db_bcstats_print_cmd, 0, NULL }, 566 { "breaks", db_listbreak_cmd, 0, NULL }, 567 { "buf", db_buf_print_cmd, 0, NULL }, 568 { "extents", db_extent_print_cmd, 0, NULL }, 569 #ifdef WITNESS 570 { "locks", db_witness_list, 0, NULL }, 571 #endif 572 { "malloc", db_malloc_print_cmd, 0, NULL }, 573 { "map", db_map_print_cmd, 0, NULL }, 574 { "mbuf", db_mbuf_print_cmd, 0, NULL }, 575 { "mount", db_mount_print_cmd, 0, NULL }, 576 #ifdef NFSCLIENT 577 { "nfsreq", db_nfsreq_print_cmd, 0, NULL }, 578 { "nfsnode", db_nfsnode_print_cmd, 0, NULL }, 579 #endif 580 { "object", db_object_print_cmd, 0, NULL }, 581 { "page", db_page_print_cmd, 0, NULL }, 582 { "panic", db_show_panic_cmd, 0, NULL }, 583 { "pool", db_pool_print_cmd, 0, NULL }, 584 { "proc", db_proc_print_cmd, 0, NULL }, 585 { "registers", db_show_regs, 0, NULL }, 586 { "socket", db_socket_print_cmd, 0, NULL }, 587 { "struct", db_ctf_show_struct, CS_OWN, NULL }, 588 { "uvmexp", db_uvmexp_print_cmd, 0, NULL }, 589 { "vnode", db_vnode_print_cmd, 0, NULL }, 590 { "watches", db_listwatch_cmd, 0, NULL }, 591 #ifdef WITNESS 592 { "witness", db_witness_display, 0, NULL }, 593 #endif 594 { NULL, NULL, 0, NULL } 595 }; 596 597 struct db_command db_boot_cmds[] = { 598 { "sync", db_boot_sync_cmd, 0, 0 }, 599 { "crash", db_boot_crash_cmd, 0, 0 }, 600 { "dump", db_boot_dump_cmd, 0, 0 }, 601 { "halt", db_boot_halt_cmd, 0, 0 }, 602 { "reboot", db_boot_reboot_cmd, 0, 0 }, 603 { "poweroff", db_boot_poweroff_cmd, 0, 0 }, 604 { NULL, } 605 }; 606 607 struct db_command db_command_table[] = { 608 #ifdef DB_MACHINE_COMMANDS 609 /* this must be the first entry, if it exists */ 610 { "machine", NULL, 0, NULL}, 611 #endif 612 { "kill", db_kill_cmd, 0, NULL }, 613 { "print", db_print_cmd, 0, NULL }, 614 { "p", db_print_cmd, 0, NULL }, 615 { "pprint", db_ctf_pprint_cmd, CS_OWN, NULL }, 616 { "examine", db_examine_cmd, CS_SET_DOT, NULL }, 617 { "x", db_examine_cmd, CS_SET_DOT, NULL }, 618 { "search", db_search_cmd, CS_OWN|CS_SET_DOT, NULL }, 619 { "set", db_set_cmd, CS_OWN, NULL }, 620 { "write", db_write_cmd, CS_MORE|CS_SET_DOT, NULL }, 621 { "w", db_write_cmd, CS_MORE|CS_SET_DOT, NULL }, 622 { "delete", db_delete_cmd, 0, NULL }, 623 { "d", db_delete_cmd, 0, NULL }, 624 { "break", db_breakpoint_cmd, 0, NULL }, 625 { "dwatch", db_deletewatch_cmd, 0, NULL }, 626 { "watch", db_watchpoint_cmd, CS_MORE, NULL }, 627 { "step", db_single_step_cmd, 0, NULL }, 628 { "s", db_single_step_cmd, 0, NULL }, 629 { "continue", db_continue_cmd, 0, NULL }, 630 { "c", db_continue_cmd, 0, NULL }, 631 { "until", db_trace_until_call_cmd,0, NULL }, 632 { "next", db_trace_until_matching_cmd,0, NULL }, 633 { "match", db_trace_until_matching_cmd,0, NULL }, 634 { "trace", db_stack_trace_cmd, 0, NULL }, 635 { "bt", db_stack_trace_cmd, 0, NULL }, 636 { "call", db_fncall, CS_OWN, NULL }, 637 { "ps", db_show_all_procs, 0, NULL }, 638 { "callout", db_show_callout, 0, NULL }, 639 { "show", NULL, 0, db_show_cmds }, 640 { "boot", NULL, 0, db_boot_cmds }, 641 { "help", db_help_cmd, 0, NULL }, 642 { "hangman", db_hangman, 0, NULL }, 643 { "dmesg", db_dmesg_cmd, 0, NULL }, 644 { NULL, NULL, 0, NULL } 645 }; 646 647 #ifdef DB_MACHINE_COMMANDS 648 649 /* this function should be called to install the machine dependent 650 commands. It should be called before the debugger is enabled */ 651 void db_machine_commands_install(struct db_command *ptr) 652 { 653 db_command_table[0].more = ptr; 654 return; 655 } 656 657 #endif 658 659 struct db_command *db_last_command = NULL; 660 661 void 662 db_help_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) 663 { 664 db_cmd_list(db_command_table); 665 } 666 667 void 668 db_command_loop(void) 669 { 670 label_t db_jmpbuf; 671 label_t *savejmp; 672 extern int db_output_line; 673 674 /* 675 * Initialize 'prev' and 'next' to dot. 676 */ 677 db_prev = db_dot; 678 db_next = db_dot; 679 680 db_cmd_loop_done = 0; 681 682 savejmp = db_recover; 683 db_recover = &db_jmpbuf; 684 (void) setjmp(&db_jmpbuf); 685 686 while (!db_cmd_loop_done) { 687 688 if (db_print_position() != 0) 689 db_printf("\n"); 690 db_output_line = 0; 691 692 #ifdef MULTIPROCESSOR 693 db_printf("ddb{%d}> ", CPU_INFO_UNIT(curcpu())); 694 #else 695 db_printf("ddb> "); 696 #endif 697 (void) db_read_line(); 698 699 db_command(&db_last_command, db_command_table); 700 } 701 702 db_recover = savejmp; 703 } 704 705 void 706 db_error(char *s) 707 { 708 if (s) 709 db_printf("%s", s); 710 db_flush_lex(); 711 if (db_recover != NULL) 712 longjmp(db_recover); 713 } 714 715 716 /* 717 * Call random function: 718 * !expr(arg,arg,arg) 719 */ 720 /*ARGSUSED*/ 721 void 722 db_fncall(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 723 { 724 db_expr_t fn_addr; 725 #define MAXARGS 11 726 db_expr_t args[MAXARGS]; 727 int nargs = 0; 728 db_expr_t retval; 729 db_expr_t (*func)(db_expr_t, ...); 730 int t; 731 char tmpfmt[28]; 732 733 if (!db_expression(&fn_addr)) { 734 db_printf("Bad function\n"); 735 db_flush_lex(); 736 return; 737 } 738 func = (db_expr_t (*)(db_expr_t, ...)) fn_addr; 739 740 t = db_read_token(); 741 if (t == tLPAREN) { 742 if (db_expression(&args[0])) { 743 nargs++; 744 while ((t = db_read_token()) == tCOMMA) { 745 if (nargs == MAXARGS) { 746 db_printf("Too many arguments\n"); 747 db_flush_lex(); 748 return; 749 } 750 if (!db_expression(&args[nargs])) { 751 db_printf("Argument missing\n"); 752 db_flush_lex(); 753 return; 754 } 755 nargs++; 756 } 757 db_unread_token(t); 758 } 759 if (db_read_token() != tRPAREN) { 760 db_printf("?\n"); 761 db_flush_lex(); 762 return; 763 } 764 } 765 db_skip_to_eol(); 766 767 while (nargs < MAXARGS) { 768 args[nargs++] = 0; 769 } 770 771 retval = (*func)(args[0], args[1], args[2], args[3], args[4], 772 args[5], args[6], args[7], args[8], args[9]); 773 db_printf("%s\n", db_format(tmpfmt, sizeof tmpfmt, retval, 774 DB_FORMAT_N, 1, 0)); 775 } 776 777 void 778 db_reboot(int howto) 779 { 780 spl0(); 781 if (!curproc) 782 curproc = &proc0; 783 reboot(howto); 784 } 785 786 void 787 db_boot_sync_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) 788 { 789 db_reboot(RB_AUTOBOOT | RB_TIMEBAD | RB_USERREQ); 790 } 791 792 void 793 db_boot_crash_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) 794 { 795 db_reboot(RB_NOSYNC | RB_DUMP | RB_TIMEBAD | RB_USERREQ); 796 } 797 798 void 799 db_boot_dump_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) 800 { 801 db_reboot(RB_DUMP | RB_TIMEBAD | RB_USERREQ); 802 } 803 804 void 805 db_boot_halt_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) 806 { 807 db_reboot(RB_NOSYNC | RB_HALT | RB_TIMEBAD | RB_USERREQ); 808 } 809 810 void 811 db_boot_reboot_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) 812 { 813 boot(RB_RESET | RB_AUTOBOOT | RB_NOSYNC | RB_TIMEBAD | RB_USERREQ); 814 } 815 816 void 817 db_boot_poweroff_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) 818 { 819 db_reboot(RB_NOSYNC | RB_HALT | RB_POWERDOWN | RB_TIMEBAD | RB_USERREQ); 820 } 821 822 void 823 db_dmesg_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) 824 { 825 int i, off; 826 char *p; 827 828 if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC) 829 return; 830 off = msgbufp->msg_bufx; 831 if (off > msgbufp->msg_bufs) 832 off = 0; 833 for (i = 0, p = msgbufp->msg_bufc + off; 834 i < msgbufp->msg_bufs; i++, p++) { 835 if (p >= msgbufp->msg_bufc + msgbufp->msg_bufs) 836 p = msgbufp->msg_bufc; 837 if (*p != '\0') 838 db_putchar(*p); 839 } 840 db_putchar('\n'); 841 } 842 843 void 844 db_stack_trace_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 845 { 846 db_stack_trace_print(addr, have_addr, count, modif, db_printf); 847 } 848 849 void 850 db_show_regs(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 851 { 852 struct db_variable *regp; 853 db_expr_t value, offset; 854 char * name; 855 char tmpfmt[28]; 856 857 for (regp = db_regs; regp < db_eregs; regp++) { 858 db_read_variable(regp, &value); 859 db_printf("%-12s%s", regp->name, db_format(tmpfmt, sizeof tmpfmt, 860 (long)value, DB_FORMAT_N, 1, sizeof(long) * 3)); 861 db_find_xtrn_sym_and_offset((vaddr_t)value, &name, &offset); 862 if (name != 0 && offset <= db_maxoff && offset != value) { 863 db_printf("\t%s", name); 864 if (offset != 0) 865 db_printf("+%s", db_format(tmpfmt, sizeof tmpfmt, 866 (long)offset, DB_FORMAT_R, 1, 0)); 867 } 868 db_printf("\n"); 869 } 870 db_print_loc_and_inst(PC_REGS(&ddb_regs)); 871 } 872 873 /* 874 * Write to file. 875 */ 876 /*ARGSUSED*/ 877 void 878 db_write_cmd(db_expr_t address, int have_addr, db_expr_t count, char *modif) 879 { 880 vaddr_t addr; 881 db_expr_t old_value; 882 db_expr_t new_value; 883 int size, wrote_one = 0; 884 char tmpfmt[28]; 885 886 addr = (vaddr_t) address; 887 888 switch (modif[0]) { 889 case 'b': 890 size = 1; 891 break; 892 case 'h': 893 size = 2; 894 break; 895 case 'l': 896 case '\0': 897 size = 4; 898 break; 899 #ifdef __LP64__ 900 case 'q': 901 size = 8; 902 break; 903 #endif 904 default: 905 size = -1; 906 db_error("Unknown size\n"); 907 /*NOTREACHED*/ 908 } 909 910 while (db_expression(&new_value)) { 911 old_value = db_get_value(addr, size, 0); 912 db_printsym(addr, DB_STGY_ANY, db_printf); 913 db_printf("\t\t%s\t", db_format(tmpfmt, sizeof tmpfmt, 914 old_value, DB_FORMAT_N, 0, 8)); 915 db_printf("=\t%s\n", db_format(tmpfmt, sizeof tmpfmt, 916 new_value, DB_FORMAT_N, 0, 8)); 917 db_put_value(addr, size, new_value); 918 addr += size; 919 920 wrote_one = 1; 921 } 922 923 if (!wrote_one) { 924 db_error("Nothing written.\n"); 925 /*NOTREACHED*/ 926 } 927 928 db_next = addr; 929 db_prev = addr - size; 930 931 db_skip_to_eol(); 932 } 933