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