The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_command.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: MIT-CMU
    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
   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  *      Author: David B. Golub, Carnegie Mellon University
   30  *      Date:   7/90
   31  */
   32 /*
   33  * Command dispatcher.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include <sys/param.h>
   40 #include <sys/linker_set.h>
   41 #include <sys/lock.h>
   42 #include <sys/kdb.h>
   43 #include <sys/mutex.h>
   44 #include <sys/proc.h>
   45 #include <sys/reboot.h>
   46 #include <sys/signalvar.h>
   47 #include <sys/systm.h>
   48 #include <sys/cons.h>
   49 #include <sys/conf.h>
   50 #include <sys/watchdog.h>
   51 #include <sys/kernel.h>
   52 
   53 #include <ddb/ddb.h>
   54 #include <ddb/db_command.h>
   55 #include <ddb/db_lex.h>
   56 #include <ddb/db_output.h>
   57 
   58 #include <machine/cpu.h>
   59 #include <machine/setjmp.h>
   60 
   61 /*
   62  * Exported global variables
   63  */
   64 int             db_cmd_loop_done;
   65 db_addr_t       db_dot;
   66 db_addr_t       db_last_addr;
   67 db_addr_t       db_prev;
   68 db_addr_t       db_next;
   69 
   70 static db_cmdfcn_t      db_dump;
   71 static db_cmdfcn_t      db_fncall;
   72 static db_cmdfcn_t      db_gdb;
   73 static db_cmdfcn_t      db_halt;
   74 static db_cmdfcn_t      db_kill;
   75 static db_cmdfcn_t      db_reset;
   76 static db_cmdfcn_t      db_stack_trace;
   77 static db_cmdfcn_t      db_stack_trace_active;
   78 static db_cmdfcn_t      db_stack_trace_all;
   79 static db_cmdfcn_t      db_watchdog;
   80 
   81 /*
   82  * 'show' commands
   83  */
   84 
   85 static struct command db_show_active_cmds[] = {
   86         { "trace",      db_stack_trace_active,  0,      NULL },
   87 };
   88 struct command_table db_show_active_table =
   89     LIST_HEAD_INITIALIZER(db_show_active_table);
   90 
   91 static struct command db_show_all_cmds[] = {
   92         { "trace",      db_stack_trace_all,     0,      NULL },
   93 };
   94 struct command_table db_show_all_table =
   95     LIST_HEAD_INITIALIZER(db_show_all_table);
   96 
   97 static struct command db_show_cmds[] = {
   98         { "active",     0,                      0,      &db_show_active_table },
   99         { "all",        0,                      0,      &db_show_all_table },
  100         { "registers",  db_show_regs,           0,      NULL },
  101         { "breaks",     db_listbreak_cmd,       0,      NULL },
  102         { "threads",    db_show_threads,        0,      NULL },
  103 };
  104 struct command_table db_show_table = LIST_HEAD_INITIALIZER(db_show_table);
  105 
  106 static struct command db_cmds[] = {
  107         { "print",      db_print_cmd,           0,      NULL },
  108         { "p",          db_print_cmd,           0,      NULL },
  109         { "examine",    db_examine_cmd,         CS_SET_DOT, NULL },
  110         { "x",          db_examine_cmd,         CS_SET_DOT, NULL },
  111         { "search",     db_search_cmd,          CS_OWN|CS_SET_DOT, NULL },
  112         { "set",        db_set_cmd,             CS_OWN, NULL },
  113         { "write",      db_write_cmd,           CS_MORE|CS_SET_DOT, NULL },
  114         { "w",          db_write_cmd,           CS_MORE|CS_SET_DOT, NULL },
  115         { "delete",     db_delete_cmd,          0,      NULL },
  116         { "d",          db_delete_cmd,          0,      NULL },
  117         { "dump",       db_dump,                0,      NULL },
  118         { "break",      db_breakpoint_cmd,      0,      NULL },
  119         { "b",          db_breakpoint_cmd,      0,      NULL },
  120         { "dwatch",     db_deletewatch_cmd,     0,      NULL },
  121         { "watch",      db_watchpoint_cmd,      CS_MORE,NULL },
  122         { "dhwatch",    db_deletehwatch_cmd,    0,      NULL },
  123         { "hwatch",     db_hwatchpoint_cmd,     0,      NULL },
  124         { "step",       db_single_step_cmd,     0,      NULL },
  125         { "s",          db_single_step_cmd,     0,      NULL },
  126         { "continue",   db_continue_cmd,        0,      NULL },
  127         { "c",          db_continue_cmd,        0,      NULL },
  128         { "until",      db_trace_until_call_cmd,0,      NULL },
  129         { "next",       db_trace_until_matching_cmd,0,  NULL },
  130         { "match",      db_trace_until_matching_cmd,0,  NULL },
  131         { "trace",      db_stack_trace,         CS_OWN, NULL },
  132         { "t",          db_stack_trace,         CS_OWN, NULL },
  133         /* XXX alias for active trace */
  134         { "acttrace",   db_stack_trace_active,  0,      NULL },
  135         /* XXX alias for all trace */
  136         { "alltrace",   db_stack_trace_all,     0,      NULL },
  137         { "where",      db_stack_trace,         CS_OWN, NULL },
  138         { "bt",         db_stack_trace,         CS_OWN, NULL },
  139         { "call",       db_fncall,              CS_OWN, NULL },
  140         { "show",       0,                      0,      &db_show_table },
  141         { "ps",         db_ps,                  0,      NULL },
  142         { "gdb",        db_gdb,                 0,      NULL },
  143         { "halt",       db_halt,                0,      NULL },
  144         { "reboot",     db_reset,               0,      NULL },
  145         { "reset",      db_reset,               0,      NULL },
  146         { "kill",       db_kill,                CS_OWN, NULL },
  147         { "watchdog",   db_watchdog,            CS_OWN, NULL },
  148         { "thread",     db_set_thread,          CS_OWN, NULL },
  149         { "run",        db_run_cmd,             CS_OWN, NULL },
  150         { "script",     db_script_cmd,          CS_OWN, NULL },
  151         { "scripts",    db_scripts_cmd,         0,      NULL },
  152         { "unscript",   db_unscript_cmd,        CS_OWN, NULL },
  153         { "capture",    db_capture_cmd,         CS_OWN, NULL },
  154         { "textdump",   db_textdump_cmd,        CS_OWN, NULL },
  155         { "findstack",  db_findstack_cmd,       0,      NULL },
  156 };
  157 struct command_table db_cmd_table = LIST_HEAD_INITIALIZER(db_cmd_table);
  158 
  159 static struct command   *db_last_command = NULL;
  160 
  161 /*
  162  * if 'ed' style: 'dot' is set at start of last item printed,
  163  * and '+' points to next line.
  164  * Otherwise: 'dot' points to next item, '..' points to last.
  165  */
  166 static bool     db_ed_style = true;
  167 
  168 /*
  169  * Utility routine - discard tokens through end-of-line.
  170  */
  171 void
  172 db_skip_to_eol(void)
  173 {
  174         int     t;
  175         do {
  176             t = db_read_token();
  177         } while (t != tEOL);
  178 }
  179 
  180 /*
  181  * Results of command search.
  182  */
  183 #define CMD_UNIQUE      0
  184 #define CMD_FOUND       1
  185 #define CMD_NONE        2
  186 #define CMD_AMBIGUOUS   3
  187 #define CMD_HELP        4
  188 
  189 static void     db_cmd_match(char *name, struct command *cmd,
  190                     struct command **cmdp, int *resultp);
  191 static void     db_cmd_list(struct command_table *table);
  192 static int      db_cmd_search(char *name, struct command_table *table,
  193                     struct command **cmdp);
  194 static void     db_command(struct command **last_cmdp,
  195                     struct command_table *cmd_table, int dopager);
  196 
  197 /*
  198  * Initialize the command lists from the static tables.
  199  */
  200 void
  201 db_command_init(void)
  202 {
  203 #define N(a)    (sizeof(a) / sizeof(a[0]))
  204         int i;
  205 
  206         for (i = 0; i < N(db_cmds); i++)
  207                 db_command_register(&db_cmd_table, &db_cmds[i]);
  208         for (i = 0; i < N(db_show_cmds); i++)
  209                 db_command_register(&db_show_table, &db_show_cmds[i]);
  210         for (i = 0; i < N(db_show_active_cmds); i++)
  211                 db_command_register(&db_show_active_table,
  212                     &db_show_active_cmds[i]);
  213         for (i = 0; i < N(db_show_all_cmds); i++)
  214                 db_command_register(&db_show_all_table, &db_show_all_cmds[i]);
  215 #undef N
  216 }
  217 
  218 /*
  219  * Register a command.
  220  */
  221 void
  222 db_command_register(struct command_table *list, struct command *cmd)
  223 {
  224         struct command *c, *last;
  225 
  226         last = NULL;
  227         LIST_FOREACH(c, list, next) {
  228                 int n = strcmp(cmd->name, c->name);
  229 
  230                 /* Check that the command is not already present. */
  231                 if (n == 0) {
  232                         printf("%s: Warning, the command \"%s\" already exists;"
  233                              " ignoring request\n", __func__, cmd->name);
  234                         return;
  235                 }
  236                 if (n < 0) {
  237                         /* NB: keep list sorted lexicographically */
  238                         LIST_INSERT_BEFORE(c, cmd, next);
  239                         return;
  240                 }
  241                 last = c;
  242         }
  243         if (last == NULL)
  244                 LIST_INSERT_HEAD(list, cmd, next);
  245         else
  246                 LIST_INSERT_AFTER(last, cmd, next);
  247 }
  248 
  249 /*
  250  * Remove a command previously registered with db_command_register.
  251  */
  252 void
  253 db_command_unregister(struct command_table *list, struct command *cmd)
  254 {
  255         struct command *c;
  256 
  257         LIST_FOREACH(c, list, next) {
  258                 if (cmd == c) {
  259                         LIST_REMOVE(cmd, next);
  260                         return;
  261                 }
  262         }
  263         /* NB: intentionally quiet */
  264 }
  265 
  266 /*
  267  * Helper function to match a single command.
  268  */
  269 static void
  270 db_cmd_match(char *name, struct command *cmd, struct command **cmdp,
  271     int *resultp)
  272 {
  273         char *lp, *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                         *resultp = CMD_UNIQUE;
  283                         return;
  284                 }
  285                 lp++;
  286                 rp++;
  287         }
  288         if (c == 0) {
  289                 /* end of name, not end of command -
  290                    partial match */
  291                 if (*resultp == CMD_FOUND) {
  292                         *resultp = CMD_AMBIGUOUS;
  293                         /* but keep looking for a full match -
  294                            this lets us match single letters */
  295                 } else {
  296                         *cmdp = cmd;
  297                         *resultp = CMD_FOUND;
  298                 }
  299         }
  300 }
  301 
  302 /*
  303  * Search for command prefix.
  304  */
  305 static int
  306 db_cmd_search(char *name, struct command_table *table, struct command **cmdp)
  307 {
  308         struct command  *cmd;
  309         int             result = CMD_NONE;
  310 
  311         LIST_FOREACH(cmd, table, next) {
  312                 db_cmd_match(name,cmd,cmdp,&result);
  313                 if (result == CMD_UNIQUE)
  314                         break;
  315         }
  316 
  317         if (result == CMD_NONE) {
  318                 /* check for 'help' */
  319                 if (name[0] == 'h' && name[1] == 'e'
  320                     && name[2] == 'l' && name[3] == 'p')
  321                         result = CMD_HELP;
  322         }
  323         return (result);
  324 }
  325 
  326 static void
  327 db_cmd_list(struct command_table *table)
  328 {
  329         struct command  *cmd;
  330         int have_subcommands;
  331 
  332         have_subcommands = 0;
  333         LIST_FOREACH(cmd, table, next) {
  334                 if (cmd->more != NULL)
  335                         have_subcommands++;
  336                 db_printf("%-16s", cmd->name);
  337                 db_end_line(16);
  338         }
  339 
  340         if (have_subcommands > 0) {
  341                 db_printf("\nThe following have subcommands; append \"help\" "
  342                     "to list (e.g. \"show help\"):\n");
  343                 LIST_FOREACH(cmd, table, next) {
  344                         if (cmd->more == NULL)
  345                                 continue;
  346                         db_printf("%-16s", cmd->name);
  347                         db_end_line(16);
  348                 }
  349         }
  350 }
  351 
  352 static void
  353 db_command(struct command **last_cmdp, struct command_table *cmd_table,
  354     int dopager)
  355 {
  356         struct command  *cmd = NULL;
  357         int             t;
  358         char            modif[TOK_STRING_SIZE];
  359         db_expr_t       addr, count;
  360         bool            have_addr = false;
  361         int             result;
  362 
  363         t = db_read_token();
  364         if (t == tEOL) {
  365             /* empty line repeats last command, at 'next' */
  366             cmd = *last_cmdp;
  367             addr = (db_expr_t)db_next;
  368             have_addr = false;
  369             count = 1;
  370             modif[0] = '\0';
  371         }
  372         else if (t == tEXCL) {
  373             db_fncall((db_expr_t)0, (bool)false, (db_expr_t)0, (char *)0);
  374             return;
  375         }
  376         else if (t != tIDENT) {
  377             db_printf("Unrecognized input; use \"help\" "
  378                 "to list available commands\n");
  379             db_flush_lex();
  380             return;
  381         }
  382         else {
  383             /*
  384              * Search for command
  385              */
  386             while (cmd_table) {
  387                 result = db_cmd_search(db_tok_string,
  388                                        cmd_table,
  389                                        &cmd);
  390                 switch (result) {
  391                     case CMD_NONE:
  392                         db_printf("No such command; use \"help\" "
  393                             "to list available commands\n");
  394                         db_flush_lex();
  395                         return;
  396                     case CMD_AMBIGUOUS:
  397                         db_printf("Ambiguous\n");
  398                         db_flush_lex();
  399                         return;
  400                     case CMD_HELP:
  401                         if (cmd_table == &db_cmd_table) {
  402                             db_printf("This is ddb(4), the kernel debugger; "
  403                                 "see https://man.FreeBSD.org/ddb/4 for help.\n");
  404                             db_printf("Use \"bt\" for backtrace, \"dump\" for "
  405                                 "kernel core dump, \"reset\" to reboot.\n");
  406                             db_printf("Available commands:\n");
  407                         }
  408                         db_cmd_list(cmd_table);
  409                         db_flush_lex();
  410                         return;
  411                     default:
  412                         break;
  413                 }
  414                 if ((cmd_table = cmd->more) != NULL) {
  415                     t = db_read_token();
  416                     if (t != tIDENT) {
  417                         db_printf("Subcommand required; "
  418                             "available subcommands:\n");
  419                         db_cmd_list(cmd_table);
  420                         db_flush_lex();
  421                         return;
  422                     }
  423                 }
  424             }
  425 
  426             if ((cmd->flag & CS_OWN) == 0) {
  427                 /*
  428                  * Standard syntax:
  429                  * command [/modifier] [addr] [,count]
  430                  */
  431                 t = db_read_token();
  432                 if (t == tSLASH) {
  433                     t = db_read_token();
  434                     if (t != tIDENT) {
  435                         db_printf("Bad modifier\n");
  436                         db_flush_lex();
  437                         return;
  438                     }
  439                     db_strcpy(modif, db_tok_string);
  440                 }
  441                 else {
  442                     db_unread_token(t);
  443                     modif[0] = '\0';
  444                 }
  445 
  446                 if (db_expression(&addr)) {
  447                     db_dot = (db_addr_t) addr;
  448                     db_last_addr = db_dot;
  449                     have_addr = true;
  450                 }
  451                 else {
  452                     addr = (db_expr_t) db_dot;
  453                     have_addr = false;
  454                 }
  455                 t = db_read_token();
  456                 if (t == tCOMMA) {
  457                     if (!db_expression(&count)) {
  458                         db_printf("Count missing\n");
  459                         db_flush_lex();
  460                         return;
  461                     }
  462                 }
  463                 else {
  464                     db_unread_token(t);
  465                     count = -1;
  466                 }
  467                 if ((cmd->flag & CS_MORE) == 0) {
  468                     db_skip_to_eol();
  469                 }
  470             }
  471         }
  472         *last_cmdp = cmd;
  473         if (cmd != NULL) {
  474             /*
  475              * Execute the command.
  476              */
  477             if (dopager)
  478                 db_enable_pager();
  479             else
  480                 db_disable_pager();
  481             (*cmd->fcn)(addr, have_addr, count, modif);
  482             if (dopager)
  483                 db_disable_pager();
  484 
  485             if (cmd->flag & CS_SET_DOT) {
  486                 /*
  487                  * If command changes dot, set dot to
  488                  * previous address displayed (if 'ed' style).
  489                  */
  490                 if (db_ed_style) {
  491                     db_dot = db_prev;
  492                 }
  493                 else {
  494                     db_dot = db_next;
  495                 }
  496             }
  497             else {
  498                 /*
  499                  * If command does not change dot,
  500                  * set 'next' location to be the same.
  501                  */
  502                 db_next = db_dot;
  503             }
  504         }
  505 }
  506 
  507 /*
  508  * At least one non-optional command must be implemented using
  509  * DB_COMMAND() so that db_cmd_set gets created.  Here is one.
  510  */
  511 DB_COMMAND(panic, db_panic)
  512 {
  513         db_disable_pager();
  514         panic("from debugger");
  515 }
  516 
  517 void
  518 db_command_loop(void)
  519 {
  520         /*
  521          * Initialize 'prev' and 'next' to dot.
  522          */
  523         db_prev = db_dot;
  524         db_next = db_dot;
  525 
  526         db_cmd_loop_done = 0;
  527         while (!db_cmd_loop_done) {
  528             if (db_print_position() != 0)
  529                 db_printf("\n");
  530 
  531             db_printf("db> ");
  532             (void) db_read_line();
  533 
  534             db_command(&db_last_command, &db_cmd_table, /* dopager */ 1);
  535         }
  536 }
  537 
  538 /*
  539  * Execute a command on behalf of a script.  The caller is responsible for
  540  * making sure that the command string is < DB_MAXLINE or it will be
  541  * truncated.
  542  *
  543  * XXXRW: Runs by injecting faked input into DDB input stream; it would be
  544  * nicer to use an alternative approach that didn't mess with the previous
  545  * command buffer.
  546  */
  547 void
  548 db_command_script(const char *command)
  549 {
  550         db_prev = db_next = db_dot;
  551         db_inject_line(command);
  552         db_command(&db_last_command, &db_cmd_table, /* dopager */ 0);
  553 }
  554 
  555 void
  556 db_error(const char *s)
  557 {
  558         if (s)
  559             db_printf("%s", s);
  560         db_flush_lex();
  561         kdb_reenter_silent();
  562 }
  563 
  564 static void
  565 db_dump(db_expr_t dummy, bool dummy2, db_expr_t dummy3, char *dummy4)
  566 {
  567         int error;
  568 
  569         if (textdump_pending) {
  570                 db_printf("textdump_pending set.\n"
  571                     "run \"textdump unset\" first or \"textdump dump\" for a textdump.\n");
  572                 return;
  573         }
  574         error = doadump(false);
  575         if (error) {
  576                 db_printf("Cannot dump: ");
  577                 switch (error) {
  578                 case EBUSY:
  579                         db_printf("debugger got invoked while dumping.\n");
  580                         break;
  581                 case ENXIO:
  582                         db_printf("no dump device specified.\n");
  583                         break;
  584                 default:
  585                         db_printf("unknown error (error=%d).\n", error);
  586                         break;
  587                 }
  588         }
  589 }
  590 
  591 /*
  592  * Call random function:
  593  * !expr(arg,arg,arg)
  594  */
  595 
  596 /* The generic implementation supports a maximum of 10 arguments. */
  597 typedef db_expr_t __db_f(db_expr_t, db_expr_t, db_expr_t, db_expr_t,
  598     db_expr_t, db_expr_t, db_expr_t, db_expr_t, db_expr_t, db_expr_t);
  599 
  600 static __inline int
  601 db_fncall_generic(db_expr_t addr, db_expr_t *rv, int nargs, db_expr_t args[])
  602 {
  603         __db_f *f = (__db_f *)addr;
  604 
  605         if (nargs > 10) {
  606                 db_printf("Too many arguments (max 10)\n");
  607                 return (0);
  608         }
  609         *rv = (*f)(args[0], args[1], args[2], args[3], args[4], args[5],
  610             args[6], args[7], args[8], args[9]);
  611         return (1);
  612 }
  613 
  614 static void
  615 db_fncall(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4)
  616 {
  617         db_expr_t       fn_addr;
  618         db_expr_t       args[DB_MAXARGS];
  619         int             nargs = 0;
  620         db_expr_t       retval;
  621         int             t;
  622 
  623         if (!db_expression(&fn_addr)) {
  624             db_printf("Bad function\n");
  625             db_flush_lex();
  626             return;
  627         }
  628 
  629         t = db_read_token();
  630         if (t == tLPAREN) {
  631             if (db_expression(&args[0])) {
  632                 nargs++;
  633                 while ((t = db_read_token()) == tCOMMA) {
  634                     if (nargs == DB_MAXARGS) {
  635                         db_printf("Too many arguments (max %d)\n", DB_MAXARGS);
  636                         db_flush_lex();
  637                         return;
  638                     }
  639                     if (!db_expression(&args[nargs])) {
  640                         db_printf("Argument missing\n");
  641                         db_flush_lex();
  642                         return;
  643                     }
  644                     nargs++;
  645                 }
  646                 db_unread_token(t);
  647             }
  648             if (db_read_token() != tRPAREN) {
  649                 db_printf("Mismatched parens\n");
  650                 db_flush_lex();
  651                 return;
  652             }
  653         }
  654         db_skip_to_eol();
  655         db_disable_pager();
  656 
  657         if (DB_CALL(fn_addr, &retval, nargs, args))
  658                 db_printf("= %#lr\n", (long)retval);
  659 }
  660 
  661 static void
  662 db_halt(db_expr_t dummy, bool dummy2, db_expr_t dummy3, char *dummy4)
  663 {
  664 
  665         cpu_halt();
  666 }
  667 
  668 static void
  669 db_kill(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4)
  670 {
  671         db_expr_t old_radix, pid, sig;
  672         struct proc *p;
  673 
  674 #define DB_ERROR(f)     do { db_printf f; db_flush_lex(); goto out; } while (0)
  675 
  676         /*
  677          * PIDs and signal numbers are typically represented in base
  678          * 10, so make that the default here.  It can, of course, be
  679          * overridden by specifying a prefix.
  680          */
  681         old_radix = db_radix;
  682         db_radix = 10;
  683         /* Retrieve arguments. */
  684         if (!db_expression(&sig))
  685                 DB_ERROR(("Missing signal number\n"));
  686         if (!db_expression(&pid))
  687                 DB_ERROR(("Missing process ID\n"));
  688         db_skip_to_eol();
  689         if (!_SIG_VALID(sig))
  690                 DB_ERROR(("Signal number out of range\n"));
  691 
  692         /*
  693          * Find the process in question.  allproc_lock is not needed
  694          * since we're in DDB.
  695          */
  696         /* sx_slock(&allproc_lock); */
  697         FOREACH_PROC_IN_SYSTEM(p)
  698             if (p->p_pid == pid)
  699                     break;
  700         /* sx_sunlock(&allproc_lock); */
  701         if (p == NULL)
  702                 DB_ERROR(("Can't find process with pid %ld\n", (long) pid));
  703 
  704         /* If it's already locked, bail; otherwise, do the deed. */
  705         if (PROC_TRYLOCK(p) == 0)
  706                 DB_ERROR(("Can't lock process with pid %ld\n", (long) pid));
  707         else {
  708                 pksignal(p, sig, NULL);
  709                 PROC_UNLOCK(p);
  710         }
  711 
  712 out:
  713         db_radix = old_radix;
  714 #undef DB_ERROR
  715 }
  716 
  717 /*
  718  * Reboot.  In case there is an additional argument, take it as delay in
  719  * seconds.  Default to 15s if we cannot parse it and make sure we will
  720  * never wait longer than 1 week.  Some code is similar to
  721  * kern_shutdown.c:shutdown_panic().
  722  */
  723 #ifndef DB_RESET_MAXDELAY
  724 #define DB_RESET_MAXDELAY       (3600 * 24 * 7)
  725 #endif
  726 
  727 static void
  728 db_reset(db_expr_t addr, bool have_addr, db_expr_t count __unused,
  729     char *modif __unused)
  730 {
  731         int delay, loop;
  732 
  733         if (have_addr) {
  734                 delay = (int)db_hex2dec(addr);
  735 
  736                 /* If we parse to fail, use 15s. */
  737                 if (delay == -1)
  738                         delay = 15;
  739 
  740                 /* Cap at one week. */
  741                 if ((uintmax_t)delay > (uintmax_t)DB_RESET_MAXDELAY)
  742                         delay = DB_RESET_MAXDELAY;
  743 
  744                 db_printf("Automatic reboot in %d seconds - "
  745                     "press a key on the console to abort\n", delay);
  746                 for (loop = delay * 10; loop > 0; --loop) {
  747                         DELAY(1000 * 100); /* 1/10th second */
  748                         /* Did user type a key? */
  749                         if (cncheckc() != -1)
  750                                 return;
  751                 }
  752         }
  753 
  754         cpu_reset();
  755 }
  756 
  757 static void
  758 db_watchdog(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4)
  759 {
  760         db_expr_t old_radix, tout;
  761         int err, i;
  762 
  763         old_radix = db_radix;
  764         db_radix = 10;
  765         err = db_expression(&tout);
  766         db_skip_to_eol();
  767         db_radix = old_radix;
  768 
  769         /* If no argument is provided the watchdog will just be disabled. */
  770         if (err == 0) {
  771                 db_printf("No argument provided, disabling watchdog\n");
  772                 tout = 0;
  773         } else if ((tout & WD_INTERVAL) == WD_TO_NEVER) {
  774                 db_error("Out of range watchdog interval\n");
  775                 return;
  776         }
  777         EVENTHANDLER_INVOKE(watchdog_list, tout, &i);
  778 }
  779 
  780 static void
  781 db_gdb(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4)
  782 {
  783 
  784         if (kdb_dbbe_select("gdb") != 0) {
  785                 db_printf("The remote GDB backend could not be selected.\n");
  786                 return;
  787         }
  788         /*
  789          * Mark that we are done in the debugger.  kdb_trap()
  790          * should re-enter with the new backend.
  791          */
  792         db_cmd_loop_done = 1;
  793         db_printf("(ctrl-c will return control to ddb)\n");
  794 }
  795 
  796 static void
  797 db_stack_trace(db_expr_t tid, bool hastid, db_expr_t count, char *modif)
  798 {
  799         struct thread *td;
  800         db_expr_t radix;
  801         pid_t pid;
  802         int t;
  803 
  804         /*
  805          * We parse our own arguments. We don't like the default radix.
  806          */
  807         radix = db_radix;
  808         db_radix = 10;
  809         hastid = db_expression(&tid);
  810         t = db_read_token();
  811         if (t == tCOMMA) {
  812                 if (!db_expression(&count)) {
  813                         db_printf("Count missing\n");
  814                         db_flush_lex();
  815                         db_radix = radix;
  816                         return;
  817                 }
  818         } else {
  819                 db_unread_token(t);
  820                 count = -1;
  821         }
  822         db_skip_to_eol();
  823         db_radix = radix;
  824 
  825         if (hastid) {
  826                 td = kdb_thr_lookup((lwpid_t)tid);
  827                 if (td == NULL)
  828                         td = kdb_thr_from_pid((pid_t)tid);
  829                 if (td == NULL) {
  830                         db_printf("Thread %d not found\n", (int)tid);
  831                         return;
  832                 }
  833         } else
  834                 td = kdb_thread;
  835         if (td->td_proc != NULL)
  836                 pid = td->td_proc->p_pid;
  837         else
  838                 pid = -1;
  839         db_printf("Tracing pid %d tid %ld td %p\n", pid, (long)td->td_tid, td);
  840         db_trace_thread(td, count);
  841 }
  842 
  843 static void
  844 _db_stack_trace_all(bool active_only)
  845 {
  846         struct proc *p;
  847         struct thread *td;
  848         jmp_buf jb;
  849         void *prev_jb;
  850 
  851         FOREACH_PROC_IN_SYSTEM(p) {
  852                 prev_jb = kdb_jmpbuf(jb);
  853                 if (setjmp(jb) == 0) {
  854                         FOREACH_THREAD_IN_PROC(p, td) {
  855                                 if (td->td_state == TDS_RUNNING)
  856                                         db_printf("\nTracing command %s pid %d"
  857                                             " tid %ld td %p (CPU %d)\n",
  858                                             p->p_comm, p->p_pid,
  859                                             (long)td->td_tid, td,
  860                                             td->td_oncpu);
  861                                 else if (active_only)
  862                                         continue;
  863                                 else
  864                                         db_printf("\nTracing command %s pid %d"
  865                                             " tid %ld td %p\n", p->p_comm,
  866                                             p->p_pid, (long)td->td_tid, td);
  867                                 db_trace_thread(td, -1);
  868                                 if (db_pager_quit) {
  869                                         kdb_jmpbuf(prev_jb);
  870                                         return;
  871                                 }
  872                         }
  873                 }
  874                 kdb_jmpbuf(prev_jb);
  875         }
  876 }
  877 
  878 static void
  879 db_stack_trace_active(db_expr_t dummy, bool dummy2, db_expr_t dummy3,
  880     char *dummy4)
  881 {
  882 
  883         _db_stack_trace_all(true);
  884 }
  885 
  886 static void
  887 db_stack_trace_all(db_expr_t dummy, bool dummy2, db_expr_t dummy3,
  888     char *dummy4)
  889 {
  890 
  891         _db_stack_trace_all(false);
  892 }
  893 
  894 /*
  895  * Take the parsed expression value from the command line that was parsed
  896  * as a hexadecimal value and convert it as if the expression was parsed
  897  * as a decimal value.  Returns -1 if the expression was not a valid
  898  * decimal value.
  899  */
  900 db_expr_t
  901 db_hex2dec(db_expr_t expr)
  902 {
  903         uintptr_t x, y;
  904         db_expr_t val;
  905 
  906         y = 1;
  907         val = 0;
  908         x = expr;
  909         while (x != 0) {
  910                 if (x % 16 > 9)
  911                         return (-1);
  912                 val += (x % 16) * (y);
  913                 x >>= 4;
  914                 y *= 10;
  915         }
  916         return (val);
  917 }

Cache object: 7cd2edfaaafceeacceaa550736dfda32


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.