root/ddb/db_command.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. db_skip_to_eol
  2. db_cmd_search
  3. db_cmd_list
  4. db_command
  5. db_buf_print_cmd
  6. db_map_print_cmd
  7. db_malloc_print_cmd
  8. db_mount_print_cmd
  9. db_object_print_cmd
  10. db_page_print_cmd
  11. db_vnode_print_cmd
  12. db_show_panic_cmd
  13. db_extent_print_cmd
  14. db_pool_print_cmd
  15. db_proc_print_cmd
  16. db_uvmexp_print_cmd
  17. db_machine_commands_install
  18. db_help_cmd
  19. db_command_loop
  20. db_error
  21. db_fncall
  22. db_boot_sync_cmd
  23. db_boot_crash_cmd
  24. db_boot_dump_cmd
  25. db_boot_halt_cmd
  26. db_boot_reboot_cmd
  27. db_boot_poweroff_cmd
  28. db_dmesg_cmd
  29. db_stack_trace_cmd

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

/* [<][>][^][v][top][bottom][index][help] */