xref: /plan9/sys/src/cmd/vi/cmd.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 #include <ctype.h>
6 #define Extern extern
7 #include "mips.h"
8 
9 char	buf[128], lastcmd[128];
10 char	fmt = 'X';
11 int	width = 60;
12 int	inc;
13 
14 ulong	expr(char*);
15 ulong	expr1(char*);
16 char*	term(char*, ulong*);
17 
18 char *
nextc(char * p)19 nextc(char *p)
20 {
21 	while(*p && (*p == ' ' || *p == '\t') && *p != '\n')
22 		p++;
23 
24 	if(*p == '\n')
25 		*p = '\0';
26 
27 	return p;
28 }
29 
30 char *
numsym(char * addr,ulong * val)31 numsym(char *addr, ulong *val)
32 {
33 	char tsym[128], *t;
34 	static char *delim = "`'<>/\\@*|-~+-/=?\n";
35 	Symbol s;
36 	char c;
37 
38 	t = tsym;
39 	while(c = *addr) {
40 		if(strchr(delim, c))
41 			break;
42 		*t++ = c;
43 		addr++;
44 	}
45 	t[0] = '\0';
46 
47 	if(strcmp(tsym, ".") == 0) {
48 		*val = dot;
49 		return addr;
50 	}
51 
52 	if(lookup(0, tsym, &s))
53 		*val = s.value;
54 	else {
55 		if(tsym[0] == '#')
56 			*val = strtoul(tsym+1, 0, 16);
57 		else
58 			*val = strtoul(tsym, 0, 0);
59 	}
60 	return addr;
61 }
62 
63 ulong
expr(char * addr)64 expr(char *addr)
65 {
66 	ulong t, t2;
67 	char op;
68 
69 	if(*addr == '\0')
70 		return dot;
71 
72 	addr = numsym(addr, &t);
73 
74 	if(*addr == '\0')
75 		return t;
76 
77 	addr = nextc(addr);
78 	op = *addr++;
79 	numsym(addr, &t2);
80 	switch(op) {
81 	default:
82 		Bprint(bioout, "expr syntax\n");
83 		return 0;
84 	case '+':
85 		t += t2;
86 		break;
87 	case '-':
88 		t -= t2;
89 		break;
90 	case '%':
91 		t /= t2;
92 		break;
93 	case '&':
94 		t &= t2;
95 		break;
96 	case '|':
97 		t |= t2;
98 		break;
99 	}
100 
101 	return t;
102 }
103 
104 int
buildargv(char * str,char ** args,int max)105 buildargv(char *str, char **args, int max)
106 {
107 	int na = 0;
108 
109 	while (na < max) {
110 		while((*str == ' ' || *str == '\t' || *str == '\n') && *str != '\0')
111 			str++;
112 
113 		if(*str == '\0')
114 			return na;
115 
116 		args[na++] = str;
117 		while(!(*str == ' ' || *str == '\t'|| *str == '\n') && *str != '\0')
118 			str++;
119 
120 		if(*str == '\n')
121 			*str = '\0';
122 
123 		if(*str == '\0')
124 			break;
125 
126 		*str++ = '\0';
127 	}
128 	return na;
129 }
130 
131 void
colon(char * addr,char * cp)132 colon(char *addr, char *cp)
133 {
134 	int argc;
135 	char *argv[100];
136 	char tbuf[512];
137 
138 	cp = nextc(cp);
139 	switch(*cp) {
140 	default:
141 		Bprint(bioout, "?\n");
142 		return;
143 	case 'b':
144 		breakpoint(addr, cp+1);
145 		return;
146 
147 	case 'd':
148 		delbpt(addr);
149 		return;
150 
151 	/* These fall through to print the stopped address */
152 	case 'r':
153 		reset();
154 		argc = buildargv(cp+1, argv, 100);
155 		initstk(argc, argv);
156 		count = 0;
157 		atbpt = 0;
158 		run();
159 		break;
160 	case 'c':
161 		count = 0;
162 		atbpt = 0;
163 		run();
164 		break;
165 	case 's':
166 		cp = nextc(cp+1);
167 		count = 0;
168 		if(*cp)
169 			count = strtoul(cp, 0, 0);
170 		if(count == 0)
171 			count = 1;
172 		atbpt = 0;
173 		run();
174 		break;
175 	}
176 
177 	dot = reg.pc;
178 	Bprint(bioout, "%s at #%lux ", atbpt ? "breakpoint" : "stopped", dot);
179 	symoff(tbuf, sizeof(tbuf), dot, CTEXT);
180 	Bprint(bioout, tbuf);
181 	if(fmt == 'z')
182 		printsource(dot);
183 
184 	Bprint(bioout, "\n");
185 }
186 
187 
188 void
dollar(char * cp)189 dollar(char *cp)
190 {
191 	int nr;
192 
193 	cp = nextc(cp);
194 	switch(*cp) {
195 	default:
196 		Bprint(bioout, "?\n");
197 		break;
198 
199 	case 'c':
200 		stktrace(*cp);
201 		break;
202 
203 	case 'C':
204 		stktrace(*cp);
205 		break;
206 
207 	case 'b':
208 		dobplist();
209 		break;
210 
211 	case 'r':
212 		dumpreg();
213 		break;
214 
215 	case 'R':
216 		dumpreg();
217 
218 	case 'f':
219 		dumpfreg();
220 		break;
221 
222 	case 'F':
223 		dumpdreg();
224 		break;
225 
226 	case 'q':
227 		exits(0);
228 		break;
229 
230 	case 'Q':
231 		isum();
232 		tlbsum();
233 		segsum();
234 		break;
235 
236 	case 't':
237 		cp++;
238 		switch(*cp) {
239 		default:
240 			Bprint(bioout, "$t[0sicr#]\n");
241 			break;
242 		case '\0':
243 			trace = 1;
244 			break;
245 		case '0':
246 			trace = 0;
247 			sysdbg = 0;
248 			calltree = 0;
249 			break;
250 		case 's':
251 			sysdbg = 1;
252 			break;
253 		case 'i':
254 			trace = 1;
255 			break;
256 		case 'c':
257 			calltree = 1;
258 			break;
259 		case 'r':
260 			nr = atoi(cp+1);
261 			if(nr < 0 || nr > 31) {
262 				print("bad register\n");
263 				break;
264 			}
265 			rtrace ^= (1<<nr);
266 			print("%.8ux\n", rtrace);
267 			break;
268 		}
269 		break;
270 
271 	case 'i':
272 		cp++;
273 		switch(*cp) {
274 		default:
275 			Bprint(bioout, "$i[itsa]\n");
276 			break;
277 		case 'i':
278 			isum();
279 			break;
280 		case 't':
281 			tlbsum();
282 			break;
283 		case 's':
284 			segsum();
285 			break;
286 		case 'a':
287 			isum();
288 			tlbsum();
289 			segsum();
290 			iprofile();
291 			break;
292 		case 'p':
293 			iprofile();
294 			break;
295 		}
296 	}
297 }
298 
299 int
pfmt(char fmt,int mem,ulong val)300 pfmt(char fmt, int mem, ulong val)
301 {
302 	int c, i;
303 	Symbol s;
304 	char *p, ch, str[1024];
305 
306 	c = 0;
307 	switch(fmt) {
308 	default:
309 		Bprint(bioout, "bad modifier\n");
310 		return 0;
311 	case 'o':
312 		c = Bprint(bioout, "%-4lo ", mem ? (ushort)getmem_2(dot) : val);
313 		inc = 2;
314 		break;
315 
316 	case 'O':
317 		c = Bprint(bioout, "%-8lo ", mem ? getmem_4(dot) : val);
318 		inc = 4;
319 		break;
320 
321 	case 'q':
322 		c = Bprint(bioout, "%-4lo ", mem ? (short)getmem_2(dot) : val);
323 		inc = 2;
324 		break;
325 
326 	case 'Q':
327 		c = Bprint(bioout, "%-8lo ", mem ? (long)getmem_4(dot) : val);
328 		inc = 4;
329 		break;
330 
331 	case 'd':
332 		c = Bprint(bioout, "%-5ld ", mem ? (short)getmem_2(dot) : val);
333 		inc = 2;
334 		break;
335 
336 
337 	case 'D':
338 		c = Bprint(bioout, "%-8ld ", mem ? (long)getmem_4(dot) : val);
339 		inc = 4;
340 		break;
341 
342 	case 'x':
343 		c = Bprint(bioout, "#%-4lux ", mem ? (long)getmem_2(dot) : val);
344 		inc = 2;
345 		break;
346 
347 	case 'X':
348 		c = Bprint(bioout, "#%-8lux ", mem ? (long)getmem_4(dot) : val);
349 		inc = 4;
350 		break;
351 
352 	case 'u':
353 		c = Bprint(bioout, "%-5ld ", mem ? (ushort)getmem_2(dot) : val);
354 		inc = 2;
355 		break;
356 
357 	case 'U':
358 		c = Bprint(bioout, "%-8ld ", mem ? (ulong)getmem_4(dot) : val);
359 		inc = 4;
360 		break;
361 
362 	case 'b':
363 		c = Bprint(bioout, "%-3ld ", mem ? getmem_b(dot) : val);
364 		inc = 1;
365 		break;
366 
367 	case 'c':
368 		c = Bprint(bioout, "%c ", (int)(mem ? getmem_b(dot) : val));
369 		inc = 1;
370 		break;
371 
372 	case 'C':
373 		ch = mem ? getmem_b(dot) : val;
374 		if(isprint(ch))
375 			c = Bprint(bioout, "%c ", ch);
376 		else
377 			c = Bprint(bioout, "\\x%.2x ", ch);
378 		inc = 1;
379 		break;
380 
381 	case 's':
382 		i = 0;
383 		while(ch = getmem_b(dot+i))
384 			str[i++] = ch;
385 		str[i] = '\0';
386 		dot += i;
387 		c = Bprint(bioout, "%s", str);
388 		inc = 0;
389 		break;
390 
391 	case 'S':
392 		i = 0;
393 		while(ch = getmem_b(dot+i))
394 			str[i++] = ch;
395 		str[i] = '\0';
396 		dot += i;
397 		for(p = str; *p; p++)
398 			if(isprint(*p))
399 				c += Bprint(bioout, "%c", *p);
400 			else
401 				c += Bprint(bioout, "\\x%.2ux", *p);
402 		inc = 0;
403 		break;
404 
405 	case 'Y':
406 		p = ctime(mem ? getmem_b(dot) : val);
407 		p[30] = '\0';
408 		c = Bprint(bioout, "%s", p);
409 		inc = 4;
410 		break;
411 
412 	case 'a':
413 		symoff(str, sizeof(str), dot, CTEXT);
414 		c = Bprint(bioout, str);
415 		inc = 0;
416 		break;
417 
418 	case 'e':
419 		for (i = 0; globalsym(&s, i); i++)
420 			Bprint(bioout, "%-15s #%lux\n", s.name,	getmem_4(s.value));
421 		inc = 0;
422 		break;
423 
424 	case 'i':
425 		inc = _mipscoinst(symmap, dot, str, sizeof(str));
426 		if (inc < 0) {
427 			Bprint(bioout, "vi: %r\n");
428 			return 0;
429 		}
430 		c = Bprint(bioout, str);
431 		break;
432 
433 	case 'n':
434 		c = width+1;
435 		inc = 0;
436 		break;
437 
438 	case '-':
439 		c = 0;
440 		inc = -1;
441 		break;
442 
443 	case '+':
444 		c = 0;
445 		inc = 1;
446 		break;
447 
448 	case '^':
449 		c = 0;
450 		if(inc > 0)
451 			inc = -inc;
452 		break;
453 
454 	case 'z':
455 		if (findsym(dot, CTEXT, &s))
456 			Bprint(bioout, "  %s() ", s.name);
457 		printsource(dot);
458 		inc = 0;
459 		break;
460 	}
461 	return c;
462 }
463 
464 void
eval(char * addr,char * p)465 eval(char *addr, char *p)
466 {
467 	ulong val;
468 
469 	val = expr(addr);
470 	p = nextc(p);
471 	if(*p == '\0') {
472 		p[0] = fmt;
473 		p[1] = '\0';
474 	}
475 	pfmt(*p, 0, val);
476 	Bprint(bioout, "\n");
477 }
478 
479 void
quesie(char * p)480 quesie(char *p)
481 {
482 	int c, count, i;
483 	char tbuf[512];
484 
485 	c = 0;
486 	symoff(tbuf, sizeof(tbuf), dot, CTEXT);
487 	Bprint(bioout, "%s?\t", tbuf);
488 
489 	while(*p) {
490 		p = nextc(p);
491 		if(*p == '"') {
492 			for(p++; *p && *p != '"'; p++) {
493 				Bputc(bioout, *p);
494 				c++;
495 			}
496 			if(*p)
497 				p++;
498 			continue;
499 		}
500 		count = 0;
501 		while(*p >= '0' && *p <= '9')
502 			count = count*10 + (*p++ - '0');
503 		if(count == 0)
504 			count = 1;
505 		p = nextc(p);
506 		if(*p == '\0') {
507 			p[0] = fmt;
508 			p[1] = '\0';
509 		}
510 		for(i = 0; i < count; i++) {
511 			c += pfmt(*p, 1, 0);
512 			dot += inc;
513 			if(c > width) {
514 				Bprint(bioout, "\n");
515 				symoff(tbuf, sizeof(tbuf), dot, CTEXT);
516 				Bprint(bioout, "%s?\t", tbuf);
517 				c = 0;
518 			}
519 		}
520 		fmt = *p++;
521 		p = nextc(p);
522 	}
523 	Bprint(bioout, "\n");
524 }
525 
526 void
catcher(void * a,char * msg)527 catcher(void *a, char *msg)
528 {
529 	USED(a);
530 	if(strcmp(msg, "interrupt") != 0)
531 		noted(NDFLT);
532 
533 	count = 1;
534 	print("vi\n");
535 	noted(NCONT);
536 }
537 
538 void
setreg(char * addr,char * cp)539 setreg(char *addr, char *cp)
540 {
541 	int rn;
542 
543 	dot = expr(addr);
544 	cp = nextc(cp);
545 	if(strcmp(cp, "pc") == 0) {
546 		reg.pc = dot;
547 		return;
548 	}
549 	if(strcmp(cp, "sp") == 0) {
550 		reg.r[29] = dot;
551 		return;
552 	}
553 	if(strcmp(cp, "mh") == 0) {
554 		reg.mhi = dot;
555 		return;
556 	}
557 	if(strcmp(cp, "ml") == 0) {
558 		reg.mlo = dot;
559 		return;
560 	}
561 	if(*cp++ == 'r') {
562 		rn = strtoul(cp, 0, 10);
563 		if(rn > 0 && rn < 32) {
564 			reg.r[rn] = dot;
565 			return;
566 		}
567 	}
568 	Bprint(bioout, "bad register\n");
569 }
570 
571 void
cmd(void)572 cmd(void)
573 {
574 	char *p, *a, *cp, *gotint;
575 	char addr[128];
576 	static char *cmdlet = ":$?/=>";
577 	int n, i;
578 
579 	notify(catcher);
580 
581 	dot = reg.pc;
582 	setjmp(errjmp);
583 
584 	for(;;) {
585 		Bflush(bioout);
586 		p = buf;
587 		n = 0;
588 		for(;;) {
589 			i = Bgetc(bin);
590 			if(i < 0)
591 				exits(0);
592 			*p++ = i;
593 			n++;
594 			if(i == '\n')
595 				break;
596 		}
597 
598 		if(buf[0] == '\n')
599 			strcpy(buf, lastcmd);
600 		else {
601 			buf[n-1] = '\0';
602 			strcpy(lastcmd, buf);
603 		}
604 		p = buf;
605 		a = addr;
606 
607 		for(;;) {
608 			p = nextc(p);
609 			if(*p == 0 || strchr(cmdlet, *p))
610 				break;
611 			*a++ = *p++;
612 		}
613 
614 		*a = '\0';
615 		cmdcount = 1;
616 		cp = strchr(addr, ',');
617 		if(cp != 0) {
618 			if(cp[1] == '#')
619 				cmdcount = strtoul(cp+2, &gotint, 16);
620 			else
621 				cmdcount = strtoul(cp+1, &gotint, 0);
622 			*cp = '\0';
623 		}
624 
625 		switch(*p) {
626 		case '$':
627 			dollar(p+1);
628 			break;
629 		case ':':
630 			colon(addr, p+1);
631 			break;
632 		case '/':
633 		case '?':
634 			dot = expr(addr);
635 			for(i = 0; i < cmdcount; i++)
636 				quesie(p+1);
637 			break;
638 		case '=':
639 			eval(addr, p+1);
640 			break;
641 		case '>':
642 			setreg(addr, p+1);
643 			break;
644 		default:
645 			Bprint(bioout, "?\n");
646 			break;
647 		}
648 	}
649 }
650