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 /*      $NetBSD: db_command.c,v 1.181 2022/04/28 07:08:38 msaitoh Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1996, 1997, 1998, 1999, 2002, 2009, 2019
    5  *     The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Adam Hamsik, and by Andrew Doran.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Mach Operating System
   35  * Copyright (c) 1991,1990 Carnegie Mellon University
   36  * All Rights Reserved.
   37  *
   38  * Permission to use, copy, modify and distribute this software and its
   39  * documentation is hereby granted, provided that both the copyright
   40  * notice and this permission notice appear in all copies of the
   41  * software, derivative works or modified versions, and any portions
   42  * thereof, and that both notices appear in supporting documentation.
   43  *
   44  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   45  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   46  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   47  *
   48  * Carnegie Mellon requests users of this software to return to
   49  *
   50  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   51  *  School of Computer Science
   52  *  Carnegie Mellon University
   53  *  Pittsburgh PA 15213-3890
   54  *
   55  * any improvements or extensions that they make and grant Carnegie the
   56  * rights to redistribute these changes.
   57  */
   58 
   59 /*
   60  * Command dispatcher.
   61  */
   62 
   63 #include <sys/cdefs.h>
   64 __KERNEL_RCSID(0, "$NetBSD: db_command.c,v 1.181 2022/04/28 07:08:38 msaitoh Exp $");
   65 
   66 #ifdef _KERNEL_OPT
   67 #include "opt_aio.h"
   68 #include "opt_ddb.h"
   69 #include "opt_fdt.h"
   70 #include "opt_kgdb.h"
   71 #include "opt_mqueue.h"
   72 #include "opt_inet.h"
   73 #include "opt_kernhist.h"
   74 #include "opt_ddbparam.h"
   75 #include "opt_multiprocessor.h"
   76 #endif
   77 
   78 #include <sys/param.h>
   79 #include <sys/systm.h>
   80 #include <sys/reboot.h>
   81 #include <sys/device.h>
   82 #include <sys/eventvar.h>
   83 #include <sys/lwp.h>
   84 #include <sys/mbuf.h>
   85 #include <sys/namei.h>
   86 #include <sys/pool.h>
   87 #include <sys/proc.h>
   88 #include <sys/vnode.h>
   89 #include <sys/vmem.h>
   90 #include <sys/lockdebug.h>
   91 #include <sys/cpu.h>
   92 #include <sys/buf.h>
   93 #include <sys/module.h>
   94 #include <sys/kernhist.h>
   95 #include <sys/socketvar.h>
   96 #include <sys/queue.h>
   97 
   98 #include <dev/cons.h>
   99 
  100 #include <ddb/ddb.h>
  101 
  102 #include <uvm/uvm_extern.h>
  103 #include <uvm/uvm_ddb.h>
  104 
  105 #include <net/route.h>
  106 
  107 #ifdef FDT
  108 #include <dev/fdt/fdtvar.h>
  109 #include <dev/fdt/fdt_ddb.h>
  110 #endif
  111 
  112 /*
  113  * Results of command search.
  114  */
  115 #define CMD_EXACT               0
  116 #define CMD_PREFIX              1
  117 #define CMD_NONE                2
  118 #define CMD_AMBIGUOUS   3
  119 
  120 /*
  121  * Exported global variables
  122  */
  123 bool            db_cmd_loop_done;
  124 label_t         *db_recover;
  125 db_addr_t       db_dot;
  126 db_addr_t       db_last_addr;
  127 db_addr_t       db_prev;
  128 db_addr_t       db_next;
  129 
  130 
  131 /*
  132  * New DDB api for adding and removing commands uses three lists, because
  133  * we use two types of commands
  134  * a) standard commands without subcommands -> reboot
  135  * b) show commands which are subcommands of show command -> show aio_jobs
  136  * c) if defined machine specific commands
  137  *
  138  * ddb_add_cmd, ddb_rem_cmd use type (DDB_SHOW_CMD||DDB_BASE_CMD)argument to
  139  * add them to representativ lists.
  140  */
  141 
  142 static const struct db_command db_command_table[];
  143 static const struct db_command db_show_cmds[];
  144 
  145 #ifdef DB_MACHINE_COMMANDS
  146 /* arch/<arch>/<arch>/db_interface.c */
  147 extern const struct db_command db_machine_command_table[];
  148 #endif
  149 
  150 /* the global queue of all command tables */
  151 TAILQ_HEAD(db_cmd_tbl_en_head, db_cmd_tbl_en);
  152 
  153 /* TAILQ entry used to register command tables */
  154 struct db_cmd_tbl_en {
  155         const struct db_command *db_cmd;        /* cmd table */
  156         TAILQ_ENTRY(db_cmd_tbl_en) db_cmd_next;
  157 };
  158 
  159 /* head of base commands list */
  160 static struct db_cmd_tbl_en_head db_base_cmd_list =
  161         TAILQ_HEAD_INITIALIZER(db_base_cmd_list);
  162 static struct db_cmd_tbl_en db_base_cmd_builtins =
  163      { .db_cmd = db_command_table };
  164 
  165 /* head of show commands list */
  166 static struct db_cmd_tbl_en_head db_show_cmd_list =
  167         TAILQ_HEAD_INITIALIZER(db_show_cmd_list);
  168 static struct db_cmd_tbl_en db_show_cmd_builtins =
  169      { .db_cmd = db_show_cmds };
  170 
  171 /* head of machine commands list */
  172 static struct db_cmd_tbl_en_head db_mach_cmd_list =
  173         TAILQ_HEAD_INITIALIZER(db_mach_cmd_list);
  174 #ifdef DB_MACHINE_COMMANDS
  175 static struct db_cmd_tbl_en db_mach_cmd_builtins =
  176      { .db_cmd = db_machine_command_table };
  177 #endif
  178 
  179 /*
  180  * if 'ed' style: 'dot' is set at start of last item printed,
  181  * and '+' points to next line.
  182  * Otherwise: 'dot' points to next item, '..' points to last.
  183  */
  184 static bool      db_ed_style = true;
  185 
  186 static void     db_init_commands(void);
  187 static int      db_register_tbl_entry(uint8_t type,
  188     struct db_cmd_tbl_en *list_ent);
  189 static void     db_cmd_list(const struct db_cmd_tbl_en_head *);
  190 static int      db_cmd_search(const char *, struct db_cmd_tbl_en_head *,
  191                               const struct db_command **);
  192 static int      db_cmd_search_table(const char *, const struct db_command *,
  193                                     const struct db_command **);
  194 static void     db_cmd_search_failed(char *, int);
  195 static const struct db_command *db_read_command(void);
  196 static void     db_command(const struct db_command **);
  197 static void     db_buf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  198 static void     db_event_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  199 static void     db_fncall(db_expr_t, bool, db_expr_t, const char *);
  200 static void     db_help_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  201 static void     db_lock_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  202 static void     db_show_all_locks(db_expr_t, bool, db_expr_t, const char *);
  203 static void     db_show_lockstats(db_expr_t, bool, db_expr_t, const char *);
  204 static void     db_show_all_freelists(db_expr_t, bool, db_expr_t, const char *);
  205 static void     db_mount_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  206 static void     db_show_all_mount(db_expr_t, bool, db_expr_t, const char *);
  207 static void     db_mbuf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  208 static void     db_kqueue_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  209 static void     db_map_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  210 static void     db_namecache_print_cmd(db_expr_t, bool, db_expr_t,
  211                     const char *);
  212 static void     db_object_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  213 static void     db_page_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  214 static void     db_show_all_pages(db_expr_t, bool, db_expr_t, const char *);
  215 static void     db_pool_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  216 static void     db_reboot_cmd(db_expr_t, bool, db_expr_t, const char *);
  217 static void     db_sifting_cmd(db_expr_t, bool, db_expr_t, const char *);
  218 static void     db_socket_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  219 static void     db_stack_trace_cmd(db_expr_t, bool, db_expr_t, const char *);
  220 static void     db_sync_cmd(db_expr_t, bool, db_expr_t, const char *);
  221 static void     db_whatis_cmd(db_expr_t, bool, db_expr_t, const char *);
  222 static void     db_uvmexp_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  223 #ifdef KERNHIST
  224 static void     db_kernhist_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  225 #endif
  226 static void     db_vnode_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  227 static void     db_vnode_lock_print_cmd(db_expr_t, bool, db_expr_t,
  228                     const char *);
  229 static void     db_vmem_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  230 #ifdef FDT
  231 static void     db_fdt_print_cmd(db_expr_t, bool, db_expr_t, const char *);
  232 #endif
  233 
  234 static const struct db_command db_show_cmds[] = {
  235         { DDB_ADD_CMD("all",    NULL,
  236             CS_COMPAT, NULL,NULL,NULL) },
  237 #ifdef AIO
  238         { DDB_ADD_CMD("aio_jobs",       db_show_aio_jobs,       0,
  239             "Show aio jobs",NULL,NULL) },
  240 #endif
  241 #ifdef _KERNEL
  242         { DDB_ADD_CMD("breaks", db_listbreak_cmd,       0,
  243             "Display all breaks.",NULL,NULL) },
  244 #endif
  245         { DDB_ADD_CMD("buf",    db_buf_print_cmd,       0,
  246             "Print the struct buf at address.", "[/f] address",NULL) },
  247         /* added from all sub cmds */
  248         { DDB_ADD_CMD("callout",  db_show_callout,
  249             0 ,"List all used callout functions.",NULL,NULL) },
  250         { DDB_ADD_CMD("devices", db_show_all_devices,   0,NULL,NULL,NULL) },
  251         { DDB_ADD_CMD("event",  db_event_print_cmd,     0,
  252             "Print all the non-zero evcnt(9) event counters.", "[/fitm]",NULL) },
  253 #ifdef FDT
  254         { DDB_ADD_CMD("fdt", db_fdt_print_cmd, 0,
  255             "Show FDT information", NULL, NULL) },
  256 #endif
  257         { DDB_ADD_CMD("files", db_show_files_cmd,       0,
  258             "Print the files open by process at address",
  259             "[/f] address", NULL) },
  260         { DDB_ADD_CMD("freelists",      db_show_all_freelists,
  261             0 ,"Show all freelists", NULL, NULL) },
  262 #ifdef KERNHIST
  263         { DDB_ADD_CMD("kernhist", db_kernhist_print_cmd, 0,
  264             "Print the UVM history logs.",
  265             NULL,NULL) },
  266 #endif
  267         /* added from all sub cmds */
  268         { DDB_ADD_CMD("locks",  db_show_all_locks,
  269             0 ,"Show all held locks", "[/t]", NULL) },
  270         { DDB_ADD_CMD("lock",   db_lock_print_cmd,      0,NULL,NULL,NULL) },
  271         { DDB_ADD_CMD("lockstats",
  272                                 db_show_lockstats,      0,
  273             "Print statistics of locks", NULL, NULL) },
  274         { DDB_ADD_CMD("kqueue", db_kqueue_print_cmd,    0,
  275             "Print the kqueue at address.", "[/f] address",NULL) },
  276         { DDB_ADD_CMD("map",    db_map_print_cmd,       0,
  277             "Print the vm_map at address.", "[/f] address",NULL) },
  278         { DDB_ADD_CMD("mbuf",   db_mbuf_print_cmd,      0,NULL,NULL,
  279             "-c prints all mbuf chains") },
  280         { DDB_ADD_CMD("module", db_show_module_cmd,     0,
  281             "Print kernel modules", NULL, NULL) },
  282         { DDB_ADD_CMD("mount",  db_show_all_mount,      0,
  283             "Print all mount structures.", "[/f]", NULL) },
  284         { DDB_ADD_CMD("mount",  db_mount_print_cmd,     0,
  285             "Print the mount structure at address.", "[/f] address",NULL) },
  286 #ifdef MQUEUE
  287         { DDB_ADD_CMD("mqueue", db_show_mqueue_cmd,     0,
  288             "Print the message queues", NULL, NULL) },
  289 #endif
  290         { DDB_ADD_CMD("ncache", db_namecache_print_cmd, 0,
  291             "Dump the namecache list.", "address",NULL) },
  292         { DDB_ADD_CMD("object", db_object_print_cmd,    0,
  293             "Print the vm_object at address.", "[/f] address",NULL) },
  294         { DDB_ADD_CMD("page",   db_page_print_cmd,      0,
  295             "Print the vm_page at address.", "[/f] address",NULL) },
  296         { DDB_ADD_CMD("pages",  db_show_all_pages,
  297             0 ,"List all used memory pages.",NULL,NULL) },
  298         { DDB_ADD_CMD("panic",  db_show_panic,  0,
  299             "Print the current panic string",NULL,NULL) },
  300         { DDB_ADD_CMD("pool",   db_pool_print_cmd,      0,
  301             "Print the pool at address.", "[/clp] address",NULL) },
  302         /* added from all sub cmds */
  303         { DDB_ADD_CMD("pools",  db_show_all_pools,
  304             0 ,"Show all pools",NULL,NULL) },
  305         { DDB_ADD_CMD("proc",   db_show_proc,
  306             0 ,"Print process information.",NULL,NULL) },
  307         /* added from all sub cmds */
  308         { DDB_ADD_CMD("procs",  db_show_all_procs,
  309             0 ,"List all processes.",NULL,NULL) },
  310         { DDB_ADD_CMD("registers",      db_show_regs,           0,
  311             "Display the register set.", "[/u]",NULL) },
  312 #if defined(INET)
  313         { DDB_ADD_CMD("routes", db_show_routes,         0,NULL,NULL,NULL) },
  314 #endif
  315         { DDB_ADD_CMD("sched_qs",       db_show_sched_qs,       0,
  316             "Print the state of the scheduler's run queues.",
  317             NULL,NULL) },
  318         { DDB_ADD_CMD("socket", db_socket_print_cmd,    0,NULL,NULL,NULL) },
  319         { DDB_ADD_CMD("uvmexp", db_uvmexp_print_cmd, 0,
  320             "Print a selection of UVM counters and statistics.",
  321             NULL,NULL) },
  322         { DDB_ADD_CMD("vmem", db_vmem_print_cmd,        0,
  323             "Print the vmem usage.", "address", NULL) },
  324         { DDB_ADD_CMD("vmems", db_show_all_vmems,       0,
  325             "Show all vmems.", NULL, NULL) },
  326         { DDB_ADD_CMD("vnode",  db_vnode_print_cmd,     0,
  327             "Print the vnode at address.", "[/f] address",NULL) },
  328         { DDB_ADD_CMD("vnode_lock",     db_vnode_lock_print_cmd,        0,
  329             "Print the vnode having that address as v_lock.",
  330             "[/f] address",NULL) },
  331 #ifdef _KERNEL
  332         { DDB_ADD_CMD("watches",        db_listwatch_cmd,       0,
  333             "Display all watchpoints.", NULL,NULL) },
  334 #endif
  335         { DDB_END_CMD },
  336 };
  337 
  338 static const struct db_command db_command_table[] = {
  339         { DDB_ADD_CMD("b",              db_breakpoint_cmd,      0,
  340             "Set a breakpoint at address", "[/u] address[,count].",NULL) },
  341         { DDB_ADD_CMD("break",  db_breakpoint_cmd,      0,
  342             "Set a breakpoint at address", "[/u] address[,count].",NULL) },
  343         { DDB_ADD_CMD("bt",             db_stack_trace_cmd,     0,
  344             "Show backtrace.", "See help trace.",NULL) },
  345         { DDB_ADD_CMD("c",              db_continue_cmd,        0,
  346             "Continue execution.", "[/c]",NULL) },
  347         { DDB_ADD_CMD("call",   db_fncall,              CS_OWN,
  348             "Call the function", "address[(expression[,...])]",NULL) },
  349         { DDB_ADD_CMD("callout",        db_show_callout,        0, NULL,
  350             NULL,NULL ) },
  351         { DDB_ADD_CMD("continue",       db_continue_cmd,        0,
  352             "Continue execution.", "[/c]",NULL) },
  353         { DDB_ADD_CMD("d",              db_delete_cmd,          0,
  354             "Delete a breakpoint.", "address | #number",NULL) },
  355         { DDB_ADD_CMD("delete", db_delete_cmd,          0,
  356             "Delete a breakpoint.", "address | #number",NULL) },
  357         { DDB_ADD_CMD("dmesg",  db_dmesg,               0,
  358             "Show kernel message buffer.", "[count]",NULL) },
  359         { DDB_ADD_CMD("dwatch", db_deletewatch_cmd,     0,
  360             "Delete the watchpoint.", "address",NULL) },
  361         { DDB_ADD_CMD("examine",        db_examine_cmd,         CS_SET_DOT,
  362             "Display the address locations.",
  363             "[/modifier] address[,count]",NULL) },
  364         { DDB_ADD_CMD("exit",           db_continue_cmd,        0,
  365             "Continue execution.", "[/c]",NULL) },
  366         { DDB_ADD_CMD("help",   db_help_print_cmd, CS_OWN|CS_NOREPEAT,
  367             "Display help about commands",
  368             "Use other commands as arguments.",NULL) },
  369         { DDB_ADD_CMD("kill",   db_kill_proc,           CS_OWN,
  370             "Send a signal to the process","pid[,signal_number]",
  371             "   pid:\t\t\tthe process id (may need 0t prefix for decimal)\n"
  372             "   signal_number:\tthe signal to send") },
  373 #ifdef KGDB
  374         { DDB_ADD_CMD("kgdb",   db_kgdb_cmd,    0,      NULL,NULL,NULL) },
  375 #endif
  376         { DDB_ADD_CMD("machine",NULL,CS_MACH,
  377             "Architecture specific functions.",NULL,NULL) },
  378         { DDB_ADD_CMD("match",  db_trace_until_matching_cmd,0,
  379             "Stop at the matching return instruction.","See help next",NULL) },
  380         { DDB_ADD_CMD("next",   db_trace_until_matching_cmd,0,
  381             "Stop at the matching return instruction.","[/p]",NULL) },
  382         { DDB_ADD_CMD("p",              db_print_cmd,           0,
  383             "Print address according to the format.",
  384             "[/axzodurc] address [address ...]",NULL) },
  385         { DDB_ADD_CMD("print",  db_print_cmd,           0,
  386             "Print address according to the format.",
  387             "[/axzodurc] address [address ...]",NULL) },
  388         { DDB_ADD_CMD("ps",             db_show_all_procs,      0,
  389             "Print all processes.","See show all procs",NULL) },
  390         { DDB_ADD_CMD("quit",           db_continue_cmd,        0,
  391             "Continue execution.", "[/c]",NULL) },
  392         { DDB_ADD_CMD("reboot", db_reboot_cmd,          CS_OWN,
  393             "Reboot","0x1  RB_ASKNAME, 0x2 RB_SINGLE, 0x4 RB_NOSYNC, 0x8 RB_HALT,"
  394             "0x40 RB_KDB, 0x100 RB_DUMP, 0x808 RB_POWERDOWN",NULL) },
  395         { DDB_ADD_CMD("s",              db_single_step_cmd,     0,
  396             "Single-step count times.","[/p] [,count]",NULL) },
  397         { DDB_ADD_CMD("search", db_search_cmd,          CS_OWN|CS_SET_DOT,
  398             "Search memory from address for value.",
  399             "[/bhl] address value [mask] [,count]",NULL) },
  400         { DDB_ADD_CMD("set",    db_set_cmd,             CS_OWN,
  401             "Set the named variable","$variable [=] expression",NULL) },
  402         { DDB_ADD_CMD("show",   NULL, CS_SHOW,
  403             "Show kernel stats.", NULL,NULL) },
  404         { DDB_ADD_CMD("sifting",        db_sifting_cmd,         CS_OWN,
  405             "Search the symbol tables ","[/F] string",NULL) },
  406         { DDB_ADD_CMD("step",   db_single_step_cmd,     0,
  407             "Single-step count times.","[/p] [,count]",NULL) },
  408         { DDB_ADD_CMD("sync",   db_sync_cmd,            CS_OWN,
  409             "Force a crash dump, and then reboot.",NULL,NULL) },
  410         { DDB_ADD_CMD("trace",  db_stack_trace_cmd,     0,
  411             "Stack trace from frame-address.",
  412             "[/u[l]] [frame-address][,count]",NULL) },
  413         { DDB_ADD_CMD("until",  db_trace_until_call_cmd,0,
  414             "Stop at the next call or return instruction.","[/p]",NULL) },
  415         { DDB_ADD_CMD("w",              db_write_cmd,           CS_MORE|CS_SET_DOT,
  416             "Write the expressions at succeeding locations.",
  417             "[/bhl] address expression [expression ...]",NULL) },
  418         { DDB_ADD_CMD("watch",  db_watchpoint_cmd,      CS_MORE,
  419             "Set a watchpoint for a region. ","address[,size]",NULL) },
  420         { DDB_ADD_CMD("whatis", db_whatis_cmd, 0,
  421             "Describe what an address is", "address", NULL) },
  422         { DDB_ADD_CMD("write",  db_write_cmd,           CS_MORE|CS_SET_DOT,
  423             "Write the expressions at succeeding locations.",
  424             "[/bhl] address expression [expression ...]",NULL) },
  425         { DDB_ADD_CMD("x",              db_examine_cmd,         CS_SET_DOT,
  426             "Display the address locations.",
  427             "[/modifier] address[,count]",NULL) },
  428         { DDB_END_CMD },
  429 };
  430 
  431 static const struct db_command  *db_last_command = NULL;
  432 #if defined(DDB_COMMANDONENTER)
  433 char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ___STRING(DDB_COMMANDONENTER);
  434 #else /* defined(DDB_COMMANDONENTER) */
  435 char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = "";
  436 #endif /* defined(DDB_COMMANDONENTER) */
  437 #define DB_LINE_SEP     ';'
  438 
  439 /*
  440  * Execute commandlist after ddb start
  441  * This function goes through the command list created from commands and ';'
  442  */
  443 static void
  444 db_execute_commandlist(const char *cmdlist)
  445 {
  446         const char *cmd = cmdlist;
  447         const struct db_command *dummy = NULL;
  448 
  449         while (*cmd != '\0') {
  450                 const char *ep = cmd;
  451 
  452                 while (*ep != '\0' && *ep != DB_LINE_SEP) {
  453                         ep++;
  454                 }
  455                 db_set_line(cmd, ep);
  456                 db_command(&dummy);
  457                 cmd = ep;
  458                 if (*cmd == DB_LINE_SEP) {
  459                         cmd++;
  460                 }
  461         }
  462 }
  463 
  464 /* Initialize ddb command tables */
  465 void
  466 db_init_commands(void)
  467 {
  468         static bool done = false;
  469 
  470         if (done) return;
  471         done = true;
  472 
  473         /* register command tables */
  474         (void)db_register_tbl_entry(DDB_BASE_CMD, &db_base_cmd_builtins);
  475 #ifdef DB_MACHINE_COMMANDS
  476         (void)db_register_tbl_entry(DDB_MACH_CMD, &db_mach_cmd_builtins);
  477 #endif
  478         (void)db_register_tbl_entry(DDB_SHOW_CMD, &db_show_cmd_builtins);
  479 }
  480 
  481 
  482 /*
  483  * Add command table to the specified list
  484  * Arg:
  485  * int type specifies type of command table DDB_SHOW_CMD|DDB_BASE_CMD|DDB_MAC_CMD
  486  * *cmd_tbl pointer to static allocated db_command table
  487  *
  488  * Command table must be NULL terminated array of struct db_command
  489  */
  490 int
  491 db_register_tbl(uint8_t type, const struct db_command *cmd_tbl)
  492 {
  493         struct db_cmd_tbl_en *list_ent;
  494 
  495         /* empty list - ignore */
  496         if (cmd_tbl->name == 0)
  497                 return 0;
  498 
  499         /* force builtin commands to be registered first */
  500         db_init_commands();
  501 
  502         /* now create a list entry for this table */
  503         list_ent = db_zalloc(sizeof(*list_ent));
  504         if (list_ent == NULL)
  505                 return ENOMEM;
  506         list_ent->db_cmd=cmd_tbl;
  507 
  508         /* and register it */
  509         return db_register_tbl_entry(type, list_ent);
  510 }
  511 
  512 static int
  513 db_register_tbl_entry(uint8_t type, struct db_cmd_tbl_en *list_ent)
  514 {
  515         struct db_cmd_tbl_en_head *list;
  516 
  517         switch(type) {
  518         case DDB_BASE_CMD:
  519                 list = &db_base_cmd_list;
  520                 break;
  521         case DDB_SHOW_CMD:
  522                 list = &db_show_cmd_list;
  523                 break;
  524         case DDB_MACH_CMD:
  525                 list = &db_mach_cmd_list;
  526                 break;
  527         default:
  528                 return ENOENT;
  529         }
  530 
  531         TAILQ_INSERT_TAIL(list, list_ent, db_cmd_next);
  532 
  533         return 0;
  534 }
  535 
  536 /*
  537  * Remove command table specified with db_cmd address == cmd_tbl
  538  */
  539 int
  540 db_unregister_tbl(uint8_t type,const struct db_command *cmd_tbl)
  541 {
  542         struct db_cmd_tbl_en *list_ent;
  543         struct db_cmd_tbl_en_head *list;
  544 
  545         /* find list on which the entry should live */
  546         switch (type) {
  547         case DDB_BASE_CMD:
  548                 list=&db_base_cmd_list;
  549                 break;
  550         case DDB_SHOW_CMD:
  551                 list=&db_show_cmd_list;
  552                 break;
  553         case DDB_MACH_CMD:
  554                 list=&db_mach_cmd_list;
  555                 break;
  556         default:
  557                 return EINVAL;
  558         }
  559 
  560         TAILQ_FOREACH (list_ent, list, db_cmd_next) {
  561                 if (list_ent->db_cmd == cmd_tbl){
  562                         TAILQ_REMOVE(list,
  563                             list_ent, db_cmd_next);
  564                         db_free(list_ent, sizeof(*list_ent));
  565                         return 0;
  566                 }
  567         }
  568         return ENOENT;
  569 }
  570 
  571 #ifndef _KERNEL
  572 #define cnpollc(c)      __nothing
  573 #endif
  574 
  575 /*
  576  * This function is called via db_trap() or directly from
  577  * machine trap code.
  578  */
  579 void
  580 db_command_loop(void)
  581 {
  582         label_t db_jmpbuf;
  583         label_t *savejmp;
  584 
  585         /*
  586          * Initialize 'prev' and 'next' to dot.
  587          */
  588         db_prev = db_dot;
  589         db_next = db_dot;
  590 
  591         db_cmd_loop_done = false;
  592 
  593         /* Init default command tables add machine, base,
  594            show command tables to the list */
  595         db_init_commands();
  596 
  597         /* save context for return from ddb */
  598         savejmp = db_recover;
  599         db_recover = &db_jmpbuf;
  600 
  601         /*
  602          * Execute default ddb start commands only if this is the
  603          * first entry into DDB, in case the start commands fault
  604          * and we recurse into here.
  605          */
  606         if (savejmp == NULL && db_cmd_on_enter[0] != '\0') {
  607                 if (setjmp(&db_jmpbuf) == 0)
  608                         db_execute_commandlist(db_cmd_on_enter);
  609         }
  610 
  611         (void) setjmp(&db_jmpbuf);
  612         while (!db_cmd_loop_done) {
  613                 if (db_print_position() != 0)
  614                         db_printf("\n");
  615                 db_output_line = 0;
  616                 cnpollc(1);
  617                 (void) db_read_line();
  618                 cnpollc(0);
  619                 db_command(&db_last_command);
  620         }
  621 
  622         db_recover = savejmp;
  623 }
  624 
  625 /*
  626  * Search command table for command prefix
  627  */
  628 static int
  629 db_cmd_search_table(const char *name,
  630                     const struct db_command *table,
  631                     const struct db_command **cmdp)
  632 {
  633 
  634         const struct db_command *cmd;
  635         int result;
  636 
  637         result = CMD_NONE;
  638         *cmdp = NULL;
  639 
  640         for (cmd = table; cmd->name != 0; cmd++) {
  641                 const char *lp;
  642                 const char *rp;
  643 
  644                 lp = name;
  645                 rp = cmd->name;
  646                 while (*lp != '\0' && *lp == *rp) {
  647                         rp++;
  648                         lp++;
  649                 }
  650 
  651                 if (*lp != '\0') /* mismatch or extra chars in name */
  652                         continue;
  653 
  654                 if (*rp == '\0') { /* exact match */
  655                         *cmdp = cmd;
  656                         return (CMD_EXACT);
  657                 }
  658 
  659                 /* prefix match: end of name, not end of command */
  660                 if (result == CMD_NONE) {
  661                         result = CMD_PREFIX;
  662                         *cmdp = cmd;
  663                 }
  664                 else if (result == CMD_PREFIX) {
  665                         result = CMD_AMBIGUOUS;
  666                         *cmdp = NULL;
  667                 }
  668         }
  669 
  670         return (result);
  671 }
  672 
  673 
  674 /*
  675  * Search list of command tables for command
  676  */
  677 static int
  678 db_cmd_search(const char *name,
  679               struct db_cmd_tbl_en_head *list_head,
  680               const struct db_command **cmdp)
  681 {
  682         struct db_cmd_tbl_en *list_ent;
  683         const struct db_command *found_command;
  684         bool accept_prefix_match;
  685         int result;
  686 
  687         result = CMD_NONE;
  688         found_command = NULL;
  689         accept_prefix_match = true;
  690 
  691         TAILQ_FOREACH(list_ent, list_head, db_cmd_next) {
  692                 const struct db_command *cmd;
  693                 int found;
  694 
  695                 found = db_cmd_search_table(name, list_ent->db_cmd, &cmd);
  696                 if (found == CMD_EXACT) {
  697                         result = CMD_EXACT;
  698                         found_command = cmd;
  699                         break;
  700                 }
  701 
  702                 if (found == CMD_PREFIX) {
  703                         if (accept_prefix_match) {
  704                                 /*
  705                                  * Continue search, but note current result
  706                                  * in case we won't find anything else.
  707                                  */
  708                                 accept_prefix_match = false;
  709                                 result = CMD_PREFIX;
  710                                 found_command = cmd;
  711                         } else {
  712                                 /*
  713                                  * Watch out for globally ambiguous
  714                                  * prefix match that is not locally
  715                                  * ambiguous - with one match in one
  716                                  * table and another match(es) in
  717                                  * another table.
  718                                  */
  719                                 result = CMD_AMBIGUOUS;
  720                                 found_command = NULL;
  721                         }
  722                 }
  723                 else if (found == CMD_AMBIGUOUS) {
  724                         accept_prefix_match = false;
  725                         result = CMD_AMBIGUOUS;
  726                         found_command = NULL;
  727                 }
  728         }
  729 
  730         *cmdp = found_command;
  731         return result;
  732 }
  733 
  734 static void
  735 db_cmd_search_failed(char *name, int search_result)
  736 {
  737         if (search_result == CMD_NONE)
  738                 db_printf("No such command: %s\n", name);
  739         else
  740                 db_printf("Ambiguous command: %s\n", name);
  741 }
  742 
  743 
  744 /*
  745  * List commands to the console.
  746  */
  747 static void
  748 db_cmd_list(const struct db_cmd_tbl_en_head *list)
  749 {
  750 
  751         struct db_cmd_tbl_en *list_ent;
  752         const struct db_command *table;
  753         size_t          i, j, w, columns, lines, numcmds, width=0;
  754         const char      *p;
  755 
  756         TAILQ_FOREACH(list_ent,list,db_cmd_next) {
  757                 table = list_ent->db_cmd;
  758                 for (i = 0; table[i].name != NULL; i++) {
  759                         w = strlen(table[i].name);
  760                         if (w > width)
  761                                 width = w;
  762                 }
  763         }
  764 
  765         width = DB_NEXT_TAB(width);
  766 
  767         columns = db_max_width / width;
  768         if (columns == 0)
  769                 columns = 1;
  770 
  771         TAILQ_FOREACH(list_ent,list,db_cmd_next) {
  772                 table = list_ent->db_cmd;
  773 
  774                 for (numcmds = 0; table[numcmds].name != NULL; numcmds++)
  775                         ;
  776                 lines = (numcmds + columns - 1) / columns;
  777 
  778                 for (i = 0; i < lines; i++) {
  779                         for (j = 0; j < columns; j++) {
  780                                 p = table[j * lines + i].name;
  781                                 if (p)
  782                                         db_printf("%s", p);
  783                                 if (j * lines + i + lines >= numcmds) {
  784                                         db_putchar('\n');
  785                                         break;
  786                                 }
  787                                 if (p) {
  788                                         w = strlen(p);
  789                                         while (w < width) {
  790                                                 w = DB_NEXT_TAB(w);
  791                                                 db_putchar('\t');
  792                                         }
  793                                 }
  794                         }
  795                 }
  796         }
  797         return;
  798 }
  799 
  800 /*
  801  * Read complete command with all subcommands, starting with current
  802  * db_tok_string. If subcommand is missing, print the list of all
  803  * subcommands.  If command/subcommand is not found, print an error
  804  * message.  Returns pointer to "leaf" command or NULL.
  805  */
  806 static const struct db_command *
  807 db_read_command(void)
  808 {
  809         const struct db_command *command;
  810         struct db_cmd_tbl_en_head *list;
  811         int found;
  812         int t;
  813 
  814         list = &db_base_cmd_list;
  815         do {
  816                 found = db_cmd_search(db_tok_string, list, &command);
  817                 if (command == NULL) {
  818                         db_cmd_search_failed(db_tok_string, found);
  819                         db_flush_lex();
  820                         return NULL;
  821                 }
  822 
  823                 if (command->flag == CS_SHOW)
  824                         list = &db_show_cmd_list;
  825                 else if (command->flag == CS_MACH)
  826                         list = &db_mach_cmd_list;
  827                 else if (command->flag == CS_COMPAT)
  828                         /* same list */;
  829                 else
  830                         break; /* expect no more subcommands */
  831 
  832                 t = db_read_token(); /* read subcommand */
  833                 if (t != tIDENT) {
  834                         /* if none given - just print all of them */
  835                         db_cmd_list(list);
  836                         db_flush_lex();
  837                         return NULL;
  838                 }
  839         } while (list != NULL);
  840 
  841         return command;
  842 }
  843 
  844 /*
  845  * Parse command line and execute appropriate function.
  846  */
  847 static void
  848 db_command(const struct db_command **last_cmdp)
  849 {
  850         static db_expr_t last_count = 0;
  851 
  852         int t;
  853         const struct db_command *command;
  854         db_expr_t addr, count;
  855         bool have_addr;
  856         char modif[TOK_STRING_SIZE];
  857 
  858         command = NULL;
  859         have_addr = false;
  860         count = -1;
  861 
  862         t = db_read_token();
  863         if ((t == tEOL) || (t == tCOMMA)) {
  864                 /*
  865                  * An empty line repeats last command, at 'next'.
  866                  * Only a count repeats the last command with the new count.
  867                  */
  868                 command = *last_cmdp;
  869 
  870                 if (!command)
  871                         return;
  872 
  873                 addr = (db_expr_t)db_next;
  874                 if (t == tCOMMA) {
  875                         if (!db_expression(&count)) {
  876                                 db_printf("Count missing\n");
  877                                 db_flush_lex();
  878                                 return;
  879                         }
  880                 } else
  881                         count = last_count;
  882                 modif[0] = '\0';
  883                 db_skip_to_eol();
  884 
  885         } else if (t == tEXCL) {
  886                 db_fncall(0, 0, 0, NULL);
  887                 return;
  888 
  889         } else if (t != tIDENT) {
  890                 db_printf("?\n");
  891                 db_flush_lex();
  892                 return;
  893 
  894         } else {
  895 
  896                 command = db_read_command();
  897                 if (command == NULL)
  898                         return;
  899 
  900                 if ((command->flag & CS_OWN) == 0) {
  901 
  902                         /*
  903                          * Standard syntax:
  904                          * command [/modifier] [addr] [,count]
  905                          */
  906                         t = db_read_token(); /* get modifier */
  907                         if (t == tSLASH) {
  908                                 t = db_read_token();
  909                                 if (t != tIDENT) {
  910                                         db_printf("Bad modifier\n");
  911                                         db_flush_lex();
  912                                         return;
  913                                 }
  914                                 /* save modifier */
  915                                 strlcpy(modif, db_tok_string, sizeof(modif));
  916 
  917                         } else {
  918                                 db_unread_token(t);
  919                                 modif[0] = '\0';
  920                         }
  921 
  922                         if (db_expression(&addr)) { /*get address*/
  923                                 db_dot = (db_addr_t) addr;
  924                                 db_last_addr = db_dot;
  925                                 have_addr = true;
  926                         } else {
  927                                 addr = (db_expr_t) db_dot;
  928                         }
  929 
  930                         t = db_read_token();
  931                         if (t == tCOMMA) { /*Get count*/
  932                                 if (!db_expression(&count)) {
  933                                         db_printf("Count missing\n");
  934                                         db_flush_lex();
  935                                         return;
  936                                 }
  937                         } else {
  938                                 db_unread_token(t);
  939                         }
  940                         if ((command->flag & CS_MORE) == 0) {
  941                                 db_skip_to_eol();
  942                         }
  943                 }
  944         }
  945 
  946         if (command != NULL && command->flag & CS_NOREPEAT) {
  947                 *last_cmdp = NULL;
  948                 last_count = 0;
  949         } else {
  950                 *last_cmdp = command;
  951                 last_count = count;
  952         }
  953 
  954 
  955         if (command != NULL) {
  956                 /*
  957                  * Execute the command.
  958                  */
  959                 if (command->fcn != NULL)
  960                         (*command->fcn)(addr, have_addr, count, modif);
  961 
  962                 if (command->flag & CS_SET_DOT) {
  963                         /*
  964                          * If command changes dot, set dot to
  965                          * previous address displayed (if 'ed' style).
  966                          */
  967                         if (db_ed_style)
  968                                 db_dot = db_prev;
  969                         else
  970                                 db_dot = db_next;
  971                 } else {
  972                         /*
  973                          * If command does not change dot,
  974                          * set 'next' location to be the same.
  975                          */
  976                         db_next = db_dot;
  977                 }
  978         }
  979 }
  980 
  981 /*
  982  * Print help for commands
  983  */
  984 static void
  985 db_help_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
  986 const char *modif)
  987 {
  988         const struct db_command *command;
  989         int t;
  990 
  991         t = db_read_token();
  992 
  993         /* is there another command after the "help"? */
  994         if (t != tIDENT) {
  995                 /* print base commands */
  996                 db_cmd_list(&db_base_cmd_list);
  997                 return;
  998         }
  999 
 1000         command = db_read_command();
 1001         if (command == NULL)
 1002                 return;
 1003 
 1004 #ifdef DDB_VERBOSE_HELP
 1005         db_printf("Command: %s\n", command->name);
 1006         if (command->cmd_descr != NULL)
 1007                 db_printf(" Description: %s\n", command->cmd_descr);
 1008         if (command->cmd_arg != NULL)
 1009                 db_printf(" Arguments: %s\n", command->cmd_arg);
 1010         if (command->cmd_arg_help != NULL)
 1011                 db_printf(" Arguments description:\n%s\n",
 1012                           command->cmd_arg_help);
 1013         if ((command->cmd_arg == NULL) && (command->cmd_descr == NULL))
 1014                 db_printf(" No help message.\n");
 1015 #endif
 1016 
 1017         db_skip_to_eol();
 1018 }
 1019 
 1020 /*ARGSUSED*/
 1021 static void
 1022 db_kqueue_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
 1023     const char *modif)
 1024 {
 1025 #ifdef _KERNEL
 1026         bool full = false;
 1027 
 1028         if (modif[0] == 'f')
 1029                 full = true;
 1030 
 1031         if (have_addr == false) {
 1032                 db_printf("%s: must specify kqueue address\n", __func__);
 1033                 return;
 1034         }
 1035 
 1036         kqueue_printit((struct kqueue *)(uintptr_t) addr, full, db_printf);
 1037 #else
 1038         db_kernelonly();
 1039 #endif  /* XXX CRASH(8) */
 1040 }
 1041 
 1042 /*ARGSUSED*/
 1043 static void
 1044 db_map_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
 1045     const char *modif)
 1046 {
 1047 #ifdef _KERNEL
 1048         bool full = false;
 1049 
 1050         if (modif[0] == 'f')
 1051                 full = true;
 1052 
 1053         if (have_addr == false)
 1054                 addr = (db_expr_t)(uintptr_t)db_read_ptr("kernel_map");
 1055 
 1056         uvm_map_printit((struct vm_map *)(uintptr_t) addr, full, db_printf);
 1057 #else
 1058         db_kernelonly();
 1059 #endif  /* XXX CRASH(8) */
 1060 }
 1061 
 1062 /*ARGSUSED*/
 1063 static void
 1064 db_object_print_cmd(db_expr_t addr, bool have_addr,
 1065     db_expr_t count, const char *modif)
 1066 {
 1067 #ifdef _KERNEL /* XXX CRASH(8) */
 1068         bool full = false;
 1069 
 1070         if (modif[0] == 'f')
 1071                 full = true;
 1072 
 1073         uvm_object_printit((struct uvm_object *)(uintptr_t) addr, full,
 1074             db_printf);
 1075 #else
 1076         db_kernelonly();
 1077 #endif
 1078 }
 1079 
 1080 /*ARGSUSED*/
 1081 static void
 1082 db_page_print_cmd(db_expr_t addr, bool have_addr,
 1083     db_expr_t count, const char *modif)
 1084 {
 1085 #ifdef _KERNEL /* XXX CRASH(8) */
 1086         bool full = false;
 1087 
 1088         if (modif[0] == 'f')
 1089                 full = true;
 1090 
 1091         uvm_page_printit((struct vm_page *)(uintptr_t) addr, full, db_printf);
 1092 #else
 1093         db_kernelonly();
 1094 #endif
 1095 }
 1096 
 1097 /*ARGSUSED*/
 1098 static void
 1099 db_show_all_pages(db_expr_t addr, bool have_addr,
 1100     db_expr_t count, const char *modif)
 1101 {
 1102 
 1103 #ifdef _KERNEL /* XXX CRASH(8) */
 1104         uvm_page_printall(db_printf);
 1105 #else
 1106         db_kernelonly();
 1107 #endif
 1108 }
 1109 
 1110 /*ARGSUSED*/
 1111 static void
 1112 db_buf_print_cmd(db_expr_t addr, bool have_addr,
 1113     db_expr_t count, const char *modif)
 1114 {
 1115 #ifdef _KERNEL /* XXX CRASH(8) */
 1116         bool full = false;
 1117 
 1118         if (modif[0] == 'f')
 1119                 full = true;
 1120 
 1121         vfs_buf_print((struct buf *)(uintptr_t) addr, full, db_printf);
 1122 #else
 1123         db_kernelonly();
 1124 #endif
 1125 }
 1126 
 1127 /*ARGSUSED*/
 1128 static void
 1129 db_event_print_cmd(db_expr_t addr, bool have_addr,
 1130     db_expr_t count, const char *modif)
 1131 {
 1132         bool showzero = false;
 1133         bool showall = true;
 1134         bool showintr = false;
 1135         bool showtrap = false;
 1136         bool showmisc = false;
 1137         struct evcnt ev, *evp;
 1138         char buf[80];
 1139         int i;
 1140 
 1141         i = 0;
 1142         while (modif[i]) {
 1143                 switch (modif[i]) {
 1144                 case 'f':
 1145                         showzero = true;
 1146                         break;
 1147                 case 'i':
 1148                         showintr = true;
 1149                         showall = false;
 1150                         break;
 1151                 case 't':
 1152                         showtrap = true;
 1153                         showall = false;
 1154                         break;
 1155                 case 'm':
 1156                         showmisc = true;
 1157                         showall = false;
 1158                         break;
 1159                 }
 1160                 i++;
 1161         }
 1162 
 1163         if (showall)
 1164                 showmisc = showintr = showtrap = true;
 1165 
 1166         evp = (struct evcnt *)db_read_ptr("allevents");
 1167         while (evp != NULL) {
 1168                 db_read_bytes((db_addr_t)evp, sizeof(ev), (char *)&ev);
 1169                 evp = ev.ev_list.tqe_next;
 1170                 if (ev.ev_count == 0 && !showzero)
 1171                         continue;
 1172                 if (ev.ev_type == EVCNT_TYPE_INTR && !showintr)
 1173                         continue;
 1174                 if (ev.ev_type == EVCNT_TYPE_TRAP && !showtrap)
 1175                         continue;
 1176                 if (ev.ev_type == EVCNT_TYPE_MISC && !showmisc)
 1177                         continue;
 1178                 db_read_bytes((db_addr_t)ev.ev_group, ev.ev_grouplen + 1, buf);
 1179                 db_printf("evcnt type %d: %s ", ev.ev_type, buf);
 1180                 db_read_bytes((db_addr_t)ev.ev_name, ev.ev_namelen + 1, buf);
 1181                 db_printf("%s = %lld\n", buf, (long long)ev.ev_count);
 1182         }
 1183 }
 1184 
 1185 /*ARGSUSED*/
 1186 static void
 1187 db_vnode_print_cmd(db_expr_t addr, bool have_addr,
 1188     db_expr_t count, const char *modif)
 1189 {
 1190 #ifdef _KERNEL /* XXX CRASH(8) */
 1191         bool full = false;
 1192 
 1193         if (modif[0] == 'f')
 1194                 full = true;
 1195 
 1196         vfs_vnode_print((struct vnode *)(uintptr_t) addr, full, db_printf);
 1197 #else
 1198         db_kernelonly();
 1199 #endif
 1200 }
 1201 
 1202 /*ARGSUSED*/
 1203 static void
 1204 db_vnode_lock_print_cmd(db_expr_t addr, bool have_addr,
 1205     db_expr_t count, const char *modif)
 1206 {
 1207 #ifdef _KERNEL /* XXX CRASH(8) */
 1208         bool full = false;
 1209 
 1210         if (modif[0] == 'f')
 1211                 full = true;
 1212 
 1213         vfs_vnode_lock_print((struct vnode *)(uintptr_t) addr, full, db_printf);
 1214 #else
 1215         db_kernelonly();
 1216 #endif
 1217 }
 1218 
 1219 /*ARGSUSED*/
 1220 static void
 1221 db_vmem_print_cmd(db_expr_t addr, bool have_addr,
 1222     db_expr_t count, const char *modif)
 1223 {
 1224 
 1225 #ifdef _KERNEL /* XXX CRASH(8) */
 1226         vmem_print((uintptr_t) addr, modif, db_printf);
 1227 #else
 1228         db_kernelonly();
 1229 #endif
 1230 }
 1231 
 1232 static void
 1233 db_mount_print_cmd(db_expr_t addr, bool have_addr,
 1234     db_expr_t count, const char *modif)
 1235 {
 1236 #ifdef _KERNEL  /* XXX CRASH(8) */
 1237         bool full = false;
 1238 
 1239         if (modif[0] == 'f')
 1240                 full = true;
 1241 
 1242         vfs_mount_print((struct mount *)(uintptr_t) addr, full, db_printf);
 1243 #endif
 1244 }
 1245 
 1246 static void
 1247 db_show_all_mount(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
 1248 {
 1249 #ifdef _KERNEL  /* XXX CRASH(8) */
 1250         bool full = false;
 1251 
 1252         if (modif[0] == 'f')
 1253                 full = true;
 1254 
 1255         vfs_mount_print_all(full, db_printf);
 1256 #else
 1257         db_kernelonly();
 1258 #endif
 1259 }
 1260 
 1261 /*ARGSUSED*/
 1262 static void
 1263 db_mbuf_print_cmd(db_expr_t addr, bool have_addr,
 1264     db_expr_t count, const char *modif)
 1265 {
 1266 
 1267 #ifdef _KERNEL /* XXX CRASH(8) */
 1268         m_print((const struct mbuf *)(uintptr_t) addr, modif, db_printf);
 1269 #else
 1270         db_kernelonly();
 1271 #endif
 1272 }
 1273 
 1274 /*ARGSUSED*/
 1275 static void
 1276 db_pool_print_cmd(db_expr_t addr, bool have_addr,
 1277     db_expr_t count, const char *modif)
 1278 {
 1279 
 1280 #ifdef _KERNEL /* XXX CRASH(8) */
 1281         pool_printit((struct pool *)(uintptr_t) addr, modif, db_printf);
 1282 #else
 1283         db_kernelonly();
 1284 #endif
 1285 }
 1286 
 1287 /*ARGSUSED*/
 1288 static void
 1289 db_namecache_print_cmd(db_expr_t addr, bool have_addr,
 1290     db_expr_t count, const char *modif)
 1291 {
 1292 
 1293 #ifdef _KERNEL /* XXX CRASH(8) */
 1294         namecache_print((struct vnode *)(uintptr_t) addr, db_printf);
 1295 #else
 1296         db_kernelonly();
 1297 #endif
 1298 }
 1299 
 1300 /*ARGSUSED*/
 1301 static void
 1302 db_uvmexp_print_cmd(db_expr_t addr, bool have_addr,
 1303     db_expr_t count, const char *modif)
 1304 {
 1305 
 1306 #ifdef _KERNEL  /* XXX CRASH(8) */
 1307         uvmexp_print(db_printf);
 1308 #else
 1309         db_kernelonly();
 1310 #endif
 1311 }
 1312 
 1313 /*ARGSUSED */
 1314 static void
 1315 db_socket_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
 1316     const char *modif)
 1317 {
 1318 
 1319 #ifdef _KERNEL  /* XXX CRASH(8) */
 1320         socket_print(modif, db_printf);
 1321 #else
 1322         db_kernelonly();
 1323 #endif
 1324 }
 1325 
 1326 #ifdef KERNHIST
 1327 /*ARGSUSED*/
 1328 static void
 1329 db_kernhist_print_cmd(db_expr_t addr, bool have_addr,
 1330     db_expr_t count, const char *modif)
 1331 {
 1332 
 1333         if (!have_addr)
 1334                 addr = 0;
 1335 
 1336         if (count == -1)
 1337                 count = 0;
 1338 
 1339         kernhist_print((void *)(uintptr_t)addr, count, modif, db_printf);
 1340 }
 1341 #endif
 1342 
 1343 /*ARGSUSED*/
 1344 static void
 1345 db_lock_print_cmd(db_expr_t addr, bool have_addr,
 1346     db_expr_t count, const char *modif)
 1347 {
 1348 
 1349         lockdebug_lock_print(have_addr ? (void *)(uintptr_t)addr : NULL,
 1350             db_printf);
 1351 }
 1352 
 1353 static void
 1354 db_show_all_locks(db_expr_t addr, bool have_addr,
 1355     db_expr_t count, const char *modif)
 1356 {
 1357 
 1358 #ifdef _KERNEL  /* XXX CRASH(8) */
 1359         lockdebug_show_all_locks(db_printf, modif);
 1360 #else
 1361         db_kernelonly();
 1362 #endif
 1363 }
 1364 
 1365 static void
 1366 db_show_all_freelists(db_expr_t addr, bool have_addr,
 1367     db_expr_t count, const char *modif)
 1368 {
 1369 
 1370 #ifdef _KERNEL  /* XXX CRASH(8) */
 1371         uvm_page_print_freelists(db_printf);
 1372 #else
 1373         db_kernelonly();
 1374 #endif
 1375 }
 1376 
 1377 static void
 1378 db_show_lockstats(db_expr_t addr, bool have_addr,
 1379     db_expr_t count, const char *modif)
 1380 {
 1381 
 1382 #ifdef _KERNEL  /* XXX CRASH(8) */
 1383         lockdebug_show_lockstats(db_printf);
 1384 #else
 1385         db_kernelonly();
 1386 #endif
 1387 }
 1388 
 1389 #ifdef FDT
 1390 /*ARGSUSED*/
 1391 static void
 1392 db_fdt_print_cmd(db_expr_t addr, bool have_addr,
 1393     db_expr_t count, const char *modif)
 1394 {
 1395 #ifdef _KERNEL /* XXX CRASH(8) */
 1396         bool full = false;
 1397 
 1398         if (modif[0] == 'f')
 1399                 full = true;
 1400 
 1401         fdt_print(have_addr ? (void *)(uintptr_t)addr : fdtbus_get_data(),
 1402             full, db_printf);
 1403 #else
 1404         db_kernelonly();
 1405 #endif
 1406 }
 1407 #endif
 1408 
 1409 /*
 1410  * Call random function:
 1411  * !expr(arg,arg,arg)
 1412  */
 1413 /*ARGSUSED*/
 1414 static void
 1415 db_fncall(db_expr_t addr, bool have_addr,
 1416     db_expr_t count, const char *modif)
 1417 {
 1418 #ifdef _KERNEL
 1419         db_expr_t       fn_addr;
 1420 #define MAXARGS         11
 1421         db_expr_t       args[MAXARGS];
 1422         int             nargs = 0;
 1423         db_expr_t       retval;
 1424         db_expr_t       (*func)(db_expr_t, ...);
 1425         int             t;
 1426 
 1427         if (!db_expression(&fn_addr)) {
 1428                 db_printf("Bad function\n");
 1429                 db_flush_lex();
 1430                 return;
 1431         }
 1432         func = (db_expr_t (*)(db_expr_t, ...))(uintptr_t) fn_addr;
 1433 
 1434         t = db_read_token();
 1435         if (t == tLPAREN) {
 1436                 if (db_expression(&args[0])) {
 1437                         nargs++;
 1438                         while ((t = db_read_token()) == tCOMMA) {
 1439                                 if (nargs == MAXARGS) {
 1440                                         db_printf("Too many arguments\n");
 1441                                         db_flush_lex();
 1442                                         return;
 1443                                 }
 1444                                 if (!db_expression(&args[nargs])) {
 1445                                         db_printf("Argument missing\n");
 1446                                         db_flush_lex();
 1447                                         return;
 1448                                 }
 1449                                 nargs++;
 1450                         }
 1451                         db_unread_token(t);
 1452                 }
 1453                 if (db_read_token() != tRPAREN) {
 1454                         db_printf("?\n");
 1455                         db_flush_lex();
 1456                         return;
 1457                 }
 1458         }
 1459         db_skip_to_eol();
 1460 
 1461         while (nargs < MAXARGS) {
 1462                 args[nargs++] = 0;
 1463         }
 1464 
 1465         retval = (*func)(args[0], args[1], args[2], args[3], args[4],
 1466                          args[5], args[6], args[7], args[8], args[9]);
 1467         db_printf("%s\n", db_num_to_str(retval));
 1468 #else   /* _KERNEL */
 1469         db_kernelonly();
 1470 #endif  /* _KERNEL */
 1471 }
 1472 
 1473 static void
 1474 db_reboot_cmd(db_expr_t addr, bool have_addr,
 1475     db_expr_t count, const char *modif)
 1476 {
 1477 #ifdef _KERNEL
 1478         db_expr_t bootflags;
 1479 
 1480         /* Flags, default to RB_AUTOBOOT */
 1481         if (!db_expression(&bootflags))
 1482                 bootflags = (db_expr_t)RB_AUTOBOOT;
 1483         if (db_read_token() != tEOL) {
 1484                 db_error("?\n");
 1485                 /*NOTREACHED*/
 1486         }
 1487         /*
 1488          * We are leaving DDB, never to return upward.
 1489          * Clear db_recover so that we can debug faults in functions
 1490          * called from cpu_reboot.
 1491          */
 1492         db_recover = 0;
 1493         /* Avoid all mutex errors */
 1494         lockdebug_dismiss();
 1495         panicstr = "reboot forced via kernel debugger";
 1496         /* Make it possible to break into the debugger again */
 1497         spl0();
 1498         kern_reboot((int)bootflags, NULL);
 1499 #else   /* _KERNEL */
 1500         db_kernelonly();
 1501 #endif  /* _KERNEL */
 1502 }
 1503 
 1504 static void
 1505 db_sifting_cmd(db_expr_t addr, bool have_addr,
 1506     db_expr_t count, const char *modif)
 1507 {
 1508         int     mode, t;
 1509 
 1510         t = db_read_token();
 1511         if (t == tSLASH) {
 1512                 t = db_read_token();
 1513                 if (t != tIDENT) {
 1514                         bad_modifier:
 1515                         db_printf("Bad modifier\n");
 1516                         db_flush_lex();
 1517                         return;
 1518                 }
 1519                 if (!strcmp(db_tok_string, "F"))
 1520                         mode = 'F';
 1521                 else
 1522                         goto bad_modifier;
 1523                 t = db_read_token();
 1524         } else
 1525                 mode = 0;
 1526 
 1527         if (t == tIDENT)
 1528                 db_sifting(db_tok_string, mode);
 1529         else {
 1530                 db_printf("Bad argument (non-string)\n");
 1531                 db_flush_lex();
 1532         }
 1533 }
 1534 
 1535 static void
 1536 db_stack_trace_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
 1537 {
 1538         register const char *cp = modif;
 1539         register char c;
 1540         void (*pr)(const char *, ...);
 1541 
 1542         pr = db_printf;
 1543         while ((c = *cp++) != 0)
 1544                 if (c == 'l')
 1545                         pr = (void (*)(const char *, ...))printf;
 1546 
 1547         if (count == -1)
 1548                 count = 65535;
 1549 
 1550         db_stack_trace_print(addr, have_addr, count, modif, pr);
 1551 }
 1552 
 1553 static void
 1554 db_sync_cmd(db_expr_t addr, bool have_addr,
 1555     db_expr_t count, const char *modif)
 1556 {
 1557 #ifdef _KERNEL
 1558         /*
 1559          * We are leaving DDB, never to return upward.
 1560          * Clear db_recover so that we can debug faults in functions
 1561          * called from cpu_reboot.
 1562          */
 1563         db_recover = 0;
 1564         panicstr = "dump forced via kernel debugger";
 1565         kern_reboot(RB_DUMP, NULL);
 1566 #else   /* _KERNEL */
 1567         db_kernelonly();
 1568 #endif  /* _KERNEL */
 1569 }
 1570 
 1571 /*
 1572  * Describe what an address is
 1573  */
 1574 void
 1575 db_whatis_cmd(db_expr_t address, bool have_addr,
 1576     db_expr_t count, const char *modif)
 1577 {
 1578         const uintptr_t addr = (uintptr_t)address;
 1579 
 1580         db_lwp_whatis(addr, db_printf);
 1581 #ifdef _KERNEL  /* XXX CRASH(8) */
 1582         pool_whatis(addr, db_printf);
 1583         vmem_whatis(addr, db_printf);
 1584         uvm_whatis(addr, db_printf);
 1585         module_whatis(addr, db_printf);
 1586 #else
 1587         db_kernelonly();
 1588 #endif
 1589 }

Cache object: c724a0d5bf3368a6da0c0eaf4c7fb2f5


[ 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.