xref: /inferno-os/utils/libmach/5db.c (revision 50b0dbb170df61467e42c7ea4deb0b5692d15f4c)
1 #include <lib9.h>
2 #include <bio.h>
3 #include "mach.h"
4 
5 static int debug = 0;
6 
7 #define	BITS(a, b)	((1<<(b+1))-(1<<a))
8 
9 #define LSR(v, s)	((ulong)(v) >> (s))
10 #define ASR(v, s)	((long)(v) >> (s))
11 #define ROR(v, s)	(LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
12 
13 
14 
15 typedef struct	Instr	Instr;
16 struct	Instr
17 {
18 	Map	*map;
19 	ulong	w;
20 	uvlong	addr;
21 	uchar	op;			/* super opcode */
22 
23 	uchar	cond;			/* bits 28-31 */
24 	uchar	store;			/* bit 20 */
25 
26 	uchar	rd;			/* bits 12-15 */
27 	uchar	rn;			/* bits 16-19 */
28 	uchar	rs;			/* bits 0-11 (shifter operand) */
29 
30 	long	imm;			/* rotated imm */
31 	char*	curr;			/* fill point in buffer */
32 	char*	end;			/* end of buffer */
33 	char*	err;			/* error message */
34 };
35 
36 typedef struct Opcode Opcode;
37 struct Opcode
38 {
39 	char*	o;
40 	void	(*fmt)(Opcode*, Instr*);
41 	uvlong	(*foll)(Map*, Rgetter, Instr*, uvlong);
42 	char*	a;
43 };
44 
45 static	void	format(char*, Instr*, char*);
46 static	char	FRAMENAME[] = ".frame";
47 
48 /*
49  * Arm-specific debugger interface
50  */
51 
52 static	char	*armexcep(Map*, Rgetter);
53 static	int	armfoll(Map*, uvlong, Rgetter, uvlong*);
54 static	int	arminst(Map*, uvlong, char, char*, int);
55 static	int	armdas(Map*, uvlong, char*, int);
56 static	int	arminstlen(Map*, uvlong);
57 
58 /*
59  *	Debugger interface
60  */
61 Machdata armmach =
62 {
63 	{0x70, 0x00, 0x20, 0xD1},		/* break point */	/* D1200070 */
64 	4,			/* break point size */
65 
66 	leswab,			/* short to local byte order */
67 	leswal,			/* long to local byte order */
68 	leswav,			/* long to local byte order */
69 	risctrace,		/* C traceback */
70 	riscframe,		/* Frame finder */
71 	armexcep,			/* print exception */
72 	0,			/* breakpoint fixup */
73 	0,			/* single precision float printer */
74 	0,			/* double precision float printer */
75 	armfoll,		/* following addresses */
76 	arminst,		/* print instruction */
77 	armdas,			/* dissembler */
78 	arminstlen,		/* instruction size */
79 };
80 
81 static char*
82 armexcep(Map *map, Rgetter rget)
83 {
84 	uvlong c;
85 
86 	c = (*rget)(map, "TYPE");
87 	switch ((int)c&0x1f) {
88 	case 0x11:
89 		return "Fiq interrupt";
90 	case 0x12:
91 		return "Mirq interrupt";
92 	case 0x13:
93 		return "SVC/SWI Exception";
94 	case 0x17:
95 		return "Prefetch Abort/Data Abort";
96 	case 0x18:
97 		return "Data Abort";
98 	case 0x1b:
99 		return "Undefined instruction/Breakpoint";
100 	case 0x1f:
101 		return "Sys trap";
102 	default:
103 		return "Undefined trap";
104 	}
105 }
106 
107 static
108 char*	cond[16] =
109 {
110 	"EQ",	"NE",	"CS",	"CC",
111 	"MI",	"PL",	"VS",	"VC",
112 	"HI",	"LS",	"GE",	"LT",
113 	"GT",	"LE",	0,	"NV"
114 };
115 
116 static
117 char*	shtype[4] =
118 {
119 	"<<",	">>",	"->",	"@>"
120 };
121 
122 static
123 char *hb[4] =
124 {
125 	"?",	"HU", "B", "H"
126 };
127 
128 static
129 char*	addsub[2] =
130 {
131 	"-",	"+",
132 };
133 
134 int
135 armclass(long w)
136 {
137 	int op, done;
138 
139 	op = (w >> 25) & 0x7;
140 	switch(op) {
141 	case 0:	/* data processing r,r,r */
142 		op = ((w >> 4) & 0xf);
143 		if(op == 0x9) {
144 			op = 48+16;		/* mul, swp or *rex */
145 			if((w & 0x0ff00fff) == 0x01900f9f) {
146 				op = 93;	/* ldrex */
147 				break;
148 			}
149 			if((w & 0x0ff00ff0) == 0x01800f90) {
150 				op = 94;	/* strex */
151 				break;
152 			}
153 			if(w & (1<<24)) {
154 				op += 2;
155 				if(w & (1<<22))
156 					op++;	/* swpb */
157 				break;
158 			}
159 			if(w & (1<<23)) {	/* mullu */
160 				op = (48+24+4+4+2+2+4);
161 				if(w & (1<<22))	/* mull */
162 					op += 2;
163 			}
164 			if(w & (1<<21))
165 				op++;		/* mla */
166 			break;
167 		}
168 		if((op & 0x9) == 0x9)		/* ld/st byte/half s/u */
169 		{
170 			op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
171 			break;
172 		}
173 		op = (w >> 21) & 0xf;
174 		if(w & (1<<4))
175 			op += 32;
176 		else
177 		if((w & (31<<7)) || (w & (1<<5)))
178 			op += 16;
179 		break;
180 	case 1:	/* data processing i,r,r */
181 		op = (48) + ((w >> 21) & 0xf);
182 		break;
183 	case 2:	/* load/store byte/word i(r) */
184 		if ((w & 0xffffff8f) == 0xf57ff00f) {	/* barriers, clrex */
185 			done = 1;
186 			switch ((w >> 4) & 7) {
187 			case 1:
188 				op = 95;	/* clrex */
189 				break;
190 			case 4:
191 				op = 96;	/* dsb */
192 				break;
193 			case 5:
194 				op = 97;	/* dmb */
195 				break;
196 			case 6:
197 				op = 98;	/* isb */
198 				break;
199 			default:
200 				done = 0;
201 				break;
202 			}
203 			if (done)
204 				break;
205 		}
206 		op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
207 		break;
208 	case 3:	/* load/store byte/word (r)(r) */
209 		op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
210 		break;
211 	case 4:	/* block data transfer (r)(r) */
212 		if ((w & 0xfe50ffff) == 0xf8100a00) {	/* v7 RFE */
213 			op = 99;
214 			break;
215 		}
216 		op = (48+24+4+4) + ((w >> 20) & 0x1);
217 		break;
218 	case 5:	/* branch / branch link */
219 		op = (48+24+4+4+2) + ((w >> 24) & 0x1);
220 		break;
221 	case 7:	/* coprocessor crap */
222 		op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
223 		break;
224 	default:
225 		op = (48+24+4+4+2+2+4+4);
226 		break;
227 	}
228 	return op;
229 }
230 
231 static int
232 decode(Map *map, uvlong pc, Instr *i)
233 {
234 	ulong w;
235 
236 	if(get4(map, pc, &w) < 0) {
237 		werrstr("can't read instruction: %r");
238 		return -1;
239 	}
240 	i->w = w;
241 	i->addr = pc;
242 	i->cond = (w >> 28) & 0xF;
243 	i->op = armclass(w);
244 	i->map = map;
245 	return 1;
246 }
247 
248 #pragma	varargck	argpos	bprint		2
249 
250 static void
251 bprint(Instr *i, char *fmt, ...)
252 {
253 	va_list arg;
254 
255 	va_start(arg, fmt);
256 	i->curr = vseprint(i->curr, i->end, fmt, arg);
257 	va_end(arg);
258 }
259 
260 static int
261 plocal(Instr *i)
262 {
263 	char *reg;
264 	Symbol s;
265 	char *fn;
266 	int class;
267 	int offset;
268 
269 	if(!findsym(i->addr, CTEXT, &s)) {
270 		if(debug)fprint(2,"fn not found @%llux: %r\n", i->addr);
271 		return 0;
272 	}
273 	fn = s.name;
274 	if (!findlocal(&s, FRAMENAME, &s)) {
275 		if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
276 			return 0;
277 	}
278 	if(s.value > i->imm) {
279 		class = CAUTO;
280 		offset = s.value-i->imm;
281 		reg = "(SP)";
282 	} else {
283 		class = CPARAM;
284 		offset = i->imm-s.value-4;
285 		reg = "(FP)";
286 	}
287 	if(!getauto(&s, offset, class, &s)) {
288 		if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
289 			class == CAUTO ? " auto" : "param", offset);
290 		return 0;
291 	}
292 	bprint(i, "%s%c%lld%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
293 	return 1;
294 }
295 
296 /*
297  * Print value v as name[+offset]
298  */
299 static int
300 gsymoff(char *buf, int n, long v, int space)
301 {
302 	Symbol s;
303 	int r;
304 	long delta;
305 
306 	r = delta = 0;		/* to shut compiler up */
307 	if (v) {
308 		r = findsym(v, space, &s);
309 		if (r)
310 			delta = v-s.value;
311 		if (delta < 0)
312 			delta = -delta;
313 	}
314 	if (v == 0 || r == 0 || delta >= 4096)
315 		return snprint(buf, n, "#%lux", v);
316 	if (strcmp(s.name, ".string") == 0)
317 		return snprint(buf, n, "#%lux", v);
318 	if (!delta)
319 		return snprint(buf, n, "%s", s.name);
320 	if (s.type != 't' && s.type != 'T')
321 		return snprint(buf, n, "%s+%llux", s.name, v-s.value);
322 	else
323 		return snprint(buf, n, "#%lux", v);
324 }
325 
326 static void
327 armdps(Opcode *o, Instr *i)
328 {
329 	i->store = (i->w >> 20) & 1;
330 	i->rn = (i->w >> 16) & 0xf;
331 	i->rd = (i->w >> 12) & 0xf;
332 	i->rs = (i->w >> 0) & 0xf;
333 	if(i->rn == 15 && i->rs == 0) {
334 		if(i->op == 8) {
335 			format("MOVW", i,"CPSR, R%d");
336 			return;
337 		} else
338 		if(i->op == 10) {
339 			format("MOVW", i,"SPSR, R%d");
340 			return;
341 		}
342 	} else
343 	if(i->rn == 9 && i->rd == 15) {
344 		if(i->op == 9) {
345 			format("MOVW", i, "R%s, CPSR");
346 			return;
347 		} else
348 		if(i->op == 11) {
349 			format("MOVW", i, "R%s, SPSR");
350 			return;
351 		}
352 	}
353 	format(o->o, i, o->a);
354 }
355 
356 static void
357 armdpi(Opcode *o, Instr *i)
358 {
359 	ulong v;
360 	int c;
361 
362 	v = (i->w >> 0) & 0xff;
363 	c = (i->w >> 8) & 0xf;
364 	while(c) {
365 		v = (v<<30) | (v>>2);
366 		c--;
367 	}
368 	i->imm = v;
369 	i->store = (i->w >> 20) & 1;
370 	i->rn = (i->w >> 16) & 0xf;
371 	i->rd = (i->w >> 12) & 0xf;
372 	i->rs = i->w&0x0f;
373 
374 		/* RET is encoded as ADD #0,R14,R15 */
375 	if((i->w & 0x0fffffff) == 0x028ef000){
376 		format("RET%C", i, "");
377 		return;
378 	}
379 	if((i->w & 0x0ff0ffff) == 0x0280f000){
380 		format("B%C", i, "0(R%n)");
381 		return;
382 	}
383 	format(o->o, i, o->a);
384 }
385 
386 static void
387 armsdti(Opcode *o, Instr *i)
388 {
389 	ulong v;
390 
391 	v = i->w & 0xfff;
392 	if(!(i->w & (1<<23)))
393 		v = -v;
394 	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
395 	i->imm = v;
396 	i->rn = (i->w >> 16) & 0xf;
397 	i->rd = (i->w >> 12) & 0xf;
398 		/* RET is encoded as LW.P x,R13,R15 */
399 	if ((i->w & 0x0ffff000) == 0x049df000)
400 	{
401 		format("RET%C%p", i, "%I");
402 		return;
403 	}
404 	format(o->o, i, o->a);
405 }
406 
407 /* arm V4 ld/st halfword, signed byte */
408 static void
409 armhwby(Opcode *o, Instr *i)
410 {
411 	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
412 	i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf);
413 	if (!(i->w & (1 << 23)))
414 		i->imm = - i->imm;
415 	i->rn = (i->w >> 16) & 0xf;
416 	i->rd = (i->w >> 12) & 0xf;
417 	i->rs = (i->w >> 0) & 0xf;
418 	format(o->o, i, o->a);
419 }
420 
421 static void
422 armsdts(Opcode *o, Instr *i)
423 {
424 	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
425 	i->rs = (i->w >> 0) & 0xf;
426 	i->rn = (i->w >> 16) & 0xf;
427 	i->rd = (i->w >> 12) & 0xf;
428 	format(o->o, i, o->a);
429 }
430 
431 static void
432 armbdt(Opcode *o, Instr *i)
433 {
434 	i->store = (i->w >> 21) & 0x3;		/* S & W bits */
435 	i->rn = (i->w >> 16) & 0xf;
436 	i->imm = i->w & 0xffff;
437 	if(i->w == 0xe8fd8000)
438 		format("RFE", i, "");
439 	else
440 		format(o->o, i, o->a);
441 }
442 
443 static void
444 armund(Opcode *o, Instr *i)
445 {
446 	format(o->o, i, o->a);
447 }
448 
449 static void
450 armcdt(Opcode *o, Instr *i)
451 {
452 	format(o->o, i, o->a);
453 }
454 
455 static void
456 armunk(Opcode *o, Instr *i)
457 {
458 	format(o->o, i, o->a);
459 }
460 
461 static void
462 armb(Opcode *o, Instr *i)
463 {
464 	ulong v;
465 
466 	v = i->w & 0xffffff;
467 	if(v & 0x800000)
468 		v |= ~0xffffff;
469 	i->imm = (v<<2) + i->addr + 8;
470 	format(o->o, i, o->a);
471 }
472 
473 static void
474 armco(Opcode *o, Instr *i)		/* coprocessor instructions */
475 {
476 	int op, p, cp;
477 
478 	char buf[1024];
479 
480 	i->rn = (i->w >> 16) & 0xf;
481 	i->rd = (i->w >> 12) & 0xf;
482 	i->rs = i->w&0xf;
483 	cp = (i->w >> 8) & 0xf;
484 	p = (i->w >> 5) & 0x7;
485 	if(i->w&(1<<4)) {
486 		op = (i->w >> 21) & 0x07;
487 		snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p);
488 	} else {
489 		op = (i->w >> 20) & 0x0f;
490 		snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p);
491 	}
492 	format(o->o, i, buf);
493 }
494 
495 static int
496 armcondpass(Map *map, Rgetter rget, uchar cond)
497 {
498 	uvlong psr;
499 	uchar n;
500 	uchar z;
501 	uchar c;
502 	uchar v;
503 
504 	psr = rget(map, "PSR");
505 	n = (psr >> 31) & 1;
506 	z = (psr >> 30) & 1;
507 	c = (psr >> 29) & 1;
508 	v = (psr >> 28) & 1;
509 
510 	switch(cond) {
511 	default:
512 	case 0:		return z;
513 	case 1:		return !z;
514 	case 2:		return c;
515 	case 3:		return !c;
516 	case 4:		return n;
517 	case 5:		return !n;
518 	case 6:		return v;
519 	case 7:		return !v;
520 	case 8:		return c && !z;
521 	case 9:		return !c || z;
522 	case 10:	return n == v;
523 	case 11:	return n != v;
524 	case 12:	return !z && (n == v);
525 	case 13:	return z && (n != v);
526 	case 14:	return 1;
527 	case 15:	return 0;
528 	}
529 }
530 
531 static ulong
532 armshiftval(Map *map, Rgetter rget, Instr *i)
533 {
534 	if(i->w & (1 << 25)) {				/* immediate */
535 		ulong imm = i->w & BITS(0, 7);
536 		ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */
537 		return ROR(imm, s);
538 	} else {
539 		char buf[8];
540 		ulong v;
541 		ulong s = (i->w & BITS(7,11)) >> 7;
542 
543 		sprint(buf, "R%ld", i->w & 0xf);
544 		v = rget(map, buf);
545 
546 		switch((i->w & BITS(4, 6)) >> 4) {
547 		default:
548 		case 0:					/* LSLIMM */
549 			return v << s;
550 		case 1:					/* LSLREG */
551 			sprint(buf, "R%lud", s >> 1);
552 			s = rget(map, buf) & 0xFF;
553 			if(s >= 32) return 0;
554 			return v << s;
555 		case 2:					/* LSRIMM */
556 			return LSR(v, s);
557 		case 3:					/* LSRREG */
558 			sprint(buf, "R%ld", s >> 1);
559 			s = rget(map, buf) & 0xFF;
560 			if(s >= 32) return 0;
561 			return LSR(v, s);
562 		case 4:					/* ASRIMM */
563 			if(s == 0) {
564 				if((v & (1U<<31)) == 0)
565 					return 0;
566 				return 0xFFFFFFFF;
567 			}
568 			return ASR(v, s);
569 		case 5:					/* ASRREG */
570 			sprint(buf, "R%ld", s >> 1);
571 			s = rget(map, buf) & 0xFF;
572 			if(s >= 32) {
573 				if((v & (1U<<31)) == 0)
574 					return 0;
575 				return 0xFFFFFFFF;
576 			}
577 			return ASR(v, s);
578 		case 6:					/* RORIMM */
579 			if(s == 0) {
580 				ulong c = (rget(map, "PSR") >> 29) & 1;
581 
582 				return (c << 31) | LSR(v, 1);
583 			}
584 			return ROR(v, s);
585 		case 7:					/* RORREG */
586 			sprint(buf, "R%ld", (s>>1)&0xF);
587 			s = rget(map, buf);
588 			if(s == 0 || (s & 0xF) == 0)
589 				return v;
590 			return ROR(v, s & 0xF);
591 		}
592 	}
593 }
594 
595 static int
596 nbits(ulong v)
597 {
598 	int n = 0;
599 	int i;
600 
601 	for(i=0; i < 32 ; i++) {
602 		if(v & 1) ++n;
603 		v >>= 1;
604 	}
605 
606 	return n;
607 }
608 
609 static ulong
610 armmaddr(Map *map, Rgetter rget, Instr *i)
611 {
612 	ulong v;
613 	ulong nb;
614 	char buf[8];
615 	ulong rn;
616 
617 	rn = (i->w >> 16) & 0xf;
618 	sprint(buf,"R%ld", rn);
619 
620 	v = rget(map, buf);
621 	nb = nbits(i->w & ((1 << 15) - 1));
622 
623 	switch((i->w >> 23) & 3) {
624 	default:
625 	case 0: return (v - (nb*4)) + 4;
626 	case 1: return v;
627 	case 2: return v - (nb*4);
628 	case 3: return v + 4;
629 	}
630 }
631 
632 static uvlong
633 armaddr(Map *map, Rgetter rget, Instr *i)
634 {
635 	char buf[8];
636 	ulong rn;
637 
638 	snprint(buf, sizeof(buf), "R%ld", (i->w >> 16) & 0xf);
639 	rn = rget(map, buf);
640 
641 	if((i->w & (1<<24)) == 0)			/* POSTIDX */
642 		return rn;
643 
644 	if((i->w & (1<<25)) == 0) {			/* OFFSET */
645 		if(i->w & (1U<<23))
646 			return rn + (i->w & BITS(0,11));
647 		return rn - (i->w & BITS(0,11));
648 	} else {					/* REGOFF */
649 		ulong index = 0;
650 		uchar c;
651 		uchar rm;
652 
653 		sprint(buf, "R%ld", i->w & 0xf);
654 		rm = rget(map, buf);
655 
656 		switch((i->w & BITS(5,6)) >> 5) {
657 		case 0: index = rm << ((i->w & BITS(7,11)) >> 7);	break;
658 		case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7));	break;
659 		case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7));	break;
660 		case 3:
661 			if((i->w & BITS(7,11)) == 0) {
662 				c = (rget(map, "PSR") >> 29) & 1;
663 				index = c << 31 | LSR(rm, 1);
664 			} else {
665 				index = ROR(rm, ((i->w & BITS(7,11)) >> 7));
666 			}
667 			break;
668 		}
669 		if(i->w & (1<<23))
670 			return rn + index;
671 		return rn - index;
672 	}
673 }
674 
675 static uvlong
676 armfadd(Map *map, Rgetter rget, Instr *i, uvlong pc)
677 {
678 	char buf[8];
679 	int r;
680 
681 	r = (i->w >> 12) & 0xf;
682 	if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf))
683 		return pc+4;
684 
685 	r = (i->w >> 16) & 0xf;
686 	sprint(buf, "R%d", r);
687 
688 	return rget(map, buf) + armshiftval(map, rget, i);
689 }
690 
691 static uvlong
692 armfmovm(Map *map, Rgetter rget, Instr *i, uvlong pc)
693 {
694 	ulong v;
695 	ulong addr;
696 
697 	v = i->w & 1<<15;
698 	if(!v || !armcondpass(map, rget, (i->w>>28)&0xf))
699 		return pc+4;
700 
701 	addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15));
702 	if(get4(map, addr, &v) < 0) {
703 		werrstr("can't read addr: %r");
704 		return -1;
705 	}
706 	return v;
707 }
708 
709 static uvlong
710 armfbranch(Map *map, Rgetter rget, Instr *i, uvlong pc)
711 {
712 	if(!armcondpass(map, rget, (i->w >> 28) & 0xf))
713 		return pc+4;
714 
715 	return pc + (((signed long)i->w << 8) >> 6) + 8;
716 }
717 
718 static uvlong
719 armfmov(Map *map, Rgetter rget, Instr *i, uvlong pc)
720 {
721 	ulong rd, v;
722 
723 	rd = (i->w >> 12) & 0xf;
724 	if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf))
725 		return pc+4;
726 
727 	 /* LDR */
728 	/* BUG: Needs LDH/B, too */
729 	if(((i->w>>26)&0x3) == 1) {
730 		if(get4(map, armaddr(map, rget, i), &v) < 0) {
731 			werrstr("can't read instruction: %r");
732 			return pc+4;
733 		}
734 		return v;
735 	}
736 
737 	 /* MOV */
738 	v = armshiftval(map, rget, i);
739 
740 	return v;
741 }
742 
743 static Opcode opcodes[] =
744 {
745 	"AND%C%S",	armdps, 0,	"R%s,R%n,R%d",
746 	"EOR%C%S",	armdps, 0,	"R%s,R%n,R%d",
747 	"SUB%C%S",	armdps, 0,	"R%s,R%n,R%d",
748 	"RSB%C%S",	armdps, 0,	"R%s,R%n,R%d",
749 	"ADD%C%S",	armdps, armfadd,	"R%s,R%n,R%d",
750 	"ADC%C%S",	armdps, 0,	"R%s,R%n,R%d",
751 	"SBC%C%S",	armdps, 0,	"R%s,R%n,R%d",
752 	"RSC%C%S",	armdps, 0,	"R%s,R%n,R%d",
753 	"TST%C%S",	armdps, 0,	"R%s,R%n",
754 	"TEQ%C%S",	armdps, 0,	"R%s,R%n",
755 	"CMP%C%S",	armdps, 0,	"R%s,R%n",
756 	"CMN%C%S",	armdps, 0,	"R%s,R%n",
757 	"ORR%C%S",	armdps, 0,	"R%s,R%n,R%d",
758 	"MOVW%C%S",	armdps, armfmov,	"R%s,R%d",
759 	"BIC%C%S",	armdps, 0,	"R%s,R%n,R%d",
760 	"MVN%C%S",	armdps, 0,	"R%s,R%d",
761 
762 /* 16 */
763 	"AND%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
764 	"EOR%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
765 	"SUB%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
766 	"RSB%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
767 	"ADD%C%S",	armdps, armfadd,	"(R%s%h%m),R%n,R%d",
768 	"ADC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
769 	"SBC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
770 	"RSC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
771 	"TST%C%S",	armdps, 0,	"(R%s%h%m),R%n",
772 	"TEQ%C%S",	armdps, 0,	"(R%s%h%m),R%n",
773 	"CMP%C%S",	armdps, 0,	"(R%s%h%m),R%n",
774 	"CMN%C%S",	armdps, 0,	"(R%s%h%m),R%n",
775 	"ORR%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
776 	"MOVW%C%S",	armdps, armfmov,	"(R%s%h%m),R%d",
777 	"BIC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
778 	"MVN%C%S",	armdps, 0,	"(R%s%h%m),R%d",
779 
780 /* 32 */
781 	"AND%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
782 	"EOR%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
783 	"SUB%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
784 	"RSB%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
785 	"ADD%C%S",	armdps, armfadd,	"(R%s%hR%M),R%n,R%d",
786 	"ADC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
787 	"SBC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
788 	"RSC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
789 	"TST%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
790 	"TEQ%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
791 	"CMP%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
792 	"CMN%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
793 	"ORR%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
794 	"MOVW%C%S",	armdps, armfmov,	"(R%s%hR%M),R%d",
795 	"BIC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
796 	"MVN%C%S",	armdps, 0,	"(R%s%hR%M),R%d",
797 
798 /* 48 */
799 	"AND%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
800 	"EOR%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
801 	"SUB%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
802 	"RSB%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
803 	"ADD%C%S",	armdpi, armfadd,	"$#%i,R%n,R%d",
804 	"ADC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
805 	"SBC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
806 	"RSC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
807 	"TST%C%S",	armdpi, 0,	"$#%i,R%n",
808 	"TEQ%C%S",	armdpi, 0,	"$#%i,R%n",
809 	"CMP%C%S",	armdpi, 0,	"$#%i,R%n",
810 	"CMN%C%S",	armdpi, 0,	"$#%i,R%n",
811 	"ORR%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
812 	"MOVW%C%S",	armdpi, armfmov,	"$#%i,R%d",
813 	"BIC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
814 	"MVN%C%S",	armdpi, 0,	"$#%i,R%d",
815 
816 /* 48+16 */
817 	"MUL%C%S",	armdpi, 0,	"R%M,R%s,R%n",
818 	"MULA%C%S",	armdpi, 0,	"R%M,R%s,R%n,R%d",
819 	"SWPW",		armdpi, 0,	"R%s,(R%n),R%d",
820 	"SWPB",		armdpi, 0,	"R%s,(R%n),R%d",
821 
822 /* 48+16+4 */
823 	"MOV%u%C%p",	armhwby, 0,	"R%d,(R%n%UR%M)",
824 	"MOV%u%C%p",	armhwby, 0,	"R%d,%I",
825 	"MOV%u%C%p",	armhwby, armfmov,	"(R%n%UR%M),R%d",
826 	"MOV%u%C%p",	armhwby, armfmov,	"%I,R%d",
827 
828 /* 48+24 */
829 	"MOVW%C%p",	armsdti, 0,	"R%d,%I",
830 	"MOVB%C%p",	armsdti, 0,	"R%d,%I",
831 	"MOVW%C%p",	armsdti, armfmov,	"%I,R%d",
832 	"MOVBU%C%p",	armsdti, armfmov,	"%I,R%d",
833 
834 	"MOVW%C%p",	armsdts, 0,	"R%d,(R%s%h%m)(R%n)",
835 	"MOVB%C%p",	armsdts, 0,	"R%d,(R%s%h%m)(R%n)",
836 	"MOVW%C%p",	armsdts, armfmov,	"(R%s%h%m)(R%n),R%d",
837 	"MOVBU%C%p",	armsdts, armfmov,	"(R%s%h%m)(R%n),R%d",
838 
839 	"MOVM%C%P%a",	armbdt, armfmovm,		"[%r],(R%n)",
840 	"MOVM%C%P%a",	armbdt, armfmovm,		"(R%n),[%r]",
841 
842 	"B%C",		armb, armfbranch,		"%b",
843 	"BL%C",		armb, armfbranch,		"%b",
844 
845 	"CDP%C",	armco, 0,		"",
846 	"CDP%C",	armco, 0,		"",
847 	"MCR%C",	armco, 0,		"",
848 	"MRC%C",	armco, 0,		"",
849 
850 /* 48+24+4+4+2+2+4 */
851 	"MULLU%C%S",	armdpi, 0,	"R%M,R%s,(R%n,R%d)",
852 	"MULALU%C%S",	armdpi, 0,	"R%M,R%s,(R%n,R%d)",
853 	"MULL%C%S",	armdpi, 0,	"R%M,R%s,(R%n,R%d)",
854 	"MULAL%C%S",	armdpi, 0,	"R%M,R%s,(R%n,R%d)",
855 
856 /* 48+24+4+4+2+2+4+4 = 92 */
857 	"UNK",		armunk, 0,	"",
858 
859 	/* new v7 arch instructions */
860 /* 93 */
861 	"LDREX",	armdpi, 0,	"(R%n),R%d",
862 	"STREX",	armdpi, 0,	"R%s,(R%n),R%d",
863 	"CLREX",	armunk, 0,	"",
864 
865 /* 96 */
866 	"DSB",		armunk, 0,	"",
867 	"DMB",		armunk, 0,	"",
868 	"ISB",		armunk, 0,	"",
869 
870 /* 99 */
871 	"RFEV7%P%a",	armbdt, 0,	"(R%n)",
872 };
873 
874 static void
875 gaddr(Instr *i)
876 {
877 	*i->curr++ = '$';
878 	i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
879 }
880 
881 static	char *mode[] = { 0, "IA", "DB", "IB" };
882 static	char *pw[] = { "P", "PW", 0, "W" };
883 static	char *sw[] = { 0, "W", "S", "SW" };
884 
885 static void
886 format(char *mnemonic, Instr *i, char *f)
887 {
888 	int j, k, m, n;
889 	int g;
890 	char *fmt;
891 
892 	if(mnemonic)
893 		format(0, i, mnemonic);
894 	if(f == 0)
895 		return;
896 	if(mnemonic)
897 		if(i->curr < i->end)
898 			*i->curr++ = '\t';
899 	for ( ; *f && i->curr < i->end; f++) {
900 		if(*f != '%') {
901 			*i->curr++ = *f;
902 			continue;
903 		}
904 		switch (*++f) {
905 
906 		case 'C':	/* .CONDITION */
907 			if(cond[i->cond])
908 				bprint(i, ".%s", cond[i->cond]);
909 			break;
910 
911 		case 'S':	/* .STORE */
912 			if(i->store)
913 				bprint(i, ".S");
914 			break;
915 
916 		case 'P':	/* P & U bits for block move */
917 			n = (i->w >>23) & 0x3;
918 			if (mode[n])
919 				bprint(i, ".%s", mode[n]);
920 			break;
921 
922 		case 'p':	/* P & W bits for single data xfer*/
923 			if (pw[i->store])
924 				bprint(i, ".%s", pw[i->store]);
925 			break;
926 
927 		case 'a':	/* S & W bits for single data xfer*/
928 			if (sw[i->store])
929 				bprint(i, ".%s", sw[i->store]);
930 			break;
931 
932 		case 's':
933 			bprint(i, "%d", i->rs & 0xf);
934 			break;
935 
936 		case 'M':
937 			bprint(i, "%lud", (i->w>>8) & 0xf);
938 			break;
939 
940 		case 'm':
941 			bprint(i, "%lud", (i->w>>7) & 0x1f);
942 			break;
943 
944 		case 'h':
945 			bprint(i, shtype[(i->w>>5) & 0x3]);
946 			break;
947 
948 		case 'u':		/* Signed/unsigned Byte/Halfword */
949 			bprint(i, hb[(i->w>>5) & 0x3]);
950 			break;
951 
952 		case 'I':
953 			if (i->rn == 13) {
954 				if (plocal(i))
955 					break;
956 			}
957 			g = 0;
958 			fmt = "#%lx(R%d)";
959 			if (i->rn == 15) {
960 				/* convert load of offset(PC) to a load immediate */
961 				if (get4(i->map, i->addr+i->imm+8, (ulong*)&i->imm) > 0)
962 				{
963 					g = 1;
964 					fmt = "";
965 				}
966 			}
967 			if (mach->sb)
968 			{
969 				if (i->rd == 11) {
970 					ulong nxti;
971 
972 					if (get4(i->map, i->addr+4, &nxti) > 0) {
973 						if ((nxti & 0x0e0f0fff) == 0x060c000b) {
974 							i->imm += mach->sb;
975 							g = 1;
976 							fmt = "-SB";
977 						}
978 					}
979 				}
980 				if (i->rn == 12)
981 				{
982 					i->imm += mach->sb;
983 					g = 1;
984 					fmt = "-SB(SB)";
985 				}
986 			}
987 			if (g)
988 			{
989 				gaddr(i);
990 				bprint(i, fmt, i->rn);
991 			}
992 			else
993 				bprint(i, fmt, i->imm, i->rn);
994 			break;
995 		case 'U':		/* Add/subtract from base */
996 			bprint(i, addsub[(i->w >> 23) & 1]);
997 			break;
998 
999 		case 'n':
1000 			bprint(i, "%d", i->rn);
1001 			break;
1002 
1003 		case 'd':
1004 			bprint(i, "%d", i->rd);
1005 			break;
1006 
1007 		case 'i':
1008 			bprint(i, "%lux", i->imm);
1009 			break;
1010 
1011 		case 'b':
1012 			i->curr += symoff(i->curr, i->end-i->curr,
1013 				i->imm, CTEXT);
1014 			break;
1015 
1016 		case 'g':
1017 			i->curr += gsymoff(i->curr, i->end-i->curr,
1018 				i->imm, CANY);
1019 			break;
1020 
1021 		case 'r':
1022 			n = i->imm&0xffff;
1023 			j = 0;
1024 			k = 0;
1025 			while(n) {
1026 				m = j;
1027 				while(n&0x1) {
1028 					j++;
1029 					n >>= 1;
1030 				}
1031 				if(j != m) {
1032 					if(k)
1033 						bprint(i, ",");
1034 					if(j == m+1)
1035 						bprint(i, "R%d", m);
1036 					else
1037 						bprint(i, "R%d-R%d", m, j-1);
1038 					k = 1;
1039 				}
1040 				j++;
1041 				n >>= 1;
1042 			}
1043 			break;
1044 
1045 		case '\0':
1046 			*i->curr++ = '%';
1047 			return;
1048 
1049 		default:
1050 			bprint(i, "%%%c", *f);
1051 			break;
1052 		}
1053 	}
1054 	*i->curr = 0;
1055 }
1056 
1057 static int
1058 printins(Map *map, uvlong pc, char *buf, int n)
1059 {
1060 	Instr i;
1061 
1062 	i.curr = buf;
1063 	i.end = buf+n-1;
1064 	if(decode(map, pc, &i) < 0)
1065 		return -1;
1066 
1067 	(*opcodes[i.op].fmt)(&opcodes[i.op], &i);
1068 	return 4;
1069 }
1070 
1071 static int
1072 arminst(Map *map, uvlong pc, char modifier, char *buf, int n)
1073 {
1074 	USED(modifier);
1075 	return printins(map, pc, buf, n);
1076 }
1077 
1078 static int
1079 armdas(Map *map, uvlong pc, char *buf, int n)
1080 {
1081 	Instr i;
1082 
1083 	i.curr = buf;
1084 	i.end = buf+n;
1085 	if(decode(map, pc, &i) < 0)
1086 		return -1;
1087 	if(i.end-i.curr > 8)
1088 		i.curr = _hexify(buf, i.w, 7);
1089 	*i.curr = 0;
1090 	return 4;
1091 }
1092 
1093 static int
1094 arminstlen(Map *map, uvlong pc)
1095 {
1096 	Instr i;
1097 
1098 	if(decode(map, pc, &i) < 0)
1099 		return -1;
1100 	return 4;
1101 }
1102 
1103 static int
1104 armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1105 {
1106 	uvlong d;
1107 	Instr i;
1108 
1109 	if(decode(map, pc, &i) < 0)
1110 		return -1;
1111 
1112 	if(opcodes[i.op].foll) {
1113 		d = (*opcodes[i.op].foll)(map, rget, &i, pc);
1114 		if(d == -1)
1115 			return -1;
1116 	} else
1117 		d = pc+4;
1118 
1119 	foll[0] = d;
1120 	return 1;
1121 }
1122