[BACK]Return to db_command.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / ddb

Annotation of src/sys/ddb/db_command.c, Revision 1.107

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

CVSweb <webmaster@jp.NetBSD.org>