]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmach/5db.c
add arm vfp support to compiler and linker (from sources)
[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, cp;
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                 cp = (w >> 8) & 0xF;
224                 if(cp == 10 || cp == 11){       /* vfp */
225                         if((w >> 4) & 0x1){
226                                 /* vfp register transfer */
227                                 switch((w >> 21) & 0x7){
228                                 case 0:
229                                         op = 118 + ((w >> 20) & 0x1);
230                                         break;
231                                 case 7:
232                                         op = 118+2 + ((w >> 20) & 0x1);
233                                         break;
234                                 default:
235                                         op = (48+24+4+4+2+2+4+4);
236                                         break;
237                                 }
238                                 break;
239                         }
240                         /* vfp data processing */
241                         if(((w >> 23) & 0x1) == 0){
242                                 op = 100 + ((w >> 19) & 0x6) + ((w >> 6) & 0x1);
243                                 break;
244                         }
245                         switch(((w >> 19) & 0x6) + ((w >> 6) & 0x1)){
246                         case 0:
247                                 op = 108;
248                                 break;
249                         case 7:
250                                 if(((w >> 19) & 0x1) == 0)
251                                         if(((w >> 17) & 0x1) == 0)
252                                                 op = 109 + ((w >> 16) & 0x4) +
253                                                         ((w >> 15) & 0x2) +
254                                                         ((w >> 7) & 0x1);
255                                         else if(((w >> 16) & 0x7) == 0x7)
256                                                 op = 117;
257                                 else
258                                         switch((w >> 16) & 0x7){
259                                         case 0:
260                                         case 4:
261                                         case 5:
262                                                 op = 117;
263                                                 break;
264                                         }
265                                 break;
266                         }
267                         if(op == 7)
268                                 op = (48+24+4+4+2+2+4+4);
269                         break;
270                 }
271                 op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
272                 break;
273         case 6: /* vfp load / store */
274                 if(((w >> 21) &0x9) == 0x8){
275                         op = 122 + ((w >> 20) & 0x1);
276                         break;
277                 }
278                 /* fall through */
279         default:          
280                 op = (48+24+4+4+2+2+4+4);
281                 break;
282         }
283         return op;
284 }
285
286 static int
287 decode(Map *map, uvlong pc, Instr *i)
288 {
289         ulong w;
290
291         if(get4(map, pc, &w) < 0) {
292                 werrstr("can't read instruction: %r");
293                 return -1;
294         }
295         i->w = w;
296         i->addr = pc;
297         i->cond = (w >> 28) & 0xF;
298         i->op = armclass(w);
299         i->map = map;
300         return 1;
301 }
302
303 #pragma varargck        argpos  bprint          2
304
305 static void
306 bprint(Instr *i, char *fmt, ...)
307 {
308         va_list arg;
309
310         va_start(arg, fmt);
311         i->curr = vseprint(i->curr, i->end, fmt, arg);
312         va_end(arg);
313 }
314
315 static int
316 plocal(Instr *i)
317 {
318         char *reg;
319         Symbol s;
320         char *fn;
321         int class;
322         int offset;
323
324         if(!findsym(i->addr, CTEXT, &s)) {
325                 if(debug)fprint(2,"fn not found @%llux: %r\n", i->addr);
326                 return 0;
327         }
328         fn = s.name;
329         if (!findlocal(&s, FRAMENAME, &s)) {
330                 if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
331                         return 0;
332         }
333         if(s.value > i->imm) {
334                 class = CAUTO;
335                 offset = s.value-i->imm;
336                 reg = "(SP)";
337         } else {
338                 class = CPARAM;
339                 offset = i->imm-s.value-4;
340                 reg = "(FP)";
341         }
342         if(!getauto(&s, offset, class, &s)) {
343                 if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
344                         class == CAUTO ? " auto" : "param", offset);
345                 return 0;
346         }
347         bprint(i, "%s%c%lld%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
348         return 1;
349 }
350
351 /*
352  * Print value v as name[+offset]
353  */
354 static int
355 gsymoff(char *buf, int n, ulong v, int space)
356 {
357         Symbol s;
358         int r;
359         long delta;
360
361         r = delta = 0;          /* to shut compiler up */
362         if (v) {
363                 r = findsym(v, space, &s);
364                 if (r)
365                         delta = v-s.value;
366                 if (delta < 0)
367                         delta = -delta;
368         }
369         if (v == 0 || r == 0 || delta >= 4096)
370                 return snprint(buf, n, "#%lux", v);
371         if (strcmp(s.name, ".string") == 0)
372                 return snprint(buf, n, "#%lux", v);
373         if (!delta)
374                 return snprint(buf, n, "%s", s.name);
375         if (s.type != 't' && s.type != 'T')
376                 return snprint(buf, n, "%s+%llux", s.name, v-s.value);
377         else
378                 return snprint(buf, n, "#%lux", v);
379 }
380
381 static void
382 armdps(Opcode *o, Instr *i)
383 {
384         i->store = (i->w >> 20) & 1;
385         i->rn = (i->w >> 16) & 0xf;
386         i->rd = (i->w >> 12) & 0xf;
387         i->rs = (i->w >> 0) & 0xf;
388         if(i->rn == 15 && i->rs == 0) {
389                 if(i->op == 8) {
390                         format("MOVW", i,"CPSR, R%d");
391                         return;
392                 } else
393                 if(i->op == 10) {
394                         format("MOVW", i,"SPSR, R%d");
395                         return;
396                 }
397         } else
398         if(i->rn == 9 && i->rd == 15) {
399                 if(i->op == 9) {
400                         format("MOVW", i, "R%s, CPSR");
401                         return;
402                 } else
403                 if(i->op == 11) {
404                         format("MOVW", i, "R%s, SPSR");
405                         return;
406                 }
407         }
408         format(o->o, i, o->a);
409 }
410
411 static void
412 armdpi(Opcode *o, Instr *i)
413 {
414         ulong v;
415         int c;
416
417         v = (i->w >> 0) & 0xff;
418         c = (i->w >> 8) & 0xf;
419         while(c) {
420                 v = (v<<30) | (v>>2);
421                 c--;
422         }
423         i->imm = v;
424         i->store = (i->w >> 20) & 1;
425         i->rn = (i->w >> 16) & 0xf;
426         i->rd = (i->w >> 12) & 0xf;
427         i->rs = i->w&0x0f;
428
429                 /* RET is encoded as ADD #0,R14,R15 */
430         if((i->w & 0x0fffffff) == 0x028ef000){
431                 format("RET%C", i, "");
432                 return;
433         }
434         if((i->w & 0x0ff0ffff) == 0x0280f000){
435                 format("B%C", i, "0(R%n)");
436                 return;
437         }
438         format(o->o, i, o->a);
439 }
440
441 static void
442 armsdti(Opcode *o, Instr *i)
443 {
444         ulong v;
445
446         v = i->w & 0xfff;
447         if(!(i->w & (1<<23)))
448                 v = -v;
449         i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
450         i->imm = v;
451         i->rn = (i->w >> 16) & 0xf;
452         i->rd = (i->w >> 12) & 0xf;
453                 /* RET is encoded as LW.P x,R13,R15 */
454         if ((i->w & 0x0ffff000) == 0x049df000)
455         {
456                 format("RET%C%p", i, "%I");
457                 return;
458         }
459         format(o->o, i, o->a);
460 }
461
462 static void
463 armvstdi(Opcode *o, Instr *i)
464 {
465         ulong v;
466
467         v = (i->w & 0xff) << 2;
468         if(!(i->w & (1<<23)))
469                 v = -v;
470         i->imm = v;
471         i->rn = (i->w >> 16) & 0xf;
472         i->rd = (i->w >> 12) & 0xf;
473         format(o->o, i, o->a);
474 }
475
476 /* arm V4 ld/st halfword, signed byte */
477 static void
478 armhwby(Opcode *o, Instr *i)
479 {
480         i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
481         i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf);
482         if (!(i->w & (1 << 23)))
483                 i->imm = - i->imm;
484         i->rn = (i->w >> 16) & 0xf;
485         i->rd = (i->w >> 12) & 0xf;
486         i->rs = (i->w >> 0) & 0xf;
487         format(o->o, i, o->a);
488 }
489
490 static void
491 armsdts(Opcode *o, Instr *i)
492 {
493         i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
494         i->rs = (i->w >> 0) & 0xf;
495         i->rn = (i->w >> 16) & 0xf;
496         i->rd = (i->w >> 12) & 0xf;
497         format(o->o, i, o->a);
498 }
499
500 static void
501 armbdt(Opcode *o, Instr *i)
502 {
503         i->store = (i->w >> 21) & 0x3;          /* S & W bits */
504         i->rn = (i->w >> 16) & 0xf;
505         i->imm = i->w & 0xffff;
506         if(i->w == 0xe8fd8000)
507                 format("RFE", i, "");
508         else
509                 format(o->o, i, o->a);
510 }
511
512 static void
513 armund(Opcode *o, Instr *i)
514 {
515         format(o->o, i, o->a);
516 }
517
518 static void
519 armcdt(Opcode *o, Instr *i)
520 {
521         format(o->o, i, o->a);
522 }
523
524 static void
525 armunk(Opcode *o, Instr *i)
526 {
527         format(o->o, i, o->a);
528 }
529
530 static void
531 armb(Opcode *o, Instr *i)
532 {
533         ulong v;
534
535         v = i->w & 0xffffff;
536         if(v & 0x800000)
537                 v |= ~0xffffff;
538         i->imm = (v<<2) + i->addr + 8;
539         format(o->o, i, o->a);
540 }
541
542 static void
543 armco(Opcode *o, Instr *i)              /* coprocessor instructions */
544 {
545         int op, p, cp;
546
547         char buf[1024];
548
549         i->rn = (i->w >> 16) & 0xf;
550         i->rd = (i->w >> 12) & 0xf;
551         i->rs = i->w&0xf;
552         cp = (i->w >> 8) & 0xf;
553         p = (i->w >> 5) & 0x7;
554         if(i->w&(1<<4)) {
555                 op = (i->w >> 21) & 0x07;
556                 snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p);
557         } else {
558                 op = (i->w >> 20) & 0x0f;
559                 snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p);
560         }
561         format(o->o, i, buf);
562 }
563
564 static int
565 armcondpass(Map *map, Rgetter rget, uchar cond)
566 {
567         uvlong psr;
568         uchar n;
569         uchar z;
570         uchar c;
571         uchar v;
572
573         psr = rget(map, "PSR");
574         n = (psr >> 31) & 1;
575         z = (psr >> 30) & 1;
576         c = (psr >> 29) & 1;
577         v = (psr >> 28) & 1;
578
579         switch(cond) {
580         default:
581         case 0:         return z;
582         case 1:         return !z;
583         case 2:         return c;
584         case 3:         return !c;
585         case 4:         return n;
586         case 5:         return !n;
587         case 6:         return v;
588         case 7:         return !v;
589         case 8:         return c && !z;
590         case 9:         return !c || z;
591         case 10:        return n == v;
592         case 11:        return n != v;
593         case 12:        return !z && (n == v);
594         case 13:        return z && (n != v);
595         case 14:        return 1;
596         case 15:        return 0;
597         }
598 }
599
600 static ulong
601 armshiftval(Map *map, Rgetter rget, Instr *i)
602 {
603         if(i->w & (1 << 25)) {                          /* immediate */
604                 ulong imm = i->w & BITS(0, 7);
605                 ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */
606                 return ROR(imm, s);
607         } else {
608                 char buf[8];
609                 ulong v;
610                 ulong s = (i->w & BITS(7,11)) >> 7;
611
612                 sprint(buf, "R%ld", i->w & 0xf);
613                 v = rget(map, buf);
614
615                 switch((i->w & BITS(4, 6)) >> 4) {
616                 default:
617                 case 0:                                 /* LSLIMM */
618                         return v << s;
619                 case 1:                                 /* LSLREG */
620                         sprint(buf, "R%lud", s >> 1);
621                         s = rget(map, buf) & 0xFF;
622                         if(s >= 32) return 0;
623                         return v << s;
624                 case 2:                                 /* LSRIMM */
625                         return LSR(v, s);
626                 case 3:                                 /* LSRREG */
627                         sprint(buf, "R%ld", s >> 1);
628                         s = rget(map, buf) & 0xFF;
629                         if(s >= 32) return 0;
630                         return LSR(v, s);
631                 case 4:                                 /* ASRIMM */
632                         if(s == 0) {
633                                 if((v & (1U<<31)) == 0)
634                                         return 0;
635                                 return 0xFFFFFFFF;
636                         }
637                         return ASR(v, s);
638                 case 5:                                 /* ASRREG */
639                         sprint(buf, "R%ld", s >> 1);
640                         s = rget(map, buf) & 0xFF;
641                         if(s >= 32) {
642                                 if((v & (1U<<31)) == 0)
643                                         return 0;
644                                 return 0xFFFFFFFF;
645                         }
646                         return ASR(v, s);
647                 case 6:                                 /* RORIMM */
648                         if(s == 0) {
649                                 ulong c = (rget(map, "PSR") >> 29) & 1;
650
651                                 return (c << 31) | LSR(v, 1);
652                         }
653                         return ROR(v, s);
654                 case 7:                                 /* RORREG */
655                         sprint(buf, "R%ld", (s>>1)&0xF);
656                         s = rget(map, buf);
657                         if(s == 0 || (s & 0xF) == 0)
658                                 return v;
659                         return ROR(v, s & 0xF);
660                 }
661         }
662 }
663
664 static int
665 nbits(ulong v)
666 {
667         int n = 0;
668         int i;
669
670         for(i=0; i < 32 ; i++) {
671                 if(v & 1) ++n;
672                 v >>= 1;
673         }
674
675         return n;
676 }
677
678 static ulong
679 armmaddr(Map *map, Rgetter rget, Instr *i)
680 {
681         ulong v;
682         ulong nb;
683         char buf[8];
684         ulong rn;
685
686         rn = (i->w >> 16) & 0xf;
687         sprint(buf,"R%ld", rn);
688
689         v = rget(map, buf);
690         nb = nbits(i->w & ((1 << 15) - 1));
691
692         switch((i->w >> 23) & 3) {
693         default:
694         case 0: return (v - (nb*4)) + 4;
695         case 1: return v;
696         case 2: return v - (nb*4);
697         case 3: return v + 4;
698         }
699 }
700
701 static uvlong
702 armaddr(Map *map, Rgetter rget, Instr *i)
703 {
704         char buf[8];
705         ulong rn;
706
707         snprint(buf, sizeof(buf), "R%ld", (i->w >> 16) & 0xf);
708         rn = rget(map, buf);
709
710         if((i->w & (1<<24)) == 0)                       /* POSTIDX */
711                 return rn;
712
713         if((i->w & (1<<25)) == 0) {                     /* OFFSET */
714                 if(i->w & (1U<<23))
715                         return rn + (i->w & BITS(0,11));
716                 return rn - (i->w & BITS(0,11));
717         } else {                                        /* REGOFF */
718                 ulong index = 0;
719                 uchar c;
720                 uchar rm;
721
722                 sprint(buf, "R%ld", i->w & 0xf);
723                 rm = rget(map, buf);
724
725                 switch((i->w & BITS(5,6)) >> 5) {
726                 case 0: index = rm << ((i->w & BITS(7,11)) >> 7);       break;
727                 case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7));    break;
728                 case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7));    break;
729                 case 3:
730                         if((i->w & BITS(7,11)) == 0) {
731                                 c = (rget(map, "PSR") >> 29) & 1;
732                                 index = c << 31 | LSR(rm, 1);
733                         } else {
734                                 index = ROR(rm, ((i->w & BITS(7,11)) >> 7));
735                         }
736                         break;
737                 }
738                 if(i->w & (1<<23))
739                         return rn + index;
740                 return rn - index;
741         }
742 }
743
744 static uvlong
745 armfadd(Map *map, Rgetter rget, Instr *i, uvlong pc)
746 {
747         char buf[8];
748         int r;
749
750         r = (i->w >> 12) & 0xf;
751         if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf))
752                 return pc+4;
753
754         r = (i->w >> 16) & 0xf;
755         sprint(buf, "R%d", r);
756
757         return rget(map, buf) + armshiftval(map, rget, i);
758 }
759
760 static uvlong
761 armfmovm(Map *map, Rgetter rget, Instr *i, uvlong pc)
762 {
763         ulong v;
764         ulong addr;
765
766         v = i->w & 1<<15;
767         if(!v || !armcondpass(map, rget, (i->w>>28)&0xf))
768                 return pc+4;
769
770         addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15));
771         if(get4(map, addr, &v) < 0) {
772                 werrstr("can't read addr: %r");
773                 return -1;
774         }
775         return v;
776 }
777
778 static uvlong
779 armfbranch(Map *map, Rgetter rget, Instr *i, uvlong pc)
780 {
781         if(!armcondpass(map, rget, (i->w >> 28) & 0xf))
782                 return pc+4;
783
784         return pc + (((signed long)i->w << 8) >> 6) + 8;
785 }
786
787 static uvlong
788 armfmov(Map *map, Rgetter rget, Instr *i, uvlong pc)
789 {
790         ulong rd, v;
791
792         rd = (i->w >> 12) & 0xf;
793         if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf))
794                 return pc+4;
795
796          /* LDR */
797         /* BUG: Needs LDH/B, too */
798         if(((i->w>>26)&0x3) == 1) {
799                 if(get4(map, armaddr(map, rget, i), &v) < 0) {
800                         werrstr("can't read instruction: %r");
801                         return pc+4;
802                 }
803                 return v;
804         }
805
806          /* MOV */
807         v = armshiftval(map, rget, i);
808
809         return v;
810 }
811
812 static Opcode opcodes[] =
813 {
814         "AND%C%S",      armdps, 0,      "R%s,R%n,R%d",
815         "EOR%C%S",      armdps, 0,      "R%s,R%n,R%d",
816         "SUB%C%S",      armdps, 0,      "R%s,R%n,R%d",
817         "RSB%C%S",      armdps, 0,      "R%s,R%n,R%d",
818         "ADD%C%S",      armdps, armfadd,        "R%s,R%n,R%d",
819         "ADC%C%S",      armdps, 0,      "R%s,R%n,R%d",
820         "SBC%C%S",      armdps, 0,      "R%s,R%n,R%d",
821         "RSC%C%S",      armdps, 0,      "R%s,R%n,R%d",
822         "TST%C%S",      armdps, 0,      "R%s,R%n",
823         "TEQ%C%S",      armdps, 0,      "R%s,R%n",
824         "CMP%C%S",      armdps, 0,      "R%s,R%n",
825         "CMN%C%S",      armdps, 0,      "R%s,R%n",
826         "ORR%C%S",      armdps, 0,      "R%s,R%n,R%d",
827         "MOVW%C%S",     armdps, armfmov,        "R%s,R%d",
828         "BIC%C%S",      armdps, 0,      "R%s,R%n,R%d",
829         "MVN%C%S",      armdps, 0,      "R%s,R%d",
830
831 /* 16 */
832         "AND%C%S",      armdps, 0,      "(R%s%h%m),R%n,R%d",
833         "EOR%C%S",      armdps, 0,      "(R%s%h%m),R%n,R%d",
834         "SUB%C%S",      armdps, 0,      "(R%s%h%m),R%n,R%d",
835         "RSB%C%S",      armdps, 0,      "(R%s%h%m),R%n,R%d",
836         "ADD%C%S",      armdps, armfadd,        "(R%s%h%m),R%n,R%d",
837         "ADC%C%S",      armdps, 0,      "(R%s%h%m),R%n,R%d",
838         "SBC%C%S",      armdps, 0,      "(R%s%h%m),R%n,R%d",
839         "RSC%C%S",      armdps, 0,      "(R%s%h%m),R%n,R%d",
840         "TST%C%S",      armdps, 0,      "(R%s%h%m),R%n",
841         "TEQ%C%S",      armdps, 0,      "(R%s%h%m),R%n",
842         "CMP%C%S",      armdps, 0,      "(R%s%h%m),R%n",
843         "CMN%C%S",      armdps, 0,      "(R%s%h%m),R%n",
844         "ORR%C%S",      armdps, 0,      "(R%s%h%m),R%n,R%d",
845         "MOVW%C%S",     armdps, armfmov,        "(R%s%h%m),R%d",
846         "BIC%C%S",      armdps, 0,      "(R%s%h%m),R%n,R%d",
847         "MVN%C%S",      armdps, 0,      "(R%s%h%m),R%d",
848
849 /* 32 */
850         "AND%C%S",      armdps, 0,      "(R%s%hR%M),R%n,R%d",
851         "EOR%C%S",      armdps, 0,      "(R%s%hR%M),R%n,R%d",
852         "SUB%C%S",      armdps, 0,      "(R%s%hR%M),R%n,R%d",
853         "RSB%C%S",      armdps, 0,      "(R%s%hR%M),R%n,R%d",
854         "ADD%C%S",      armdps, armfadd,        "(R%s%hR%M),R%n,R%d",
855         "ADC%C%S",      armdps, 0,      "(R%s%hR%M),R%n,R%d",
856         "SBC%C%S",      armdps, 0,      "(R%s%hR%M),R%n,R%d",
857         "RSC%C%S",      armdps, 0,      "(R%s%hR%M),R%n,R%d",
858         "TST%C%S",      armdps, 0,      "(R%s%hR%M),R%n",
859         "TEQ%C%S",      armdps, 0,      "(R%s%hR%M),R%n",
860         "CMP%C%S",      armdps, 0,      "(R%s%hR%M),R%n",
861         "CMN%C%S",      armdps, 0,      "(R%s%hR%M),R%n",
862         "ORR%C%S",      armdps, 0,      "(R%s%hR%M),R%n,R%d",
863         "MOVW%C%S",     armdps, armfmov,        "(R%s%hR%M),R%d",
864         "BIC%C%S",      armdps, 0,      "(R%s%hR%M),R%n,R%d",
865         "MVN%C%S",      armdps, 0,      "(R%s%hR%M),R%d",
866
867 /* 48 */
868         "AND%C%S",      armdpi, 0,      "$#%i,R%n,R%d",
869         "EOR%C%S",      armdpi, 0,      "$#%i,R%n,R%d",
870         "SUB%C%S",      armdpi, 0,      "$#%i,R%n,R%d",
871         "RSB%C%S",      armdpi, 0,      "$#%i,R%n,R%d",
872         "ADD%C%S",      armdpi, armfadd,        "$#%i,R%n,R%d",
873         "ADC%C%S",      armdpi, 0,      "$#%i,R%n,R%d",
874         "SBC%C%S",      armdpi, 0,      "$#%i,R%n,R%d",
875         "RSC%C%S",      armdpi, 0,      "$#%i,R%n,R%d",
876         "TST%C%S",      armdpi, 0,      "$#%i,R%n",
877         "TEQ%C%S",      armdpi, 0,      "$#%i,R%n",
878         "CMP%C%S",      armdpi, 0,      "$#%i,R%n",
879         "CMN%C%S",      armdpi, 0,      "$#%i,R%n",
880         "ORR%C%S",      armdpi, 0,      "$#%i,R%n,R%d",
881         "MOVW%C%S",     armdpi, armfmov,        "$#%i,R%d",
882         "BIC%C%S",      armdpi, 0,      "$#%i,R%n,R%d",
883         "MVN%C%S",      armdpi, 0,      "$#%i,R%d",
884
885 /* 48+16 */
886         "MUL%C%S",      armdpi, 0,      "R%M,R%s,R%n",
887         "MULA%C%S",     armdpi, 0,      "R%M,R%s,R%n,R%d",
888         "SWPW",         armdpi, 0,      "R%s,(R%n),R%d",
889         "SWPB",         armdpi, 0,      "R%s,(R%n),R%d",
890
891 /* 48+16+4 */
892         "MOV%u%C%p",    armhwby, 0,     "R%d,(R%n%UR%M)",
893         "MOV%u%C%p",    armhwby, 0,     "R%d,%I",
894         "MOV%u%C%p",    armhwby, armfmov,       "(R%n%UR%M),R%d",
895         "MOV%u%C%p",    armhwby, armfmov,       "%I,R%d",
896
897 /* 48+24 */
898         "MOVW%C%p",     armsdti, 0,     "R%d,%I",
899         "MOVB%C%p",     armsdti, 0,     "R%d,%I",
900         "MOVW%C%p",     armsdti, armfmov,       "%I,R%d",
901         "MOVBU%C%p",    armsdti, armfmov,       "%I,R%d",
902
903         "MOVW%C%p",     armsdts, 0,     "R%d,(R%s%h%m)(R%n)",
904         "MOVB%C%p",     armsdts, 0,     "R%d,(R%s%h%m)(R%n)",
905         "MOVW%C%p",     armsdts, armfmov,       "(R%s%h%m)(R%n),R%d",
906         "MOVBU%C%p",    armsdts, armfmov,       "(R%s%h%m)(R%n),R%d",
907
908         "MOVM%C%P%a",   armbdt, armfmovm,               "[%r],(R%n)",
909         "MOVM%C%P%a",   armbdt, armfmovm,               "(R%n),[%r]",
910
911         "B%C",          armb, armfbranch,               "%b",
912         "BL%C",         armb, armfbranch,               "%b",
913
914         "CDP%C",        armco, 0,               "",
915         "CDP%C",        armco, 0,               "",
916         "MCR%C",        armco, 0,               "",
917         "MRC%C",        armco, 0,               "",
918
919 /* 48+24+4+4+2+2+4 */
920         "MULLU%C%S",    armdpi, 0,      "R%M,R%s,(R%n,R%d)",
921         "MULALU%C%S",   armdpi, 0,      "R%M,R%s,(R%n,R%d)",
922         "MULL%C%S",     armdpi, 0,      "R%M,R%s,(R%n,R%d)",
923         "MULAL%C%S",    armdpi, 0,      "R%M,R%s,(R%n,R%d)",
924
925 /* 48+24+4+4+2+2+4+4 = 92 */
926         "UNK",          armunk, 0,      "",
927
928         /* new v7 arch instructions */
929 /* 93 */
930         "LDREX",        armdpi, 0,      "(R%n),R%d",
931         "STREX",        armdpi, 0,      "R%s,(R%n),R%d",
932         "CLREX",        armunk, 0,      "",
933
934 /* 96 */
935         "DSB",          armunk, 0,      "",
936         "DMB",          armunk, 0,      "",
937         "ISB",          armunk, 0,      "",
938
939 /* 99 */
940         "RFEV7%P%a",    armbdt, 0,      "(R%n)",
941
942 /* 100 */
943         "MLA%f%C",      armdps, 0,      "F%s,F%n,F%d",
944         "MLS%f%C",      armdps, 0,      "F%s,F%n,F%d",
945         "NMLS%f%C",     armdps, 0,      "F%s,F%n,F%d",
946         "NMLA%f%C",     armdps, 0,      "F%s,F%n,F%d",
947         "MUL%f%C",      armdps, 0,      "F%s,F%n,F%d",
948         "NMUL%f%C",     armdps, 0,      "F%s,F%n,F%d",
949         "ADD%f%C",      armdps, 0,      "F%s,F%n,F%d",
950         "SUB%f%C",      armdps, 0,      "F%s,F%n,F%d",
951         "DIV%f%C",      armdps, 0,      "F%s,F%n,F%d",
952
953 /* 109 */
954         "MOV%f%C",      armdps, 0,      "F%s,F%d",
955         "ABS%f%C",      armdps, 0,      "F%s,F%d",
956         "NEG%f%C",      armdps, 0,      "F%s,F%d",
957         "SQRT%f%C",     armdps, 0,      "F%s,F%d",
958         "CMP%f%C",      armdps, 0,      "F%s,F%d",
959         "CMPE%f%C",     armdps, 0,      "F%s,F%d",
960         "CMP%f%C",      armdps, 0,      "$0.0,F%d",
961         "CMPE%f%C",     armdps, 0,      "$0.0,F%d",
962
963 /* 117 */
964         "MOV%F%R%C",    armdps, 0,      "F%s,F%d",
965
966 /* 118 */
967         "MOVW%C",       armdps, 0,      "R%d,F%n",
968         "MOVW%C",       armdps, 0,      "F%n,R%d",
969         "MOVW%C",       armdps, 0,      "R%d,%x",
970         "MOVW%C",       armdps, 0,      "%x,R%d",
971
972 /* 122 */
973         "MOV%f%C",      armvstdi,       0,      "F%d,%I",
974         "MOV%f%C",      armvstdi,       0,      "%I,F%d",
975 };
976
977 static void
978 gaddr(Instr *i)
979 {
980         *i->curr++ = '$';
981         i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
982 }
983
984 static  char *mode[] = { 0, "IA", "DB", "IB" };
985 static  char *pw[] = { "P", "PW", 0, "W" };
986 static  char *sw[] = { 0, "W", "S", "SW" };
987
988 static void
989 format(char *mnemonic, Instr *i, char *f)
990 {
991         int j, k, m, n;
992         int g;
993         char *fmt;
994
995         if(mnemonic)
996                 format(0, i, mnemonic);
997         if(f == 0)
998                 return;
999         if(mnemonic)
1000                 if(i->curr < i->end)
1001                         *i->curr++ = '\t';
1002         for ( ; *f && i->curr < i->end; f++) {
1003                 if(*f != '%') {
1004                         *i->curr++ = *f;
1005                         continue;
1006                 }
1007                 switch (*++f) {
1008
1009                 case 'C':       /* .CONDITION */
1010                         if(cond[i->cond])
1011                                 bprint(i, ".%s", cond[i->cond]);
1012                         break;
1013
1014                 case 'S':       /* .STORE */
1015                         if(i->store)
1016                                 bprint(i, ".S");
1017                         break;
1018
1019                 case 'P':       /* P & U bits for block move */
1020                         n = (i->w >>23) & 0x3;
1021                         if (mode[n])
1022                                 bprint(i, ".%s", mode[n]);
1023                         break;
1024
1025                 case 'p':       /* P & W bits for single data xfer*/
1026                         if (pw[i->store])
1027                                 bprint(i, ".%s", pw[i->store]);
1028                         break;
1029
1030                 case 'a':       /* S & W bits for single data xfer*/
1031                         if (sw[i->store])
1032                                 bprint(i, ".%s", sw[i->store]);
1033                         break;
1034
1035                 case 's':
1036                         bprint(i, "%d", i->rs & 0xf);
1037                         break;
1038                                 
1039                 case 'M':
1040                         bprint(i, "%lud", (i->w>>8) & 0xf);
1041                         break;
1042                                 
1043                 case 'm':
1044                         bprint(i, "%lud", (i->w>>7) & 0x1f);
1045                         break;
1046
1047                 case 'h':
1048                         bprint(i, shtype[(i->w>>5) & 0x3]);
1049                         break;
1050
1051                 case 'u':               /* Signed/unsigned Byte/Halfword */
1052                         bprint(i, hb[(i->w>>5) & 0x3]);
1053                         break;
1054
1055                 case 'I':
1056                         if (i->rn == 13) {
1057                                 if (plocal(i))
1058                                         break;
1059                         }
1060                         g = 0;
1061                         fmt = "#%lx(R%d)";
1062                         if (i->rn == 15) {
1063                                 /* convert load of offset(PC) to a load immediate */
1064                                 if (get4(i->map, i->addr+i->imm+8, (ulong*)&i->imm) > 0)
1065                                 {
1066                                         g = 1;
1067                                         fmt = "";
1068                                 }
1069                         }
1070                         if (mach->sb)
1071                         {
1072                                 if (i->rd == 11) {
1073                                         ulong nxti;
1074
1075                                         if (get4(i->map, i->addr+4, &nxti) > 0) {
1076                                                 if ((nxti & 0x0e0f0fff) == 0x060c000b) {
1077                                                         i->imm += mach->sb;
1078                                                         g = 1;
1079                                                         fmt = "-SB";
1080                                                 }
1081                                         }
1082                                 }
1083                                 if (i->rn == 12)
1084                                 {
1085                                         i->imm += mach->sb;
1086                                         g = 1;
1087                                         fmt = "-SB(SB)";
1088                                 }
1089                         }
1090                         if (g)
1091                         {
1092                                 gaddr(i);
1093                                 bprint(i, fmt, i->rn);
1094                         }
1095                         else
1096                                 bprint(i, fmt, i->imm, i->rn);
1097                         break;
1098                 case 'U':               /* Add/subtract from base */
1099                         bprint(i, addsub[(i->w >> 23) & 1]);
1100                         break;
1101
1102                 case 'n':
1103                         bprint(i, "%d", i->rn);
1104                         break;
1105
1106                 case 'd':
1107                         bprint(i, "%d", i->rd);
1108                         break;
1109
1110                 case 'i':
1111                         bprint(i, "%lux", i->imm);
1112                         break;
1113
1114                 case 'b':
1115                         i->curr += symoff(i->curr, i->end-i->curr,
1116                                 (ulong)i->imm, CTEXT);
1117                         break;
1118
1119                 case 'g':
1120                         i->curr += gsymoff(i->curr, i->end-i->curr,
1121                                 i->imm, CANY);
1122                         break;
1123
1124                 case 'f':
1125                         switch((i->w >> 8) & 0xF){
1126                         case 10:
1127                                 bprint(i, "F");
1128                                 break;
1129                         case 11:
1130                                 bprint(i, "D");
1131                                 break;
1132                         }
1133                         break;
1134
1135                 case 'F':
1136                         switch(((i->w >> 15) & 0xE) + ((i->w >> 8) & 0x1)){
1137                         case 0x0:
1138                                 bprint(i, ((i->w >> 7) & 0x1)? "WF" : "WF.U");
1139                                 break;
1140                         case 0x1:
1141                                 bprint(i, ((i->w >> 7) & 0x1)? "WD" : "WD.U");
1142                                 break;
1143                         case 0x8:
1144                                 bprint(i, "FW.U");
1145                                 break;
1146                         case 0x9:
1147                                 bprint(i, "DW.U");
1148                                 break;
1149                         case 0xA:
1150                                 bprint(i, "FW");
1151                                 break;
1152                         case 0xB:
1153                                 bprint(i, "DW");
1154                                 break;
1155                         case 0xE:
1156                                 bprint(i, "FD");
1157                                 break;
1158                         case 0xF:
1159                                 bprint(i, "DF");
1160                                 break;
1161                         }
1162                         break;
1163
1164                 case 'R':
1165                         if(((i->w >> 7) & 0x1) == 0)
1166                                 bprint(i, "R");
1167                         break;
1168
1169                 case 'x':
1170                         switch(i->rn){
1171                         case 0:
1172                                 bprint(i, "FPSID");
1173                                 break;
1174                         case 1:
1175                                 bprint(i, "FPSCR");
1176                                 break;
1177                         case 2:
1178                                 bprint(i, "FPEXC");
1179                                 break;
1180                         default:
1181                                 bprint(i, "FPS(%d)", i->rn);
1182                                 break;
1183                         }
1184                         break;
1185
1186                 case 'r':
1187                         n = i->imm&0xffff;
1188                         j = 0;
1189                         k = 0;
1190                         while(n) {
1191                                 m = j;
1192                                 while(n&0x1) {
1193                                         j++;
1194                                         n >>= 1;
1195                                 }
1196                                 if(j != m) {
1197                                         if(k)
1198                                                 bprint(i, ",");
1199                                         if(j == m+1)
1200                                                 bprint(i, "R%d", m);
1201                                         else
1202                                                 bprint(i, "R%d-R%d", m, j-1);
1203                                         k = 1;
1204                                 }
1205                                 j++;
1206                                 n >>= 1;
1207                         }
1208                         break;
1209
1210                 case '\0':
1211                         *i->curr++ = '%';
1212                         return;
1213
1214                 default:
1215                         bprint(i, "%%%c", *f);
1216                         break;
1217                 }
1218         }
1219         *i->curr = 0;
1220 }
1221
1222 static int
1223 printins(Map *map, uvlong pc, char *buf, int n)
1224 {
1225         Instr i;
1226
1227         i.curr = buf;
1228         i.end = buf+n-1;
1229         if(decode(map, pc, &i) < 0)
1230                 return -1;
1231
1232         (*opcodes[i.op].fmt)(&opcodes[i.op], &i);
1233         return 4;
1234 }
1235
1236 static int
1237 arminst(Map *map, uvlong pc, char modifier, char *buf, int n)
1238 {
1239         USED(modifier);
1240         return printins(map, pc, buf, n);
1241 }
1242
1243 static int
1244 armdas(Map *map, uvlong pc, char *buf, int n)
1245 {
1246         Instr i;
1247
1248         i.curr = buf;
1249         i.end = buf+n;
1250         if(decode(map, pc, &i) < 0)
1251                 return -1;
1252         if(i.end-i.curr > 8)
1253                 i.curr = _hexify(buf, i.w, 7);
1254         *i.curr = 0;
1255         return 4;
1256 }
1257
1258 static int
1259 arminstlen(Map *map, uvlong pc)
1260 {
1261         Instr i;
1262
1263         if(decode(map, pc, &i) < 0)
1264                 return -1;
1265         return 4;
1266 }
1267
1268 static int
1269 armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1270 {
1271         uvlong d;
1272         Instr i;
1273
1274         if(decode(map, pc, &i) < 0)
1275                 return -1;
1276
1277         if(opcodes[i.op].foll) {
1278                 d = (*opcodes[i.op].foll)(map, rget, &i, pc);
1279                 if(d == -1)
1280                         return -1;
1281         } else
1282                 d = pc+4;
1283
1284         foll[0] = d;
1285         return 1;
1286 }