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