xref: /inferno-os/utils/libmach/tdb.c (revision 1981fff245dfce579ef416fa767eb69d462039e9)
1 #include <lib9.h>
2 #include <bio.h>
3 #include "mach.h"
4 
5 static int debug = 0;
6 
7 typedef struct	Instr	Instr;
8 struct	Instr
9 {
10 	Map	*map;
11 	ulong	w;
12 	ulong	addr;
13 	uchar	op;			/* super opcode */
14 
15 	uchar	rd;
16 	uchar	rn;
17 	uchar	rs;
18 
19 	long	imm;			/* imm */
20 
21 	char*	curr;			/* fill point in buffer */
22 	char*	end;			/* end of buffer */
23 	char*	err;			/* error message */
24 };
25 
26 typedef struct Opcode Opcode;
27 struct Opcode
28 {
29 	char*	o;
30 	void	(*fmt)(Opcode*, Instr*);
31 	uvlong	(*foll)(Map*, Rgetter, Instr*, uvlong);
32 	char*	a;
33 };
34 
35 static	void	format(char*, Instr*, char*);
36 static	char	FRAMENAME[] = ".frame";
37 
38 /*
39  * Thumb-specific debugger interface
40  */
41 
42 static	char	*thumbexcep(Map*, Rgetter);
43 static	int	thumbfoll(Map*, uvlong, Rgetter, uvlong*);
44 static	int	thumbinst(Map*, uvlong, char, char*, int);
45 static	int	thumbdas(Map*, uvlong, char*, int);
46 static	int	thumbinstlen(Map*, uvlong);
47 
48 /*
49  *	Debugger interface
50  */
51 Machdata thumbmach =
52 {
53 	{0x0, 0xE8},		/* break point */
54 	2,				/* break point size */
55 
56 	leswab,			/* short to local byte order */
57 	leswal,			/* long to local byte order */
58 	leswav,			/* long to local byte order */
59 	risctrace,		/* C traceback */
60 	riscframe,		/* Frame finder */
61 	thumbexcep,			/* print exception */
62 	0,			/* breakpoint fixup */
63 	0,			/* single precision float printer */
64 	0,			/* double precision float printer */
65 	thumbfoll,		/* following addresses */
66 	thumbinst,		/* print instruction */
67 	thumbdas,			/* dissembler */
68 	thumbinstlen,		/* instruction size */
69 };
70 
71 static void thumbrrh(Opcode *, Instr *);
72 static void thumbbcc(Opcode *, Instr *);
73 static void thumbb(Opcode *, Instr *);
74 static void thumbbl(Opcode *, Instr *);
75 
76 static char*
77 thumbexcep(Map *map, Rgetter rget)
78 {
79 	long c;
80 
81 	c = (*rget)(map, "TYPE");
82 	switch (c&0x1f) {
83 	case 0x11:
84 		return "Fiq interrupt";
85 	case 0x12:
86 		return "Mirq interrupt";
87 	case 0x13:
88 		return "SVC/SWI Exception";
89 	case 0x17:
90 		return "Prefetch Abort/Data Abort";
91 	case 0x18:
92 		return "Data Abort";
93 	case 0x1b:
94 		return "Undefined instruction/Breakpoint";
95 	case 0x1f:
96 		return "Sys trap";
97 	default:
98 		return "Undefined trap";
99 	}
100 }
101 
102 static
103 char*	cond[16] =
104 {
105 	"EQ",	"NE",	"CS",	"CC",
106 	"MI",	"PL",	"VS",	"VC",
107 	"HI",	"LS",	"GE",	"LT",
108 	"GT",	"LE",	"\0",	"NV"
109 };
110 
111 #define B(h, l)		bits(ins, h, l)
112 
113 static int
114 bits(int i, int h, int l)
115 {
116 	if(h < l)
117 		print("h < l in bits");
118 	return (i&(((1<<(h-l+1))-1)<<l))>>l;
119 }
120 
121 int
122 thumbclass(long w)
123 {
124 	int o;
125 	int ins = w;
126 
127 	if(ins&0xffff0000)
128 		return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2;
129 	o = B(15, 13);
130 	switch(o){
131 	case 0:
132 		o = B(12, 11);
133 		switch(o){
134 			case 0:
135 			case 1:
136 			case 2:
137 				return B(12, 11);
138 			case 3:
139 				if(B(10, 10) == 0)
140 					return 3+B(9, 9);
141 				else
142 					return 3+2+B(9, 9);
143 		}
144 	case 1:
145 		return 3+2+2+B(12, 11);
146 	case 2:
147 		o = B(12, 10);
148 		if(o == 0)
149 			return 3+2+2+4+B(9, 6);
150 		if(o == 1){
151 			o = B(9, 8);
152 			if(o == 3)
153 				return 3+2+2+4+16+B(9, 8);
154 			return 3+2+2+4+16+B(9, 8);
155 		}
156 		if(o == 2 || o == 3)
157 			return 3+2+2+4+16+4;
158 		return 3+2+2+4+16+4+1+B(11, 9);
159 	case 3:
160 		return 3+2+2+4+16+4+1+8+B(12, 11);
161 	case 4:
162 		if(B(12, 12) == 0)
163 			return 3+2+2+4+16+4+1+8+4+B(11, 11);
164 		return 3+2+2+4+16+4+1+8+6+B(11, 11);
165 	case 5:
166 		if(B(12, 12) == 0)
167 			return 3+2+2+4+16+4+1+8+6+2+B(11, 11);
168 		if(B(11, 8) == 0)
169 			return 3+2+2+4+16+4+1+8+6+2+2+B(7, 7);
170 		return 3+2+2+4+16+4+1+8+6+2+2+2+B(11, 11);
171 	case 6:
172 		if(B(12, 12) == 0)
173 			return 3+2+2+4+16+4+1+8+6+2+2+2+2+B(11, 11);
174 		if(B(11, 8) == 0xf)
175 			return 3+2+2+4+16+4+1+8+6+2+2+2+4;
176 		return 3+2+2+4+16+4+1+8+6+2+2+2+4+1;
177 	case 7:
178 		o = B(12, 11);
179 		switch(o){
180 			case 0:
181 				return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1;
182 			case 1:
183 				return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2;
184 			case 2:
185 				return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1;
186 			case 3:
187 				return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+1;
188 		}
189 	}
190 	return 0;
191 }
192 
193 static int
194 decode(Map *map, uvlong pc, Instr *i)
195 {
196 	ushort w;
197 
198 	if(get2(map, pc, &w) < 0) {
199 		werrstr("can't read instruction: %r");
200 		return -1;
201 	}
202 	i->w = w;
203 	i->addr = pc;
204 	i->op = thumbclass(w);
205 	i->map = map;
206 	return 1;
207 }
208 
209 static void
210 bprint(Instr *i, char *fmt, ...)
211 {
212 	va_list arg;
213 
214 	va_start(arg, fmt);
215 	i->curr = vseprint(i->curr, i->end, fmt, arg);
216 	va_end(arg);
217 }
218 
219 static int
220 plocal(Instr *i)
221 {
222 	char *reg;
223 	Symbol s;
224 	char *fn;
225 	int class;
226 	int offset;
227 
228 	if(!findsym(i->addr, CTEXT, &s)) {
229 		if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr);
230 		return 0;
231 	}
232 	fn = s.name;
233 	if (!findlocal(&s, FRAMENAME, &s)) {
234 		if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
235 			return 0;
236 	}
237 	if(s.value > i->imm) {
238 		class = CAUTO;
239 		offset = s.value-i->imm;
240 		reg = "(SP)";
241 	} else {
242 		class = CPARAM;
243 		offset = i->imm-s.value-4;
244 		reg = "(FP)";
245 	}
246 	if(!getauto(&s, offset, class, &s)) {
247 		if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
248 			class == CAUTO ? " auto" : "param", offset);
249 		return 0;
250 	}
251 	bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
252 	return 1;
253 }
254 
255 /*
256  * Print value v as name[+offset]
257  */
258 static int
259 gsymoff(char *buf, int n, long v, int space)
260 {
261 	Symbol s;
262 	int r;
263 	long delta;
264 
265 	r = delta = 0;		/* to shut compiler up */
266 	if (v) {
267 		r = findsym(v, space, &s);
268 		if (r)
269 			delta = v-s.value;
270 		if (delta < 0)
271 			delta = -delta;
272 	}
273 	if (v == 0 || r == 0 || delta >= 4096)
274 		return snprint(buf, n, "#%lux", v);
275 	if (strcmp(s.name, ".string") == 0)
276 		return snprint(buf, n, "#%lux", v);
277 	if (!delta)
278 		return snprint(buf, n, "%s", s.name);
279 	if (s.type != 't' && s.type != 'T')
280 		return snprint(buf, n, "%s+%llux", s.name, v-s.value);
281 	else
282 		return snprint(buf, n, "#%lux", v);
283 }
284 
285 static int
286 thumbcondpass(Map *map, Rgetter rget, uchar cond)
287 {
288 	ulong psr;
289 	uchar n;
290 	uchar z;
291 	uchar c;
292 	uchar v;
293 
294 	psr = rget(map, "PSR");
295 	n = (psr >> 31) & 1;
296 	z = (psr >> 30) & 1;
297 	c = (psr >> 29) & 1;
298 	v = (psr >> 28) & 1;
299 
300 	switch(cond) {
301 		case 0:		return z;
302 		case 1:		return !z;
303 		case 2:		return c;
304 		case 3:		return !c;
305 		case 4:		return n;
306 		case 5:		return !n;
307 		case 6:		return v;
308 		case 7:		return !v;
309 		case 8:		return c && !z;
310 		case 9:		return !c || z;
311 		case 10:	return n == v;
312 		case 11:	return n != v;
313 		case 12:	return !z && (n == v);
314 		case 13:	return z && (n != v);
315 		case 14:	return 1;
316 		case 15:	return 0;
317 	}
318 	return 0;
319 }
320 
321 static uvlong
322 thumbfbranch(Map *map, Rgetter rget, Instr *i, uvlong pc)
323 {
324 	char buf[8];
325 
326 	if(i->op == 30){	// BX
327 		thumbrrh(nil, i);
328 		sprint(buf, "R%ud", i->rn);
329 		return rget(map, buf)&~1;		// clear T bit
330 	}
331 	if(i->op == 57){	// Bcc
332 		thumbbcc(nil, i);
333 		if(thumbcondpass(map, rget, (i->w >> 8) & 0xf))
334 			return i->imm;
335 		return pc+2;
336 	}
337 	if(i->op == 58){	// B
338 		thumbb(nil, i);
339 		return i->imm;
340 	}
341 	if(i->op == 60){	// BL
342 		thumbbl(nil, i);
343 		return i->imm;
344 	}
345 	print("bad thumbfbranch call");
346 	return 0;
347 }
348 
349 static uvlong
350 thumbfmov(Map *map, Rgetter rget, Instr *i, uvlong pc)
351 {
352 	char buf[8];
353 	ulong rd;
354 
355 	thumbrrh(nil, i);
356 	rd = i->rd;
357 	if(rd != 15)
358 		return pc+2;
359 	sprint(buf, "R%ud", i->rn);
360 	return rget(map, buf);
361 }
362 
363 static uvlong
364 thumbfadd(Map *map, Rgetter rget, Instr *i, uvlong pc)
365 {
366 	char buf[8];
367 	ulong rd, v;
368 
369 	thumbrrh(nil, i);
370 	rd = i->rd;
371 	if(rd != 15)
372 		return pc+2;
373 	sprint(buf, "R%ud", i->rn);
374 	v = rget(map, buf);
375 	sprint(buf, "R15");
376 	return rget(map, buf) + v;
377 }
378 
379 static void
380 thumbshift(Opcode *o, Instr *i)
381 {
382 	int ins = i->w;
383 
384 	i->rd = B(2, 0);
385 	i->rn = B(5, 3);
386 	i->imm = B(10, 6);
387 	format(o->o, i, o->a);
388 }
389 
390 static void
391 thumbrrr(Opcode *o, Instr *i)
392 {
393 	int ins = i->w;
394 
395 	i->rd = B(2, 0);
396 	i->rn = B(5, 3);
397 	i->rs = B(8, 6);
398 	format(o->o, i, o->a);
399 }
400 
401 static void
402 thumbirr(Opcode *o, Instr *i)
403 {
404 	int ins = i->w;
405 
406 	i->rd = B(2, 0);
407 	i->rn = B(5, 3);
408 	i->imm = B(8, 6);
409 	format(o->o, i, o->a);
410 }
411 
412 static void
413 thumbir(Opcode *o, Instr *i)
414 {
415 	int ins = i->w;
416 
417 	i->rd = B(10, 8);
418 	i->imm = B(7, 0);
419 	format(o->o, i, o->a);
420 }
421 
422 static void
423 thumbrr(Opcode *o, Instr *i)
424 {
425 	int ins = i->w;
426 
427 	i->rd = B(2, 0);
428 	i->rn = B(5, 3);
429 	format(o->o, i, o->a);
430 }
431 
432 static void
433 thumbrrh(Opcode *o, Instr *i)
434 {
435 	int ins = i->w;
436 
437 	i->rd = B(2, 0);
438 	i->rn = B(5, 3);
439 	if(B(6, 6))
440 		i->rn += 8;
441 	if(B(7, 7))
442 		i->rd += 8;
443 	if(o != nil){
444 		if(i->w == 0x46b7 || i->w == 0x46f7 || i->w == 0x4730 || i->w == 0x4770)	// mov r6, pc or mov lr, pc or bx r6 or bx lr
445 			format("RET", i, "");
446 		else
447 			format(o->o, i, o->a);
448 	}
449 }
450 
451 static void
452 thumbpcrel(Opcode *o, Instr *i)
453 {
454 	int ins = i->w;
455 
456 	i->rn = 15;
457 	i->rd = B(10, 8);
458 	i->imm = 4*(B(7, 0)+1);
459 	if(i->addr & 3)
460 		i->imm -= 2;
461 	format(o->o, i, o->a);
462 }
463 
464 static void
465 thumbmovirr(Opcode *o, Instr *i)
466 {
467 	int ins = i->w;
468 
469 	i->rd = B(2, 0);
470 	i->rn = B(5, 3);
471 	i->imm = B(10, 6);
472 	if(strcmp(o->o, "MOVW") == 0)
473 		i->imm *= 4;
474 	else if(strncmp(o->o, "MOVH", 4) == 0)
475 		i->imm *= 2;
476 	format(o->o, i, o->a);
477 }
478 
479 static void
480 thumbmovsp(Opcode *o, Instr *i)
481 {
482 	int ins = i->w;
483 
484 	i->rn = 13;
485 	i->rd = B(10, 8);
486 	i->imm = 4*B(7, 0);
487 	format(o->o, i, o->a);
488 }
489 
490 static void
491 thumbaddsppc(Opcode *o, Instr *i)
492 {
493 	int ins = i->w;
494 
495 	i->rd = B(10, 8);
496 	i->imm = 4*B(7, 0);
497 	if(i->op == 48)
498 		i->imm += 4;
499 	format(o->o, i, o->a);
500 }
501 
502 static void
503 thumbaddsp(Opcode *o, Instr *i)
504 {
505 	int ins = i->w;
506 
507 	i->imm = 4*B(6, 0);
508 	format(o->o, i, o->a);
509 }
510 
511 static void
512 thumbswi(Opcode *o, Instr *i)
513 {
514 	int ins = i->w;
515 
516 	i->imm = B(7, 0);
517 	format(o->o, i, o->a);
518 }
519 
520 static void
521 thumbbcc(Opcode *o, Instr *i)
522 {
523 	int off, ins = i->w;
524 
525 	off = B(7, 0);
526 	if(off & 0x80)
527 		off |= 0xffffff00;
528 	i->imm = i->addr + 2*off + 4;
529 	if(o != nil)
530 		format(o->o, i, o->a);
531 }
532 
533 static void
534 thumbb(Opcode *o, Instr *i)
535 {
536 	int off, ins = i->w;
537 
538 	off = B(10, 0);
539 	if(off & 0x400)
540 		off |= 0xfffff800;
541 	i->imm = i->addr + 2*off + 4;
542 	if(o != nil)
543 		format(o->o, i, o->a);
544 }
545 
546 static void
547 thumbbl(Opcode *o, Instr *i)
548 {
549 	int off, h, ins = i->w;
550 	static int reglink;
551 
552 	h = B(11, 11);
553 	off = B(10, 0);
554 	if(h == 0){
555 		if(off & 0x400)
556 			off |= 0xfffff800;
557 		i->imm = i->addr + (off<<12) + 4;
558 		reglink = i->imm;
559 	}
560 	else{
561 		i->imm = reglink + 2*off;
562 	}
563 	if(o != nil)
564 		format(o->o, i, o->a);
565 }
566 
567 static void
568 thumbregs(Opcode *o, Instr *i)
569 {
570 	int ins = i->w;
571 
572 	if(i->op == 52 || i->op == 53)
573 		i->rd = 13;
574 	else
575 		i->rd = B(10, 8);
576 	i->imm = B(7, 0);
577 	format(o->o, i, o->a);
578 }
579 
580 static void
581 thumbunk(Opcode *o, Instr *i)
582 {
583 	format(o->o, i, o->a);
584 }
585 
586 static Opcode opcodes[] =
587 {
588 	"LSL",	thumbshift,	0,	"$#%i,R%n,R%d",	// 0
589 	"LSR",	thumbshift,	0,	"$#%i,R%n,R%d",	// 1
590 	"ASR",	thumbshift,	0,	"$#%i,R%n,R%d",	// 2
591 	"ADD",	thumbrrr,		0,	"R%s,R%n,R%d",		// 3
592 	"SUB",	thumbrrr,		0,	"R%s,R%n,R%d",		// 4
593 	"ADD",	thumbirr,		0,	"$#%i,R%n,R%d",	// 5
594 	"SUB",	thumbirr,		0,	"$#%i,R%n,R%d",	// 6
595 	"MOVW",	thumbir,		0,	"$#%i,R%d",		// 7
596 	"CMP",	thumbir,		0,	"$#%i,R%d",		// 8
597 	"ADD",	thumbir,		0,	"$#%i,R%d,R%d",	// 9
598 	"SUB",	thumbir,		0,	"$#%i,R%d,R%d",	// 10
599 	"AND",	thumbrr,		0,	"R%n,R%d,R%d",	// 11
600 	"EOR",	thumbrr,		0,	"R%n,R%d,R%d",	// 12
601 	"LSL",	thumbrr,		0,	"R%n,R%d,R%d",	// 13
602 	"LSR",	thumbrr,		0,	"R%n,R%d,R%d",	// 14
603 	"ASR",	thumbrr,		0,	"R%n,R%d,R%d",	// 15
604 	"ADC",	thumbrr,		0,	"R%n,R%d,R%d",	// 16
605 	"SBC",	thumbrr,		0,	"R%n,R%d,R%d",	// 17
606 	"ROR",	thumbrr,		0,	"R%n,R%d,R%d",	// 18
607 	"TST",	thumbrr,		0,	"R%n,R%d",		// 19
608 	"NEG",	thumbrr,		0,	"R%n,R%d",		// 20
609 	"CMP",	thumbrr,		0,	"R%n,R%d",		// 21
610 	"CMPN",	thumbrr,		0,	"R%n,R%d",		// 22
611 	"OR",	thumbrr,		0,	"R%n,R%d,R%d",	// 23
612 	"MUL",	thumbrr,		0,	"R%n,R%d,R%d",	// 24
613 	"BITC",	thumbrr,		0,	"R%n,R%d,R%d",	// 25
614 	"MOVN",	thumbrr,		0,	"R%n,R%d",		// 26
615 	"ADD",	thumbrrh,		thumbfadd,	"R%n,R%d,R%d",	// 27
616 	"CMP",	thumbrrh,		0,	"R%n,R%d",		// 28
617 	"MOVW",	thumbrrh,		thumbfmov,	"R%n,R%d",	// 29
618 	"BX",		thumbrrh,		thumbfbranch,	"R%n",	// 30
619 	"MOVW",	thumbpcrel,	0,	"$%I,R%d",		// 31
620 	"MOVW",	thumbrrr,		0,	"R%d, [R%s,R%n]",	// 32
621 	"MOVH",	thumbrrr,		0,	"R%d, [R%s,R%n]",	// 33
622 	"MOVB",	thumbrrr,		0,	"R%d, [R%s,R%n]",	// 34
623 	"MOVB",	thumbrrr,		0,	"[R%s,R%n],R%d",	// 35
624 	"MOVW",	thumbrrr,		0,	"[R%s,R%n],R%d",	// 36
625 	"MOVHU",	thumbrrr,		0,	"[R%s,R%n],R%d",	// 37
626 	"MOVBU",	thumbrrr,		0,	"[R%s,R%n],R%d",	// 38
627 	"MOVH",	thumbrrr,		0,	"[R%s,R%n],R%d",	// 39
628 	"MOVW",	thumbmovirr,	0,	"R%d,%I",			// 40
629 	"MOVW",	thumbmovirr,	0,	"%I,R%d",			// 41
630 	"MOVB",	thumbmovirr,	0,	"R%d,%I",			// 42
631 	"MOVBU",	thumbmovirr,	0,	"$%I,R%d",		// 43
632 	"MOVH",	thumbmovirr,	0,	"R%d,%I",			// 44
633 	"MOVHU",	thumbmovirr,	0,	"%I,R%d",			// 45
634 	"MOVW",	thumbmovsp,	0,	"R%d,%I",			// 46
635 	"MOVW",	thumbmovsp,	0,	"%I,R%d",			// 47
636 	"ADD",	thumbaddsppc,0,	"$#%i,PC,R%d",		// 48
637 	"ADD",	thumbaddsppc,0,	"$#%i,SP,R%d",		// 49
638 	"ADD",	thumbaddsp,	0,	"$#%i,SP,SP",		// 50
639 	"SUB",	thumbaddsp,	0,	"$#%i,SP,SP",		// 51
640 	"PUSH",	thumbregs,	0,	"R%d, %r",			// 52
641 	"POP",	thumbregs,	0,	"R%d, %r",			// 53
642 	"STMIA",	thumbregs,	0,	"R%d, %r",			// 54
643 	"LDMIA",	thumbregs,	0,	"R%d, %r",			// 55
644 	"SWI",	thumbswi,	0,	"$#%i",			// 56
645 	"B%c",	thumbbcc,	thumbfbranch,	"%b",		// 57
646 	"B",		thumbb,		thumbfbranch,	"%b",		// 58
647 	"BL",		thumbbl,		0,	"",				// 59
648 	"BL",		thumbbl,		thumbfbranch,	"%b",		// 60
649 	"UNK",	thumbunk,	0,	"",				// 61
650 };
651 
652 static void
653 gaddr(Instr *i)
654 {
655 	*i->curr++ = '$';
656 	i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
657 }
658 
659 static void
660 format(char *mnemonic, Instr *i, char *f)
661 {
662 	int j, k, m, n;
663 	int g;
664 	char *fmt;
665 	int ins = i->w;
666 
667 	if(mnemonic)
668 		format(0, i, mnemonic);
669 	if(f == 0)
670 		return;
671 	if(mnemonic)
672 		if(i->curr < i->end)
673 			*i->curr++ = '\t';
674 	for ( ; *f && i->curr < i->end; f++) {
675 		if(*f != '%') {
676 			*i->curr++ = *f;
677 			continue;
678 		}
679 		switch (*++f) {
680 
681 		case 'c':	/*Bcc */
682 			bprint(i, "%s", cond[B(11, 8)]);
683 			break;
684 
685 		case 's':
686 			bprint(i, "%d", i->rs);
687 			break;
688 
689 		case 'n':
690 			bprint(i, "%d", i->rn);
691 			break;
692 
693 		case 'd':
694 			bprint(i, "%d", i->rd);
695 			break;
696 
697 		case 'i':
698 			bprint(i, "%lux", i->imm);
699 			break;
700 
701 		case 'b':
702 			i->curr += symoff(i->curr, i->end-i->curr,
703 				i->imm, CTEXT);
704 			break;
705 
706 		case 'I':
707 			if (i->rn == 13) {
708 				if (plocal(i))
709 					break;
710 			}
711 			g = 0;
712 			fmt = "#%lx(R%d)";
713 			if (i->rn == 15) {
714 				/* convert load of offset(PC) to a load immediate */
715 				if (get4(i->map, i->addr + i->imm, (ulong*)&i->imm) > 0)
716 				{
717 					g = 1;
718 					fmt = "";
719 				}
720 			}
721 			if (mach->sb)
722 			{
723 				if (i->rn == 12)
724 				{
725 					i->imm += mach->sb;
726 					g = 1;
727 					fmt = "-SB(SB)";
728 				}
729 			}
730 			if (g)
731 			{
732 				gaddr(i);
733 				bprint(i, fmt, i->rn);
734 			}
735 			else
736 				bprint(i, fmt, i->imm, i->rn);
737 			break;
738 
739 		case 'r':
740 			n = i->imm&0xff;
741 			j = 0;
742 			k = 0;
743 			while(n) {
744 				m = j;
745 				while(n&0x1) {
746 					j++;
747 					n >>= 1;
748 				}
749 				if(j != m) {
750 					if(k)
751 						bprint(i, ",");
752 					if(j == m+1)
753 						bprint(i, "R%d", m);
754 					else
755 						bprint(i, "R%d-R%d", m, j-1);
756 					k = 1;
757 				}
758 				j++;
759 				n >>= 1;
760 			}
761 			break;
762 
763 		case '\0':
764 			*i->curr++ = '%';
765 			return;
766 
767 		default:
768 			bprint(i, "%%%c", *f);
769 			break;
770 		}
771 	}
772 	*i->curr = 0;
773 }
774 
775 static int
776 printins(Map *map, uvlong pc, char *buf, int n)
777 {
778 	Instr i;
779 
780 	i.curr = buf;
781 	i.end = buf+n-1;
782 	if(decode(map, pc, &i) < 0)
783 		return -1;
784 
785 	(*opcodes[i.op].fmt)(&opcodes[i.op], &i);
786 	return 2;
787 }
788 
789 static int
790 thumbinst(Map *map, uvlong pc, char modifier, char *buf, int n)
791 {
792 	USED(modifier);
793 	return printins(map, pc, buf, n);
794 }
795 
796 static int
797 thumbdas(Map *map, uvlong pc, char *buf, int n)
798 {
799 	Instr i;
800 
801 	i.curr = buf;
802 	i.end = buf+n;
803 	if(decode(map, pc, &i) < 0)
804 		return -1;
805 	if(i.end-i.curr > 8)
806 		i.curr = _hexify(buf, i.w, 7);
807 	*i.curr = 0;
808 	return 2;
809 }
810 
811 static int
812 thumbinstlen(Map *map, uvlong pc)
813 {
814 	Instr i;
815 
816 	if(decode(map, pc, &i) < 0)
817 		return -1;
818 	return 2;
819 }
820 
821 static int
822 thumbfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
823 {
824 	ulong d;
825 	Instr i;
826 
827 	if(decode(map, pc, &i) < 0)
828 		return -1;
829 
830 	if(opcodes[i.op].foll) {
831 		d = (*opcodes[i.op].foll)(map, rget, &i, pc);
832 		if(d == -1)
833 			return -1;
834 	} else
835 		d = pc+2;
836 
837 	foll[0] = d;
838 	return 1;
839 }
840