#include #include #include "mach.h" #include "uregq.h" #define STARTSYM "_main" #define PROFSYM "_mainp" #define FRAMENAME ".frame" /* * PowerPC-specific debugger interface * forsyth@vitanuova.com */ static char *powerexcep(Map*, Rgetter); static int powerfoll(Map*, ulong, Rgetter, ulong*); static int powerinst(Map*, ulong, char, char*, int); static int powerinstlen(Map*, ulong); static int powerdas(Map*, ulong, char*, int); static int powertrace(Map*, ulong, ulong, ulong, Tracer); /* * Machine description */ Machdata powermach = { {0x07f, 0xe0, 0x00, 0x08}, /* breakpoint (tw 31,r0,r0) */ 4, /* break point size */ beswab, /* convert short to local byte order */ beswal, /* convert long to local byte order */ beswav, /* vlong to local byte order */ powertrace, /* print C traceback */ riscframe, /* frame finder */ powerexcep, /* print exception */ 0, /* breakpoint fixup */ beieeesftos, /* single precision float printer */ beieeedftos, /* double precisioin float printer */ powerfoll, /* following addresses */ powerinst, /* print instruction */ powerdas, /* dissembler */ powerinstlen, /* instruction size */ }; static char *excname[] = { "reserved 0", "system reset", "machine check", "data access", "instruction access", "external interrupt", "alignment", "program exception", "floating-point unavailable", "decrementer", "i/o controller interface error", "reserved B", "system call", "trace trap", "floating point assist", "reserved", "ITLB miss", "DTLB load miss", "DTLB store miss", "instruction address breakpoint" "SMI interrupt" "reserved 15", "reserved 16", "reserved 17", "reserved 18", "reserved 19", "reserved 1A", /* the following are made up on a program exception */ "floating point exception", /* 1B: FPEXC */ "illegal instruction", /* 1C */ "privileged instruction", /* 1D */ "trap", /* 1E */ "illegal operation", /* 1F */ "breakpoint", /* 20 */ }; static char* powerexcep(Map *map, Rgetter rget) { long c; static char buf[32]; c = (*rget)(map, "CAUSE") >> 8; if(c < nelem(excname)) return excname[c]; sprint(buf, "unknown trap #%x", c); return buf; } /* * disassemble PowerPC opcodes */ #define REGSP 1 /* should come from q.out.h, but there's a clash */ #define REGSB 2 static Map *mymap; /* * ibm conventions for these: bit 0 is top bit * from table 10-1 */ typedef struct { uchar aa; /* bit 30 */ uchar crba; /* bits 11-15 */ uchar crbb; /* bits 16-20 */ long bd; /* bits 16-29 */ uchar crfd; /* bits 6-8 */ uchar crfs; /* bits 11-13 */ uchar bi; /* bits 11-15 */ uchar bo; /* bits 6-10 */ uchar crbd; /* bits 6-10 */ /*union {*/ short d; /* bits 16-31 */ short simm; ushort uimm; /*};*/ uchar fm; /* bits 7-14 */ uchar fra; /* bits 11-15 */ uchar frb; /* bits 16-20 */ uchar frc; /* bits 21-25 */ uchar frs; /* bits 6-10 */ uchar frd; /* bits 6-10 */ uchar crm; /* bits 12-19 */ long li; /* bits 6-29 || b'00' */ uchar lk; /* bit 31 */ uchar mb; /* bits 21-25 */ uchar me; /* bits 26-30 */ uchar nb; /* bits 16-20 */ uchar op; /* bits 0-5 */ uchar oe; /* bit 21 */ uchar ra; /* bits 11-15 */ uchar rb; /* bits 16-20 */ uchar rc; /* bit 31 */ /* union {*/ uchar rs; /* bits 6-10 */ uchar rd; /*};*/ uchar sh; /* bits 16-20 */ ushort spr; /* bits 11-20 */ uchar to; /* bits 6-10 */ uchar imm; /* bits 16-19 */ ushort xo; /* bits 21-30, 22-30, 26-30, or 30 (beware) */ long immediate; long w0; long w1; ulong addr; /* pc of instruction */ short target; char *curr; /* current fill level in output buffer */ char *end; /* end of buffer */ int size; /* number of longs in instr */ char *err; /* errmsg */ } Instr; #define IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1)))) #define IB(v,b) IBF((v),(b),(b)) static void bprint(Instr *i, char *fmt, ...) { va_list arg; va_start(arg, fmt); i->curr = doprint(i->curr, i->end, fmt, arg); va_end(arg); } static int decode(ulong pc, Instr *i) { long w; if (get4(mymap, pc, &w) < 0) { werrstr("can't read instruction: %r"); return -1; } i->aa = IB(w, 30); i->crba = IBF(w, 11, 15); i->crbb = IBF(w, 16, 20); i->bd = IBF(w, 16, 29)<<2; if(i->bd & 0x8000) i->bd |= ~0L<<16; i->crfd = IBF(w, 6, 8); i->crfs = IBF(w, 11, 13); i->bi = IBF(w, 11, 15); i->bo = IBF(w, 6, 10); i->crbd = IBF(w, 6, 10); i->uimm = IBF(w, 16, 31); /* also d, simm */ i->simm = i->uimm; i->d = i->uimm; i->fm = IBF(w, 7, 14); i->fra = IBF(w, 11, 15); i->frb = IBF(w, 16, 20); i->frc = IBF(w, 21, 25); i->frs = IBF(w, 6, 10); i->frd = IBF(w, 6, 10); i->crm = IBF(w, 12, 19); i->li = IBF(w, 6, 29)<<2; if(IB(w, 6)) i->li |= ~0<<25; i->lk = IB(w, 31); i->mb = IBF(w, 21, 25); i->me = IBF(w, 26, 30); i->nb = IBF(w, 16, 20); i->op = IBF(w, 0, 5); i->oe = IB(w, 21); i->ra = IBF(w, 11, 15); i->rb = IBF(w, 16, 20); i->rc = IB(w, 31); i->rs = IBF(w, 6, 10); /* also rd */ i->rd = i->rs; i->sh = IBF(w, 16, 20); i->spr = IBF(w, 11, 20); i->to = IBF(w, 6, 10); i->imm = IBF(w, 16, 19); i->xo = IBF(w, 21, 30); /* bits 21-30, 22-30, 26-30, or 30 (beware) */ i->immediate = i->simm; if(i->op == 15) i->immediate <<= 16; i->w0 = w; i->target = -1; i->addr = pc; i->size = 1; return 1; } static int mkinstr(ulong pc, Instr *i) { Instr x; if(decode(pc, i) < 0) return -1; /* * combine ADDIS/ORI (CAU/ORIL) into MOVW */ if (i->op == 15 && i->ra==0) { if(decode(pc+4, &x) < 0) return -1; if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) { i->immediate |= (x.immediate & 0xFFFF); i->w1 = x.w0; i->target = x.rd; i->size++; return 1; } } if (i->op == 15 && i->ra==REGSB && mach->sb) { if(decode(pc+4, &x) < 0) return -1; if (x.op >= 32 && x.op < 54 && i->rd == x.ra) { i->op = x.op; i->ra = REGSB; i->rs = i->rd = x.rd; i->immediate += x.simm; i->w1 = x.w0; i->target = x.rd; i->size++; return 1; } } return 1; } static int plocal(Instr *i) { int offset; Symbol s; if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) return -1; offset = s.value - i->immediate; if (offset > 0) { if(getauto(&s, offset, CAUTO, &s)) { bprint(i, "%s+%d(SP)", s.name, s.value); return 1; } } else { if (getauto(&s, -offset-4, CPARAM, &s)) { bprint(i, "%s+%d(FP)", s.name, -offset); return 1; } } return -1; } static int pglobal(Instr *i, long off, int anyoff, char *reg) { Symbol s, s2; long off1; if(findsym(off, CANY, &s) && strcmp(s.name, ".string") != 0 && (ulong)(off-s.value) < 4096 && (s.class == CDATA || s.class == CTEXT)) { if(off==s.value && s.name[0]=='$'){ off1 = 0; get4(mymap, s.value, &off1); if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){ bprint(i, "$%s%s", s2.name, reg); return 1; } } bprint(i, "%s", s.name); if (s.value != off) bprint(i, "+%lux", off-s.value); bprint(i, reg); return 1; } if(!anyoff) return 0; bprint(i, "%lux%s", off, reg); return 1; } static void address(Instr *i) { if (i->ra == REGSP && plocal(i) >= 0) return; if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->immediate, 0, "(SB)") > 0) return; if(i->immediate < 0) bprint(i, "-%lx", -i->immediate); else bprint(i, "%lux", i->immediate); if (i->ra == REGSB && mach->sb) bprint(i, "(SB)"); else bprint(i, "(R%d)", i->ra); } static char *tcrbits[] = {"LT", "GT", "EQ", "VS"}; static char *fcrbits[] = {"GE", "LE", "NE", "VC"}; typedef struct Opcode Opcode; struct Opcode { uchar op; ushort xo; ushort xomask; char *mnemonic; void (*f)(Opcode *, Instr *); char *ken; int flags; }; static void format(char *, Instr *, char *); static void branch(Opcode *o, Instr *i) { char buf[8]; int bo, bi; bo = i->bo & ~1; /* ignore prediction bit */ if(bo==4 || bo==12 || bo==20) { /* simple forms */ if(bo != 20) { bi = i->bi&3; sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]); format(buf, i, 0); bprint(i, "\t"); if(i->bi > 4) bprint(i, "CR(%d),", i->bi/4); } else format("BR%L\t", i, 0); if(i->op == 16) format(0, i, "%J"); else if(i->op == 19 && i->xo == 528) format(0, i, "(CTR)"); else if(i->op == 19 && i->xo == 16) format(0, i, "(LR)"); } else format(o->mnemonic, i, o->ken); } static void addi(Opcode *o, Instr *i) { if (i->op==14 && i->ra == 0) format("MOVW", i, "%i,R%d"); else if (i->ra == REGSP || i->ra == REGSB) { bprint(i, "MOVW\t$"); address(i); bprint(i, ",R%d", i->rd); } else if(i->op==14 && i->simm < 0) { bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra); if(i->rd != i->ra) bprint(i, ",R%d", i->rd); } else if(i->ra == i->rd) { format(o->mnemonic, i, "%i"); bprint(i, ",R%d", i->rd); } else format(o->mnemonic, i, o->ken); } static void addis(Opcode *o, Instr *i) { long v; v = i->immediate; if (i->op==15 && i->ra == 0) { bprint(i, "MOVW\t$"); pglobal(i, i->immediate, 1, ""); bprint(i, ",R%d", i->rd); } else if (i->op==15 && i->ra == REGSB && mach->sb) { bprint(i, "MOVW\t$"); address(i); bprint(i, ",R%d", i->rd); /* how about auto/param addresses? */ } else if(i->op==15 && v < 0) { bprint(i, "SUB\t$%d,R%d", -v, i->ra); if(i->rd != i->ra) bprint(i, ",R%d", i->rd); } else { format(o->mnemonic, i, 0); bprint(i, "\t$%ld,R%d", v, i->ra); if(i->rd != i->ra) bprint(i, ",R%d", i->rd); } } static void andi(Opcode *o, Instr *i) { if (i->ra == i->rs) format(o->mnemonic, i, "%I,R%d"); else format(o->mnemonic, i, o->ken); } static void gencc(Opcode *o, Instr *i) { format(o->mnemonic, i, o->ken); } static void gen(Opcode *o, Instr *i) { format(o->mnemonic, i, o->ken); if (i->rc) bprint(i, " [illegal Rc]"); } static void ldx(Opcode *o, Instr *i) { if(i->ra == 0) format(o->mnemonic, i, "(R%b),R%d"); else format(o->mnemonic, i, "(R%b+R%a),R%d"); if(i->rc) bprint(i, " [illegal Rc]"); } static void stx(Opcode *o, Instr *i) { if(i->ra == 0) format(o->mnemonic, i, "R%d,(R%b)"); else format(o->mnemonic, i, "R%d,(R%b+R%a)"); if(i->rc && i->xo != 150) bprint(i, " [illegal Rc]"); } static void fldx(Opcode *o, Instr *i) { if(i->ra == 0) format(o->mnemonic, i, "(R%b),F%d"); else format(o->mnemonic, i, "(R%b+R%a),F%d"); if(i->rc) bprint(i, " [illegal Rc]"); } static void fstx(Opcode *o, Instr *i) { if(i->ra == 0) format(o->mnemonic, i, "F%d,(R%b)"); else format(o->mnemonic, i, "F%d,(R%b+R%a)"); if(i->rc) bprint(i, " [illegal Rc]"); } static void dcb(Opcode *o, Instr *i) { if(i->ra == 0) format(o->mnemonic, i, "(R%b)"); else format(o->mnemonic, i, "(R%b+R%a)"); if(i->rd) bprint(i, " [illegal Rd]"); if(i->rc) bprint(i, " [illegal Rc]"); } static void lw(Opcode *o, Instr *i, char r) { bprint(i, "%s\t", o->mnemonic); address(i); bprint(i, ",%c%d", r, i->rd); } static void load(Opcode *o, Instr *i) { lw(o, i, 'R'); } static void fload(Opcode *o, Instr *i) { lw(o, i, 'F'); } static void sw(Opcode *o, Instr *i, char r) { int offset; char *m; Symbol s; m = o->mnemonic; if ((i->ra == REGSP) || (i->ra == REGSB && mach->sb)) { bprint(i, "%s\t%c%d,", m, r, i->rs); address(i); return; } if (r == 'F') format(m, i, "F%d,%l"); else format(m, i, o->ken); } static void store(Opcode *o, Instr *i) { sw(o, i, 'R'); } static void fstore(Opcode *o, Instr *i) { sw(o, i, 'F'); } static void shifti(Opcode *o, Instr *i) { if (i->ra == i->rs) format(o->mnemonic, i, "$%k,R%a"); else format(o->mnemonic, i, o->ken); } static void shift(Opcode *o, Instr *i) { if (i->ra == i->rs) format(o->mnemonic, i, "R%b,R%a"); else format(o->mnemonic, i, o->ken); } static void add(Opcode *o, Instr *i) { if (i->rd == i->ra) format(o->mnemonic, i, "R%b,R%d"); else if (i->rd == i->rb) format(o->mnemonic, i, "R%a,R%d"); else format(o->mnemonic, i, o->ken); } static void sub(Opcode *o, Instr *i) { format(o->mnemonic, i, 0); if(i->op == 31) { bprint(i, "\tR%d,R%d", i->ra, i->rb); /* subtract Ra from Rb */ if(i->rd != i->rb) bprint(i, ",R%d", i->rd); } else bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd); } static void qdiv(Opcode *o, Instr *i) { format(o->mnemonic, i, 0); if(i->op == 31) bprint(i, "\tR%d,R%d", i->rb, i->ra); else bprint(i, "\t$%d,R%d", i->simm, i->ra); if(i->ra != i->rd) bprint(i, ",R%d", i->rd); } static void and(Opcode *o, Instr *i) { if (i->op == 31) { /* Rb,Rs,Ra */ if (i->ra == i->rs) format(o->mnemonic, i, "R%b,R%a"); else if (i->ra == i->rb) format(o->mnemonic, i, "R%s,R%a"); else format(o->mnemonic, i, o->ken); } else { /* imm,Rs,Ra */ if (i->ra == i->rs) format(o->mnemonic, i, "%I,R%a"); else format(o->mnemonic, i, o->ken); } } static void or(Opcode *o, Instr *i) { if (i->op == 31) { /* Rb,Rs,Ra */ if (i->rs == 0 && i->ra == 0 && i->rb == 0) format("NOP", i, 0); else if (i->rs == i->rb) format("MOVW", i, "R%b,R%a"); else and(o, i); } else and(o, i); } static void shifted(Opcode *o, Instr *i) { format(o->mnemonic, i, 0); bprint(i, "\t$%lux,", (ulong)i->uimm<<16); if (i->rs == i->ra) bprint(i, "R%d", i->ra); else bprint(i, "R%d,R%d", i->rs, i->ra); } static void neg(Opcode *o, Instr *i) { if (i->rd == i->ra) format(o->mnemonic, i, "R%d"); else format(o->mnemonic, i, o->ken); } static char ir2[] = "R%a,R%d"; /* reverse of IBM order */ static char ir3[] = "R%b,R%a,R%d"; static char ir3r[] = "R%a,R%b,R%d"; static char il3[] = "R%b,R%s,R%a"; static char il2u[] = "%I,R%s,R%a"; static char il3s[] = "$%k,R%s,R%a"; static char il2[] = "R%s,R%a"; static char icmp3[] = "R%a,R%b,%D"; static char cr3op[] = "%b,%a,%d"; static char ir2i[] = "%i,R%a,R%d"; static char fp2[] = "F%b,F%d"; static char fp3[] = "F%b,F%a,F%d"; static char fp3c[] = "F%c,F%a,F%d"; static char fp4[] = "F%a,F%c,F%b,F%d"; static char fpcmp[] = "F%a,F%b,%D"; static char ldop[] = "%l,R%d"; static char stop[] = "R%d,%l"; static char fldop[] = "%l,F%d"; static char fstop[] = "F%d,%l"; static char rlim[] = "R%b,R%s,$%z,R%a"; static char rlimi[] = "$%k,R%s,$%z,R%a"; #define OEM IBF(~0,22,30) #define FP4 IBF(~0,26,30) #define ALL ((ushort)~0) /* notes: 10-26: crfD = rD>>2; rD&3 mbz also, L bit (bit 10) mbz or selects 64-bit operands */ static Opcode opcodes[] = { {31, 360, OEM, "ABS%V%C", 0, ir2}, /* POWER */ {31, 266, OEM, "ADD%V%C", add, ir3}, {31, 10, OEM, "ADDC%V%C", add, ir3}, {31, 138, OEM, "ADDE%V%C", add, ir3}, {14, 0, 0, "ADD", addi, ir2i}, {12, 0, 0, "ADDC", addi, ir2i}, {13, 0, 0, "ADDCCC", addi, ir2i}, {15, 0, 0, "ADD", addis, 0}, {31, 234, OEM, "ADDME%V%C", gencc, ir2}, {31, 202, OEM, "ADDZE%V%C", gencc, ir2}, {31, 28, ALL, "AND%C", and, il3}, {31, 60, ALL, "ANDN%C", and, il3}, {28, 0, 0, "ANDCC", andi, il2u}, {29, 0, 0, "ANDCC", shifted, 0}, {18, 0, 0, "B%L", gencc, "%j"}, {16, 0, 0, "BC%L", branch, "%d,%a,%J"}, {19, 528, ALL, "BC%L", branch, "%d,%a,(CTR)"}, {19, 16, ALL, "BC%L", branch, "%d,%a,(LR)"}, {31, 531, ALL, "CLCS", gen, ir2}, /* POWER */ {31, 0, ALL, "CMP", 0, icmp3}, {11, 0, 0, "CMP", 0, "R%a,%i,%D"}, {31, 32, ALL, "CMPU", 0, icmp3}, {10, 0, 0, "CMPU", 0, "R%a,%I,%D"}, {31, 26, ALL, "CNTLZ%C", gencc, ir2}, {19, 257, ALL, "CRAND", gen, cr3op}, {19, 129, ALL, "CRANDN", gen, cr3op}, {19, 289, ALL, "CREQV", gen, cr3op}, {19, 225, ALL, "CRNAND", gen, cr3op}, {19, 33, ALL, "CRNOR", gen, cr3op}, {19, 449, ALL, "CROR", gen, cr3op}, {19, 417, ALL, "CRORN", gen, cr3op}, {19, 193, ALL, "CRXOR", gen, cr3op}, {31, 86, ALL, "DCBF", dcb, 0}, {31, 470, ALL, "DCBI", dcb, 0}, {31, 54, ALL, "DCBST", dcb, 0}, {31, 278, ALL, "DCBT", dcb, 0}, {31, 246, ALL, "DCBTST", dcb, 0}, {31, 1014, ALL, "DCBZ", dcb, 0}, {31, 331, OEM, "DIV%V%C", qdiv, ir3}, /* POWER */ {31, 363, OEM, "DIVS%V%C", qdiv, ir3}, /* POWER */ {31, 491, OEM, "DIVW%V%C", qdiv, ir3}, {31, 459, OEM, "DIVWU%V%C", qdiv, ir3}, {31, 264, OEM, "DOZ%V%C", gencc, ir3r}, /* POWER */ {9, 0, 0, "DOZ", gen, ir2i}, /* POWER */ {31, 310, ALL, "ECIWX", ldx, 0}, {31, 438, ALL, "ECOWX", stx, 0}, {31, 854, ALL, "EIEIO", gen, 0}, {31, 284, ALL, "EQV%C", gencc, il3}, {31, 954, ALL, "EXTSB%C", gencc, il2}, {31, 922, ALL, "EXTSH%C", gencc, il2}, {63, 264, ALL, "FABS%C", gencc, fp2}, {63, 21, ALL, "FADD%C", gencc, fp3}, {59, 21, ALL, "FADDS%C", gencc, fp3}, {63, 32, ALL, "FCMPO", gen, fpcmp}, {63, 0, ALL, "FCMPU", gen, fpcmp}, {63, 14, ALL, "FCTIW%C", gencc, fp2}, {63, 15, ALL, "FCTIWZ%C", gencc, fp2}, {63, 18, ALL, "FDIV%C", gencc, fp3}, {59, 18, ALL, "FDIVS%C", gencc, fp3}, {63, 29, FP4, "FMADD%C", gencc, fp4}, {59, 29, FP4, "FMADDS%C", gencc, fp4}, {63, 72, ALL, "FMOVD%C", gencc, fp2}, {63, 28, FP4, "FMSUB%C", gencc, fp4}, {59, 28, FP4, "FMSUBS%C", gencc, fp4}, {63, 25, FP4, "FMUL%C", gencc, fp3c}, {59, 25, FP4, "FMULS%C", gencc, fp3c}, {63, 136, ALL, "FNABS%C", gencc, fp2}, {63, 40, ALL, "FNEG%C", gencc, fp2}, {63, 31, FP4, "FNMADD%C", gencc, fp4}, {59, 31, FP4, "FNMADDS%C", gencc, fp4}, {63, 30, FP4, "FNMSUB%C", gencc, fp4}, {59, 30, FP4, "FNMSUBS%C", gencc, fp4}, {63, 12, ALL, "FRSP%C", gencc, fp2}, {63, 20, FP4, "FSUB%C", gencc, fp3}, {59, 20, FP4, "FSUBS%C", gencc, fp3}, {31, 982, ALL, "ICBI", dcb, 0}, {19, 150, ALL, "ISYNC", gen, 0}, {34, 0, 0, "MOVBZ", load, ldop}, {35, 0, 0, "MOVBZU", load, ldop}, {31, 119, ALL, "MOVBZU", ldx, 0}, {31, 87, ALL, "MOVBZ", ldx, 0}, {50, 0, 0, "FMOVD", fload, fldop}, {51, 0, 0, "FMOVDU", fload, fldop}, {31, 631, ALL, "FMOVDU", fldx, 0}, {31, 599, ALL, "FMOVD", fldx, 0}, {48, 0, 0, "FMOVS", load, fldop}, {49, 0, 0, "FMOVSU", load, fldop}, {31, 567, ALL, "FMOVSU", fldx, 0}, {31, 535, ALL, "FMOVS", fldx, 0}, {42, 0, 0, "MOVH", load, ldop}, {43, 0, 0, "MOVHU", load, ldop}, {31, 375, ALL, "MOVHU", ldx, 0}, {31, 343, ALL, "MOVH", ldx, 0}, {31, 790, ALL, "MOVHBR", ldx, 0}, {40, 0, 0, "MOVHZ", load, ldop}, {41, 0, 0, "MOVHZU", load, ldop}, {31, 311, ALL, "MOVHZU", ldx, 0}, {31, 279, ALL, "MOVHZ", ldx, 0}, {46, 0, 0, "MOVMW", load, ldop}, {31, 277, ALL, "LSCBX%C", ldx, 0}, /* POWER */ {31, 597, ALL, "LSW", gen, "(R%a),$%n,R%d"}, {31, 533, ALL, "LSW", ldx, 0}, {31, 20, ALL, "LWAR", ldx, 0}, {31, 534, ALL, "MOVWBR", ldx, 0}, {32, 0, 0, "MOVW", load, ldop}, {33, 0, 0, "MOVWU", load, ldop}, {31, 55, ALL, "MOVWU", ldx, 0}, {31, 23, ALL, "MOVW", ldx, 0}, {31, 29, ALL, "MASKG%C", gencc, "R%s:R%b,R%d"}, /* POWER */ {31, 541, ALL, "MASKIR%C", gencc, "R%s,R%b,R%a"}, /* POWER */ {19, 0, ALL, "MOVFL", gen, "%S,%D"}, {63, 64, ALL, "MOVCRFS", gen, "%S,%D"}, {31, 512, ALL, "MOVW", gen, "XER,%D"}, {31, 19, ALL, "MOVW", gen, "CR,R%d"}, {63, 583, ALL, "MOVW%C", gen, "FPSCR, F%d"}, /* mffs */ {31, 83, ALL, "MOVW", gen, "MSR,R%d"}, {31, 339, ALL, "MOVW", gen, "%P,R%d"}, {31, 595, ALL, "MOVW", gen, "SEG(%a),R%d"}, {31, 659, ALL, "MOVW", gen, "SEG(R%b),R%d"}, {31, 144, ALL, "MOVFL", gen, "R%s,%m,CR"}, {63, 70, ALL, "MTFSB0%C", gencc, "%D"}, {63, 38, ALL, "MTFSB1%C", gencc, "%D"}, {63, 711, ALL, "MOVFL%C", gencc, "F%b,%M,FPSCR"}, /* mtfsf */ {63, 134, ALL, "MOVFL%C", gencc, "%K,%D"}, {31, 146, ALL, "MOVW", gen, "R%s,MSR"}, {31, 467, ALL, "MOVW", gen, "R%s,%P"}, {31, 210, ALL, "MOVW", gen, "R%s,SEG(%a)"}, {31, 242, ALL, "MOVW", gen, "R%s,SEG(R%b)"}, {31, 107, OEM, "MUL%V%C", gencc, ir3}, /* POWER */ {31, 75, ALL, "MULHW%C", gencc, ir3}, /* POWER */ {31, 11, ALL, "MULHWU%C", gencc, ir3}, /* POWER */ {31, 235, OEM, "MULLW%V%C", gencc, ir3}, {7, 0, 0, "MULLW", qdiv, "%i,R%a,R%d"}, {31, 488, OEM, "NABS%V%C", neg, ir2}, /* POWER */ {31, 476, ALL, "NAND%C", gencc, il3}, {31, 104, OEM, "NEG%V%C", neg, ir2}, {31, 124, ALL, "NOR%C", gencc, il3}, {31, 444, ALL, "OR%C", or, il3}, {31, 412, ALL, "ORN%C", or, il3}, {24, 0, 0, "OR", and, "%I,R%d,R%a"}, {25, 0, 0, "OR", shifted, 0}, {19, 50, ALL, "RFI", gen, 0}, {22, 0, 0, "RLMI%C", gencc, rlim}, /* POWER */ {20, 0, 0, "RLWMI%C", gencc, rlimi}, {21, 0, 0, "RLWNM%C", gencc, rlimi}, {23, 0, 0, "RLWNM%C", gencc, rlim}, {31, 537, ALL, "RRIB%C", gencc, il3}, /* POWER */ {17, 1, ALL, "SYSCALL", gen, 0}, {31, 153, ALL, "SLE%C", shift, il3}, /* POWER */ {31, 217, ALL, "SLEQ%C", shift, il3}, /* POWER */ {31, 184, ALL, "SLQ%C", shifti, il3s}, /* POWER */ {31, 248, ALL, "SLLQ%C", shifti, il3s}, /* POWER */ {31, 216, ALL, "SLLQ%C", shift, il3}, /* POWER */ {31, 152, ALL, "SLQ%C", shift, il3}, /* POWER */ {31, 24, ALL, "SLW%C", shift, il3}, {31, 920, ALL, "SRAQ%C", shift, il3}, /* POWER */ {31, 952, ALL, "SRAQ%C", shifti, il3s}, /* POWER */ {31, 792, ALL, "SRAW%C", shift, il3}, {31, 824, ALL, "SRAW%C", shifti, il3s}, {31, 665, ALL, "SRE%C", shift, il3}, /* POWER */ {31, 921, ALL, "SREA%C", shift, il3}, /* POWER */ {31, 729, ALL, "SREQ%C", shift, il3}, /* POWER */ {31, 696, ALL, "SRQ%C", shifti, il3s}, /* POWER */ {31, 760, ALL, "SRLQ%C", shifti, il3s}, /* POWER */ {31, 728, ALL, "SRLQ%C", shift, il3}, /* POWER */ {31, 664, ALL, "SRQ%C", shift, il3}, /* POWER */ {31, 536, ALL, "SRW%C", shift, il3}, {38, 0, 0, "MOVB", store, stop}, {39, 0, 0, "MOVBU", store, stop}, {31, 247, ALL, "MOVBU", stx, 0}, {31, 215, ALL, "MOVB", stx, 0}, {54, 0, 0, "FMOVD", fstore, fstop}, {55, 0, 0, "FMOVDU", fstore, fstop}, {31, 759, ALL, "FMOVDU", fstx, 0}, {31, 727, ALL, "FMOVD", fstx, 0}, {52, 0, 0, "FMOVS", fstore, fstop}, {53, 0, 0, "FMOVSU", fstore, fstop}, {31, 695, ALL, "FMOVSU", fstx, 0}, {31, 663, ALL, "FMOVS", fstx, 0}, {44, 0, 0, "MOVH", store, stop}, {31, 918, ALL, "MOVHBR", stx, 0}, {45, 0, 0, "MOVHU", store, stop}, {31, 439, ALL, "MOVHU", stx, 0}, {31, 407, ALL, "MOVH", stx, 0}, {47, 0, 0, "MOVMW", store, stop}, {31, 725, ALL, "STSW", gen, "R%d,$%n,(R%a)"}, {31, 661, ALL, "STSW", stx, 0}, {36, 0, 0, "MOVW", store, stop}, {31, 662, ALL, "MOVWBR", stx, 0}, {31, 150, ALL, "STWCCC", stx, 0}, {37, 0, 0, "MOVWU", store, stop}, {31, 183, ALL, "MOVWU", stx, 0}, {31, 151, ALL, "MOVW", stx, 0}, {31, 40, OEM, "SUB%V%C", sub, ir3}, {31, 8, OEM, "SUBC%V%C", sub, ir3}, {31, 136, OEM, "SUBE%V%C", sub, ir3}, {8, 0, 0, "SUBC", gen, "R%a,%i,R%d"}, {31, 232, OEM, "SUBME%V%C", sub, ir2}, {31, 200, OEM, "SUBZE%V%C", sub, ir2}, {31, 598, ALL, "SYNC", gen, 0}, {31, 306, ALL, "TLBIE", gen, "R%b"}, {31, 370, ALL, "TLBIA", gen, 0}, {31, 1010, ALL, "TLBLI", gen, "R%b"}, {31, 978, ALL, "TLBLD", gen, "R%b"}, {31, 4, ALL, "TW", gen, "%d,R%a,R%b"}, {3, 0, 0, "TW", gen, "%d,R%a,%i"}, {31, 316, ALL, "XOR", and, il3}, {26, 0, 0, "XOR", and, il2u}, {27, 0, 0, "XOR", shifted, 0}, {0}, }; typedef struct Spr Spr; struct Spr { int n; char *name; }; static Spr sprname[] = { {0, "MQ"}, {1, "XER"}, {268, "TBL"}, {269, "TBU"}, {8, "LR"}, {9, "CTR"}, {528, "IBAT0U"}, {529, "IBAT0L"}, {530, "IBAT1U"}, {531, "IBAT1L"}, {532, "IBAT2U"}, {533, "IBAT2L"}, {534, "IBAT3U"}, {535, "IBAT3L"}, {536, "DBAT0U"}, {537, "DBAT0L"}, {538, "DBAT1U"}, {539, "DBAT1L"}, {540, "DBAT2U"}, {541, "DBAT2L"}, {542, "DBAT3U"}, {543, "DBAT3L"}, {25, "SDR1"}, {19, "DAR"}, {272, "SPRG0"}, {273, "SPRG1"}, {274, "SPRG2"}, {275, "SPRG3"}, {18, "DSISR"}, {26, "SRR0"}, {27, "SRR1"}, {284, "TBLW"}, {285, "TBUW"}, {22, "DEC"}, {282, "EAR"}, {1008, "HID0"}, {1009, "HID1"}, {976, "DMISS"}, {977, "DCMP"}, {978, "HASH1"}, {979, "HASH2"}, {980, "IMISS"}, {981, "ICMP"}, {982, "RPA"}, {1010, "IABR"}, {1013, "DABR"}, {0,0}, }; static void format(char *mnemonic, Instr *i, char *f) { int n, s; ulong mask; if (mnemonic) format(0, i, mnemonic); if (f == 0) return; if (mnemonic) bprint(i, "\t"); for ( ; *f; f++) { if (*f != '%') { bprint(i, "%c", *f); continue; } switch (*++f) { case 'V': if(i->oe) bprint(i, "V"); break; case 'C': if(i->rc) bprint(i, "CC"); break; case 'a': bprint(i, "%d", i->ra); break; case 'b': bprint(i, "%d", i->rb); break; case 'c': bprint(i, "%d", i->frc); break; case 'd': case 's': bprint(i, "%d", i->rd); break; case 'S': if(i->ra & 3) bprint(i, "CR(INVAL:%d)", i->ra); else if(i->op == 63) bprint(i, "FPSCR(%d)", i->crfs); else bprint(i, "CR(%d)", i->crfs); break; case 'D': if(i->rd & 3) bprint(i, "CR(INVAL:%d)", i->rd); else if(i->op == 63) bprint(i, "FPSCR(%d)", i->crfd); else bprint(i, "CR(%d)", i->crfd); break; case 'l': address(i); break; case 'i': bprint(i, "$%ld", i->simm); break; case 'I': bprint(i, "$%lx", i->uimm); break; case 'w': bprint(i, "[%lux]", i->w0); break; case 'P': n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f); for(s=0; sprname[s].name; s++) if(sprname[s].n == n) break; if(sprname[s].name) { if(n < 10) bprint(i, sprname[s].name); else bprint(i, "SPR(%s)", sprname[s].name); } else bprint(i, "SPR(%d)", n); break; case 'n': bprint(i, "%d", i->nb==0? 32: i->nb); /* eg, pg 10-103 */ break; case 'm': bprint(i, "%lx", i->crm); break; case 'M': bprint(i, "%lx", i->fm); break; case 'z': if(i->mb <= i->me) mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me)); else mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1)))); bprint(i, "%lux", mask); break; case 'k': bprint(i, "%d", i->sh); break; case 'K': bprint(i, "$%x", i->imm); break; case 'L': if(i->lk) bprint(i, "L"); break; case 'j': if(i->aa) pglobal(i, i->li, 1, "(SB)"); else pglobal(i, i->addr+i->li, 1, ""); break; case 'J': if(i->aa) pglobal(i, i->bd, 1, "(SB)"); else pglobal(i, i->addr+i->bd, 1, ""); break; case '\0': bprint(i, "%%"); return; default: bprint(i, "%%%c", *f); break; } } } static int printins(Map *map, ulong pc, char *buf, int n) { Instr i; Opcode *o; mymap = map; memset(&i, 0, sizeof(i)); i.curr = buf; i.end = buf+n-1; if(mkinstr(pc, &i) < 0) return -1; for(o = opcodes; o->mnemonic != 0; o++) if(i.op == o->op && (i.xo & o->xomask) == o->xo) { if (o->f) (*o->f)(o, &i); else format(o->mnemonic, &i, o->ken); return i.size*4; } bprint(&i, "unknown %lux", i.w0); return i.size*4; } static int powerinst(Map *map, ulong pc, char modifier, char *buf, int n) { USED(modifier); return printins(map, pc, buf, n); } static int powerdas(Map *map, ulong pc, char *buf, int n) { Instr instr; mymap = map; memset(&instr, 0, sizeof(instr)); instr.curr = buf; instr.end = buf+n-1; if (mkinstr(pc, &instr) < 0) return -1; if (instr.end-instr.curr > 8) instr.curr = _hexify(instr.curr, instr.w0, 7); if (instr.end-instr.curr > 9 && instr.size == 2) { *instr.curr++ = ' '; instr.curr = _hexify(instr.curr, instr.w1, 7); } *instr.curr = 0; return instr.size*4; } static int powerinstlen(Map *map, ulong pc) { Instr i; mymap = map; if (mkinstr(pc, &i) < 0) return -1; return i.size*4; } int powerfoll(Map *map, ulong pc, Rgetter rget, ulong *foll) { char *reg; Instr i; mymap = map; if (mkinstr(pc, &i) < 0) return -1; foll[0] = pc+4; foll[1] = pc+4; switch(i.op) { default: return 1; case 18: /* branch */ foll[0] = i.li; if(!i.aa) foll[0] += pc; break; case 16: /* conditional branch */ foll[0] = i.bd; if(!i.aa) foll[0] += pc; break; case 19: /* conditional branch to register */ if(i.xo == 528) reg = "CTR"; else if(i.xo == 16) reg = "LR"; else return 1; /* not a branch */ foll[0] = (*rget)(map, reg); break; } if(i.lk) return 2; return 1; } /* * Don't use riscframe() to allow checking for encountering an * interrupt frame on the stack. I haven't figured out a machine * independent method of detected an interrupt frame. The only way * is to check for the address being the return from the call to * trap() in l.s. */ int powertrace(Map *map, ulong pc, ulong sp, ulong link, Tracer trace) { int i; Symbol s, f; ulong oldpc; i = 0; while(findsym(pc, CTEXT, &s)) { if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) break; if(pc == s.value) /* at first instruction */ f.value = 0; else if(findlocal(&s, FRAMENAME, &f) == 0) break; oldpc = pc; if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant) pc = link; else if (get4(map, sp, (long *) &pc) < 0) break; /* was this a interrupt */ if (strcmp("intrvec", s.name) == 0) { /* Skip past interrupt frame */ sp += 2*sizeof(ulong); /* get new pc from Ureg, pc is third word */ if (get4(map, (sp+2*sizeof(ulong)), (long *) &pc) < 0) { break; } sp += sizeof(struct Ureg); } if(pc == 0 || (pc == oldpc && f.value == 0)) break; sp += f.value; (*trace)(map, pc-8, sp, &s); if(++i > 40) break; } return i; }