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