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