Commit | Line | Data |
---|---|---|
f582ecdc | 1 | #ifndef lint |
fef2e2de | 2 | static char sccsid[] = "@(#)command.c 5.4 (Berkeley) %G%"; |
f582ecdc KB |
3 | #endif |
4 | ||
5 | /* | |
6 | * adb - commands | |
7 | */ | |
8 | ||
9 | #include "defs.h" | |
10 | #include <ctype.h> | |
11 | #include <sys/wait.h> | |
fef2e2de | 12 | #include <paths.h> |
f582ecdc KB |
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) | |
67000472 | 333 | eshell = _PATH_BSHELL; |
f582ecdc KB |
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)) | |
27649f68 | 394 | return (isupper(name) ? name - 'A' + 10 : name - 'a' + 10); |
f582ecdc KB |
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 | } |