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