1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)command.c	5.5 (Berkeley) 04/04/91";
10 #endif /* not lint */
11 
12 /*
13  * adb - commands
14  */
15 
16 #include "defs.h"
17 #include <ctype.h>
18 #include <sys/wait.h>
19 #include <paths.h>
20 
21 extern char BADEQ[];		/* "unexpected `='" */
22 extern char NOMATCH[];		/* "cannot locate value" */
23 extern char BADVAR[];		/* "bad variable" */
24 extern char BADCOM[];		/* "bad command" */
25 extern char NOFORK[];		/* "try again" */
26 
27 /*
28  * executing is used in main() to see if it is necessary to
29  * delete any breakpoints that might have been set; if an
30  * error occurs while a subprocess command is running, executing
31  * will be set.
32  */
33 int	executing;
34 
35 /* lastcom remembers the previous command */
36 static struct {
37 	int	c;		/* the command */
38 	int	star;		/* true iff it was in alternate space */
39 } lastcom;
40 
41 /*
42  * Execute the given command buffer.
43  * If defcom is nonzero, it is used as the default command.
44  */
45 command(buf, defcom)
46 	char *buf;
47 	int defcom;
48 {
49 
50 	lp = buf;
51 	do {
52 		cmds(defcom);
53 		flushbuf();
54 	} while (rdc() == ';');
55 	unreadc();
56 }
57 
58 static
59 cmds(defcom)
60 	int defcom;
61 {
62 	int c;
63 	struct reglist *reg;
64 
65 	/*
66 	 * Pick up the optional first expression (`dot'),
67 	 * then, if the next character is a comma, pick up
68 	 * the second optional expression (`ecount').
69 	 */
70 	if (gavedot = oexpr())
71 		ditto = dot = edot = expv;
72 	else
73 		edot = dot;	/* probably equal, but possibly truncating */
74 	if (rdc() == ',') {
75 		if (!oexpr())
76 			error("count expected");
77 		gavecount = 1;
78 		ecount = expv;
79 	} else {
80 		gavecount = 0;
81 		ecount = 1;
82 		unreadc();
83 	}
84 
85 	/*
86 	 * Pick up the command.  If there is no command, do the
87 	 * previous (or default) command, and if no dot was given,
88 	 * use the `next' dot.
89 	 */
90 	c = rdc();
91 	if (eol(c)) {
92 		if (defcom != 0) {
93 			lastcom.c = defcom;
94 			lastcom.star = 0;
95 		}
96 		if (!gavedot)
97 			dot = inkdot(dotinc);
98 		unreadc();
99 	} else {
100 		lastcom.c = c;
101 		lastcom.star = 0;
102 	}
103 
104 	switch (lastcom.c) {
105 
106 	case '=':
107 		fmtcom(SP_NONE, 1);
108 		break;
109 
110 	case '/':
111 		fmtcom(SP_DATA, 0);
112 		break;
113 
114 	case '?':
115 		fmtcom(SP_INSTR, 0);
116 		break;
117 
118 	case '>':
119 		lastcom.c = 0;
120 		if ((reg = reglookup()) != NULL) {
121 			if (setreg(reg, edot))
122 				prints("register write failed");
123 			break;
124 		}
125 		if ((c = varlookup(rdc())) != -1)
126 			var[c] = edot;
127 		else
128 			error(BADVAR);
129 		break;
130 
131 	case '!':
132 		lastcom.c = 0;
133 		shell();
134 		break;
135 
136 	case '$':
137 		lastcom.c = 0;
138 		printtrace(nextchar());
139 		break;
140 
141 	case ':':
142 		if (!executing) {
143 			executing = 1;
144 			subpcs(nextchar());
145 			executing = 0;
146 			lastcom.c = 0;
147 		}
148 		break;
149 
150 	case 0:
151 		prints("adb\n");
152 		break;
153 
154 	default:
155 		error(BADCOM);
156 		/* NOTREACHED */
157 	}
158 }
159 
160 /*
161  * Perform a format-based command (one in ? / or =).
162  */
163 static
164 fmtcom(space, eqcom)
165 	int space, eqcom;
166 {
167 	/* special commands m, lL, wW do not operate in SP_NONE (`=') */
168 	void mcom(), lcom(), wcom();
169 	static struct fcmd {
170 		int	c;
171 		void	(*fn)();
172 	} fcmd[] = {
173 		{ 'm', mcom },
174 		{ 'l', lcom }, { 'L', lcom },
175 		{ 'w', wcom }, { 'W', wcom },
176 		0
177 	};
178 	register struct fcmd *f;
179 	register int c;
180 	int ptype = space;
181 	static char stformat[LINELEN] = "X\"= \"^i";
182 	static char eqformat[LINELEN] = "z";
183 
184 	/*
185 	 * Are we operating in the alternate `star' space?
186 	 */
187 	if (!eqcom) {
188 		if (rdc() == '*')
189 			lastcom.star = 1;
190 		else
191 			unreadc();
192 		if (lastcom.star) {
193 			space |= SP_STAR;
194 			/* print as data for instr, and vice versa */
195 			ptype = (SP_DATA + SP_INSTR) - ptype;
196 		}
197 	}
198 
199 	/*
200 	 * Check for the special commands first.
201 	 */
202 	c = rdc();
203 	for (f = fcmd; f->c; f++) {
204 		if (c == f->c) {
205 			if (eqcom)
206 				error(BADEQ);
207 			(*f->fn)(space, ptype, isupper(c));
208 			return;
209 		}
210 	}
211 	unreadc();
212 	getformat(eqcom ? eqformat : stformat, LINELEN);
213 	scanform(!eqcom, eqcom ? eqformat : stformat, space, ptype);
214 }
215 
216 /*
217  * Set a map (?m, /m commands).
218  */
219 /* ARGSUSED */
220 static void
221 mcom(space, ptype, fullword)
222 	int space, ptype, fullword;
223 {
224 	register struct map *smap;
225 	register struct m1 *mm;
226 	char c;
227 
228 	smap = space & SP_DATA ? &datmap : &txtmap;
229 	mm = space & SP_STAR ? &smap->m2 : &smap->m1;
230 	if (oexpr()) {
231 		mm->b = expv;
232 		if (oexpr()) {
233 			mm->e = expv;
234 			if (oexpr())
235 				mm->f = expv;
236 		}
237 	}
238 	if ((c = rdc()) == '?')
239 		smap->ufd = symfile.fd;
240 	else if (c == '/')
241 		smap->ufd = corefile.fd;
242 	else
243 		unreadc();
244 }
245 
246 /*
247  * Locate a value (l, L commands).
248  */
249 static void
250 lcom(space, ptype, fullword)
251 	int space, ptype, fullword;
252 {
253 	register expr_t val, mask;
254 	addr_t savdot;
255 
256 	/* search for exp */
257 	savdot = dot;
258 	val = rexpr();
259 	if (oexpr())
260 		mask = expv;
261 	else
262 		mask = ~0L;
263 	if (fullword) {
264 		expr_t w;
265 
266 		dotinc = sizeof(w);
267 		for (;;) {
268 			(void) adbread(space, dot, &w, sizeof(w));
269 			if (iserr() || (w & mask) == val)
270 				break;
271 			dot = inkdot(sizeof(w));
272 		}
273 	} else {
274 		hword_t hw;
275 
276 		dotinc = sizeof(hw);
277 		mask = (hword_t)mask;
278 		val = (hword_t)val;
279 		for (;;) {
280 			(void) adbread(space, dot, &hw, sizeof(hw));
281 			if (iserr() || (hw & mask) == val)
282 				break;
283 			dot = inkdot(sizeof(hw));
284 		}
285 	}
286 	if (iserr()) {
287 		dot = savdot;
288 		errflag = NOMATCH;
289 	}
290 	psymoff("%R", dot, ptype, maxoff, "");
291 }
292 
293 /*
294  * Write new values (w, W).
295  */
296 static void
297 wcom(space, ptype, fullword)
298 	int space, ptype, fullword;
299 {
300 	addr_t savdot;
301 	hword_t hw;
302 
303 	(void) rexpr();
304 	do {
305 		savdot = dot;
306 		pdot();
307 		showdot(fullword, space, ptype);	/* also advances */
308 		errflag = NULL;
309 		dot = savdot;
310 		if (fullword)
311 			(void) adbwrite(space, dot, &expv, sizeof(expv));
312 		else {
313 			hw = expv;
314 			(void) adbwrite(space, dot, &hw, sizeof(hw));
315 		}
316 		savdot = dot;
317 		adbprintf("=%8t");
318 		showdot(fullword, space, ptype);
319 		printc('\n');
320 	} while (oexpr() && !iserr());
321 	dot = savdot;
322 	checkerr();
323 }
324 
325 /*
326  * Do a shell escape.
327  *
328  * THE vfork CODE BELOW IS CURRENTLY BROKEN
329  * MUST CHANGE signal TO sigvec BELOW
330  */
331 static
332 shell()
333 {
334 	int rc, unixpid;
335 	union wait status;
336 	char *argp = lp;
337 	char *getenv(), *eshell = getenv("SHELL");
338 
339 	if (eshell == 0)
340 		eshell = _PATH_BSHELL;
341 	while (readchar() != '\n')
342 		/* void */;
343 #ifndef VFORK
344 #define vfork fork
345 #endif
346 	if ((unixpid = vfork()) == 0) {
347 		*lp = 0;
348 		(void) signal(SIGINT, sigint);
349 		(void) signal(SIGQUIT, sigquit);
350 		execl(eshell, "sh", "-c", argp, (char *)NULL);
351 		_exit(16);
352 		/* NOTREACHED */
353 	}
354 #ifdef VFORK
355 	*lp = '\n';
356 #endif
357 	if (unixpid == -1)
358 		error(NOFORK);
359 	(void) signal(SIGINT, SIG_IGN);
360 	while ((rc = wait(&status)) != unixpid && rc != -1)
361 		/* void */;
362 	(void) signal(SIGINT, intcatch);
363 	prints("!");
364 	unreadc();
365 }
366 
367 /*
368  * Read a format into the given buffer.  If nothing is
369  * read, leave the buffer alone.
370  */
371 static
372 getformat(buf, n)
373 	char *buf;
374 	register int n;
375 {
376 	register char *p = buf;
377 	register int c, quote = 0;
378 
379 	while ((c = readchar()), quote ? c != '\n' : !eol(c)) {
380 		if (c == '"')
381 			quote = !quote;
382 		if (--n > 0)
383 			*p++ = c;
384 	}
385 	unreadc();
386 	if (p != buf)		/* nonempty */
387 		*p++ = 0;
388 }
389 
390 /*
391  * Convert a (one-character) variable name to an index, or -1 for
392  * error.
393  */
394 varlookup(name)
395 	register int name;
396 {
397 
398 	if (isdigit(name))
399 		return (name - '0');
400 	if (isalpha(name))
401 		return (isupper(name) ? name - 'A' + 10 : name - 'a' + 10);
402 	return (-1);
403 }
404 
405 /*
406  * If the text at the current input point matches a register name,
407  * consume that text and return a pointer to the register; otherwise
408  * leave it unconsumed and return NULL.
409  */
410 struct reglist *
411 reglookup()
412 {
413 	register struct reglist *p;
414 	register char *a, *b, c0, c1;
415 	char *oldlp = lp;
416 	extern struct reglist reglist[];
417 
418 	c0 = rdc();
419 	c1 = readchar();
420 	for (p = reglist; (a = p->r_name) != NULL; p++) {
421 		if (*a++ != c0 || *a++ != c1)
422 			continue;
423 		b = lp;
424 		do {
425 			if (*a == 0) {	/* name matched: stop short */
426 				lp = b;
427 				return (p);
428 			}
429 		} while (*a++ == *b++);
430 	}
431 	lp = oldlp;
432 	return (NULL);
433 }
434