summaryrefslogtreecommitdiff
path: root/sys/src/libmach/qdb.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libmach/qdb.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libmach/qdb.c')
-rwxr-xr-xsys/src/libmach/qdb.c1363
1 files changed, 1363 insertions, 0 deletions
diff --git a/sys/src/libmach/qdb.c b/sys/src/libmach/qdb.c
new file mode 100755
index 000000000..257a69bd5
--- /dev/null
+++ b/sys/src/libmach/qdb.c
@@ -0,0 +1,1363 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+/*
+ * PowerPC-specific debugger interface,
+ * including 64-bit modes
+ * forsyth@terzarima.net
+ */
+
+static char *powerexcep(Map*, Rgetter);
+static int powerfoll(Map*, uvlong, Rgetter, uvlong*);
+static int powerinst(Map*, uvlong, char, char*, int);
+static int powerinstlen(Map*, uvlong);
+static int powerdas(Map*, uvlong, char*, int);
+
+/*
+ * Machine description
+ */
+Machdata powermach =
+{
+ {0x02, 0x8f, 0xff, 0xff}, /* break point */ /* BUG */
+ 4, /* break point size */
+
+ beswab, /* short to local byte order */
+ beswal, /* long to local byte order */
+ beswav, /* vlong to local byte order */
+ risctrace, /* 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", /* FPEXC */
+ "illegal instruction",
+ "privileged instruction",
+ "trap",
+ "illegal operation",
+};
+
+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 #%lx", c);
+ return buf;
+}
+
+/*
+ * disassemble PowerPC opcodes
+ */
+
+#define REGSP 1 /* should come from q.out.h, but there's a clash */
+#define REGSB 2
+
+static char FRAMENAME[] = ".frame";
+
+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 xmbe; /* bits 26,21-25: mb[5] || mb[0:4], also xme */
+ uchar xsh; /* bits 30,16-20: sh[5] || sh[0:4] */
+ 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) */
+ uvlong imm64;
+ long w0;
+ long w1;
+ uvlong addr; /* pc of instruction */
+ short target;
+ short m64; /* 64-bit mode */
+ 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))
+
+#pragma varargck argpos bprint 2
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+decode(uvlong pc, Instr *i)
+{
+ ulong w;
+
+ if (get4(mymap, pc, &w) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ i->m64 = asstype == APOWER64;
+ 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->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->xmbe = (IB(w,26)<<5) | i->mb;
+ 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->sh = IBF(w, 16, 20);
+ i->xsh = (IB(w, 30)<<5) | i->sh;
+ 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) */
+ if(i->op == 58){ /* class of 64-bit loads */
+ i->xo = i->simm & 3;
+ i->simm &= ~3;
+ }
+ i->imm64 = i->simm;
+ if(i->op == 15)
+ i->imm64 <<= 16;
+ else if(i->op == 25 || i->op == 27 || i->op == 29)
+ i->imm64 = (uvlong)(i->uimm<<16);
+ i->w0 = w;
+ i->target = -1;
+ i->addr = pc;
+ i->size = 1;
+ return 1;
+}
+
+static int
+mkinstr(uvlong pc, Instr *i)
+{
+ Instr x;
+
+ if(decode(pc, i) < 0)
+ return -1;
+ /*
+ * combine ADDIS/ORI (CAU/ORIL) into MOVW
+ * also ORIS/ORIL for unsigned in 64-bit mode
+ */
+ if ((i->op == 15 || i->op == 25) && i->ra==0) {
+ if(decode(pc+4, &x) < 0)
+ return -1;
+ if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
+ i->imm64 |= (x.imm64 & 0xFFFF);
+ if(i->op != 15)
+ i->imm64 &= 0xFFFFFFFFUL;
+ i->w1 = x.w0;
+ i->target = x.rd;
+ i->size++;
+ return 1;
+ }
+ }
+ return 1;
+}
+
+static int
+plocal(Instr *i)
+{
+ long offset;
+ Symbol s;
+
+ if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
+ return -1;
+ offset = s.value - i->imm64;
+ if (offset > 0) {
+ if(getauto(&s, offset, CAUTO, &s)) {
+ bprint(i, "%s+%lld(SP)", s.name, s.value);
+ return 1;
+ }
+ } else {
+ if (getauto(&s, -offset-4, CPARAM, &s)) {
+ bprint(i, "%s+%ld(FP)", s.name, -offset);
+ return 1;
+ }
+ }
+ return -1;
+}
+
+static int
+pglobal(Instr *i, uvlong off, int anyoff, char *reg)
+{
+ Symbol s, s2;
+ uvlong off1;
+
+ if(findsym(off, CANY, &s) &&
+ off-s.value < 4096 &&
+ (s.class == CDATA || s.class == CTEXT)) {
+ if(off==s.value && s.name[0]=='$'){
+ off1 = 0;
+ geta(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, "+%llux", off-s.value);
+ bprint(i, reg);
+ return 1;
+ }
+ if(!anyoff)
+ return 0;
+ bprint(i, "%llux%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->imm64, 0, "(SB)"))
+ return;
+ if(i->simm < 0)
+ bprint(i, "-%x(R%d)", -i->simm, i->ra);
+ else
+ bprint(i, "%llux(R%d)", i->imm64, 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, nil);
+ bprint(i, "\t");
+ if(i->bi > 4)
+ bprint(i, "CR(%d),", i->bi/4);
+ } else
+ format("BR%L\t", i, nil);
+ 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 == 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->imm64;
+ if (i->op==15 && i->ra == 0)
+ bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
+ else if (i->op==15 && i->ra == REGSB) {
+ bprint(i, "MOVW\t$");
+ address(i);
+ bprint(i, ",R%d", i->rd);
+ } else if(i->op==15 && v < 0) {
+ bprint(i, "SUB\t$%ld,R%d", -v, i->ra);
+ if(i->rd != i->ra)
+ bprint(i, ",R%d", i->rd);
+ } else {
+ format(o->mnemonic, i, nil);
+ 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)
+{
+ format(o->mnemonic, i, nil);
+ bprint(i, "\t");
+ 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;
+ Symbol s;
+
+ if (i->rs == REGSP) {
+ if (findsym(i->addr, CTEXT, &s) && findlocal(&s, FRAMENAME, &s)) {
+ offset = s.value-i->imm64;
+ if (offset > 0 && getauto(&s, offset, CAUTO, &s)) {
+ format(o->mnemonic, i, nil);
+ bprint(i, "\t%c%d,%s-%d(SP)", r, i->rd, s.name, offset);
+ return;
+ }
+ }
+ }
+ if (i->rs == REGSB && mach->sb) {
+ format(o->mnemonic, i, nil);
+ bprint(i, "\t%c%d,", r, i->rd);
+ address(i);
+ return;
+ }
+ if (r == 'F')
+ format(o->mnemonic, i, "F%d,%l");
+ else
+ format(o->mnemonic, 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, nil);
+ bprint(i, "\t");
+ 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, nil);
+ 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, nil);
+ 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, nil);
+ 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%d,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 rldc[] = "R%b,R%s,$%E,R%a";
+static char rlim[] = "R%b,R%s,$%z,R%a";
+static char rlimi[] = "$%k,R%s,$%z,R%a";
+static char rldi[] = "$%e,R%s,$%E,R%a";
+
+#define OEM IBF(~0,22,30)
+#define FP4 IBF(~0,26,30)
+#define ALL (~0)
+#define RLDC 0xF
+#define RLDI 0xE
+/*
+notes:
+ 10-26: crfD = rD>>2; rD&3 mbz
+ also, L bit (bit 10) mbz or selects 64-bit operands
+*/
+
+static Opcode opcodes[] = {
+ {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, 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, 58, ALL, "CNTLZD%C", gencc, ir2}, /* 64 */
+ {31, 26, ALL, "CNTLZ%W%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, 454, ALL, "DCCCI", dcb, 0},
+ {31, 966, ALL, "ICCCI", dcb, 0},
+
+ {31, 489, OEM, "DIVD%V%C", qdiv, ir3}, /* 64 */
+ {31, 457, OEM, "DIVDU%V%C", qdiv, ir3}, /* 64 */
+ {31, 491, OEM, "DIVW%V%C", qdiv, ir3},
+ {31, 459, OEM, "DIVWU%V%C", qdiv, ir3},
+
+ {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},
+ {31, 986, ALL, "EXTSW%C", gencc, il2}, /* 64 */
+
+ {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, 846, ALL, "FCFID%C", gencc, fp2}, /* 64 */
+ {63, 814, ALL, "FCTID%C", gencc, fp2}, /* 64 */
+ {63, 815, ALL, "FCTIDZ%C", gencc, fp2}, /* 64 */
+ {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},
+ {59, 24, ALL, "FRES%C", gencc, fp2}, /* optional */
+ {63, 12, ALL, "FRSP%C", gencc, fp2},
+ {63, 26, ALL, "FRSQRTE%C", gencc, fp2}, /* optional */
+ {63, 23, FP4, "FSEL%CC", gencc, fp4}, /* optional */
+ {63, 22, ALL, "FSQRT%C", gencc, fp2}, /* optional */
+ {59, 22, ALL, "FSQRTS%C", gencc, fp2}, /* optional */
+ {63, 20, FP4, "FSUB%C", gencc, fp3},
+ {59, 20, FP4, "FSUBS%C", gencc, fp3},
+
+ {31, 982, ALL, "ICBI", dcb, 0}, /* optional */
+ {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, 597, ALL, "LSW", gen, "(R%a),$%n,R%d"},
+ {31, 533, ALL, "LSW", ldx, 0},
+ {31, 20, ALL, "LWAR", ldx, 0},
+ {31, 84, ALL, "LWARD", ldx, 0}, /* 64 */
+
+ {58, 0, ALL, "MOVD", load, ldop}, /* 64 */
+ {58, 1, ALL, "MOVDU", load, ldop}, /* 64 */
+ {31, 53, ALL, "MOVDU", ldx, 0}, /* 64 */
+ {31, 21, ALL, "MOVD", ldx, 0}, /* 64 */
+
+ {31, 534, ALL, "MOVWBR", ldx, 0},
+
+ {58, 2, ALL, "MOVW", load, ldop}, /* 64 (lwa) */
+ {31, 373, ALL, "MOVWU", ldx, 0}, /* 64 */
+ {31, 341, ALL, "MOVW", ldx, 0}, /* 64 */
+
+ {32, 0, 0, "MOVW%Z", load, ldop},
+ {33, 0, 0, "MOVW%ZU", load, ldop},
+ {31, 55, ALL, "MOVW%ZU", ldx, 0},
+ {31, 23, ALL, "MOVW%Z", ldx, 0},
+
+ {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, 323, ALL, "MOVW", gen, "DCR(%Q),R%d"},
+ {31, 451, ALL, "MOVW", gen, "R%s,DCR(%Q)"},
+ {31, 259, ALL, "MOVW", gen, "DCR(R%a),R%d"},
+ {31, 387, ALL, "MOVW", gen, "R%s,DCR(R%a)"},
+ {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, 178, ALL, "MOVD", 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, 73, ALL, "MULHD%C", gencc, ir3},
+ {31, 9, ALL, "MULHDU%C", gencc, ir3},
+ {31, 233, OEM, "MULLD%V%C", gencc, ir3},
+
+ {31, 75, ALL, "MULHW%C", gencc, ir3},
+ {31, 11, ALL, "MULHWU%C", gencc, ir3},
+ {31, 235, OEM, "MULLW%V%C", gencc, ir3},
+
+ {7, 0, 0, "MULLW", qdiv, "%i,R%a,R%d"},
+
+ {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},
+ {19, 51, ALL, "RFCI", gen, 0},
+
+ {30, 8, RLDC, "RLDCL%C", gencc, rldc}, /* 64 */
+ {30, 9, RLDC, "RLDCR%C", gencc, rldc}, /* 64 */
+ {30, 0, RLDI, "RLDCL%C", gencc, rldi}, /* 64 */
+ {30, 1<<1, RLDI, "RLDCR%C", gencc, rldi}, /* 64 */
+ {30, 2<<1, RLDI, "RLDC%C", gencc, rldi}, /* 64 */
+ {30, 3<<1, RLDI, "RLDMI%C", gencc, rldi}, /* 64 */
+
+ {20, 0, 0, "RLWMI%C", gencc, rlimi},
+ {21, 0, 0, "RLWNM%C", gencc, rlimi},
+ {23, 0, 0, "RLWNM%C", gencc, rlim},
+
+ {17, 1, ALL, "SYSCALL", gen, 0},
+
+ {31, 27, ALL, "SLD%C", shift, il3}, /* 64 */
+ {31, 24, ALL, "SLW%C", shift, il3},
+
+ {31, 794, ALL, "SRAD%C", shift, il3}, /* 64 */
+ {31, (413<<1)|0, ALL, "SRAD%C", shifti, il3s}, /* 64 */
+ {31, (413<<1)|1, ALL, "SRAD%C", shifti, il3s}, /* 64 */
+ {31, 792, ALL, "SRAW%C", shift, il3},
+ {31, 824, ALL, "SRAW%C", shifti, il3s},
+
+ {31, 539, ALL, "SRD%C", shift, il3}, /* 64 */
+ {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},
+ {31, 214, ALL, "STDCCC", stx, 0}, /* 64 */
+ {37, 0, 0, "MOVWU", store, stop},
+ {31, 183, ALL, "MOVWU", stx, 0},
+ {31, 151, ALL, "MOVW", stx, 0},
+
+ {62, 0, 0, "MOVD%U", store, stop}, /* 64 */
+ {31, 149, ALL, "MOVD", stx, 0,}, /* 64 */
+ {31, 181, ALL, "MOVDU", stx, 0}, /* 64 */
+
+ {31, 498, ALL, "SLBIA", gen, 0}, /* 64 */
+ {31, 434, ALL, "SLBIE", gen, "R%b"}, /* 64 */
+ {31, 466, ALL, "SLBIEX", gen, "R%b"}, /* 64 */
+ {31, 915, ALL, "SLBMFEE", gen, "R%b,R%d"}, /* 64 */
+ {31, 851, ALL, "SLBMFEV", gen, "R%b,R%d"}, /* 64 */
+ {31, 402, ALL, "SLBMTE", gen, "R%s,R%b"}, /* 64 */
+
+ {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}, /* TO DO: there's a parameter buried in there */
+ {2, 0, 0, "TD", gen, "%d,R%a,%i"}, /* 64 */
+ {31, 370, ALL, "TLBIA", gen, 0}, /* optional */
+ {31, 306, ALL, "TLBIE", gen, "R%b"}, /* optional */
+ {31, 274, ALL, "TLBIEL", gen, "R%b"}, /* optional */
+ {31, 1010, ALL, "TLBLI", gen, "R%b"}, /* optional */
+ {31, 978, ALL, "TLBLD", gen, "R%b"}, /* optional */
+ {31, 566, ALL, "TLBSYNC", gen, 0}, /* optional */
+ {31, 68, ALL, "TD", gen, "%d,R%a,R%b"}, /* 64 */
+ {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 int
+shmask(uvlong *m)
+{
+ int i;
+
+ for(i=0; i<63; i++)
+ if(*m & ((uvlong)1<<i))
+ break;
+ if(i > 63)
+ return 0;
+ if(*m & ~((uvlong)1<<i)){ /* more than one bit: do multiples of bytes */
+ i = (i/8)*8;
+ if(i == 0)
+ return 0;
+ }
+ *m >>= i;
+ return i;
+}
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ int n, s;
+ ulong mask;
+ uvlong vmask;
+
+ 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 '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 'C':
+ if(i->rc)
+ bprint(i, "CC");
+ 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 'e':
+ bprint(i, "%d", i->xsh);
+ break;
+
+ case 'E':
+ switch(IBF(i->w0,27,30)){ /* low bit is top bit of shift in rldiX cases */
+ case 8: i->mb = i->xmbe; i->me = 63; break; /* rldcl */
+ case 9: i->mb = 0; i->me = i->xmbe; break; /* rldcr */
+ case 4: case 5:
+ i->mb = i->xmbe; i->me = 63-i->xsh; break; /* rldic */
+ case 0: case 1:
+ i->mb = i->xmbe; i->me = 63; break; /* rldicl */
+ case 2: case 3:
+ i->mb = 0; i->me = i->xmbe; break; /* rldicr */
+ case 6: case 7:
+ i->mb = i->xmbe; i->me = 63-i->xsh; break; /* rldimi */
+ }
+ vmask = (~(uvlong)0>>i->mb) & (~(uvlong)0<<(63-i->me));
+ s = shmask(&vmask);
+ if(s)
+ bprint(i, "(%llux<<%d)", vmask, s);
+ else
+ bprint(i, "%llux", vmask);
+ break;
+
+ case 'i':
+ bprint(i, "$%d", i->simm);
+ break;
+
+ case 'I':
+ bprint(i, "$%ux", i->uimm);
+ 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 '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 'l':
+ if(i->simm < 0)
+ bprint(i, "-%x(R%d)", -i->simm, i->ra);
+ else
+ bprint(i, "%x(R%d)", i->simm, i->ra);
+ break;
+
+ case 'm':
+ bprint(i, "%ux", i->crm);
+ break;
+
+ case 'M':
+ bprint(i, "%ux", i->fm);
+ break;
+
+ case 'n':
+ bprint(i, "%d", i->nb==0? 32: i->nb); /* eg, pg 10-103 */
+ 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(s < 10)
+ bprint(i, sprname[s].name);
+ else
+ bprint(i, "SPR(%s)", sprname[s].name);
+ } else
+ bprint(i, "SPR(%d)", n);
+ break;
+
+ case 'Q':
+ n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
+ bprint(i, "%d", n);
+ 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 'U':
+ if(i->rc)
+ bprint(i, "U");
+ break;
+
+ case 'V':
+ if(i->oe)
+ bprint(i, "V");
+ break;
+
+ case 'w':
+ bprint(i, "[%lux]", i->w0);
+ break;
+
+ case 'W':
+ if(i->m64)
+ bprint(i, "W");
+ break;
+
+ case 'Z':
+ if(i->m64)
+ bprint(i, "Z");
+ 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 '\0':
+ bprint(i, "%%");
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+}
+
+static int
+printins(Map *map, uvlong 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, uvlong pc, char modifier, char *buf, int n)
+{
+ USED(modifier);
+ return printins(map, pc, buf, n);
+}
+
+static int
+powerdas(Map *map, uvlong 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, uvlong pc)
+{
+ Instr i;
+
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ return i.size*4;
+}
+
+static int
+powerfoll(Map *map, uvlong pc, Rgetter rget, uvlong *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;
+}