db_command.c revision 177615
190075Sobrien/*-
290075Sobrien * Mach Operating System
390075Sobrien * Copyright (c) 1991,1990 Carnegie Mellon University
4169689Skan * All Rights Reserved.
590075Sobrien *
690075Sobrien * Permission to use, copy, modify and distribute this software and its
790075Sobrien * documentation is hereby granted, provided that both the copyright
890075Sobrien * notice and this permission notice appear in all copies of the
990075Sobrien * software, derivative works or modified versions, and any portions
1090075Sobrien * thereof, and that both notices appear in supporting documentation.
1190075Sobrien *
1290075Sobrien * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
1390075Sobrien * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1490075Sobrien * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1590075Sobrien *
1690075Sobrien * Carnegie Mellon requests users of this software to return to
1790075Sobrien *
1890075Sobrien *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
1990075Sobrien *  School of Computer Science
20169689Skan *  Carnegie Mellon University
21169689Skan *  Pittsburgh PA 15213-3890
2290075Sobrien *
23169689Skan * any improvements or extensions that they make and grant Carnegie the
24169689Skan * rights to redistribute these changes.
25169689Skan */
26169689Skan/*
27169689Skan *	Author: David B. Golub, Carnegie Mellon University
28169689Skan *	Date:	7/90
29169689Skan */
30169689Skan/*
31169689Skan * Command dispatcher.
32169689Skan */
33117395Skan
34117395Skan#include <sys/cdefs.h>
35117395Skan__FBSDID("$FreeBSD: head/sys/ddb/db_command.c 177615 2008-03-25 20:36:32Z sam $");
3690075Sobrien
3790075Sobrien#include <sys/param.h>
3890075Sobrien#include <sys/linker_set.h>
39169689Skan#include <sys/lock.h>
40169689Skan#include <sys/kdb.h>
41169689Skan#include <sys/mutex.h>
42169689Skan#include <sys/proc.h>
43169689Skan#include <sys/reboot.h>
44169689Skan#include <sys/signalvar.h>
4590075Sobrien#include <sys/systm.h>
4690075Sobrien#include <sys/cons.h>
4790075Sobrien#include <sys/watchdog.h>
4890075Sobrien
4990075Sobrien#include <ddb/ddb.h>
5090075Sobrien#include <ddb/db_command.h>
5190075Sobrien#include <ddb/db_lex.h>
5290075Sobrien#include <ddb/db_output.h>
5390075Sobrien
5490075Sobrien#include <machine/cpu.h>
5590075Sobrien#include <machine/setjmp.h>
5690075Sobrien
5790075Sobrien/*
5890075Sobrien * Exported global variables
5990075Sobrien */
6090075Sobrienboolean_t	db_cmd_loop_done;
6190075Sobriendb_addr_t	db_dot;
6290075Sobriendb_addr_t	db_last_addr;
6390075Sobriendb_addr_t	db_prev;
6490075Sobriendb_addr_t	db_next;
6590075Sobrien
6690075SobrienSET_DECLARE(db_cmd_set, struct command);
6790075SobrienSET_DECLARE(db_show_cmd_set, struct command);
6890075SobrienSET_DECLARE(db_show_all_cmd_set, struct command);
6990075Sobrien
7090075Sobrienstatic db_cmdfcn_t	db_fncall;
7190075Sobrienstatic db_cmdfcn_t	db_gdb;
7290075Sobrienstatic db_cmdfcn_t	db_halt;
7390075Sobrienstatic db_cmdfcn_t	db_kill;
7490075Sobrienstatic db_cmdfcn_t	db_reset;
7590075Sobrienstatic db_cmdfcn_t	db_stack_trace;
7690075Sobrienstatic db_cmdfcn_t	db_stack_trace_all;
7790075Sobrienstatic db_cmdfcn_t	db_watchdog;
7890075Sobrien
7990075Sobrien/*
8090075Sobrien * 'show' commands
8190075Sobrien */
8290075Sobrien
8390075Sobrienstatic struct command db_show_all_cmds[] = {
8490075Sobrien	{ (char *)0 }
8590075Sobrien};
8690075Sobrien
8790075Sobrienstatic struct command_table db_show_all_table = {
8890075Sobrien	db_show_all_cmds,
8990075Sobrien	SET_BEGIN(db_show_all_cmd_set),
9090075Sobrien	SET_LIMIT(db_show_all_cmd_set)
9190075Sobrien};
9290075Sobrien
9390075Sobrienstatic struct command db_show_cmds[] = {
9490075Sobrien	{ "all",	0,			0,	&db_show_all_table },
9590075Sobrien	{ "registers",	db_show_regs,		0,	0 },
9690075Sobrien	{ "breaks",	db_listbreak_cmd, 	0,	0 },
9790075Sobrien	{ "threads",	db_show_threads,	0,	0 },
9890075Sobrien	{ (char *)0, }
9990075Sobrien};
10090075Sobrien
101132718Skanstatic struct command_table db_show_table = {
10290075Sobrien	db_show_cmds,
103169689Skan	SET_BEGIN(db_show_cmd_set),
10490075Sobrien	SET_LIMIT(db_show_cmd_set)
105102780Skan};
106102780Skan
107102780Skanstatic struct command db_commands[] = {
108102780Skan	{ "print",	db_print_cmd,		0,	0 },
109102780Skan	{ "p",		db_print_cmd,		0,	0 },
110102780Skan	{ "examine",	db_examine_cmd,		CS_SET_DOT, 0 },
11190075Sobrien	{ "x",		db_examine_cmd,		CS_SET_DOT, 0 },
11290075Sobrien	{ "search",	db_search_cmd,		CS_OWN|CS_SET_DOT, 0 },
11390075Sobrien	{ "set",	db_set_cmd,		CS_OWN,	0 },
11490075Sobrien	{ "write",	db_write_cmd,		CS_MORE|CS_SET_DOT, 0 },
11590075Sobrien	{ "w",		db_write_cmd,		CS_MORE|CS_SET_DOT, 0 },
11690075Sobrien	{ "delete",	db_delete_cmd,		0,	0 },
11790075Sobrien	{ "d",		db_delete_cmd,		0,	0 },
11890075Sobrien	{ "break",	db_breakpoint_cmd,	0,	0 },
11990075Sobrien	{ "b",		db_breakpoint_cmd,	0,	0 },
12090075Sobrien	{ "dwatch",	db_deletewatch_cmd,	0,	0 },
12190075Sobrien	{ "watch",	db_watchpoint_cmd,	CS_MORE,0 },
12290075Sobrien	{ "dhwatch",	db_deletehwatch_cmd,	0,      0 },
12390075Sobrien	{ "hwatch",	db_hwatchpoint_cmd,	0,      0 },
12490075Sobrien	{ "step",	db_single_step_cmd,	0,	0 },
12590075Sobrien	{ "s",		db_single_step_cmd,	0,	0 },
12690075Sobrien	{ "continue",	db_continue_cmd,	0,	0 },
12790075Sobrien	{ "c",		db_continue_cmd,	0,	0 },
128117395Skan	{ "until",	db_trace_until_call_cmd,0,	0 },
12990075Sobrien	{ "next",	db_trace_until_matching_cmd,0,	0 },
13090075Sobrien	{ "match",	db_trace_until_matching_cmd,0,	0 },
131119256Skan	{ "trace",	db_stack_trace,		CS_OWN,	0 },
132119256Skan	{ "t",		db_stack_trace,		CS_OWN,	0 },
133119256Skan	{ "alltrace",	db_stack_trace_all,	0,	0 },
13490075Sobrien	{ "where",	db_stack_trace,		CS_OWN,	0 },
13590075Sobrien	{ "bt",		db_stack_trace,		CS_OWN,	0 },
13690075Sobrien	{ "call",	db_fncall,		CS_OWN,	0 },
13790075Sobrien	{ "show",	0,			0,	&db_show_table },
13890075Sobrien	{ "ps",		db_ps,			0,	0 },
13990075Sobrien	{ "gdb",	db_gdb,			0,	0 },
14090075Sobrien	{ "halt",	db_halt,		0,	0 },
14190075Sobrien	{ "reboot",	db_reset,		0,	0 },
14290075Sobrien	{ "reset",	db_reset,		0,	0 },
14390075Sobrien	{ "kill",	db_kill,		CS_OWN,	0 },
14490075Sobrien	{ "watchdog",	db_watchdog,		0,	0 },
145169689Skan	{ "thread",	db_set_thread,		CS_OWN,	0 },
14690075Sobrien	{ "run",	db_run_cmd,		CS_OWN,	0 },
14790075Sobrien	{ "script",	db_script_cmd,		CS_OWN,	0 },
148132718Skan	{ "scripts",	db_scripts_cmd,		0,	0 },
14990075Sobrien	{ "unscript",	db_unscript_cmd,	CS_OWN,	0 },
150132718Skan	{ "capture",	db_capture_cmd,		CS_OWN,	0 },
151169689Skan	{ "textdump",	db_textdump_cmd,	CS_OWN, 0 },
152169689Skan	{ (char *)0, }
153169689Skan};
154169689Skan
155169689Skanstatic struct command_table db_command_table = {
156169689Skan	db_commands,
15790075Sobrien	SET_BEGIN(db_cmd_set),
15890075Sobrien	SET_LIMIT(db_cmd_set)
15990075Sobrien};
160132718Skan
16190075Sobrienstatic struct command	*db_last_command = 0;
16290075Sobrien
16390075Sobrien/*
16490075Sobrien * if 'ed' style: 'dot' is set at start of last item printed,
165132718Skan * and '+' points to next line.
16690075Sobrien * Otherwise: 'dot' points to next item, '..' points to last.
16790075Sobrien */
168132718Skanstatic boolean_t	db_ed_style = TRUE;
16990075Sobrien
170132718Skan/*
171132718Skan * Utility routine - discard tokens through end-of-line.
172132718Skan */
17390075Sobrienvoid
17490075Sobriendb_skip_to_eol()
17590075Sobrien{
17690075Sobrien	int	t;
17790075Sobrien	do {
17890075Sobrien	    t = db_read_token();
17990075Sobrien	} while (t != tEOL);
18090075Sobrien}
18190075Sobrien
18290075Sobrien/*
18390075Sobrien * Results of command search.
18490075Sobrien */
18590075Sobrien#define	CMD_UNIQUE	0
18690075Sobrien#define	CMD_FOUND	1
18790075Sobrien#define	CMD_NONE	2
188132718Skan#define	CMD_AMBIGUOUS	3
189132718Skan#define	CMD_HELP	4
190132718Skan
191169689Skanstatic void	db_cmd_match(char *name, struct command *cmd,
192169689Skan		    struct command **cmdp, int *resultp);
193169689Skanstatic void	db_cmd_list(struct command_table *table);
194169689Skanstatic int	db_cmd_search(char *name, struct command_table *table,
195169689Skan		    struct command **cmdp);
196169689Skanstatic void	db_command(struct command **last_cmdp,
197169689Skan		    struct command_table *cmd_table, int dopager);
198169689Skan
199169689Skan/*
200169689Skan * Helper function to match a single command.
201169689Skan */
202169689Skanstatic void
203169689Skandb_cmd_match(name, cmd, cmdp, resultp)
204169689Skan	char *		name;
205169689Skan	struct command	*cmd;
206169689Skan	struct command	**cmdp;	/* out */
207169689Skan	int *		resultp;
208169689Skan{
209169689Skan	char *lp, *rp;
210169689Skan	int c;
211169689Skan
212169689Skan	lp = name;
213169689Skan	rp = cmd->name;
214169689Skan	while ((c = *lp) == *rp) {
215169689Skan		if (c == 0) {
216169689Skan			/* complete match */
217169689Skan			*cmdp = cmd;
218169689Skan			*resultp = CMD_UNIQUE;
219169689Skan			return;
220169689Skan		}
221169689Skan		lp++;
222169689Skan		rp++;
223169689Skan	}
224169689Skan	if (c == 0) {
225169689Skan		/* end of name, not end of command -
226169689Skan		   partial match */
227169689Skan		if (*resultp == CMD_FOUND) {
228169689Skan			*resultp = CMD_AMBIGUOUS;
229169689Skan			/* but keep looking for a full match -
230169689Skan			   this lets us match single letters */
231169689Skan		} else {
232169689Skan			*cmdp = cmd;
233169689Skan			*resultp = CMD_FOUND;
234169689Skan		}
235169689Skan	}
236169689Skan}
23790075Sobrien
23890075Sobrien/*
239169689Skan * Search for command prefix.
240169689Skan */
241169689Skanstatic int
242169689Skandb_cmd_search(name, table, cmdp)
243169689Skan	char *		name;
244169689Skan	struct command_table *table;
245169689Skan	struct command	**cmdp;	/* out */
246169689Skan{
247169689Skan	struct command	*cmd;
248169689Skan	struct command	**aux_cmdp;
249169689Skan	int		result = CMD_NONE;
250169689Skan
251169689Skan	for (cmd = table->table; cmd->name != 0; cmd++) {
252169689Skan		db_cmd_match(name, cmd, cmdp, &result);
253169689Skan		if (result == CMD_UNIQUE)
254169689Skan			return (CMD_UNIQUE);
255169689Skan	}
256169689Skan	if (table->aux_tablep != NULL)
257169689Skan		for (aux_cmdp = table->aux_tablep;
258169689Skan		     aux_cmdp < table->aux_tablep_end;
25990075Sobrien		     aux_cmdp++) {
26090075Sobrien			db_cmd_match(name, *aux_cmdp, cmdp, &result);
26190075Sobrien			if (result == CMD_UNIQUE)
26290075Sobrien				return (CMD_UNIQUE);
26390075Sobrien		}
26490075Sobrien	if (result == CMD_NONE) {
26590075Sobrien		/* check for 'help' */
26690075Sobrien		if (name[0] == 'h' && name[1] == 'e'
26790075Sobrien		    && name[2] == 'l' && name[3] == 'p')
26890075Sobrien			result = CMD_HELP;
26990075Sobrien	}
270169689Skan	return (result);
271169689Skan}
272169689Skan
273169689Skanstatic void
27490075Sobriendb_cmd_list(table)
27590075Sobrien	struct command_table *table;
27690075Sobrien{
27790075Sobrien	register struct command *cmd;
27890075Sobrien	register struct command **aux_cmdp;
27990075Sobrien
28090075Sobrien	for (cmd = table->table; cmd->name != 0; cmd++) {
28190075Sobrien	    db_printf("%-12s", cmd->name);
28290075Sobrien	    db_end_line(12);
28390075Sobrien	}
28490075Sobrien	if (table->aux_tablep == NULL)
285132718Skan	    return;
28690075Sobrien	for (aux_cmdp = table->aux_tablep; aux_cmdp < table->aux_tablep_end;
28790075Sobrien	     aux_cmdp++) {
28890075Sobrien	    db_printf("%-12s", (*aux_cmdp)->name);
28990075Sobrien	    db_end_line(12);
29090075Sobrien	}
29190075Sobrien}
29290075Sobrien
29390075Sobrienstatic void
29490075Sobriendb_command(last_cmdp, cmd_table, dopager)
29590075Sobrien	struct command	**last_cmdp;	/* IN_OUT */
296169689Skan	struct command_table *cmd_table;
297169689Skan	int dopager;
298169689Skan{
299169689Skan	struct command	*cmd;
300169689Skan	int		t;
301169689Skan	char		modif[TOK_STRING_SIZE];
302169689Skan	db_expr_t	addr, count;
30390075Sobrien	boolean_t	have_addr = FALSE;
30490075Sobrien	int		result;
30590075Sobrien
30690075Sobrien	t = db_read_token();
30790075Sobrien	if (t == tEOL) {
30890075Sobrien	    /* empty line repeats last command, at 'next' */
30990075Sobrien	    cmd = *last_cmdp;
31090075Sobrien	    addr = (db_expr_t)db_next;
31190075Sobrien	    have_addr = FALSE;
31290075Sobrien	    count = 1;
31390075Sobrien	    modif[0] = '\0';
31490075Sobrien	}
31590075Sobrien	else if (t == tEXCL) {
31690075Sobrien	    db_fncall((db_expr_t)0, (boolean_t)0, (db_expr_t)0, (char *)0);
31790075Sobrien	    return;
31890075Sobrien	}
319169689Skan	else if (t != tIDENT) {
320169689Skan	    db_printf("?\n");
321169689Skan	    db_flush_lex();
322169689Skan	    return;
323169689Skan	}
324169689Skan	else {
325169689Skan	    /*
326169689Skan	     * Search for command
327169689Skan	     */
328169689Skan	    while (cmd_table) {
329169689Skan		result = db_cmd_search(db_tok_string,
330169689Skan				       cmd_table,
331169689Skan				       &cmd);
332169689Skan		switch (result) {
333169689Skan		    case CMD_NONE:
334169689Skan			db_printf("No such command\n");
335169689Skan			db_flush_lex();
33690075Sobrien			return;
33790075Sobrien		    case CMD_AMBIGUOUS:
33890075Sobrien			db_printf("Ambiguous\n");
339169689Skan			db_flush_lex();
340169689Skan			return;
341169689Skan		    case CMD_HELP:
342169689Skan			db_cmd_list(cmd_table);
34390075Sobrien			db_flush_lex();
34490075Sobrien			return;
34590075Sobrien		    default:
34690075Sobrien			break;
347169689Skan		}
34890075Sobrien		if ((cmd_table = cmd->more) != NULL) {
34990075Sobrien		    t = db_read_token();
35090075Sobrien		    if (t != tIDENT) {
35190075Sobrien			db_cmd_list(cmd_table);
35290075Sobrien			db_flush_lex();
35390075Sobrien			return;
35490075Sobrien		    }
355169689Skan		}
356169689Skan	    }
357169689Skan
358169689Skan	    if ((cmd->flag & CS_OWN) == 0) {
359169689Skan		/*
360169689Skan		 * Standard syntax:
36190075Sobrien		 * command [/modifier] [addr] [,count]
362169689Skan		 */
363169689Skan		t = db_read_token();
36490075Sobrien		if (t == tSLASH) {
365169689Skan		    t = db_read_token();
366169689Skan		    if (t != tIDENT) {
367169689Skan			db_printf("Bad modifier\n");
368169689Skan			db_flush_lex();
36990075Sobrien			return;
370169689Skan		    }
371169689Skan		    db_strcpy(modif, db_tok_string);
372169689Skan		}
373169689Skan		else {
374169689Skan		    db_unread_token(t);
375169689Skan		    modif[0] = '\0';
376169689Skan		}
377169689Skan
378169689Skan		if (db_expression(&addr)) {
379169689Skan		    db_dot = (db_addr_t) addr;
380169689Skan		    db_last_addr = db_dot;
381169689Skan		    have_addr = TRUE;
382169689Skan		}
383169689Skan		else {
384169689Skan		    addr = (db_expr_t) db_dot;
385169689Skan		    have_addr = FALSE;
386169689Skan		}
387169689Skan		t = db_read_token();
388169689Skan		if (t == tCOMMA) {
389169689Skan		    if (!db_expression(&count)) {
390169689Skan			db_printf("Count missing\n");
391169689Skan			db_flush_lex();
392169689Skan			return;
393169689Skan		    }
394169689Skan		}
395169689Skan		else {
396169689Skan		    db_unread_token(t);
397169689Skan		    count = -1;
398169689Skan		}
399169689Skan		if ((cmd->flag & CS_MORE) == 0) {
400169689Skan		    db_skip_to_eol();
401169689Skan		}
402169689Skan	    }
403169689Skan	}
404169689Skan	*last_cmdp = cmd;
405169689Skan	if (cmd != 0) {
406169689Skan	    /*
407169689Skan	     * Execute the command.
408169689Skan	     */
409169689Skan	    if (dopager)
410169689Skan		db_enable_pager();
411169689Skan	    else
412169689Skan		db_disable_pager();
413169689Skan	    (*cmd->fcn)(addr, have_addr, count, modif);
414169689Skan	    if (dopager)
415169689Skan		db_disable_pager();
416169689Skan
417169689Skan	    if (cmd->flag & CS_SET_DOT) {
418169689Skan		/*
419169689Skan		 * If command changes dot, set dot to
420169689Skan		 * previous address displayed (if 'ed' style).
421169689Skan		 */
422169689Skan		if (db_ed_style) {
423169689Skan		    db_dot = db_prev;
424169689Skan		}
425169689Skan		else {
426169689Skan		    db_dot = db_next;
427169689Skan		}
428169689Skan	    }
429169689Skan	    else {
430169689Skan		/*
431169689Skan		 * If command does not change dot,
432169689Skan		 * set 'next' location to be the same.
433169689Skan		 */
434169689Skan		db_next = db_dot;
435169689Skan	    }
436169689Skan	}
437169689Skan}
438169689Skan
439169689Skan/*
440169689Skan * At least one non-optional command must be implemented using
441169689Skan * DB_COMMAND() so that db_cmd_set gets created.  Here is one.
442169689Skan */
443169689SkanDB_COMMAND(panic, db_panic)
444169689Skan{
445169689Skan	db_disable_pager();
446169689Skan	panic("from debugger");
447169689Skan}
448169689Skan
449169689Skanvoid
450169689Skandb_command_loop()
451169689Skan{
452169689Skan	/*
453169689Skan	 * Initialize 'prev' and 'next' to dot.
454169689Skan	 */
455169689Skan	db_prev = db_dot;
456169689Skan	db_next = db_dot;
457169689Skan
458169689Skan	db_cmd_loop_done = 0;
459169689Skan	while (!db_cmd_loop_done) {
460169689Skan	    if (db_print_position() != 0)
461169689Skan		db_printf("\n");
462169689Skan
463169689Skan	    db_printf("db> ");
464169689Skan	    (void) db_read_line();
465169689Skan
466169689Skan	    db_command(&db_last_command, &db_command_table, /* dopager */ 1);
467169689Skan	}
468169689Skan}
469169689Skan
470169689Skan/*
471169689Skan * Execute a command on behalf of a script.  The caller is responsible for
472169689Skan * making sure that the command string is < DB_MAXLINE or it will be
473169689Skan * truncated.
474169689Skan *
475169689Skan * XXXRW: Runs by injecting faked input into DDB input stream; it would be
476169689Skan * nicer to use an alternative approach that didn't mess with the previous
477169689Skan * command buffer.
478169689Skan */
479169689Skanvoid
480169689Skandb_command_script(const char *command)
481169689Skan{
482169689Skan	db_prev = db_next = db_dot;
483169689Skan	db_inject_line(command);
484169689Skan	db_command(&db_last_command, &db_command_table, /* dopager */ 0);
485169689Skan}
486169689Skan
487169689Skanvoid
488169689Skandb_error(s)
489169689Skan	const char *s;
490169689Skan{
491169689Skan	if (s)
492169689Skan	    db_printf("%s", s);
493169689Skan	db_flush_lex();
494169689Skan	kdb_reenter();
495169689Skan}
496169689Skan
497169689Skan
498169689Skan/*
499169689Skan * Call random function:
500169689Skan * !expr(arg,arg,arg)
501169689Skan */
502169689Skan
503169689Skan/* The generic implementation supports a maximum of 10 arguments. */
504169689Skantypedef db_expr_t __db_f(db_expr_t, db_expr_t, db_expr_t, db_expr_t,
505169689Skan    db_expr_t, db_expr_t, db_expr_t, db_expr_t, db_expr_t, db_expr_t);
506169689Skan
507169689Skanstatic __inline int
508169689Skandb_fncall_generic(db_expr_t addr, db_expr_t *rv, int nargs, db_expr_t args[])
509169689Skan{
510169689Skan	__db_f *f = (__db_f *)addr;
511169689Skan
512169689Skan	if (nargs > 10) {
513169689Skan		db_printf("Too many arguments (max 10)\n");
514169689Skan		return (0);
515169689Skan	}
516169689Skan	*rv = (*f)(args[0], args[1], args[2], args[3], args[4], args[5],
517169689Skan	    args[6], args[7], args[8], args[9]);
518169689Skan	return (1);
519169689Skan}
520169689Skan
521169689Skanstatic void
522169689Skandb_fncall(dummy1, dummy2, dummy3, dummy4)
523169689Skan	db_expr_t	dummy1;
524169689Skan	boolean_t	dummy2;
52590075Sobrien	db_expr_t	dummy3;
52690075Sobrien	char *		dummy4;
52790075Sobrien{
528132718Skan	db_expr_t	fn_addr;
529132718Skan	db_expr_t	args[DB_MAXARGS];
530132718Skan	int		nargs = 0;
531132718Skan	db_expr_t	retval;
532132718Skan	int		t;
533132718Skan
534132718Skan	if (!db_expression(&fn_addr)) {
535132718Skan	    db_printf("Bad function\n");
536132718Skan	    db_flush_lex();
537132718Skan	    return;
538132718Skan	}
539132718Skan
540132718Skan	t = db_read_token();
541132718Skan	if (t == tLPAREN) {
542132718Skan	    if (db_expression(&args[0])) {
543132718Skan		nargs++;
544132718Skan		while ((t = db_read_token()) == tCOMMA) {
545132718Skan		    if (nargs == DB_MAXARGS) {
546132718Skan			db_printf("Too many arguments (max %d)\n", DB_MAXARGS);
547132718Skan			db_flush_lex();
548132718Skan			return;
549132718Skan		    }
550132718Skan		    if (!db_expression(&args[nargs])) {
551132718Skan			db_printf("Argument missing\n");
552132718Skan			db_flush_lex();
553132718Skan			return;
554132718Skan		    }
555132718Skan		    nargs++;
556132718Skan		}
557132718Skan		db_unread_token(t);
558132718Skan	    }
559132718Skan	    if (db_read_token() != tRPAREN) {
560132718Skan		db_printf("?\n");
561132718Skan		db_flush_lex();
562132718Skan		return;
563132718Skan	    }
564132718Skan	}
565132718Skan	db_skip_to_eol();
566132718Skan	db_disable_pager();
567132718Skan
568132718Skan	if (DB_CALL(fn_addr, &retval, nargs, args))
569132718Skan		db_printf("= %#lr\n", (long)retval);
570132718Skan}
571132718Skan
572132718Skanstatic void
573132718Skandb_halt(db_expr_t dummy, boolean_t dummy2, db_expr_t dummy3, char *dummy4)
574132718Skan{
575132718Skan
576132718Skan	cpu_halt();
577132718Skan}
578132718Skan
579132718Skanstatic void
580132718Skandb_kill(dummy1, dummy2, dummy3, dummy4)
581132718Skan	db_expr_t	dummy1;
582132718Skan	boolean_t	dummy2;
583132718Skan	db_expr_t	dummy3;
584132718Skan	char *		dummy4;
585132718Skan{
586132718Skan	db_expr_t old_radix, pid, sig;
587132718Skan	struct proc *p;
588132718Skan
589132718Skan#define DB_ERROR(f)	do { db_printf f; db_flush_lex(); goto out; } while (0)
590132718Skan
591132718Skan	/*
592132718Skan	 * PIDs and signal numbers are typically represented in base
593132718Skan	 * 10, so make that the default here.  It can, of course, be
594132718Skan	 * overridden by specifying a prefix.
595132718Skan	 */
596132718Skan	old_radix = db_radix;
597132718Skan	db_radix = 10;
59890075Sobrien	/* Retrieve arguments. */
59990075Sobrien	if (!db_expression(&sig))
60090075Sobrien		DB_ERROR(("Missing signal number\n"));
60190075Sobrien	if (!db_expression(&pid))
60290075Sobrien		DB_ERROR(("Missing process ID\n"));
60390075Sobrien	db_skip_to_eol();
60490075Sobrien	if (sig < 1 || sig > _SIG_MAXSIG)
60590075Sobrien		DB_ERROR(("Signal number out of range\n"));
60690075Sobrien
607169689Skan	/*
60890075Sobrien	 * Find the process in question.  allproc_lock is not needed
60990075Sobrien	 * since we're in DDB.
610169689Skan	 */
611169689Skan	/* sx_slock(&allproc_lock); */
612132718Skan	FOREACH_PROC_IN_SYSTEM(p)
613132718Skan	    if (p->p_pid == pid)
614132718Skan		    break;
615132718Skan	/* sx_sunlock(&allproc_lock); */
616132718Skan	if (p == NULL)
617169689Skan		DB_ERROR(("Can't find process with pid %ld\n", (long) pid));
618132718Skan
619132718Skan	/* If it's already locked, bail; otherwise, do the deed. */
620132718Skan	if (PROC_TRYLOCK(p) == 0)
621132718Skan		DB_ERROR(("Can't lock process with pid %ld\n", (long) pid));
622169689Skan	else {
623169689Skan		psignal(p, sig);
624169689Skan		PROC_UNLOCK(p);
625169689Skan	}
626169689Skan
627169689Skanout:
628169689Skan	db_radix = old_radix;
629169689Skan#undef DB_ERROR
630169689Skan}
63190075Sobrien
63290075Sobrienstatic void
633132718Skandb_reset(dummy1, dummy2, dummy3, dummy4)
634169689Skan	db_expr_t	dummy1;
635132718Skan	boolean_t	dummy2;
63690075Sobrien	db_expr_t	dummy3;
637132718Skan	char *		dummy4;
638132718Skan{
639132718Skan
640132718Skan	cpu_reset();
641132718Skan}
64290075Sobrien
643169689Skanstatic void
644132718Skandb_watchdog(dummy1, dummy2, dummy3, dummy4)
64590075Sobrien	db_expr_t	dummy1;
646169689Skan	boolean_t	dummy2;
647169689Skan	db_expr_t	dummy3;
648132718Skan	char *		dummy4;
64990075Sobrien{
650169689Skan	int i;
651169689Skan
652169689Skan	/*
653169689Skan	 * XXX: It might make sense to be able to set the watchdog to a
654169689Skan	 * XXX: timeout here so that failure or hang as a result of subsequent
655169689Skan	 * XXX: ddb commands could be recovered by a reset.
65690075Sobrien	 */
657169689Skan
658169689Skan	EVENTHANDLER_INVOKE(watchdog_list, 0, &i);
659169689Skan}
660169689Skan
661169689Skanstatic void
662db_gdb(db_expr_t dummy1, boolean_t dummy2, db_expr_t dummy3, char *dummy4)
663{
664
665	if (kdb_dbbe_select("gdb") != 0)
666		db_printf("The remote GDB backend could not be selected.\n");
667	else
668		db_printf("Step to enter the remote GDB backend.\n");
669}
670
671static void
672db_stack_trace(db_expr_t tid, boolean_t hastid, db_expr_t count, char *modif)
673{
674	struct thread *td;
675	db_expr_t radix;
676	pid_t pid;
677	int t;
678
679	/*
680	 * We parse our own arguments. We don't like the default radix.
681	 */
682	radix = db_radix;
683	db_radix = 10;
684	hastid = db_expression(&tid);
685	t = db_read_token();
686	if (t == tCOMMA) {
687		if (!db_expression(&count)) {
688			db_printf("Count missing\n");
689			db_flush_lex();
690			return;
691		}
692	} else {
693		db_unread_token(t);
694		count = -1;
695	}
696	db_skip_to_eol();
697	db_radix = radix;
698
699	if (hastid) {
700		td = kdb_thr_lookup((lwpid_t)tid);
701		if (td == NULL)
702			td = kdb_thr_from_pid((pid_t)tid);
703		if (td == NULL) {
704			db_printf("Thread %d not found\n", (int)tid);
705			return;
706		}
707	} else
708		td = kdb_thread;
709	if (td->td_proc != NULL)
710		pid = td->td_proc->p_pid;
711	else
712		pid = -1;
713	db_printf("Tracing pid %d tid %ld td %p\n", pid, (long)td->td_tid, td);
714	db_trace_thread(td, count);
715}
716
717static void
718db_stack_trace_all(db_expr_t dummy, boolean_t dummy2, db_expr_t dummy3,
719    char *dummy4)
720{
721	struct proc *p;
722	struct thread *td;
723	jmp_buf jb;
724	void *prev_jb;
725
726	FOREACH_PROC_IN_SYSTEM(p) {
727		prev_jb = kdb_jmpbuf(jb);
728		if (setjmp(jb) == 0) {
729			FOREACH_THREAD_IN_PROC(p, td) {
730				db_printf("\nTracing command %s pid %d tid %ld td %p\n",
731					  p->p_comm, p->p_pid, (long)td->td_tid, td);
732				db_trace_thread(td, -1);
733				if (db_pager_quit) {
734					kdb_jmpbuf(prev_jb);
735					return;
736				}
737			}
738		}
739		kdb_jmpbuf(prev_jb);
740	}
741}
742