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