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