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 */
command(buf,defcom)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
cmds(defcom)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
fmtcom(space,eqcom)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
mcom(space,ptype,fullword)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
lcom(space,ptype,fullword)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
wcom(space,ptype,fullword)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
shell()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
getformat(buf,n)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 */
varlookup(name)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 *
reglookup()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