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