db_command.c revision 6204
14Srgrimes/*
24Srgrimes * Mach Operating System
34Srgrimes * Copyright (c) 1991,1990 Carnegie Mellon University
44Srgrimes * All Rights Reserved.
54Srgrimes *
64Srgrimes * Permission to use, copy, modify and distribute this software and its
74Srgrimes * documentation is hereby granted, provided that both the copyright
84Srgrimes * notice and this permission notice appear in all copies of the
94Srgrimes * software, derivative works or modified versions, and any portions
104Srgrimes * thereof, and that both notices appear in supporting documentation.
114Srgrimes *
124Srgrimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
134Srgrimes * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
144Srgrimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
154Srgrimes *
164Srgrimes * Carnegie Mellon requests users of this software to return to
174Srgrimes *
184Srgrimes *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
194Srgrimes *  School of Computer Science
204Srgrimes *  Carnegie Mellon University
214Srgrimes *  Pittsburgh PA 15213-3890
224Srgrimes *
234Srgrimes * any improvements or extensions that they make and grant Carnegie the
244Srgrimes * rights to redistribute these changes.
254Srgrimes *
266204Sphk *	$Id: db_command.c,v 1.8 1994/08/27 16:14:08 davidg Exp $
274Srgrimes */
28623Srgrimes
294Srgrimes/*
304Srgrimes *	Author: David B. Golub, Carnegie Mellon University
314Srgrimes *	Date:	7/90
324Srgrimes */
33623Srgrimes
344Srgrimes/*
354Srgrimes * Command dispatcher.
364Srgrimes */
372056Swollman#include <sys/param.h>
382056Swollman#include <sys/systm.h>
392056Swollman#include <sys/proc.h>
402056Swollman#include <ddb/ddb.h>
414Srgrimes
424Srgrimes#include <ddb/db_lex.h>
434Srgrimes#include <ddb/db_output.h>
444Srgrimes
454Srgrimes#include <setjmp.h>
464Srgrimes
474Srgrimes/*
484Srgrimes * Exported global variables
494Srgrimes */
504Srgrimesboolean_t	db_cmd_loop_done;
514Srgrimesjmp_buf		db_jmpbuf;
524Srgrimesdb_addr_t	db_dot;
534Srgrimesdb_addr_t	db_last_addr;
544Srgrimesdb_addr_t	db_prev;
554Srgrimesdb_addr_t	db_next;
564Srgrimes
574Srgrimes/*
584Srgrimes * if 'ed' style: 'dot' is set at start of last item printed,
594Srgrimes * and '+' points to next line.
604Srgrimes * Otherwise: 'dot' points to next item, '..' points to last.
614Srgrimes */
624Srgrimesboolean_t	db_ed_style = TRUE;
634Srgrimes
644Srgrimes
654Srgrimes/*
664Srgrimes * Utility routine - discard tokens through end-of-line.
674Srgrimes */
684Srgrimesvoid
694Srgrimesdb_skip_to_eol()
704Srgrimes{
714Srgrimes	int	t;
724Srgrimes	do {
734Srgrimes	    t = db_read_token();
744Srgrimes	} while (t != tEOL);
754Srgrimes}
764Srgrimes
774Srgrimes/*
784Srgrimes * Command table
794Srgrimes */
804Srgrimesstruct command {
814Srgrimes	char *	name;		/* command name */
824Srgrimes	void	(*fcn)();	/* function to call */
834Srgrimes	int	flag;		/* extra info: */
844Srgrimes#define	CS_OWN		0x1	    /* non-standard syntax */
854Srgrimes#define	CS_MORE		0x2	    /* standard syntax, but may have other
864Srgrimes				       words at end */
874Srgrimes#define	CS_SET_DOT	0x100	    /* set dot after command */
884Srgrimes	struct command *more;	/* another level of command */
894Srgrimes};
904Srgrimes
914Srgrimes/*
924Srgrimes * Results of command search.
934Srgrimes */
944Srgrimes#define	CMD_UNIQUE	0
954Srgrimes#define	CMD_FOUND	1
964Srgrimes#define	CMD_NONE	2
974Srgrimes#define	CMD_AMBIGUOUS	3
984Srgrimes#define	CMD_HELP	4
994Srgrimes
1004Srgrimes/*
1014Srgrimes * Search for command prefix.
1024Srgrimes */
1034Srgrimesint
1044Srgrimesdb_cmd_search(name, table, cmdp)
1054Srgrimes	char *		name;
1064Srgrimes	struct command	*table;
1074Srgrimes	struct command	**cmdp;	/* out */
1084Srgrimes{
1094Srgrimes	struct command	*cmd;
1104Srgrimes	int		result = CMD_NONE;
1114Srgrimes
1124Srgrimes	for (cmd = table; cmd->name != 0; cmd++) {
1134Srgrimes	    register char *lp;
1144Srgrimes	    register char *rp;
1154Srgrimes	    register int  c;
1164Srgrimes
1174Srgrimes	    lp = name;
1184Srgrimes	    rp = cmd->name;
1194Srgrimes	    while ((c = *lp) == *rp) {
1204Srgrimes		if (c == 0) {
1214Srgrimes		    /* complete match */
1224Srgrimes		    *cmdp = cmd;
1234Srgrimes		    return (CMD_UNIQUE);
1244Srgrimes		}
1254Srgrimes		lp++;
1264Srgrimes		rp++;
1274Srgrimes	    }
1284Srgrimes	    if (c == 0) {
1294Srgrimes		/* end of name, not end of command -
1304Srgrimes		   partial match */
1314Srgrimes		if (result == CMD_FOUND) {
1324Srgrimes		    result = CMD_AMBIGUOUS;
1334Srgrimes		    /* but keep looking for a full match -
1344Srgrimes		       this lets us match single letters */
1354Srgrimes		}
1364Srgrimes		else {
1374Srgrimes		    *cmdp = cmd;
1384Srgrimes		    result = CMD_FOUND;
1394Srgrimes		}
1404Srgrimes	    }
1414Srgrimes	}
1424Srgrimes	if (result == CMD_NONE) {
1434Srgrimes	    /* check for 'help' */
1444Srgrimes		if (name[0] == 'h' && name[1] == 'e'
1454Srgrimes		    && name[2] == 'l' && name[3] == 'p')
1464Srgrimes			result = CMD_HELP;
1474Srgrimes	}
1484Srgrimes	return (result);
1494Srgrimes}
1504Srgrimes
1514Srgrimesvoid
1524Srgrimesdb_cmd_list(table)
1534Srgrimes	struct command *table;
1544Srgrimes{
1554Srgrimes	register struct command *cmd;
1564Srgrimes
1574Srgrimes	for (cmd = table; cmd->name != 0; cmd++) {
1584Srgrimes	    db_printf("%-12s", cmd->name);
1594Srgrimes	    db_end_line();
1604Srgrimes	}
1614Srgrimes}
1624Srgrimes
1634Srgrimesvoid
1644Srgrimesdb_command(last_cmdp, cmd_table)
1654Srgrimes	struct command	**last_cmdp;	/* IN_OUT */
1664Srgrimes	struct command	*cmd_table;
1674Srgrimes{
1684Srgrimes	struct command	*cmd;
1694Srgrimes	int		t;
1704Srgrimes	char		modif[TOK_STRING_SIZE];
1714Srgrimes	db_expr_t	addr, count;
172798Swollman	boolean_t	have_addr = FALSE;
1734Srgrimes	int		result;
1744Srgrimes
1754Srgrimes	t = db_read_token();
1764Srgrimes	if (t == tEOL) {
1774Srgrimes	    /* empty line repeats last command, at 'next' */
1784Srgrimes	    cmd = *last_cmdp;
1794Srgrimes	    addr = (db_expr_t)db_next;
1804Srgrimes	    have_addr = FALSE;
1814Srgrimes	    count = 1;
1824Srgrimes	    modif[0] = '\0';
1834Srgrimes	}
1844Srgrimes	else if (t == tEXCL) {
1854Srgrimes	    void db_fncall();
1864Srgrimes	    db_fncall();
1874Srgrimes	    return;
1884Srgrimes	}
1894Srgrimes	else if (t != tIDENT) {
1904Srgrimes	    db_printf("?\n");
1914Srgrimes	    db_flush_lex();
1924Srgrimes	    return;
1934Srgrimes	}
1944Srgrimes	else {
1954Srgrimes	    /*
1964Srgrimes	     * Search for command
1974Srgrimes	     */
1984Srgrimes	    while (cmd_table) {
1994Srgrimes		result = db_cmd_search(db_tok_string,
2004Srgrimes				       cmd_table,
2014Srgrimes				       &cmd);
2024Srgrimes		switch (result) {
2034Srgrimes		    case CMD_NONE:
2044Srgrimes			db_printf("No such command\n");
2054Srgrimes			db_flush_lex();
2064Srgrimes			return;
2074Srgrimes		    case CMD_AMBIGUOUS:
2084Srgrimes			db_printf("Ambiguous\n");
2094Srgrimes			db_flush_lex();
2104Srgrimes			return;
2114Srgrimes		    case CMD_HELP:
2124Srgrimes			db_cmd_list(cmd_table);
2134Srgrimes			db_flush_lex();
2144Srgrimes			return;
2154Srgrimes		    default:
2164Srgrimes			break;
2174Srgrimes		}
2184Srgrimes		if ((cmd_table = cmd->more) != 0) {
2194Srgrimes		    t = db_read_token();
2204Srgrimes		    if (t != tIDENT) {
2214Srgrimes			db_cmd_list(cmd_table);
2224Srgrimes			db_flush_lex();
2234Srgrimes			return;
2244Srgrimes		    }
2254Srgrimes		}
2264Srgrimes	    }
2274Srgrimes
2284Srgrimes	    if ((cmd->flag & CS_OWN) == 0) {
2294Srgrimes		/*
2304Srgrimes		 * Standard syntax:
2314Srgrimes		 * command [/modifier] [addr] [,count]
2324Srgrimes		 */
2334Srgrimes		t = db_read_token();
2344Srgrimes		if (t == tSLASH) {
2354Srgrimes		    t = db_read_token();
2364Srgrimes		    if (t != tIDENT) {
2374Srgrimes			db_printf("Bad modifier\n");
2384Srgrimes			db_flush_lex();
2394Srgrimes			return;
2404Srgrimes		    }
2414Srgrimes		    db_strcpy(modif, db_tok_string);
2424Srgrimes		}
2434Srgrimes		else {
2444Srgrimes		    db_unread_token(t);
2454Srgrimes		    modif[0] = '\0';
2464Srgrimes		}
2474Srgrimes
2484Srgrimes		if (db_expression(&addr)) {
2494Srgrimes		    db_dot = (db_addr_t) addr;
2504Srgrimes		    db_last_addr = db_dot;
2514Srgrimes		    have_addr = TRUE;
2524Srgrimes		}
2534Srgrimes		else {
2544Srgrimes		    addr = (db_expr_t) db_dot;
2554Srgrimes		    have_addr = FALSE;
2564Srgrimes		}
2574Srgrimes		t = db_read_token();
2584Srgrimes		if (t == tCOMMA) {
2594Srgrimes		    if (!db_expression(&count)) {
2604Srgrimes			db_printf("Count missing\n");
2614Srgrimes			db_flush_lex();
2624Srgrimes			return;
2634Srgrimes		    }
2644Srgrimes		}
2654Srgrimes		else {
2664Srgrimes		    db_unread_token(t);
2674Srgrimes		    count = -1;
2684Srgrimes		}
2694Srgrimes		if ((cmd->flag & CS_MORE) == 0) {
2704Srgrimes		    db_skip_to_eol();
2714Srgrimes		}
2724Srgrimes	    }
2734Srgrimes	}
2744Srgrimes	*last_cmdp = cmd;
2754Srgrimes	if (cmd != 0) {
2764Srgrimes	    /*
2774Srgrimes	     * Execute the command.
2784Srgrimes	     */
2794Srgrimes	    (*cmd->fcn)(addr, have_addr, count, modif);
2804Srgrimes
2814Srgrimes	    if (cmd->flag & CS_SET_DOT) {
2824Srgrimes		/*
2834Srgrimes		 * If command changes dot, set dot to
2844Srgrimes		 * previous address displayed (if 'ed' style).
2854Srgrimes		 */
2864Srgrimes		if (db_ed_style) {
2874Srgrimes		    db_dot = db_prev;
2884Srgrimes		}
2894Srgrimes		else {
2904Srgrimes		    db_dot = db_next;
2914Srgrimes		}
2924Srgrimes	    }
2934Srgrimes	    else {
2944Srgrimes		/*
2954Srgrimes		 * If command does not change dot,
2964Srgrimes		 * set 'next' location to be the same.
2974Srgrimes		 */
2984Srgrimes		db_next = db_dot;
2994Srgrimes	    }
3004Srgrimes	}
3014Srgrimes}
3024Srgrimes
3034Srgrimes/*
3044Srgrimes * 'show' commands
3054Srgrimes */
3062112Swollman
3072112Swollmanextern void	db_show_one_thread(), db_show_all_threads();
3082112Swollmanextern void	vm_page_print();
3092320Sdgextern void	db_ps();
3104Srgrimesextern void	ipc_port_print();
3114Srgrimesvoid		db_show_help();
3126204Sphkvoid		db_panic();
3134Srgrimes
3144Srgrimesstruct command db_show_all_cmds[] = {
3154Srgrimes#if 0
3161147Sguido	{ "threads",	db_show_all_threads,	0,	0 },
3172320Sdg#endif
3181549Srgrimes	{ "procs",	db_ps,			0,	0 },
3194Srgrimes	{ (char *)0 }
3204Srgrimes};
3214Srgrimes
3224Srgrimesstruct command db_show_cmds[] = {
3234Srgrimes	{ "all",	0,			0,	db_show_all_cmds },
3244Srgrimes	{ "registers",	db_show_regs,		0,	0 },
3254Srgrimes	{ "breaks",	db_listbreak_cmd, 	0,	0 },
3264Srgrimes	{ "watches",	db_listwatch_cmd, 	0,	0 },
3274Srgrimes#if 0
3284Srgrimes	{ "thread",	db_show_one_thread,	0,	0 },
3294Srgrimes#endif
3304Srgrimes	{ "map",	vm_map_print,		0,	0 },
3314Srgrimes	{ "object",	vm_object_print,	0,	0 },
3324Srgrimes#if 0
3334Srgrimes	{ "page",	vm_page_print,		0,	0 },
3344Srgrimes#endif
3354Srgrimes#if 0
3364Srgrimes	{ "port",	ipc_port_print,		0,	0 },
3374Srgrimes#endif
3384Srgrimes	{ (char *)0, }
3394Srgrimes};
3404Srgrimes
3414Srgrimesvoid		db_help_cmd();
3424Srgrimesvoid		db_fncall();
3434Srgrimes
3444Srgrimesstruct command db_command_table[] = {
3454Srgrimes	{ "print",	db_print_cmd,		0,	0 },
3464Srgrimes	{ "examine",	db_examine_cmd,		CS_SET_DOT, 0 },
3474Srgrimes	{ "x",		db_examine_cmd,		CS_SET_DOT, 0 },
3484Srgrimes	{ "search",	db_search_cmd,		CS_OWN|CS_SET_DOT, 0 },
3494Srgrimes	{ "set",	db_set_cmd,		CS_OWN,	0 },
3504Srgrimes	{ "write",	db_write_cmd,		CS_MORE|CS_SET_DOT, 0 },
3514Srgrimes	{ "w",		db_write_cmd,		CS_MORE|CS_SET_DOT, 0 },
3524Srgrimes	{ "delete",	db_delete_cmd,		0,	0 },
3534Srgrimes	{ "d",		db_delete_cmd,		0,	0 },
3544Srgrimes	{ "break",	db_breakpoint_cmd,	0,	0 },
3554Srgrimes	{ "dwatch",	db_deletewatch_cmd,	0,	0 },
3564Srgrimes	{ "watch",	db_watchpoint_cmd,	CS_MORE,0 },
3574Srgrimes	{ "step",	db_single_step_cmd,	0,	0 },
3584Srgrimes	{ "s",		db_single_step_cmd,	0,	0 },
3594Srgrimes	{ "continue",	db_continue_cmd,	0,	0 },
3604Srgrimes	{ "c",		db_continue_cmd,	0,	0 },
3614Srgrimes	{ "until",	db_trace_until_call_cmd,0,	0 },
3624Srgrimes	{ "next",	db_trace_until_matching_cmd,0,	0 },
3634Srgrimes	{ "match",	db_trace_until_matching_cmd,0,	0 },
3644Srgrimes	{ "trace",	db_stack_trace_cmd,	0,	0 },
3654Srgrimes	{ "call",	db_fncall,		CS_OWN,	0 },
3664Srgrimes	{ "show",	0,			0,	db_show_cmds },
3671147Sguido	{ "ps",		db_ps,			0,	0 },
3686204Sphk	{ "panic",	db_panic,		0,	0 },
3694Srgrimes	{ (char *)0, }
3704Srgrimes};
3714Srgrimes
3724Srgrimesstruct command	*db_last_command = 0;
3734Srgrimes
3744Srgrimesvoid
3754Srgrimesdb_help_cmd()
3764Srgrimes{
3774Srgrimes	struct command *cmd = db_command_table;
3784Srgrimes
3794Srgrimes	while (cmd->name != 0) {
3804Srgrimes	    db_printf("%-12s", cmd->name);
3814Srgrimes	    db_end_line();
3824Srgrimes	    cmd++;
3834Srgrimes	}
3844Srgrimes}
3854Srgrimes
3864Srgrimesvoid
3876204Sphkdb_panic()
3886204Sphk{
3896204Sphk	panic("from debugger\n");
3906204Sphk}
3916204Sphk
3926204Sphkvoid
3934Srgrimesdb_command_loop()
3944Srgrimes{
3954Srgrimes	/*
3964Srgrimes	 * Initialize 'prev' and 'next' to dot.
3974Srgrimes	 */
3984Srgrimes	db_prev = db_dot;
3994Srgrimes	db_next = db_dot;
4004Srgrimes
4014Srgrimes	db_cmd_loop_done = 0;
4024Srgrimes	while (!db_cmd_loop_done) {
4034Srgrimes
4044Srgrimes	    (void) setjmp(db_jmpbuf);
4054Srgrimes	    if (db_print_position() != 0)
4064Srgrimes		db_printf("\n");
4074Srgrimes
4084Srgrimes	    db_printf("db> ");
4094Srgrimes	    (void) db_read_line();
4104Srgrimes
4114Srgrimes	    db_command(&db_last_command, db_command_table);
4124Srgrimes	}
4134Srgrimes}
4144Srgrimes
4154Srgrimesvoid
4164Srgrimesdb_error(s)
4174Srgrimes	char *s;
4184Srgrimes{
4194Srgrimes	if (s)
4204Srgrimes	    db_printf(s);
4214Srgrimes	db_flush_lex();
4224Srgrimes	longjmp(db_jmpbuf, 1);
4234Srgrimes}
4244Srgrimes
4254Srgrimes
4264Srgrimes/*
4274Srgrimes * Call random function:
4284Srgrimes * !expr(arg,arg,arg)
4294Srgrimes */
4304Srgrimesvoid
4314Srgrimesdb_fncall()
4324Srgrimes{
4334Srgrimes	db_expr_t	fn_addr;
4344Srgrimes#define	MAXARGS		11
4354Srgrimes	db_expr_t	args[MAXARGS];
4364Srgrimes	int		nargs = 0;
4374Srgrimes	db_expr_t	retval;
4384Srgrimes	db_expr_t	(*func)();
4394Srgrimes	int		t;
4404Srgrimes
4414Srgrimes	if (!db_expression(&fn_addr)) {
4424Srgrimes	    db_printf("Bad function\n");
4434Srgrimes	    db_flush_lex();
4444Srgrimes	    return;
4454Srgrimes	}
4464Srgrimes	func = (db_expr_t (*) ()) fn_addr;
4474Srgrimes
4484Srgrimes	t = db_read_token();
4494Srgrimes	if (t == tLPAREN) {
4504Srgrimes	    if (db_expression(&args[0])) {
4514Srgrimes		nargs++;
4524Srgrimes		while ((t = db_read_token()) == tCOMMA) {
4534Srgrimes		    if (nargs == MAXARGS) {
4544Srgrimes			db_printf("Too many arguments\n");
4554Srgrimes			db_flush_lex();
4564Srgrimes			return;
4574Srgrimes		    }
4584Srgrimes		    if (!db_expression(&args[nargs])) {
4594Srgrimes			db_printf("Argument missing\n");
4604Srgrimes			db_flush_lex();
4614Srgrimes			return;
4624Srgrimes		    }
4634Srgrimes		    nargs++;
4644Srgrimes		}
4654Srgrimes		db_unread_token(t);
4664Srgrimes	    }
4674Srgrimes	    if (db_read_token() != tRPAREN) {
4684Srgrimes		db_printf("?\n");
4694Srgrimes		db_flush_lex();
4704Srgrimes		return;
4714Srgrimes	    }
4724Srgrimes	}
4734Srgrimes	db_skip_to_eol();
4744Srgrimes
4754Srgrimes	while (nargs < MAXARGS) {
4764Srgrimes	    args[nargs++] = 0;
4774Srgrimes	}
4784Srgrimes
4794Srgrimes	retval = (*func)(args[0], args[1], args[2], args[3], args[4],
4804Srgrimes			 args[5], args[6], args[7], args[8], args[9] );
4814Srgrimes	db_printf("%#n\n", retval);
4824Srgrimes}
483