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*
thumbexcep(Map * map,Rgetter rget)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
bits(int i,int h,int l)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
thumbclass(long w)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
decode(Map * map,uvlong pc,Instr * i)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
bprint(Instr * i,char * fmt,...)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
plocal(Instr * i)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
gsymoff(char * buf,int n,long v,int space)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
thumbcondpass(Map * map,Rgetter rget,uchar cond)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
thumbfbranch(Map * map,Rgetter rget,Instr * i,uvlong pc)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
thumbfmov(Map * map,Rgetter rget,Instr * i,uvlong pc)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
thumbfadd(Map * map,Rgetter rget,Instr * i,uvlong pc)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
thumbshift(Opcode * o,Instr * i)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
thumbrrr(Opcode * o,Instr * i)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
thumbirr(Opcode * o,Instr * i)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
thumbir(Opcode * o,Instr * i)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
thumbrr(Opcode * o,Instr * i)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
thumbrrh(Opcode * o,Instr * i)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
thumbpcrel(Opcode * o,Instr * i)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
thumbmovirr(Opcode * o,Instr * i)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
thumbmovsp(Opcode * o,Instr * i)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
thumbaddsppc(Opcode * o,Instr * i)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
thumbaddsp(Opcode * o,Instr * i)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
thumbswi(Opcode * o,Instr * i)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
thumbbcc(Opcode * o,Instr * i)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
thumbb(Opcode * o,Instr * i)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
thumbbl(Opcode * o,Instr * i)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
thumbregs(Opcode * o,Instr * i)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
thumbunk(Opcode * o,Instr * i)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
gaddr(Instr * i)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
format(char * mnemonic,Instr * i,char * f)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
printins(Map * map,uvlong pc,char * buf,int n)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
thumbinst(Map * map,uvlong pc,char modifier,char * buf,int n)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
thumbdas(Map * map,uvlong pc,char * buf,int n)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
thumbinstlen(Map * map,uvlong pc)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
thumbfoll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)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