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