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