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