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