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