1*47822Sbostic /*-
2*47822Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*47822Sbostic  * All rights reserved.
4*47822Sbostic  *
5*47822Sbostic  * %sccs.include.proprietary.c%
6*47822Sbostic  */
7*47822Sbostic 
836559Sbostic #ifndef lint
9*47822Sbostic static char sccsid[] = "@(#)command.c	5.5 (Berkeley) 04/04/91";
10*47822Sbostic #endif /* not lint */
1136559Sbostic 
1236559Sbostic /*
1336559Sbostic  * adb - commands
1436559Sbostic  */
1536559Sbostic 
1636559Sbostic #include "defs.h"
1736559Sbostic #include <ctype.h>
1836559Sbostic #include <sys/wait.h>
1939224Storek #include <paths.h>
2036559Sbostic 
2136559Sbostic extern char BADEQ[];		/* "unexpected `='" */
2236559Sbostic extern char NOMATCH[];		/* "cannot locate value" */
2336559Sbostic extern char BADVAR[];		/* "bad variable" */
2436559Sbostic extern char BADCOM[];		/* "bad command" */
2536559Sbostic extern char NOFORK[];		/* "try again" */
2636559Sbostic 
2736559Sbostic /*
2836559Sbostic  * executing is used in main() to see if it is necessary to
2936559Sbostic  * delete any breakpoints that might have been set; if an
3036559Sbostic  * error occurs while a subprocess command is running, executing
3136559Sbostic  * will be set.
3236559Sbostic  */
3336559Sbostic int	executing;
3436559Sbostic 
3536559Sbostic /* lastcom remembers the previous command */
3636559Sbostic static struct {
3736559Sbostic 	int	c;		/* the command */
3836559Sbostic 	int	star;		/* true iff it was in alternate space */
3936559Sbostic } lastcom;
4036559Sbostic 
4136559Sbostic /*
4236559Sbostic  * Execute the given command buffer.
4336559Sbostic  * If defcom is nonzero, it is used as the default command.
4436559Sbostic  */
command(buf,defcom)4536559Sbostic command(buf, defcom)
4636559Sbostic 	char *buf;
4736559Sbostic 	int defcom;
4836559Sbostic {
4936559Sbostic 
5036559Sbostic 	lp = buf;
5136559Sbostic 	do {
5236559Sbostic 		cmds(defcom);
5336559Sbostic 		flushbuf();
5436559Sbostic 	} while (rdc() == ';');
5536559Sbostic 	unreadc();
5636559Sbostic }
5736559Sbostic 
5836559Sbostic static
cmds(defcom)5936559Sbostic cmds(defcom)
6036559Sbostic 	int defcom;
6136559Sbostic {
6236559Sbostic 	int c;
6336559Sbostic 	struct reglist *reg;
6436559Sbostic 
6536559Sbostic 	/*
6636559Sbostic 	 * Pick up the optional first expression (`dot'),
6736559Sbostic 	 * then, if the next character is a comma, pick up
6836559Sbostic 	 * the second optional expression (`ecount').
6936559Sbostic 	 */
7036559Sbostic 	if (gavedot = oexpr())
7136559Sbostic 		ditto = dot = edot = expv;
7236559Sbostic 	else
7336559Sbostic 		edot = dot;	/* probably equal, but possibly truncating */
7436559Sbostic 	if (rdc() == ',') {
7536559Sbostic 		if (!oexpr())
7636559Sbostic 			error("count expected");
7736559Sbostic 		gavecount = 1;
7836559Sbostic 		ecount = expv;
7936559Sbostic 	} else {
8036559Sbostic 		gavecount = 0;
8136559Sbostic 		ecount = 1;
8236559Sbostic 		unreadc();
8336559Sbostic 	}
8436559Sbostic 
8536559Sbostic 	/*
8636559Sbostic 	 * Pick up the command.  If there is no command, do the
8736559Sbostic 	 * previous (or default) command, and if no dot was given,
8836559Sbostic 	 * use the `next' dot.
8936559Sbostic 	 */
9036559Sbostic 	c = rdc();
9136559Sbostic 	if (eol(c)) {
9236559Sbostic 		if (defcom != 0) {
9336559Sbostic 			lastcom.c = defcom;
9436559Sbostic 			lastcom.star = 0;
9536559Sbostic 		}
9636559Sbostic 		if (!gavedot)
9736559Sbostic 			dot = inkdot(dotinc);
9836559Sbostic 		unreadc();
9936559Sbostic 	} else {
10036559Sbostic 		lastcom.c = c;
10136559Sbostic 		lastcom.star = 0;
10236559Sbostic 	}
10336559Sbostic 
10436559Sbostic 	switch (lastcom.c) {
10536559Sbostic 
10636559Sbostic 	case '=':
10736559Sbostic 		fmtcom(SP_NONE, 1);
10836559Sbostic 		break;
10936559Sbostic 
11036559Sbostic 	case '/':
11136559Sbostic 		fmtcom(SP_DATA, 0);
11236559Sbostic 		break;
11336559Sbostic 
11436559Sbostic 	case '?':
11536559Sbostic 		fmtcom(SP_INSTR, 0);
11636559Sbostic 		break;
11736559Sbostic 
11836559Sbostic 	case '>':
11936559Sbostic 		lastcom.c = 0;
12036559Sbostic 		if ((reg = reglookup()) != NULL) {
12136559Sbostic 			if (setreg(reg, edot))
12236559Sbostic 				prints("register write failed");
12336559Sbostic 			break;
12436559Sbostic 		}
12536559Sbostic 		if ((c = varlookup(rdc())) != -1)
12636559Sbostic 			var[c] = edot;
12736559Sbostic 		else
12836559Sbostic 			error(BADVAR);
12936559Sbostic 		break;
13036559Sbostic 
13136559Sbostic 	case '!':
13236559Sbostic 		lastcom.c = 0;
13336559Sbostic 		shell();
13436559Sbostic 		break;
13536559Sbostic 
13636559Sbostic 	case '$':
13736559Sbostic 		lastcom.c = 0;
13836559Sbostic 		printtrace(nextchar());
13936559Sbostic 		break;
14036559Sbostic 
14136559Sbostic 	case ':':
14236559Sbostic 		if (!executing) {
14336559Sbostic 			executing = 1;
14436559Sbostic 			subpcs(nextchar());
14536559Sbostic 			executing = 0;
14636559Sbostic 			lastcom.c = 0;
14736559Sbostic 		}
14836559Sbostic 		break;
14936559Sbostic 
15036559Sbostic 	case 0:
15136559Sbostic 		prints("adb\n");
15236559Sbostic 		break;
15336559Sbostic 
15436559Sbostic 	default:
15536559Sbostic 		error(BADCOM);
15636559Sbostic 		/* NOTREACHED */
15736559Sbostic 	}
15836559Sbostic }
15936559Sbostic 
16036559Sbostic /*
16136559Sbostic  * Perform a format-based command (one in ? / or =).
16236559Sbostic  */
16336559Sbostic static
fmtcom(space,eqcom)16436559Sbostic fmtcom(space, eqcom)
16536559Sbostic 	int space, eqcom;
16636559Sbostic {
16736559Sbostic 	/* special commands m, lL, wW do not operate in SP_NONE (`=') */
16836559Sbostic 	void mcom(), lcom(), wcom();
16936559Sbostic 	static struct fcmd {
17036559Sbostic 		int	c;
17136559Sbostic 		void	(*fn)();
17236559Sbostic 	} fcmd[] = {
17336559Sbostic 		{ 'm', mcom },
17436559Sbostic 		{ 'l', lcom }, { 'L', lcom },
17536559Sbostic 		{ 'w', wcom }, { 'W', wcom },
17636559Sbostic 		0
17736559Sbostic 	};
17836559Sbostic 	register struct fcmd *f;
17936559Sbostic 	register int c;
18036559Sbostic 	int ptype = space;
18136559Sbostic 	static char stformat[LINELEN] = "X\"= \"^i";
18236559Sbostic 	static char eqformat[LINELEN] = "z";
18336559Sbostic 
18436559Sbostic 	/*
18536559Sbostic 	 * Are we operating in the alternate `star' space?
18636559Sbostic 	 */
18736559Sbostic 	if (!eqcom) {
18836559Sbostic 		if (rdc() == '*')
18936559Sbostic 			lastcom.star = 1;
19036559Sbostic 		else
19136559Sbostic 			unreadc();
19236559Sbostic 		if (lastcom.star) {
19336559Sbostic 			space |= SP_STAR;
19436559Sbostic 			/* print as data for instr, and vice versa */
19536559Sbostic 			ptype = (SP_DATA + SP_INSTR) - ptype;
19636559Sbostic 		}
19736559Sbostic 	}
19836559Sbostic 
19936559Sbostic 	/*
20036559Sbostic 	 * Check for the special commands first.
20136559Sbostic 	 */
20236559Sbostic 	c = rdc();
20336559Sbostic 	for (f = fcmd; f->c; f++) {
20436559Sbostic 		if (c == f->c) {
20536559Sbostic 			if (eqcom)
20636559Sbostic 				error(BADEQ);
20736559Sbostic 			(*f->fn)(space, ptype, isupper(c));
20836559Sbostic 			return;
20936559Sbostic 		}
21036559Sbostic 	}
21136559Sbostic 	unreadc();
21236559Sbostic 	getformat(eqcom ? eqformat : stformat, LINELEN);
21336559Sbostic 	scanform(!eqcom, eqcom ? eqformat : stformat, space, ptype);
21436559Sbostic }
21536559Sbostic 
21636559Sbostic /*
21736559Sbostic  * Set a map (?m, /m commands).
21836559Sbostic  */
21936559Sbostic /* ARGSUSED */
22036559Sbostic static void
mcom(space,ptype,fullword)22136559Sbostic mcom(space, ptype, fullword)
22236559Sbostic 	int space, ptype, fullword;
22336559Sbostic {
22436559Sbostic 	register struct map *smap;
22536559Sbostic 	register struct m1 *mm;
22636559Sbostic 	char c;
22736559Sbostic 
22836559Sbostic 	smap = space & SP_DATA ? &datmap : &txtmap;
22936559Sbostic 	mm = space & SP_STAR ? &smap->m2 : &smap->m1;
23036559Sbostic 	if (oexpr()) {
23136559Sbostic 		mm->b = expv;
23236559Sbostic 		if (oexpr()) {
23336559Sbostic 			mm->e = expv;
23436559Sbostic 			if (oexpr())
23536559Sbostic 				mm->f = expv;
23636559Sbostic 		}
23736559Sbostic 	}
23836559Sbostic 	if ((c = rdc()) == '?')
23936559Sbostic 		smap->ufd = symfile.fd;
24036559Sbostic 	else if (c == '/')
24136559Sbostic 		smap->ufd = corefile.fd;
24236559Sbostic 	else
24336559Sbostic 		unreadc();
24436559Sbostic }
24536559Sbostic 
24636559Sbostic /*
24736559Sbostic  * Locate a value (l, L commands).
24836559Sbostic  */
24936559Sbostic static void
lcom(space,ptype,fullword)25036559Sbostic lcom(space, ptype, fullword)
25136559Sbostic 	int space, ptype, fullword;
25236559Sbostic {
25336559Sbostic 	register expr_t val, mask;
25436559Sbostic 	addr_t savdot;
25536559Sbostic 
25636559Sbostic 	/* search for exp */
25736559Sbostic 	savdot = dot;
25836559Sbostic 	val = rexpr();
25936559Sbostic 	if (oexpr())
26036559Sbostic 		mask = expv;
26136559Sbostic 	else
26236559Sbostic 		mask = ~0L;
26336559Sbostic 	if (fullword) {
26436559Sbostic 		expr_t w;
26536559Sbostic 
26636559Sbostic 		dotinc = sizeof(w);
26736559Sbostic 		for (;;) {
26836559Sbostic 			(void) adbread(space, dot, &w, sizeof(w));
26936559Sbostic 			if (iserr() || (w & mask) == val)
27036559Sbostic 				break;
27136559Sbostic 			dot = inkdot(sizeof(w));
27236559Sbostic 		}
27336559Sbostic 	} else {
27436559Sbostic 		hword_t hw;
27536559Sbostic 
27636559Sbostic 		dotinc = sizeof(hw);
27736559Sbostic 		mask = (hword_t)mask;
27836559Sbostic 		val = (hword_t)val;
27936559Sbostic 		for (;;) {
28036559Sbostic 			(void) adbread(space, dot, &hw, sizeof(hw));
28136559Sbostic 			if (iserr() || (hw & mask) == val)
28236559Sbostic 				break;
28336559Sbostic 			dot = inkdot(sizeof(hw));
28436559Sbostic 		}
28536559Sbostic 	}
28636559Sbostic 	if (iserr()) {
28736559Sbostic 		dot = savdot;
28836559Sbostic 		errflag = NOMATCH;
28936559Sbostic 	}
29036559Sbostic 	psymoff("%R", dot, ptype, maxoff, "");
29136559Sbostic }
29236559Sbostic 
29336559Sbostic /*
29436559Sbostic  * Write new values (w, W).
29536559Sbostic  */
29636559Sbostic static void
wcom(space,ptype,fullword)29736559Sbostic wcom(space, ptype, fullword)
29836559Sbostic 	int space, ptype, fullword;
29936559Sbostic {
30036559Sbostic 	addr_t savdot;
30136559Sbostic 	hword_t hw;
30236559Sbostic 
30336559Sbostic 	(void) rexpr();
30436559Sbostic 	do {
30536559Sbostic 		savdot = dot;
30636559Sbostic 		pdot();
30736559Sbostic 		showdot(fullword, space, ptype);	/* also advances */
30836559Sbostic 		errflag = NULL;
30936559Sbostic 		dot = savdot;
31036559Sbostic 		if (fullword)
31136559Sbostic 			(void) adbwrite(space, dot, &expv, sizeof(expv));
31236559Sbostic 		else {
31336559Sbostic 			hw = expv;
31436559Sbostic 			(void) adbwrite(space, dot, &hw, sizeof(hw));
31536559Sbostic 		}
31636559Sbostic 		savdot = dot;
31736559Sbostic 		adbprintf("=%8t");
31836559Sbostic 		showdot(fullword, space, ptype);
31936559Sbostic 		printc('\n');
32036559Sbostic 	} while (oexpr() && !iserr());
32136559Sbostic 	dot = savdot;
32236559Sbostic 	checkerr();
32336559Sbostic }
32436559Sbostic 
32536559Sbostic /*
32636559Sbostic  * Do a shell escape.
32736559Sbostic  *
32836559Sbostic  * THE vfork CODE BELOW IS CURRENTLY BROKEN
32936559Sbostic  * MUST CHANGE signal TO sigvec BELOW
33036559Sbostic  */
33136559Sbostic static
shell()33236559Sbostic shell()
33336559Sbostic {
33436559Sbostic 	int rc, unixpid;
33536559Sbostic 	union wait status;
33636559Sbostic 	char *argp = lp;
33736559Sbostic 	char *getenv(), *eshell = getenv("SHELL");
33836559Sbostic 
33936559Sbostic 	if (eshell == 0)
34037676Sbostic 		eshell = _PATH_BSHELL;
34136559Sbostic 	while (readchar() != '\n')
34236559Sbostic 		/* void */;
34336559Sbostic #ifndef VFORK
34436559Sbostic #define vfork fork
34536559Sbostic #endif
34636559Sbostic 	if ((unixpid = vfork()) == 0) {
34736559Sbostic 		*lp = 0;
34836559Sbostic 		(void) signal(SIGINT, sigint);
34936559Sbostic 		(void) signal(SIGQUIT, sigquit);
35036559Sbostic 		execl(eshell, "sh", "-c", argp, (char *)NULL);
35136559Sbostic 		_exit(16);
35236559Sbostic 		/* NOTREACHED */
35336559Sbostic 	}
35436559Sbostic #ifdef VFORK
35536559Sbostic 	*lp = '\n';
35636559Sbostic #endif
35736559Sbostic 	if (unixpid == -1)
35836559Sbostic 		error(NOFORK);
35936559Sbostic 	(void) signal(SIGINT, SIG_IGN);
36036559Sbostic 	while ((rc = wait(&status)) != unixpid && rc != -1)
36136559Sbostic 		/* void */;
36236559Sbostic 	(void) signal(SIGINT, intcatch);
36336559Sbostic 	prints("!");
36436559Sbostic 	unreadc();
36536559Sbostic }
36636559Sbostic 
36736559Sbostic /*
36836559Sbostic  * Read a format into the given buffer.  If nothing is
36936559Sbostic  * read, leave the buffer alone.
37036559Sbostic  */
37136559Sbostic static
getformat(buf,n)37236559Sbostic getformat(buf, n)
37336559Sbostic 	char *buf;
37436559Sbostic 	register int n;
37536559Sbostic {
37636559Sbostic 	register char *p = buf;
37736559Sbostic 	register int c, quote = 0;
37836559Sbostic 
37936559Sbostic 	while ((c = readchar()), quote ? c != '\n' : !eol(c)) {
38036559Sbostic 		if (c == '"')
38136559Sbostic 			quote = !quote;
38236559Sbostic 		if (--n > 0)
38336559Sbostic 			*p++ = c;
38436559Sbostic 	}
38536559Sbostic 	unreadc();
38636559Sbostic 	if (p != buf)		/* nonempty */
38736559Sbostic 		*p++ = 0;
38836559Sbostic }
38936559Sbostic 
39036559Sbostic /*
39136559Sbostic  * Convert a (one-character) variable name to an index, or -1 for
39236559Sbostic  * error.
39336559Sbostic  */
varlookup(name)39436559Sbostic varlookup(name)
39536559Sbostic 	register int name;
39636559Sbostic {
39736559Sbostic 
39836559Sbostic 	if (isdigit(name))
39936559Sbostic 		return (name - '0');
40036559Sbostic 	if (isalpha(name))
40137335Storek 		return (isupper(name) ? name - 'A' + 10 : name - 'a' + 10);
40236559Sbostic 	return (-1);
40336559Sbostic }
40436559Sbostic 
40536559Sbostic /*
40636559Sbostic  * If the text at the current input point matches a register name,
40736559Sbostic  * consume that text and return a pointer to the register; otherwise
40836559Sbostic  * leave it unconsumed and return NULL.
40936559Sbostic  */
41036559Sbostic struct reglist *
reglookup()41136559Sbostic reglookup()
41236559Sbostic {
41336559Sbostic 	register struct reglist *p;
41436559Sbostic 	register char *a, *b, c0, c1;
41536559Sbostic 	char *oldlp = lp;
41636559Sbostic 	extern struct reglist reglist[];
41736559Sbostic 
41836559Sbostic 	c0 = rdc();
41936559Sbostic 	c1 = readchar();
42036559Sbostic 	for (p = reglist; (a = p->r_name) != NULL; p++) {
42136559Sbostic 		if (*a++ != c0 || *a++ != c1)
42236559Sbostic 			continue;
42336559Sbostic 		b = lp;
42436559Sbostic 		do {
42536559Sbostic 			if (*a == 0) {	/* name matched: stop short */
42636559Sbostic 				lp = b;
42736559Sbostic 				return (p);
42836559Sbostic 			}
42936559Sbostic 		} while (*a++ == *b++);
43036559Sbostic 	}
43136559Sbostic 	lp = oldlp;
43236559Sbostic 	return (NULL);
43336559Sbostic }
434