3 * forsyth@plan9.cs.york.ac.uk
12 * PowerPC-specific debugger interface
13 * forsyth@plan9.cs.york.ac.uk
16 static char *powerexcep(Map*, Regs*);
17 static int powerfoll(Map*, Regs*, u64int, u64int*);
18 static int powerdas(Map*, u64int, char, char*, int);
19 static int powerinstlen(Map*, u64int);
20 static int powerhexinst(Map*, u64int, char*, int);
22 static char *excname[] =
32 "floating-point unavailable",
34 "i/o controller interface error",
38 "floating point assist",
43 "instruction address breakpoint"
51 /* the following are made up on a program exception */
52 "floating point exception", /* FPEXC */
53 "illegal instruction",
54 "privileged instruction",
60 powerexcep(Map *map, Regs *regs)
65 if(rget(regs, "CAUSE", &c) < 0)
66 return "no cause register";
68 if(c < nelem(excname))
70 sprint(buf, "unknown trap #%lux", c);
75 * disassemble PowerPC opcodes
78 #define REGSP 1 /* should come from q.out.h, but there's a clash */
81 /*static char FRAMENAME[] = ".frame"; */
86 * ibm conventions for these: bit 0 is top bit
90 uchar aa; /* bit 30 */
91 uchar crba; /* bits 11-15 */
92 uchar crbb; /* bits 16-20 */
93 long bd; /* bits 16-29 */
94 uchar crfd; /* bits 6-8 */
95 uchar crfs; /* bits 11-13 */
96 uchar bi; /* bits 11-15 */
97 uchar bo; /* bits 6-10 */
98 uchar crbd; /* bits 6-10 */
100 short d; /* bits 16-31 */
104 uchar fm; /* bits 7-14 */
105 uchar fra; /* bits 11-15 */
106 uchar frb; /* bits 16-20 */
107 uchar frc; /* bits 21-25 */
108 uchar frs; /* bits 6-10 */
109 uchar frd; /* bits 6-10 */
110 uchar crm; /* bits 12-19 */
111 long li; /* bits 6-29 || b'00' */
112 uchar lk; /* bit 31 */
113 uchar mb; /* bits 21-25 */
114 uchar me; /* bits 26-30 */
115 uchar nb; /* bits 16-20 */
116 uchar op; /* bits 0-5 */
117 uchar oe; /* bit 21 */
118 uchar ra; /* bits 11-15 */
119 uchar rb; /* bits 16-20 */
120 uchar rc; /* bit 31 */
122 uchar rs; /* bits 6-10 */
125 uchar sh; /* bits 16-20 */
126 ushort spr; /* bits 11-20 */
127 uchar to; /* bits 6-10 */
128 uchar imm; /* bits 16-19 */
129 ushort xo; /* bits 21-30, 22-30, 26-30, or 30 (beware) */
133 u64int addr; /* pc of instruction */
135 char *curr; /* current fill level in output buffer */
136 char *end; /* end of buffer */
137 int size; /* number of longs in instr */
138 char *err; /* errmsg */
141 #define IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0UL<<(((b)-(a)+1))))
142 #define IB(v,b) IBF((v),(b),(b))
145 bprint(Instr *i, char *fmt, ...)
150 i->curr = vseprint(i->curr, i->end, fmt, arg);
155 decode(ulong pc, Instr *i)
159 if (get4(mymap, pc, &w) < 0) {
160 werrstr("can't read instruction: %r");
164 i->crba = IBF(w, 11, 15);
165 i->crbb = IBF(w, 16, 20);
166 i->bd = IBF(w, 16, 29)<<2;
169 i->crfd = IBF(w, 6, 8);
170 i->crfs = IBF(w, 11, 13);
171 i->bi = IBF(w, 11, 15);
172 i->bo = IBF(w, 6, 10);
173 i->crbd = IBF(w, 6, 10);
174 i->uimm = IBF(w, 16, 31); /* also d, simm */
175 i->fm = IBF(w, 7, 14);
176 i->fra = IBF(w, 11, 15);
177 i->frb = IBF(w, 16, 20);
178 i->frc = IBF(w, 21, 25);
179 i->frs = IBF(w, 6, 10);
180 i->frd = IBF(w, 6, 10);
181 i->crm = IBF(w, 12, 19);
182 i->li = IBF(w, 6, 29)<<2;
186 i->mb = IBF(w, 21, 25);
187 i->me = IBF(w, 26, 30);
188 i->nb = IBF(w, 16, 20);
189 i->op = IBF(w, 0, 5);
191 i->ra = IBF(w, 11, 15);
192 i->rb = IBF(w, 16, 20);
194 i->rs = IBF(w, 6, 10); /* also rd */
195 i->sh = IBF(w, 16, 20);
196 i->spr = IBF(w, 11, 20);
197 i->to = IBF(w, 6, 10);
198 i->imm = IBF(w, 16, 19);
199 i->xo = IBF(w, 21, 30); /* bits 21-30, 22-30, 26-30, or 30 (beware) */
200 i->immediate = i->simm;
211 mkinstr(ulong pc, Instr *i)
215 if(decode(pc, i) < 0)
218 * combine ADDIS/ORI (CAU/ORIL) into MOVW
220 if (i->op == 15 && i->ra==0) {
221 if(decode(pc+4, &x) < 0)
223 if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
224 i->immediate |= (x.immediate & 0xFFFF);
241 l.offset = i->immediate;
246 if (findsym(li, CTEXT, &s)<0 || findlsym(&s, l, &s)<0)
248 bprint(i, "%s%+ld(SP)", s.name, (long)i->immediate);
253 pglobal(Instr *i, long off, int anyoff, char *reg)
261 if(findsym(l, CANY, &s)>=0 && s.loc.type==LADDR &&
262 s.loc.addr-off < 4096 &&
263 (s.class == CDATA || s.class == CTEXT)) {
264 if(off==s.loc.addr && s.name[0]=='$'){
266 get4(mymap, s.loc.addr, &off1);
268 if(off1 && findsym(l, CANY, &s2)>=0 && s2.loc.type==LADDR && s2.loc.addr == off1){
269 bprint(i, "$%s%s", s2.name, reg);
273 bprint(i, "%s", s.name);
274 if (s.loc.addr != off)
275 bprint(i, "+%lux", off-s.loc.addr);
281 bprint(i, "%lux%s", off, reg);
288 if (i->ra == REGSP && plocal(i) >= 0)
290 if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->immediate, 0, "(SB)") >= 0)
293 bprint(i, "-%lx(R%d)", -i->simm, i->ra);
295 bprint(i, "%lux(R%d)", i->immediate, i->ra);
298 static char *tcrbits[] = {"LT", "GT", "EQ", "VS"};
299 static char *fcrbits[] = {"GE", "LE", "NE", "VC"};
301 typedef struct Opcode Opcode;
308 void (*f)(Opcode *, Instr *);
313 static void format(char *, Instr *, char *);
316 branch(Opcode *o, Instr *i)
321 bo = i->bo & ~1; /* ignore prediction bit */
322 if(bo==4 || bo==12 || bo==20) { /* simple forms */
325 sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
329 bprint(i, "CR(%d),", i->bi/4);
331 format("BR%L\t", i, 0);
334 else if(i->op == 19 && i->xo == 528)
335 format(0, i, "(CTR)");
336 else if(i->op == 19 && i->xo == 16)
337 format(0, i, "(LR)");
339 format(o->mnemonic, i, o->ken);
343 addi(Opcode *o, Instr *i)
345 if (i->op==14 && i->ra == 0)
346 format("MOVW", i, "%i,R%d");
347 else if (i->ra == REGSB) {
348 bprint(i, "MOVW\t$");
350 bprint(i, ",R%d", i->rd);
351 } else if(i->op==14 && i->simm < 0) {
352 bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra);
354 bprint(i, ",R%d", i->rd);
355 } else if(i->ra == i->rd) {
356 format(o->mnemonic, i, "%i");
357 bprint(i, ",R%d", i->rd);
359 format(o->mnemonic, i, o->ken);
363 addis(Opcode *o, Instr *i)
368 if (i->op==15 && i->ra == 0)
369 bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
370 else if (i->op==15 && i->ra == REGSB) {
371 bprint(i, "MOVW\t$");
373 bprint(i, ",R%d", i->rd);
374 } else if(i->op==15 && v < 0) {
375 bprint(i, "SUB\t$%d,R%d", -v, i->ra);
377 bprint(i, ",R%d", i->rd);
379 format(o->mnemonic, i, 0);
380 bprint(i, "\t$%ld,R%d", v, i->ra);
382 bprint(i, ",R%d", i->rd);
387 andi(Opcode *o, Instr *i)
390 format(o->mnemonic, i, "%I,R%d");
392 format(o->mnemonic, i, o->ken);
396 gencc(Opcode *o, Instr *i)
398 format(o->mnemonic, i, o->ken);
402 gen(Opcode *o, Instr *i)
404 format(o->mnemonic, i, o->ken);
406 bprint(i, " [illegal Rc]");
410 ldx(Opcode *o, Instr *i)
413 format(o->mnemonic, i, "(R%b),R%d");
415 format(o->mnemonic, i, "(R%b+R%a),R%d");
417 bprint(i, " [illegal Rc]");
421 stx(Opcode *o, Instr *i)
424 format(o->mnemonic, i, "R%d,(R%b)");
426 format(o->mnemonic, i, "R%d,(R%b+R%a)");
427 if(i->rc && i->xo != 150)
428 bprint(i, " [illegal Rc]");
432 fldx(Opcode *o, Instr *i)
435 format(o->mnemonic, i, "(R%b),F%d");
437 format(o->mnemonic, i, "(R%b+R%a),F%d");
439 bprint(i, " [illegal Rc]");
443 fstx(Opcode *o, Instr *i)
446 format(o->mnemonic, i, "F%d,(R%b)");
448 format(o->mnemonic, i, "F%d,(R%b+R%a)");
450 bprint(i, " [illegal Rc]");
454 dcb(Opcode *o, Instr *i)
457 format(o->mnemonic, i, "(R%b)");
459 format(o->mnemonic, i, "(R%b+R%a)");
461 bprint(i, " [illegal Rd]");
463 bprint(i, " [illegal Rc]");
467 lw(Opcode *o, Instr *i, char r)
469 bprint(i, "%s\t", o->mnemonic);
471 bprint(i, ",%c%d", r, i->rd);
475 load(Opcode *o, Instr *i)
481 fload(Opcode *o, Instr *i)
487 sw(Opcode *o, Instr *i, char r)
494 if (i->rs == REGSP) {
497 if (findsym(l, CTEXT, &s)>=0) {
500 l.offset = i->immediate;
501 if (findlsym(&s, l, &s) >= 0) {
502 bprint(i, "%s\t%c%d,%s-%d(SP)", m, r, i->rd,
503 s.name, i->immediate);
508 if (i->rs == REGSB && mach->sb) {
509 bprint(i, "%s\t%c%d,", m, r, i->rd);
514 format(m, i, "F%d,%l");
516 format(m, i, o->ken);
520 store(Opcode *o, Instr *i)
526 fstore(Opcode *o, Instr *i)
532 shifti(Opcode *o, Instr *i)
535 format(o->mnemonic, i, "$%k,R%a");
537 format(o->mnemonic, i, o->ken);
541 shift(Opcode *o, Instr *i)
544 format(o->mnemonic, i, "R%b,R%a");
546 format(o->mnemonic, i, o->ken);
550 add(Opcode *o, Instr *i)
553 format(o->mnemonic, i, "R%b,R%d");
554 else if (i->rd == i->rb)
555 format(o->mnemonic, i, "R%a,R%d");
557 format(o->mnemonic, i, o->ken);
561 sub(Opcode *o, Instr *i)
563 format(o->mnemonic, i, 0);
566 bprint(i, "\tR%d,R%d", i->ra, i->rb); /* subtract Ra from Rb */
568 bprint(i, ",R%d", i->rd);
570 bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
573 #define div power_div
576 div(Opcode *o, Instr *i)
578 format(o->mnemonic, i, 0);
580 bprint(i, "\tR%d,R%d", i->rb, i->ra);
582 bprint(i, "\t$%d,R%d", i->simm, i->ra);
584 bprint(i, ",R%d", i->rd);
588 and(Opcode *o, Instr *i)
593 format(o->mnemonic, i, "R%b,R%a");
594 else if (i->ra == i->rb)
595 format(o->mnemonic, i, "R%s,R%a");
597 format(o->mnemonic, i, o->ken);
601 format(o->mnemonic, i, "%I,R%a");
603 format(o->mnemonic, i, o->ken);
608 or(Opcode *o, Instr *i)
612 if (i->rs == 0 && i->ra == 0 && i->rb == 0)
614 else if (i->rs == i->rb)
615 format("MOVW", i, "R%b,R%a");
623 shifted(Opcode *o, Instr *i)
625 format(o->mnemonic, i, 0);
626 bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
628 bprint(i, "R%d", i->ra);
630 bprint(i, "R%d,R%d", i->rs, i->ra);
634 neg(Opcode *o, Instr *i)
637 format(o->mnemonic, i, "R%d");
639 format(o->mnemonic, i, o->ken);
642 static char ir2[] = "R%a,R%d"; /* reverse of IBM order */
643 static char ir3[] = "R%b,R%a,R%d";
644 static char ir3r[] = "R%a,R%b,R%d";
645 static char il3[] = "R%b,R%s,R%a";
646 static char il2u[] = "%I,R%a,R%d";
647 static char il3s[] = "$%k,R%s,R%a";
648 static char il2[] = "R%s,R%a";
649 static char icmp3[] = "R%a,R%b,%D";
650 static char cr3op[] = "%b,%a,%d";
651 static char ir2i[] = "%i,R%a,R%d";
652 static char fp2[] = "F%b,F%d";
653 static char fp3[] = "F%b,F%a,F%d";
654 static char fp3c[] = "F%c,F%a,F%d";
655 static char fp4[] = "F%a,F%c,F%b,F%d";
656 static char fpcmp[] = "F%a,F%b,%D";
657 static char ldop[] = "%l,R%d";
658 static char stop[] = "R%d,%l";
659 static char fldop[] = "%l,F%d";
660 static char fstop[] = "F%d,%l";
661 static char rlim[] = "R%b,R%s,$%z,R%a";
662 static char rlimi[] = "$%k,R%s,$%z,R%a";
664 #define OEM IBF(~0,22,30)
665 #define FP4 IBF(~0,26,30)
666 #define ALL ((ushort)~0)
669 10-26: crfD = rD>>2; rD&3 mbz
670 also, L bit (bit 10) mbz or selects 64-bit operands
673 static Opcode opcodes[] = {
674 {31, 360, OEM, "ABS%V%C", 0, ir2}, /* POWER */
676 {31, 266, OEM, "ADD%V%C", add, ir3},
677 {31, 10, OEM, "ADDC%V%C", add, ir3},
678 {31, 138, OEM, "ADDE%V%C", add, ir3},
679 {14, 0, 0, "ADD", addi, ir2i},
680 {12, 0, 0, "ADDC", addi, ir2i},
681 {13, 0, 0, "ADDCCC", addi, ir2i},
682 {15, 0, 0, "ADD", addis, 0},
683 {31, 234, OEM, "ADDME%V%C", gencc, ir2},
684 {31, 202, OEM, "ADDZE%V%C", gencc, ir2},
686 {31, 28, ALL, "AND%C", and, il3},
687 {31, 60, ALL, "ANDN%C", and, il3},
688 {28, 0, 0, "ANDCC", andi, il2u},
689 {29, 0, 0, "ANDCC", shifted, 0},
691 {18, 0, 0, "B%L", gencc, "%j"},
692 {16, 0, 0, "BC%L", branch, "%d,%a,%J"},
693 {19, 528, ALL, "BC%L", branch, "%d,%a,(CTR)"},
694 {19, 16, ALL, "BC%L", branch, "%d,%a,(LR)"},
696 {31, 531, ALL, "CLCS", gen, ir2}, /* POWER */
698 {31, 0, ALL, "CMP", 0, icmp3},
699 {11, 0, 0, "CMP", 0, "R%a,%i,%D"},
700 {31, 32, ALL, "CMPU", 0, icmp3},
701 {10, 0, 0, "CMPU", 0, "R%a,%I,%D"},
703 {31, 26, ALL, "CNTLZ%C", gencc, ir2},
705 {19, 257, ALL, "CRAND", gen, cr3op},
706 {19, 129, ALL, "CRANDN", gen, cr3op},
707 {19, 289, ALL, "CREQV", gen, cr3op},
708 {19, 225, ALL, "CRNAND", gen, cr3op},
709 {19, 33, ALL, "CRNOR", gen, cr3op},
710 {19, 449, ALL, "CROR", gen, cr3op},
711 {19, 417, ALL, "CRORN", gen, cr3op},
712 {19, 193, ALL, "CRXOR", gen, cr3op},
714 {31, 86, ALL, "DCBF", dcb, 0},
715 {31, 470, ALL, "DCBI", dcb, 0},
716 {31, 54, ALL, "DCBST", dcb, 0},
717 {31, 278, ALL, "DCBT", dcb, 0},
718 {31, 246, ALL, "DCBTST", dcb, 0},
719 {31, 1014, ALL, "DCBZ", dcb, 0},
721 {31, 331, OEM, "DIV%V%C", div, ir3}, /* POWER */
722 {31, 363, OEM, "DIVS%V%C", div, ir3}, /* POWER */
723 {31, 491, OEM, "DIVW%V%C", div, ir3},
724 {31, 459, OEM, "DIVWU%V%C", div, ir3},
726 {31, 264, OEM, "DOZ%V%C", gencc, ir3r}, /* POWER */
727 {9, 0, 0, "DOZ", gen, ir2i}, /* POWER */
729 {31, 310, ALL, "ECIWX", ldx, 0},
730 {31, 438, ALL, "ECOWX", stx, 0},
731 {31, 854, ALL, "EIEIO", gen, 0},
733 {31, 284, ALL, "EQV%C", gencc, il3},
735 {31, 954, ALL, "EXTSB%C", gencc, il2},
736 {31, 922, ALL, "EXTSH%C", gencc, il2},
738 {63, 264, ALL, "FABS%C", gencc, fp2},
739 {63, 21, ALL, "FADD%C", gencc, fp3},
740 {59, 21, ALL, "FADDS%C", gencc, fp3},
741 {63, 32, ALL, "FCMPO", gen, fpcmp},
742 {63, 0, ALL, "FCMPU", gen, fpcmp},
743 {63, 14, ALL, "FCTIW%C", gencc, fp2},
744 {63, 15, ALL, "FCTIWZ%C", gencc, fp2},
745 {63, 18, ALL, "FDIV%C", gencc, fp3},
746 {59, 18, ALL, "FDIVS%C", gencc, fp3},
747 {63, 29, FP4, "FMADD%C", gencc, fp4},
748 {59, 29, FP4, "FMADDS%C", gencc, fp4},
749 {63, 72, ALL, "FMOVD%C", gencc, fp2},
750 {63, 28, FP4, "FMSUB%C", gencc, fp4},
751 {59, 28, FP4, "FMSUBS%C", gencc, fp4},
752 {63, 25, FP4, "FMUL%C", gencc, fp3c},
753 {59, 25, FP4, "FMULS%C", gencc, fp3c},
754 {63, 136, ALL, "FNABS%C", gencc, fp2},
755 {63, 40, ALL, "FNEG%C", gencc, fp2},
756 {63, 31, FP4, "FNMADD%C", gencc, fp4},
757 {59, 31, FP4, "FNMADDS%C", gencc, fp4},
758 {63, 30, FP4, "FNMSUB%C", gencc, fp4},
759 {59, 30, FP4, "FNMSUBS%C", gencc, fp4},
760 {63, 12, ALL, "FRSP%C", gencc, fp2},
761 {63, 20, FP4, "FSUB%C", gencc, fp3},
762 {59, 20, FP4, "FSUBS%C", gencc, fp3},
764 {31, 982, ALL, "ICBI", dcb, 0},
765 {19, 150, ALL, "ISYNC", gen, 0},
767 {34, 0, 0, "MOVBZ", load, ldop},
768 {35, 0, 0, "MOVBZU", load, ldop},
769 {31, 119, ALL, "MOVBZU", ldx, 0},
770 {31, 87, ALL, "MOVBZ", ldx, 0},
771 {50, 0, 0, "FMOVD", fload, fldop},
772 {51, 0, 0, "FMOVDU", fload, fldop},
773 {31, 631, ALL, "FMOVDU", fldx, 0},
774 {31, 599, ALL, "FMOVD", fldx, 0},
775 {48, 0, 0, "FMOVS", load, fldop},
776 {49, 0, 0, "FMOVSU", load, fldop},
777 {31, 567, ALL, "FMOVSU", fldx, 0},
778 {31, 535, ALL, "FMOVS", fldx, 0},
779 {42, 0, 0, "MOVH", load, ldop},
780 {43, 0, 0, "MOVHU", load, ldop},
781 {31, 375, ALL, "MOVHU", ldx, 0},
782 {31, 343, ALL, "MOVH", ldx, 0},
783 {31, 790, ALL, "MOVHBR", ldx, 0},
784 {40, 0, 0, "MOVHZ", load, ldop},
785 {41, 0, 0, "MOVHZU", load, ldop},
786 {31, 311, ALL, "MOVHZU", ldx, 0},
787 {31, 279, ALL, "MOVHZ", ldx, 0},
788 {46, 0, 0, "MOVMW", load, ldop},
789 {31, 277, ALL, "LSCBX%C", ldx, 0}, /* POWER */
790 {31, 597, ALL, "LSW", gen, "(R%a),$%n,R%d"},
791 {31, 533, ALL, "LSW", ldx, 0},
792 {31, 20, ALL, "LWAR", ldx, 0},
793 {31, 534, ALL, "MOVWBR", ldx, 0},
794 {32, 0, 0, "MOVW", load, ldop},
795 {33, 0, 0, "MOVWU", load, ldop},
796 {31, 55, ALL, "MOVWU", ldx, 0},
797 {31, 23, ALL, "MOVW", ldx, 0},
799 {31, 29, ALL, "MASKG%C", gencc, "R%s:R%b,R%d"}, /* POWER */
800 {31, 541, ALL, "MASKIR%C", gencc, "R%s,R%b,R%a"}, /* POWER */
802 {19, 0, ALL, "MOVFL", gen, "%S,%D"},
803 {63, 64, ALL, "MOVCRFS", gen, "%S,%D"},
804 {31, 512, ALL, "MOVW", gen, "XER,%D"},
805 {31, 19, ALL, "MOVW", gen, "CR,R%d"},
807 {63, 583, ALL, "MOVW%C", gen, "FPSCR, F%d"}, /* mffs */
808 {31, 83, ALL, "MOVW", gen, "MSR,R%d"},
809 {31, 339, ALL, "MOVW", gen, "%P,R%d"},
810 {31, 595, ALL, "MOVW", gen, "SEG(%a),R%d"},
811 {31, 659, ALL, "MOVW", gen, "SEG(R%b),R%d"},
812 {31, 144, ALL, "MOVFL", gen, "R%s,%m,CR"},
813 {63, 70, ALL, "MTFSB0%C", gencc, "%D"},
814 {63, 38, ALL, "MTFSB1%C", gencc, "%D"},
815 {63, 711, ALL, "MOVFL%C", gencc, "F%b,%M,FPSCR"}, /* mtfsf */
816 {63, 134, ALL, "MOVFL%C", gencc, "%K,%D"},
817 {31, 146, ALL, "MOVW", gen, "R%s,MSR"},
818 {31, 467, ALL, "MOVW", gen, "R%s,%P"},
819 {31, 210, ALL, "MOVW", gen, "R%s,SEG(%a)"},
820 {31, 242, ALL, "MOVW", gen, "R%s,SEG(R%b)"},
822 {31, 107, OEM, "MUL%V%C", gencc, ir3}, /* POWER */
823 {31, 75, ALL, "MULHW%C", gencc, ir3}, /* POWER */
824 {31, 11, ALL, "MULHWU%C", gencc, ir3}, /* POWER */
826 {31, 235, OEM, "MULLW%V%C", gencc, ir3},
827 {7, 0, 0, "MULLW", div, "%i,R%a,R%d"},
829 {31, 488, OEM, "NABS%V%C", neg, ir2}, /* POWER */
831 {31, 476, ALL, "NAND%C", gencc, il3},
832 {31, 104, OEM, "NEG%V%C", neg, ir2},
833 {31, 124, ALL, "NOR%C", gencc, il3},
834 {31, 444, ALL, "OR%C", or, il3},
835 {31, 412, ALL, "ORN%C", or, il3},
836 {24, 0, 0, "OR", and, "%I,R%d,R%a"},
837 {25, 0, 0, "OR", shifted, 0},
839 {19, 50, ALL, "RFI", gen, 0},
841 {22, 0, 0, "RLMI%C", gencc, rlim}, /* POWER */
842 {20, 0, 0, "RLWMI%C", gencc, rlimi},
843 {21, 0, 0, "RLWNM%C", gencc, rlimi},
844 {23, 0, 0, "RLWNM%C", gencc, rlim},
846 {31, 537, ALL, "RRIB%C", gencc, il3}, /* POWER */
848 {17, 1, ALL, "SYSCALL", gen, 0},
850 {31, 153, ALL, "SLE%C", shift, il3}, /* POWER */
851 {31, 217, ALL, "SLEQ%C", shift, il3}, /* POWER */
852 {31, 184, ALL, "SLQ%C", shifti, il3s}, /* POWER */
853 {31, 248, ALL, "SLLQ%C", shifti, il3s}, /* POWER */
854 {31, 216, ALL, "SLLQ%C", shift, il3}, /* POWER */
855 {31, 152, ALL, "SLQ%C", shift, il3}, /* POWER */
857 {31, 24, ALL, "SLW%C", shift, il3},
859 {31, 920, ALL, "SRAQ%C", shift, il3}, /* POWER */
860 {31, 952, ALL, "SRAQ%C", shifti, il3s}, /* POWER */
862 {31, 792, ALL, "SRAW%C", shift, il3},
863 {31, 824, ALL, "SRAW%C", shifti, il3s},
865 {31, 665, ALL, "SRE%C", shift, il3}, /* POWER */
866 {31, 921, ALL, "SREA%C", shift, il3}, /* POWER */
867 {31, 729, ALL, "SREQ%C", shift, il3}, /* POWER */
868 {31, 696, ALL, "SRQ%C", shifti, il3s}, /* POWER */
869 {31, 760, ALL, "SRLQ%C", shifti, il3s}, /* POWER */
870 {31, 728, ALL, "SRLQ%C", shift, il3}, /* POWER */
871 {31, 664, ALL, "SRQ%C", shift, il3}, /* POWER */
873 {31, 536, ALL, "SRW%C", shift, il3},
875 {38, 0, 0, "MOVB", store, stop},
876 {39, 0, 0, "MOVBU", store, stop},
877 {31, 247, ALL, "MOVBU", stx, 0},
878 {31, 215, ALL, "MOVB", stx, 0},
879 {54, 0, 0, "FMOVD", fstore, fstop},
880 {55, 0, 0, "FMOVDU", fstore, fstop},
881 {31, 759, ALL, "FMOVDU", fstx, 0},
882 {31, 727, ALL, "FMOVD", fstx, 0},
883 {52, 0, 0, "FMOVS", fstore, fstop},
884 {53, 0, 0, "FMOVSU", fstore, fstop},
885 {31, 695, ALL, "FMOVSU", fstx, 0},
886 {31, 663, ALL, "FMOVS", fstx, 0},
887 {44, 0, 0, "MOVH", store, stop},
888 {31, 918, ALL, "MOVHBR", stx, 0},
889 {45, 0, 0, "MOVHU", store, stop},
890 {31, 439, ALL, "MOVHU", stx, 0},
891 {31, 407, ALL, "MOVH", stx, 0},
892 {47, 0, 0, "MOVMW", store, stop},
893 {31, 725, ALL, "STSW", gen, "R%d,$%n,(R%a)"},
894 {31, 661, ALL, "STSW", stx, 0},
895 {36, 0, 0, "MOVW", store, stop},
896 {31, 662, ALL, "MOVWBR", stx, 0},
897 {31, 150, ALL, "STWCCC", stx, 0},
898 {37, 0, 0, "MOVWU", store, stop},
899 {31, 183, ALL, "MOVWU", stx, 0},
900 {31, 151, ALL, "MOVW", stx, 0},
902 {31, 40, OEM, "SUB%V%C", sub, ir3},
903 {31, 8, OEM, "SUBC%V%C", sub, ir3},
904 {31, 136, OEM, "SUBE%V%C", sub, ir3},
905 {8, 0, 0, "SUBC", gen, "R%a,%i,R%d"},
906 {31, 232, OEM, "SUBME%V%C", sub, ir2},
907 {31, 200, OEM, "SUBZE%V%C", sub, ir2},
909 {31, 598, ALL, "SYNC", gen, 0},
910 {31, 370, ALL, "TLBIA", gen, 0},
911 {31, 306, ALL, "TLBIE", gen, "R%b"},
912 {31, 1010, ALL, "TLBLI", gen, "R%b"},
913 {31, 978, ALL, "TLBLD", gen, "R%b"},
914 {31, 4, ALL, "TW", gen, "%d,R%a,R%b"},
915 {3, 0, 0, "TW", gen, "%d,R%a,%i"},
917 {31, 316, ALL, "XOR", and, il3},
918 {26, 0, 0, "XOR", and, il2u},
919 {27, 0, 0, "XOR", shifted, 0},
924 typedef struct Spr Spr;
930 static Spr sprname[] = {
980 format(char *mnemonic, Instr *i, char *f)
986 format(0, i, mnemonic);
1008 bprint(i, "%d", i->ra);
1012 bprint(i, "%d", i->rb);
1016 bprint(i, "%d", i->frc);
1021 bprint(i, "%d", i->rd);
1026 bprint(i, "CR(INVAL:%d)", i->ra);
1027 else if(i->op == 63)
1028 bprint(i, "FPSCR(%d)", i->crfs);
1030 bprint(i, "CR(%d)", i->crfs);
1035 bprint(i, "CR(INVAL:%d)", i->rd);
1036 else if(i->op == 63)
1037 bprint(i, "FPSCR(%d)", i->crfd);
1039 bprint(i, "CR(%d)", i->crfd);
1044 bprint(i, "-%lx(R%d)", -i->simm, i->ra);
1046 bprint(i, "%lx(R%d)", i->simm, i->ra);
1050 bprint(i, "$%ld", i->simm);
1054 bprint(i, "$%lx", i->uimm);
1058 bprint(i, "[%lux]", i->w0);
1062 n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
1063 for(s=0; sprname[s].name; s++)
1064 if(sprname[s].n == n)
1066 if(sprname[s].name) {
1068 bprint(i, sprname[s].name);
1070 bprint(i, "SPR(%s)", sprname[s].name);
1072 bprint(i, "SPR(%d)", n);
1076 bprint(i, "%d", i->nb==0? 32: i->nb); /* eg, pg 10-103 */
1080 bprint(i, "%lx", i->crm);
1084 bprint(i, "%lx", i->fm);
1089 mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
1091 mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
1092 bprint(i, "%lux", mask);
1096 bprint(i, "%d", i->sh);
1100 bprint(i, "$%x", i->imm);
1110 pglobal(i, i->li, 1, "(SB)");
1112 pglobal(i, i->addr+i->li, 1, "");
1117 pglobal(i, i->bd, 1, "(SB)");
1119 pglobal(i, i->addr+i->bd, 1, "");
1127 bprint(i, "%%%c", *f);
1134 printins(Map *map, ulong pc, char *buf, int n)
1140 memset(&i, 0, sizeof(i));
1143 if(mkinstr(pc, &i) < 0)
1145 for(o = opcodes; o->mnemonic != 0; o++)
1146 if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
1150 format(o->mnemonic, &i, o->ken);
1153 bprint(&i, "unknown %lux", i.w0);
1158 powerdas(Map *map, u64int pc, char modifier, char *buf, int n)
1161 return printins(map, pc, buf, n);
1165 powerhexinst(Map *map, u64int pc, char *buf, int n)
1170 memset(&instr, 0, sizeof(instr));
1172 instr.end = buf+n-1;
1173 if (mkinstr(pc, &instr) < 0)
1175 if (instr.end-instr.curr > 8)
1176 instr.curr = _hexify(instr.curr, instr.w0, 7);
1177 if (instr.end-instr.curr > 9 && instr.size == 2) {
1178 *instr.curr++ = ' ';
1179 instr.curr = _hexify(instr.curr, instr.w1, 7);
1182 return instr.size*4;
1186 powerinstlen(Map *map, u64int pc)
1191 if (mkinstr(pc, &i) < 0)
1197 powerfoll(Map *map, Regs *regs, u64int pc, u64int *foll)
1203 if (mkinstr(pc, &i) < 0)
1211 case 18: /* branch */
1217 case 16: /* conditional branch */
1223 case 19: /* conditional branch to register */
1229 return 1; /* not a branch */
1230 if(rget(regs, reg, &foll[0]) < 0)
1239 #define REGOFF(x) (ulong) (&((struct Ureg *) 0)->x)
1241 #define SP REGOFF(r1)
1242 #define PC REGOFF(pc)
1243 #define R3 REGOFF(r3) /* return reg */
1244 #define LR REGOFF(lr)
1245 #define R31 REGOFF(r31)
1246 #define FP_REG(x) (R31+4+8*(x))
1248 #define REGSIZE sizeof(struct Ureg)
1249 #define FPREGSIZE (8*33)
1251 Regdesc powerreglist[] =
1253 {"CAUSE", REGOFF(cause), RINT|RRDONLY, 'X'},
1254 {"SRR1", REGOFF(srr1), RINT|RRDONLY, 'X'},
1255 {"PC", REGOFF(pc), RINT, 'X'},
1256 {"LR", REGOFF(lr), RINT, 'X'},
1257 {"CR", REGOFF(cr), RINT, 'X'},
1258 {"XER", REGOFF(xer), RINT, 'X'},
1259 {"CTR", REGOFF(ctr), RINT, 'X'},
1260 {"PC", PC, RINT, 'X'},
1261 {"SP", SP, RINT, 'X'},
1262 {"R0", REGOFF(r0), RINT, 'X'},
1264 {"R2", REGOFF(r2), RINT, 'X'},
1265 {"R3", REGOFF(r3), RINT, 'X'},
1266 {"R4", REGOFF(r4), RINT, 'X'},
1267 {"R5", REGOFF(r5), RINT, 'X'},
1268 {"R6", REGOFF(r6), RINT, 'X'},
1269 {"R7", REGOFF(r7), RINT, 'X'},
1270 {"R8", REGOFF(r8), RINT, 'X'},
1271 {"R9", REGOFF(r9), RINT, 'X'},
1272 {"R10", REGOFF(r10), RINT, 'X'},
1273 {"R11", REGOFF(r11), RINT, 'X'},
1274 {"R12", REGOFF(r12), RINT, 'X'},
1275 {"R13", REGOFF(r13), RINT, 'X'},
1276 {"R14", REGOFF(r14), RINT, 'X'},
1277 {"R15", REGOFF(r15), RINT, 'X'},
1278 {"R16", REGOFF(r16), RINT, 'X'},
1279 {"R17", REGOFF(r17), RINT, 'X'},
1280 {"R18", REGOFF(r18), RINT, 'X'},
1281 {"R19", REGOFF(r19), RINT, 'X'},
1282 {"R20", REGOFF(r20), RINT, 'X'},
1283 {"R21", REGOFF(r21), RINT, 'X'},
1284 {"R22", REGOFF(r22), RINT, 'X'},
1285 {"R23", REGOFF(r23), RINT, 'X'},
1286 {"R24", REGOFF(r24), RINT, 'X'},
1287 {"R25", REGOFF(r25), RINT, 'X'},
1288 {"R26", REGOFF(r26), RINT, 'X'},
1289 {"R27", REGOFF(r27), RINT, 'X'},
1290 {"R28", REGOFF(r28), RINT, 'X'},
1291 {"R29", REGOFF(r29), RINT, 'X'},
1292 {"R30", REGOFF(r30), RINT, 'X'},
1293 {"R31", REGOFF(r31), RINT, 'X'},
1294 {"VRSAVE", REGOFF(vrsave), RINT, 'X'},
1295 {"F0", FP_REG(0), RFLT, 'F'},
1296 {"F1", FP_REG(1), RFLT, 'F'},
1297 {"F2", FP_REG(2), RFLT, 'F'},
1298 {"F3", FP_REG(3), RFLT, 'F'},
1299 {"F4", FP_REG(4), RFLT, 'F'},
1300 {"F5", FP_REG(5), RFLT, 'F'},
1301 {"F6", FP_REG(6), RFLT, 'F'},
1302 {"F7", FP_REG(7), RFLT, 'F'},
1303 {"F8", FP_REG(8), RFLT, 'F'},
1304 {"F9", FP_REG(9), RFLT, 'F'},
1305 {"F10", FP_REG(10), RFLT, 'F'},
1306 {"F11", FP_REG(11), RFLT, 'F'},
1307 {"F12", FP_REG(12), RFLT, 'F'},
1308 {"F13", FP_REG(13), RFLT, 'F'},
1309 {"F14", FP_REG(14), RFLT, 'F'},
1310 {"F15", FP_REG(15), RFLT, 'F'},
1311 {"F16", FP_REG(16), RFLT, 'F'},
1312 {"F17", FP_REG(17), RFLT, 'F'},
1313 {"F18", FP_REG(18), RFLT, 'F'},
1314 {"F19", FP_REG(19), RFLT, 'F'},
1315 {"F20", FP_REG(20), RFLT, 'F'},
1316 {"F21", FP_REG(21), RFLT, 'F'},
1317 {"F22", FP_REG(22), RFLT, 'F'},
1318 {"F23", FP_REG(23), RFLT, 'F'},
1319 {"F24", FP_REG(24), RFLT, 'F'},
1320 {"F25", FP_REG(25), RFLT, 'F'},
1321 {"F26", FP_REG(26), RFLT, 'F'},
1322 {"F27", FP_REG(27), RFLT, 'F'},
1323 {"F28", FP_REG(28), RFLT, 'F'},
1324 {"F29", FP_REG(29), RFLT, 'F'},
1325 {"F30", FP_REG(30), RFLT, 'F'},
1326 {"F31", FP_REG(31), RFLT, 'F'},
1327 {"FPSCR", FP_REG(32)+4, RFLT, 'X'},
1331 static char *powerwindregs[] =
1340 powerunwind(Map *map, Regs *regs, u64int *next, Symbol *sym)
1343 * This is tremendously hard. The best we're going to
1344 * do without better debugger support is trace through
1345 * the stack frame links and pull the link registers out of 8(R1).
1346 * Anything more requires knowing which registers got saved,
1347 * and the compiler appears not to record that. Gdb appears
1348 * to disassemble the function prologues in order to figure
1352 /* if in this function, no good - go to saved one. */
1353 /* set next[sp] to *cur[sp] */
1354 /* set next[pc] to lr */
1355 /* set next[lr] to lr */
1357 werrstr("powerunwind not implemented");
1361 /* the machine description */
1365 MPOWER, /* machine type */
1366 powerreglist, /* register set */
1367 REGSIZE, /* number of bytes in register set */
1368 FPREGSIZE, /* number of bytes in FP register set */
1369 "PC", /* name of PC */
1370 "SP", /* name of SP */
1372 "LR", /* name of link register */
1373 "setSB", /* static base register name */
1375 0x1000, /* page size */
1376 0x80000000, /* kernel base */
1377 0, /* kernel text mask */
1378 4, /* quantization of pc */
1384 powerwindregs, /* locations unwound in stack trace */
1387 {0x02, 0x8F, 0xFF, 0xFF}, /* break point */ /* BUG */
1390 powerfoll, /* following addresses */
1391 powerexcep, /* print exception */
1392 powerunwind, /* stack unwind */
1394 beswap2, /* convert short to local byte order */
1395 beswap4, /* convert long to local byte order */
1396 beswap8, /* convert vlong to local byte order */
1397 beieeeftoa32, /* single precision float pointer */
1398 beieeeftoa64, /* double precision float pointer */
1399 beieeeftoa80, /* long double precision floating point */
1401 powerdas, /* dissembler */
1402 powerdas, /* plan9-format disassembler */
1403 0, /* commercial disassembler */
1404 powerhexinst, /* print instruction */
1405 powerinstlen, /* instruction size calculation */