db_command.c revision 138038
18876Srgrimes/*
24Srgrimes * Mach Operating System
34Srgrimes * Copyright (c) 1991,1990 Carnegie Mellon University
44Srgrimes * All Rights Reserved.
58876Srgrimes *
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.
118876Srgrimes *
128876Srgrimes * 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.
158876Srgrimes *
164Srgrimes * Carnegie Mellon requests users of this software to return to
178876Srgrimes *
184Srgrimes *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
194Srgrimes *  School of Computer Science
204Srgrimes *  Carnegie Mellon University
214Srgrimes *  Pittsburgh PA 15213-3890
228876Srgrimes *
234Srgrimes * any improvements or extensions that they make and grant Carnegie the
244Srgrimes * rights to redistribute these changes.
254Srgrimes */
264Srgrimes/*
274Srgrimes *	Author: David B. Golub, Carnegie Mellon University
284Srgrimes *	Date:	7/90
294Srgrimes */
304Srgrimes/*
314Srgrimes * Command dispatcher.
324Srgrimes */
33116176Sobrien
34116176Sobrien#include <sys/cdefs.h>
35116176Sobrien__FBSDID("$FreeBSD: head/sys/ddb/db_command.c 138038 2004-11-23 23:11:47Z rwatson $");
36116176Sobrien
372056Swollman#include <sys/param.h>
3842654Sjdp#include <sys/linker_set.h>
3986998Sdd#include <sys/lock.h>
40131952Smarcel#include <sys/kdb.h>
4186998Sdd#include <sys/mutex.h>
4286998Sdd#include <sys/proc.h>
4317848Spst#include <sys/reboot.h>
4486998Sdd#include <sys/signalvar.h>
452056Swollman#include <sys/systm.h>
4649558Sphk#include <sys/cons.h>
47126399Sphk#include <sys/watchdog.h>
4812734Sbde
492056Swollman#include <ddb/ddb.h>
5012473Sbde#include <ddb/db_command.h>
514Srgrimes#include <ddb/db_lex.h>
524Srgrimes#include <ddb/db_output.h>
534Srgrimes
54118990Smarcel#include <machine/cpu.h>
5579418Sjulian#include <machine/setjmp.h>
564Srgrimes
574Srgrimes/*
584Srgrimes * Exported global variables
594Srgrimes */
604Srgrimesboolean_t	db_cmd_loop_done;
6118296Sbdedb_addr_t	db_dot;
624Srgrimesdb_addr_t	db_last_addr;
634Srgrimesdb_addr_t	db_prev;
644Srgrimesdb_addr_t	db_next;
654Srgrimes
6678161SpeterSET_DECLARE(db_cmd_set, struct command);
6778161SpeterSET_DECLARE(db_show_cmd_set, struct command);
6878161Speter
6912515Sphkstatic db_cmdfcn_t	db_fncall;
70132002Smarcelstatic db_cmdfcn_t	db_gdb;
7186998Sddstatic db_cmdfcn_t	db_kill;
7285944Speterstatic db_cmdfcn_t	db_reset;
73132482Smarcelstatic db_cmdfcn_t	db_stack_trace;
74126399Sphkstatic db_cmdfcn_t	db_watchdog;
7517848Spst
7618296Sbde/* XXX this is actually forward-static. */
7718296Sbdeextern struct command	db_show_cmds[];
7818296Sbde
794Srgrimes/*
804Srgrimes * if 'ed' style: 'dot' is set at start of last item printed,
814Srgrimes * and '+' points to next line.
824Srgrimes * Otherwise: 'dot' points to next item, '..' points to last.
834Srgrimes */
8412515Sphkstatic boolean_t	db_ed_style = TRUE;
854Srgrimes
864Srgrimes/*
874Srgrimes * Utility routine - discard tokens through end-of-line.
884Srgrimes */
894Srgrimesvoid
904Srgrimesdb_skip_to_eol()
914Srgrimes{
924Srgrimes	int	t;
934Srgrimes	do {
944Srgrimes	    t = db_read_token();
954Srgrimes	} while (t != tEOL);
964Srgrimes}
974Srgrimes
984Srgrimes/*
994Srgrimes * Results of command search.
1004Srgrimes */
1014Srgrimes#define	CMD_UNIQUE	0
1024Srgrimes#define	CMD_FOUND	1
1034Srgrimes#define	CMD_NONE	2
1044Srgrimes#define	CMD_AMBIGUOUS	3
1054Srgrimes#define	CMD_HELP	4
1064Srgrimes
10793009Sbdestatic void	db_cmd_list(struct command *table, struct command **aux_tablep,
10893009Sbde		    struct command **aux_tablep_end);
10992756Salfredstatic int	db_cmd_search(char *name, struct command *table,
11093009Sbde		    struct command **aux_tablep,
11193009Sbde		    struct command **aux_tablep_end, struct command **cmdp);
11292756Salfredstatic void	db_command(struct command **last_cmdp,
11393009Sbde		    struct command *cmd_table, struct command **aux_cmd_tablep,
11493009Sbde		    struct command **aux_cmd_tablep_end);
11512473Sbde
1164Srgrimes/*
1174Srgrimes * Search for command prefix.
1184Srgrimes */
11912515Sphkstatic int
12078161Speterdb_cmd_search(name, table, aux_tablep, aux_tablep_end, cmdp)
1214Srgrimes	char *		name;
1224Srgrimes	struct command	*table;
12318296Sbde	struct command	**aux_tablep;
12478161Speter	struct command	**aux_tablep_end;
1254Srgrimes	struct command	**cmdp;	/* out */
1264Srgrimes{
1274Srgrimes	struct command	*cmd;
12818296Sbde	struct command	**aux_cmdp;
1294Srgrimes	int		result = CMD_NONE;
1304Srgrimes
1314Srgrimes	for (cmd = table; cmd->name != 0; cmd++) {
1324Srgrimes	    register char *lp;
1334Srgrimes	    register char *rp;
1344Srgrimes	    register int  c;
1354Srgrimes
1364Srgrimes	    lp = name;
1374Srgrimes	    rp = cmd->name;
1384Srgrimes	    while ((c = *lp) == *rp) {
1394Srgrimes		if (c == 0) {
1404Srgrimes		    /* complete match */
1414Srgrimes		    *cmdp = cmd;
1424Srgrimes		    return (CMD_UNIQUE);
1434Srgrimes		}
1444Srgrimes		lp++;
1454Srgrimes		rp++;
1464Srgrimes	    }
1474Srgrimes	    if (c == 0) {
1484Srgrimes		/* end of name, not end of command -
1494Srgrimes		   partial match */
1504Srgrimes		if (result == CMD_FOUND) {
1514Srgrimes		    result = CMD_AMBIGUOUS;
1524Srgrimes		    /* but keep looking for a full match -
1534Srgrimes		       this lets us match single letters */
1544Srgrimes		}
1554Srgrimes		else {
1564Srgrimes		    *cmdp = cmd;
1574Srgrimes		    result = CMD_FOUND;
1584Srgrimes		}
1594Srgrimes	    }
1604Srgrimes	}
16118296Sbde	if (result == CMD_NONE && aux_tablep != 0)
16218296Sbde	    /* XXX repeat too much code. */
16378161Speter	    for (aux_cmdp = aux_tablep; aux_cmdp < aux_tablep_end; aux_cmdp++) {
16418296Sbde		register char *lp;
16518296Sbde		register char *rp;
16618296Sbde		register int  c;
16718296Sbde
16818296Sbde		lp = name;
16918296Sbde		rp = (*aux_cmdp)->name;
17018296Sbde		while ((c = *lp) == *rp) {
17118296Sbde		    if (c == 0) {
17218296Sbde			/* complete match */
17318296Sbde			*cmdp = *aux_cmdp;
17418296Sbde			return (CMD_UNIQUE);
17518296Sbde		    }
17618296Sbde		    lp++;
17718296Sbde		    rp++;
17818296Sbde		}
17918296Sbde		if (c == 0) {
18018296Sbde		    /* end of name, not end of command -
18118296Sbde		       partial match */
18218296Sbde		    if (result == CMD_FOUND) {
18318296Sbde			result = CMD_AMBIGUOUS;
18418296Sbde			/* but keep looking for a full match -
18518296Sbde			   this lets us match single letters */
18618296Sbde		    }
18718296Sbde		    else {
18818296Sbde			*cmdp = *aux_cmdp;
18918296Sbde			result = CMD_FOUND;
19018296Sbde		    }
19118296Sbde		}
19218296Sbde	    }
1934Srgrimes	if (result == CMD_NONE) {
1944Srgrimes	    /* check for 'help' */
1954Srgrimes		if (name[0] == 'h' && name[1] == 'e'
1964Srgrimes		    && name[2] == 'l' && name[3] == 'p')
1974Srgrimes			result = CMD_HELP;
1984Srgrimes	}
1994Srgrimes	return (result);
2004Srgrimes}
2014Srgrimes
20212515Sphkstatic void
20378161Speterdb_cmd_list(table, aux_tablep, aux_tablep_end)
2044Srgrimes	struct command *table;
20518296Sbde	struct command **aux_tablep;
20678161Speter	struct command **aux_tablep_end;
2074Srgrimes{
2084Srgrimes	register struct command *cmd;
20918296Sbde	register struct command **aux_cmdp;
2104Srgrimes
2114Srgrimes	for (cmd = table; cmd->name != 0; cmd++) {
2124Srgrimes	    db_printf("%-12s", cmd->name);
2134Srgrimes	    db_end_line();
2144Srgrimes	}
21518296Sbde	if (aux_tablep == 0)
21618296Sbde	    return;
21778161Speter	for (aux_cmdp = aux_tablep; aux_cmdp < aux_tablep_end; aux_cmdp++) {
21818296Sbde	    db_printf("%-12s", (*aux_cmdp)->name);
21918296Sbde	    db_end_line();
22018296Sbde	}
2214Srgrimes}
2224Srgrimes
22312515Sphkstatic void
22478161Speterdb_command(last_cmdp, cmd_table, aux_cmd_tablep, aux_cmd_tablep_end)
2254Srgrimes	struct command	**last_cmdp;	/* IN_OUT */
2264Srgrimes	struct command	*cmd_table;
22718296Sbde	struct command	**aux_cmd_tablep;
22878161Speter	struct command	**aux_cmd_tablep_end;
2294Srgrimes{
2304Srgrimes	struct command	*cmd;
2314Srgrimes	int		t;
2324Srgrimes	char		modif[TOK_STRING_SIZE];
2334Srgrimes	db_expr_t	addr, count;
234798Swollman	boolean_t	have_addr = FALSE;
2354Srgrimes	int		result;
2364Srgrimes
2374Srgrimes	t = db_read_token();
2384Srgrimes	if (t == tEOL) {
2394Srgrimes	    /* empty line repeats last command, at 'next' */
2404Srgrimes	    cmd = *last_cmdp;
2414Srgrimes	    addr = (db_expr_t)db_next;
2424Srgrimes	    have_addr = FALSE;
2434Srgrimes	    count = 1;
2444Srgrimes	    modif[0] = '\0';
2454Srgrimes	}
2464Srgrimes	else if (t == tEXCL) {
24710348Sbde	    db_fncall((db_expr_t)0, (boolean_t)0, (db_expr_t)0, (char *)0);
2484Srgrimes	    return;
2494Srgrimes	}
2504Srgrimes	else if (t != tIDENT) {
2514Srgrimes	    db_printf("?\n");
2524Srgrimes	    db_flush_lex();
2534Srgrimes	    return;
2544Srgrimes	}
2554Srgrimes	else {
2564Srgrimes	    /*
2574Srgrimes	     * Search for command
2584Srgrimes	     */
2594Srgrimes	    while (cmd_table) {
2604Srgrimes		result = db_cmd_search(db_tok_string,
2614Srgrimes				       cmd_table,
26218296Sbde				       aux_cmd_tablep,
26378161Speter				       aux_cmd_tablep_end,
2644Srgrimes				       &cmd);
2654Srgrimes		switch (result) {
2664Srgrimes		    case CMD_NONE:
2674Srgrimes			db_printf("No such command\n");
2684Srgrimes			db_flush_lex();
2694Srgrimes			return;
2704Srgrimes		    case CMD_AMBIGUOUS:
2714Srgrimes			db_printf("Ambiguous\n");
2724Srgrimes			db_flush_lex();
2734Srgrimes			return;
2744Srgrimes		    case CMD_HELP:
27578161Speter			db_cmd_list(cmd_table, aux_cmd_tablep, aux_cmd_tablep_end);
2764Srgrimes			db_flush_lex();
2774Srgrimes			return;
2784Srgrimes		    default:
2794Srgrimes			break;
2804Srgrimes		}
2814Srgrimes		if ((cmd_table = cmd->more) != 0) {
28218296Sbde		    /* XXX usually no more aux's. */
28318296Sbde		    aux_cmd_tablep = 0;
284104321Sphk		    if (cmd_table == db_show_cmds) {
28578161Speter			aux_cmd_tablep = SET_BEGIN(db_show_cmd_set);
28678161Speter			aux_cmd_tablep_end = SET_LIMIT(db_show_cmd_set);
287104321Sphk		    }
28818296Sbde
2894Srgrimes		    t = db_read_token();
2904Srgrimes		    if (t != tIDENT) {
29178161Speter			db_cmd_list(cmd_table, aux_cmd_tablep, aux_cmd_tablep_end);
2924Srgrimes			db_flush_lex();
2934Srgrimes			return;
2944Srgrimes		    }
2954Srgrimes		}
2964Srgrimes	    }
2974Srgrimes
2984Srgrimes	    if ((cmd->flag & CS_OWN) == 0) {
2994Srgrimes		/*
3004Srgrimes		 * Standard syntax:
3014Srgrimes		 * command [/modifier] [addr] [,count]
3024Srgrimes		 */
3034Srgrimes		t = db_read_token();
3044Srgrimes		if (t == tSLASH) {
3054Srgrimes		    t = db_read_token();
3064Srgrimes		    if (t != tIDENT) {
3074Srgrimes			db_printf("Bad modifier\n");
3084Srgrimes			db_flush_lex();
3094Srgrimes			return;
3104Srgrimes		    }
3114Srgrimes		    db_strcpy(modif, db_tok_string);
3124Srgrimes		}
3134Srgrimes		else {
3144Srgrimes		    db_unread_token(t);
3154Srgrimes		    modif[0] = '\0';
3164Srgrimes		}
3174Srgrimes
3184Srgrimes		if (db_expression(&addr)) {
3194Srgrimes		    db_dot = (db_addr_t) addr;
3204Srgrimes		    db_last_addr = db_dot;
3214Srgrimes		    have_addr = TRUE;
3224Srgrimes		}
3234Srgrimes		else {
3244Srgrimes		    addr = (db_expr_t) db_dot;
3254Srgrimes		    have_addr = FALSE;
3264Srgrimes		}
3274Srgrimes		t = db_read_token();
3284Srgrimes		if (t == tCOMMA) {
3294Srgrimes		    if (!db_expression(&count)) {
3304Srgrimes			db_printf("Count missing\n");
3314Srgrimes			db_flush_lex();
3324Srgrimes			return;
3334Srgrimes		    }
3344Srgrimes		}
3354Srgrimes		else {
3364Srgrimes		    db_unread_token(t);
3374Srgrimes		    count = -1;
3384Srgrimes		}
3394Srgrimes		if ((cmd->flag & CS_MORE) == 0) {
3404Srgrimes		    db_skip_to_eol();
3414Srgrimes		}
3424Srgrimes	    }
3434Srgrimes	}
3444Srgrimes	*last_cmdp = cmd;
3454Srgrimes	if (cmd != 0) {
3464Srgrimes	    /*
3474Srgrimes	     * Execute the command.
3484Srgrimes	     */
3494Srgrimes	    (*cmd->fcn)(addr, have_addr, count, modif);
350118268Sjhb	    db_setup_paging(NULL, NULL, -1);
3514Srgrimes
3524Srgrimes	    if (cmd->flag & CS_SET_DOT) {
3534Srgrimes		/*
3544Srgrimes		 * If command changes dot, set dot to
3554Srgrimes		 * previous address displayed (if 'ed' style).
3564Srgrimes		 */
3574Srgrimes		if (db_ed_style) {
3584Srgrimes		    db_dot = db_prev;
3594Srgrimes		}
3604Srgrimes		else {
3614Srgrimes		    db_dot = db_next;
3624Srgrimes		}
3634Srgrimes	    }
3644Srgrimes	    else {
3654Srgrimes		/*
3664Srgrimes		 * If command does not change dot,
3674Srgrimes		 * set 'next' location to be the same.
3684Srgrimes		 */
3694Srgrimes		db_next = db_dot;
3704Srgrimes	    }
3714Srgrimes	}
3724Srgrimes}
3734Srgrimes
3744Srgrimes/*
3754Srgrimes * 'show' commands
3764Srgrimes */
3772112Swollman
37812515Sphkstatic struct command db_show_all_cmds[] = {
3791549Srgrimes	{ "procs",	db_ps,			0,	0 },
3804Srgrimes	{ (char *)0 }
3814Srgrimes};
3824Srgrimes
38312515Sphkstatic struct command db_show_cmds[] = {
3844Srgrimes	{ "all",	0,			0,	db_show_all_cmds },
3854Srgrimes	{ "registers",	db_show_regs,		0,	0 },
3864Srgrimes	{ "breaks",	db_listbreak_cmd, 	0,	0 },
387131952Smarcel	{ "threads",	db_show_threads,	0,	0 },
3884Srgrimes	{ (char *)0, }
3894Srgrimes};
3904Srgrimes
39112515Sphkstatic struct command db_command_table[] = {
3924Srgrimes	{ "print",	db_print_cmd,		0,	0 },
3936920Sjoerg	{ "p",		db_print_cmd,		0,	0 },
3944Srgrimes	{ "examine",	db_examine_cmd,		CS_SET_DOT, 0 },
3954Srgrimes	{ "x",		db_examine_cmd,		CS_SET_DOT, 0 },
3964Srgrimes	{ "search",	db_search_cmd,		CS_OWN|CS_SET_DOT, 0 },
3974Srgrimes	{ "set",	db_set_cmd,		CS_OWN,	0 },
3984Srgrimes	{ "write",	db_write_cmd,		CS_MORE|CS_SET_DOT, 0 },
3994Srgrimes	{ "w",		db_write_cmd,		CS_MORE|CS_SET_DOT, 0 },
4004Srgrimes	{ "delete",	db_delete_cmd,		0,	0 },
4014Srgrimes	{ "d",		db_delete_cmd,		0,	0 },
4024Srgrimes	{ "break",	db_breakpoint_cmd,	0,	0 },
4034Srgrimes	{ "dwatch",	db_deletewatch_cmd,	0,	0 },
4044Srgrimes	{ "watch",	db_watchpoint_cmd,	CS_MORE,0 },
40579573Sbsd	{ "dhwatch",	db_deletehwatch_cmd,	0,      0 },
40679573Sbsd	{ "hwatch",	db_hwatchpoint_cmd,	0,      0 },
4074Srgrimes	{ "step",	db_single_step_cmd,	0,	0 },
4084Srgrimes	{ "s",		db_single_step_cmd,	0,	0 },
4094Srgrimes	{ "continue",	db_continue_cmd,	0,	0 },
4104Srgrimes	{ "c",		db_continue_cmd,	0,	0 },
4114Srgrimes	{ "until",	db_trace_until_call_cmd,0,	0 },
4124Srgrimes	{ "next",	db_trace_until_matching_cmd,0,	0 },
4134Srgrimes	{ "match",	db_trace_until_matching_cmd,0,	0 },
414132484Smarcel	{ "trace",	db_stack_trace,		CS_OWN,	0 },
415132484Smarcel	{ "where",	db_stack_trace,		CS_OWN,	0 },
4164Srgrimes	{ "call",	db_fncall,		CS_OWN,	0 },
4174Srgrimes	{ "show",	0,			0,	db_show_cmds },
4181147Sguido	{ "ps",		db_ps,			0,	0 },
419132002Smarcel	{ "gdb",	db_gdb,			0,	0 },
42085944Speter	{ "reset",	db_reset,		0,	0 },
42186998Sdd	{ "kill",	db_kill,		CS_OWN,	0 },
422126399Sphk	{ "watchdog",	db_watchdog,		0,	0 },
423131952Smarcel	{ "thread",	db_set_thread,		CS_OWN,	0 },
4244Srgrimes	{ (char *)0, }
4254Srgrimes};
4264Srgrimes
42712515Sphkstatic struct command	*db_last_command = 0;
4284Srgrimes
42933296Sbde/*
43033296Sbde * At least one non-optional command must be implemented using
43133296Sbde * DB_COMMAND() so that db_cmd_set gets created.  Here is one.
43233296Sbde */
43333296SbdeDB_COMMAND(panic, db_panic)
4346204Sphk{
4357170Sdg	panic("from debugger");
4366204Sphk}
4376204Sphk
4386204Sphkvoid
4394Srgrimesdb_command_loop()
4404Srgrimes{
4414Srgrimes	/*
4424Srgrimes	 * Initialize 'prev' and 'next' to dot.
4434Srgrimes	 */
4444Srgrimes	db_prev = db_dot;
4454Srgrimes	db_next = db_dot;
4464Srgrimes
4474Srgrimes	db_cmd_loop_done = 0;
4484Srgrimes	while (!db_cmd_loop_done) {
4494Srgrimes	    if (db_print_position() != 0)
4504Srgrimes		db_printf("\n");
4514Srgrimes
4524Srgrimes	    db_printf("db> ");
4534Srgrimes	    (void) db_read_line();
4544Srgrimes
45518296Sbde	    db_command(&db_last_command, db_command_table,
45678161Speter		       SET_BEGIN(db_cmd_set), SET_LIMIT(db_cmd_set));
4574Srgrimes	}
4584Srgrimes}
4594Srgrimes
4604Srgrimesvoid
4614Srgrimesdb_error(s)
462103746Smarkm	const char *s;
4634Srgrimes{
4644Srgrimes	if (s)
46579884Skris	    db_printf("%s", s);
4664Srgrimes	db_flush_lex();
467131952Smarcel	kdb_reenter();
4684Srgrimes}
4694Srgrimes
4704Srgrimes
4714Srgrimes/*
4724Srgrimes * Call random function:
4734Srgrimes * !expr(arg,arg,arg)
4744Srgrimes */
47512515Sphkstatic void
47610348Sbdedb_fncall(dummy1, dummy2, dummy3, dummy4)
47710348Sbde	db_expr_t	dummy1;
47810348Sbde	boolean_t	dummy2;
47910348Sbde	db_expr_t	dummy3;
48010348Sbde	char *		dummy4;
4814Srgrimes{
4824Srgrimes	db_expr_t	fn_addr;
48312473Sbde#define	MAXARGS		11	/* XXX only 10 are passed */
4844Srgrimes	db_expr_t	args[MAXARGS];
4854Srgrimes	int		nargs = 0;
4864Srgrimes	db_expr_t	retval;
48792756Salfred	typedef db_expr_t fcn_10args_t(db_expr_t, db_expr_t, db_expr_t,
48893009Sbde			    db_expr_t, db_expr_t, db_expr_t, db_expr_t,
48993009Sbde			    db_expr_t, db_expr_t, db_expr_t);
49012473Sbde	fcn_10args_t	*func;
4914Srgrimes	int		t;
4924Srgrimes
4934Srgrimes	if (!db_expression(&fn_addr)) {
4944Srgrimes	    db_printf("Bad function\n");
4954Srgrimes	    db_flush_lex();
4964Srgrimes	    return;
4974Srgrimes	}
49812473Sbde	func = (fcn_10args_t *)fn_addr;	/* XXX */
4994Srgrimes
5004Srgrimes	t = db_read_token();
5014Srgrimes	if (t == tLPAREN) {
5024Srgrimes	    if (db_expression(&args[0])) {
5034Srgrimes		nargs++;
5044Srgrimes		while ((t = db_read_token()) == tCOMMA) {
5054Srgrimes		    if (nargs == MAXARGS) {
5064Srgrimes			db_printf("Too many arguments\n");
5074Srgrimes			db_flush_lex();
5084Srgrimes			return;
5094Srgrimes		    }
5104Srgrimes		    if (!db_expression(&args[nargs])) {
5114Srgrimes			db_printf("Argument missing\n");
5124Srgrimes			db_flush_lex();
5134Srgrimes			return;
5144Srgrimes		    }
5154Srgrimes		    nargs++;
5164Srgrimes		}
5174Srgrimes		db_unread_token(t);
5184Srgrimes	    }
5194Srgrimes	    if (db_read_token() != tRPAREN) {
5204Srgrimes		db_printf("?\n");
5214Srgrimes		db_flush_lex();
5224Srgrimes		return;
5234Srgrimes	    }
5244Srgrimes	}
5254Srgrimes	db_skip_to_eol();
5264Srgrimes
5274Srgrimes	while (nargs < MAXARGS) {
5284Srgrimes	    args[nargs++] = 0;
5294Srgrimes	}
5304Srgrimes
5314Srgrimes	retval = (*func)(args[0], args[1], args[2], args[3], args[4],
5324Srgrimes			 args[5], args[6], args[7], args[8], args[9] );
53348407Speter	db_printf("%#lr\n", (long)retval);
5344Srgrimes}
53517848Spst
53617848Spststatic void
53786998Sdddb_kill(dummy1, dummy2, dummy3, dummy4)
53886998Sdd	db_expr_t	dummy1;
53986998Sdd	boolean_t	dummy2;
54086998Sdd	db_expr_t	dummy3;
54186998Sdd	char *		dummy4;
54286998Sdd{
54386998Sdd	db_expr_t old_radix, pid, sig;
54486998Sdd	struct proc *p;
54586998Sdd
54686998Sdd#define DB_ERROR(f)	do { db_printf f; db_flush_lex(); goto out; } while (0)
54786998Sdd
54886998Sdd	/*
54986998Sdd	 * PIDs and signal numbers are typically represented in base
55086998Sdd	 * 10, so make that the default here.  It can, of course, be
55186998Sdd	 * overridden by specifying a prefix.
55286998Sdd	 */
55386998Sdd	old_radix = db_radix;
55486998Sdd	db_radix = 10;
55586998Sdd	/* Retrieve arguments. */
55686998Sdd	if (!db_expression(&sig))
55786998Sdd		DB_ERROR(("Missing signal number\n"));
55886998Sdd	if (!db_expression(&pid))
55986998Sdd		DB_ERROR(("Missing process ID\n"));
56086998Sdd	db_skip_to_eol();
56186998Sdd	if (sig < 0 || sig > _SIG_MAXSIG)
56286998Sdd		DB_ERROR(("Signal number out of range\n"));
56386998Sdd
56486998Sdd	/*
56586998Sdd	 * Find the process in question.  allproc_lock is not needed
56686998Sdd	 * since we're in DDB.
56786998Sdd	 */
56886998Sdd	/* sx_slock(&allproc_lock); */
56986998Sdd	LIST_FOREACH(p, &allproc, p_list)
57086998Sdd	    if (p->p_pid == pid)
57186998Sdd		    break;
57286998Sdd	/* sx_sunlock(&allproc_lock); */
57386998Sdd	if (p == NULL)
57489442Smjacob		DB_ERROR(("Can't find process with pid %ld\n", (long) pid));
57586998Sdd
57686998Sdd	/* If it's already locked, bail; otherwise, do the deed. */
57786998Sdd	if (PROC_TRYLOCK(p) == 0)
57889442Smjacob		DB_ERROR(("Can't lock process with pid %ld\n", (long) pid));
57986998Sdd	else {
58086998Sdd		psignal(p, sig);
58186998Sdd		PROC_UNLOCK(p);
58286998Sdd	}
58386998Sdd
58486998Sddout:
58586998Sdd	db_radix = old_radix;
58686998Sdd#undef DB_ERROR
58786998Sdd}
58886998Sdd
58986998Sddstatic void
59085944Speterdb_reset(dummy1, dummy2, dummy3, dummy4)
59185944Speter	db_expr_t	dummy1;
59285944Speter	boolean_t	dummy2;
59385944Speter	db_expr_t	dummy3;
59485944Speter	char *		dummy4;
59585944Speter{
59685944Speter
59785944Speter	cpu_reset();
59885944Speter}
599126399Sphk
600126399Sphkstatic void
601126399Sphkdb_watchdog(dummy1, dummy2, dummy3, dummy4)
602126399Sphk	db_expr_t	dummy1;
603126399Sphk	boolean_t	dummy2;
604126399Sphk	db_expr_t	dummy3;
605126399Sphk	char *		dummy4;
606126399Sphk{
607126399Sphk	int i;
608126399Sphk
609126399Sphk	/*
610126399Sphk	 * XXX: It might make sense to be able to set the watchdog to a
611126399Sphk	 * XXX: timeout here so that failure or hang as a result of subsequent
612126399Sphk	 * XXX: ddb commands could be recovered by a reset.
613126399Sphk	 */
614126399Sphk
615126399Sphk	EVENTHANDLER_INVOKE(watchdog_list, 0, &i);
616126399Sphk}
617132002Smarcel
618132002Smarcelstatic void
619132002Smarceldb_gdb(db_expr_t dummy1, boolean_t dummy2, db_expr_t dummy3, char *dummy4)
620132002Smarcel{
621132002Smarcel
622132002Smarcel	if (kdb_dbbe_select("gdb") != 0)
623132002Smarcel		db_printf("The remote GDB backend could not be selected.\n");
624132002Smarcel	else
625132002Smarcel		db_printf("Step to enter the remote GDB backend.\n");
626132002Smarcel}
627132482Smarcel
628132482Smarcelstatic void
629132482Smarceldb_stack_trace(db_expr_t tid, boolean_t hastid, db_expr_t count, char *modif)
630132482Smarcel{
631132482Smarcel	struct thread *td;
632132482Smarcel	db_expr_t radix;
633138038Srwatson	pid_t pid;
634132482Smarcel	int t;
635132482Smarcel
636132482Smarcel	/*
637132482Smarcel	 * We parse our own arguments. We don't like the default radix.
638132482Smarcel	 */
639132482Smarcel	radix = db_radix;
640132482Smarcel	db_radix = 10;
641132482Smarcel	hastid = db_expression(&tid);
642132482Smarcel	t = db_read_token();
643132482Smarcel	if (t == tCOMMA) {
644132482Smarcel		if (!db_expression(&count)) {
645132482Smarcel			db_printf("Count missing\n");
646132482Smarcel			db_flush_lex();
647132482Smarcel			return;
648132482Smarcel		}
649132482Smarcel	} else {
650132482Smarcel		db_unread_token(t);
651132482Smarcel		count = -1;
652132482Smarcel	}
653132482Smarcel	db_skip_to_eol();
654132482Smarcel	db_radix = radix;
655132482Smarcel
656132482Smarcel	if (hastid) {
657132482Smarcel		td = kdb_thr_lookup((lwpid_t)tid);
658132482Smarcel		if (td == NULL)
659132482Smarcel			td = kdb_thr_from_pid((pid_t)tid);
660132482Smarcel		if (td == NULL) {
661132482Smarcel			db_printf("Thread %d not found\n", (int)tid);
662132482Smarcel			return;
663132482Smarcel		}
664132482Smarcel	} else
665132482Smarcel		td = kdb_thread;
666138038Srwatson	if (td->td_proc != NULL)
667138038Srwatson		pid = td->td_proc->p_pid;
668138038Srwatson	else
669138038Srwatson		pid = -1;
670138038Srwatson	db_printf("Tracing pid %d tid %ld td %p\n", pid, (long)td->td_tid, td);
671132482Smarcel	db_trace_thread(td, count);
672132482Smarcel}
673