#ifdef _KERNEL
#include <sys/param.h>
#include <sys/systm.h>
#else
#include <unistd.h>
#include <stdio.h>
#endif
#ifdef _KERNEL
#include <machine/db_machdep.h>
#endif
#include <machine/mips_opcode.h>
#include <machine/regnum.h>
#ifdef _KERNEL
#include <ddb/db_interface.h>
#include <ddb/db_output.h>
#include <ddb/db_sym.h>
#else
#define db_printsym(addr,flags,fn) (fn)("%p",addr)
#endif
static const char *op_name[64] = {
NULL,
NULL,
"j",
"jal",
"beq",
"bne",
"blez",
"bgtz",
"addi",
"addiu",
"slti",
"sltiu",
"andi",
"ori",
"xori",
"lui",
"cop0",
"cop1",
"cop2",
"cop1x",
"beql",
"bnel",
"blezl",
"bgtzl",
"daddi",
"daddiu",
"ldl",
"ldr",
NULL,
NULL,
NULL,
NULL,
"lb",
"lh",
"lwl",
"lw",
"lbu",
"lhu",
"lwr",
"lwu",
"sb",
"sh",
"swl",
"sw",
"sdl",
"sdr",
"swr",
"cache",
"ll",
"lwc1",
"lwc2",
"pref",
"lld",
"ldc1",
"ldc2",
"ld",
"sc",
"swc1",
"swc2",
"swc3",
"scd",
"sdc1",
"sdc2",
"sd"
};
static const char *special_name[64] = {
"sll",
NULL,
"srl",
"sra",
"sllv",
NULL,
"srlv",
"srav",
"jr",
"jalr",
"movz",
"movn",
"syscall",
"break",
NULL,
"sync",
"mfhi",
"mthi",
"mflo",
"mtlo",
"dsllv",
NULL,
"dsrlv",
"dsrav",
"mult",
"multu",
"div",
"divu",
"dmult",
"dmultu",
"ddiv",
"ddivu",
"add",
"addu",
"sub",
"subu",
"and",
"or",
"xor",
"nor",
NULL,
NULL,
"slt",
"sltu",
"dadd",
"daddu",
"dsub",
"dsubu",
"tge",
"tgeu",
"tlt",
"tltu",
"teq",
NULL,
"tne",
NULL,
"dsll",
NULL,
"dsrl",
"dsra",
"dsll32",
NULL,
"dsrl32",
"dsra32"
};
static const char *bcond_name[32] = {
"bltz",
"bgez",
"bltzl",
"bgezl",
NULL,
NULL,
NULL,
NULL,
"tgei",
"tgeiu",
"tlti",
"tltiu",
"teqi",
NULL,
"tnei",
NULL,
"bltzal",
"bgezal",
"bltzall",
"bgezall",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"synci"
};
static const char *cop_std[OP_MTH + 1] = {
"mfc",
"dmfc",
"cfc",
"mfhc",
"mtc",
"dmtc",
"ctc",
"mthc"
};
static const char *cop1_name[64] = {
"add",
"sub",
"mul",
"div",
"sqrt",
"abs",
"mov",
"neg",
"round.l",
"trunc.l",
"ceil.l",
"floor.l",
"round.w",
"trunc.w",
"ceil.w",
"floor.w",
NULL,
NULL,
"movz",
"movn",
NULL,
"recip",
"rsqrt",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"cvt.s",
"cvt.d",
NULL,
NULL,
"cvt.w",
"cvt.l",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"c.f",
"c.un",
"c.eq",
"c.ueq",
"c.olt",
"c.ult",
"c.ole",
"c.ule",
"c.sf",
"c.ngle",
"c.seq",
"c.ngl",
"c.lt",
"c.nge",
"c.le",
"c.ngt"
};
static const char *fmt_name[16] = {
"s",
"d",
NULL,
NULL,
"w",
"l",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
static const char *cop1x_op4[8] = {
NULL,
NULL,
NULL,
NULL,
"madd",
"msub",
"nmadd",
"nmsub"
};
static const char *cop1x_std[32] = {
"lwxc1",
"ldxc1",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"swxc1",
"sdxc1",
NULL,
NULL,
NULL,
NULL,
NULL,
"prefx",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
static const char *reg_name[32] = {
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
"a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
};
static const char *cop0_miscname[64] = {
NULL,
"tlbr",
"tlbwi",
NULL,
NULL,
NULL,
"tlbwr",
NULL,
"tlbp",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"eret",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"wait"
};
static const char *cop0_tfp_miscname[64] = {
NULL,
"tlbr",
"tlbw",
NULL,
NULL,
NULL,
"tlbwr",
NULL,
"tlbp",
"dctr",
"dctw"
};
static const char *cop0_reg0[32] = {
"Index",
"Random",
"EntryLo0",
"EntryLo1",
"Context",
"PageMask",
"Wired",
"Info",
"BadVAddr",
"Count",
"EntryHi",
"Compare",
"Status",
"Cause",
"EPC",
"PRId",
"Config",
"LLAddr",
"WatchLo",
"WatchHi",
"XContext",
NULL,
"PerfControl",
NULL,
"WatchMask",
"PerfCount",
"ECC",
"CacheErr",
"TagLo",
"TagHi",
"ErrorEPC",
NULL
};
static const char *cop0_reg1[32] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"IPLLo",
"IPLHi",
"IntCtl",
NULL,
NULL,
NULL,
NULL,
NULL,
"DErrAddr0",
"DErrAddr1",
NULL,
NULL,
NULL,
NULL,
};
int
dbmd_print_insn(uint32_t ins, vaddr_t mdbdot, int (*pr)(const char *, ...))
{
InstFmt i;
int delay = 0;
const char *insn, *descr;
i.word = ins;
insn = op_name[i.JType.op];
switch (i.JType.op) {
case OP_SPECIAL:
if (i.word == 0) {
(*pr)("nop");
break;
} else if (i.word == 1 << 6) {
(*pr)("ssnop");
break;
}
if (i.RType.func == OP_DADDU && i.RType.rt == 0) {
(*pr)("move\t%s,%s",
reg_name[i.RType.rd], reg_name[i.RType.rs]);
break;
}
if (i.RType.func == OP_MOVCI) {
(*pr)("mov%c\t%s,%s,%d",
i.RType.rt & 1 ? 't' : 'f',
reg_name[i.RType.rd], reg_name[i.RType.rs],
i.RType.rt >> 2);
break;
}
insn = special_name[i.RType.func];
switch (i.RType.func) {
case OP_SRL:
if (i.RType.rs != 0)
insn = "rotr";
break;
case OP_SRLV:
if (i.RType.shamt != 0)
insn = "rotrv";
break;
case OP_JR:
if (i.RType.shamt != 0)
insn = "jr.hb";
break;
case OP_JALR:
if (i.RType.shamt != 0)
insn = "jalr.hb";
break;
case OP_DSRL:
if (i.RType.rs != 0)
insn = "drotr";
break;
case OP_DSRLV:
if (i.RType.shamt != 0)
insn = "drotrv";
break;
}
if (insn == NULL)
goto unknown;
(*pr)("%s", insn);
switch (i.RType.func) {
case OP_SLL:
case OP_SRL:
case OP_SRA:
case OP_DSLL:
case OP_DSRL:
case OP_DSRA:
case OP_DSLL32:
case OP_DSRL32:
case OP_DSRA32:
(*pr)("\t%s,%s,%d",
reg_name[i.RType.rd], reg_name[i.RType.rt],
i.RType.shamt);
break;
case OP_SLLV:
case OP_SRLV:
case OP_SRAV:
case OP_DSLLV:
case OP_DSRLV:
case OP_DSRAV:
(*pr)("\t%s,%s,%s",
reg_name[i.RType.rd], reg_name[i.RType.rt],
reg_name[i.RType.rs]);
break;
case OP_MFHI:
case OP_MFLO:
(*pr)("\t%s", reg_name[i.RType.rd]);
break;
case OP_JALR:
delay = 1;
if (i.RType.rd != RA)
(*pr)("\t%s,%s",
reg_name[i.RType.rd], reg_name[i.RType.rs]);
else
(*pr)("\t%s", reg_name[i.RType.rs]);
break;
case OP_JR:
delay = 1;
case OP_MTLO:
case OP_MTHI:
(*pr)("\t%s", reg_name[i.RType.rs]);
break;
case OP_MULT:
case OP_MULTU:
case OP_DIV:
case OP_DIVU:
case OP_DMULT:
case OP_DMULTU:
case OP_DDIV:
case OP_DDIVU:
case OP_TGE:
case OP_TGEU:
case OP_TLT:
case OP_TLTU:
case OP_TEQ:
case OP_TNE:
(*pr)("\t%s,%s",
reg_name[i.RType.rs], reg_name[i.RType.rt]);
break;
case OP_SYSCALL:
if ((ins >> 6) != 0)
(*pr)("\t%d", ins >> 6);
break;
case OP_SYNC:
break;
case OP_BREAK:
(*pr)("\t%d", ins >> 16);
break;
case OP_MOVZ:
case OP_MOVN:
default:
(*pr)("\t%s,%s,%s",
reg_name[i.RType.rd], reg_name[i.RType.rs],
reg_name[i.RType.rt]);
}
break;
case OP_BCOND:
insn = bcond_name[i.IType.rt];
if (insn == NULL)
goto unknown;
if (i.IType.rt == 31) {
(*pr)("%s\t", insn);
goto loadstore;
}
(*pr)("%s\t%s,", insn, reg_name[i.IType.rs]);
if ((i.IType.rt & 0x18) == 0x08)
(*pr)("%d", i.IType.imm);
else
goto pr_displ;
case OP_J:
case OP_JAL:
delay = 1;
(*pr)("%s\t", insn);
db_printsym((mdbdot & ~0x0fffffffUL) |
(vaddr_t)(i.JType.target << 2), DB_STGY_PROC, pr);
break;
case OP_BEQ:
case OP_BEQL:
if (i.IType.rs == ZERO && i.IType.rt == ZERO) {
(*pr)("b\t");
goto pr_displ;
}
case OP_BNE:
case OP_BNEL:
if (i.IType.rt == ZERO) {
if (i.IType.op == OP_BEQL || i.IType.op == OP_BNEL) {
insn = op_name[i.IType.op & 0x07];
(*pr)("%szl\t%s,", insn, reg_name[i.IType.rs]);
} else
(*pr)("%sz\t%s,", insn, reg_name[i.IType.rs]);
} else
(*pr)("%s\t%s,%s,", insn,
reg_name[i.IType.rs], reg_name[i.IType.rt]);
pr_displ:
delay = 1;
db_printsym(mdbdot + 4 + ((int16_t)i.IType.imm << 2),
DB_STGY_PROC, pr);
break;
case OP_BLEZ:
case OP_BGTZ:
case OP_BLEZL:
case OP_BGTZL:
(*pr)("%s\t%s,", insn, reg_name[i.IType.rs]);
goto pr_displ;
case OP_ADDI:
case OP_ADDIU:
case OP_DADDI:
case OP_DADDIU:
if (i.IType.rs == 0) {
(*pr)("li\t%s,%d",
reg_name[i.IType.rt], (int16_t)i.IType.imm);
break;
}
case OP_SLTI:
case OP_SLTIU:
default:
if (insn != NULL)
(*pr)("%s\t%s,%s,%d", insn,
reg_name[i.IType.rt], reg_name[i.IType.rs],
(int16_t)i.IType.imm);
else {
unknown:
(*pr)(".word\t%08x", ins);
}
break;
case OP_ORI:
case OP_XORI:
if (i.IType.rs == 0) {
(*pr)("li\t%s,0x%x", reg_name[i.IType.rt], i.IType.imm);
break;
}
case OP_ANDI:
(*pr)("%s\t%s,%s,0x%x", insn,
reg_name[i.IType.rt], reg_name[i.IType.rs], i.IType.imm);
break;
case OP_LUI:
(*pr)("%s\t%s,0x%x", insn, reg_name[i.IType.rt], i.IType.imm);
break;
case OP_COP0:
switch (i.RType.rs) {
case OP_MF:
case OP_DMF:
case OP_MT:
case OP_DMT:
if ((i.RType.func & 0x07) != 0) {
insn = cop_std[i.RType.rs];
descr = cop0_reg0[i.RType.rd];
if (descr != NULL)
(*pr)("%s0\t%s,%d,%d # %s.%d", insn,
reg_name[i.RType.rt], i.RType.rd,
i.RType.func & 0x07, descr,
i.RType.func & 0x07);
else
(*pr)("%s0\t%s,%d,%d", insn,
reg_name[i.RType.rt], i.RType.rd,
i.RType.func & 0x07);
break;
}
case OP_CF:
case OP_CT:
insn = cop_std[i.RType.rs];
if (i.RType.rs == OP_CF || i.RType.rs == OP_CT)
descr = cop0_reg1[i.RType.rd];
else
descr = cop0_reg0[i.RType.rd];
if (descr != NULL)
(*pr)("%s0\t%s,%d # %s", insn,
reg_name[i.RType.rt], i.RType.rd, descr);
else
(*pr)("%s0\t%s,%d", insn,
reg_name[i.RType.rt], i.RType.rd);
break;
case OP_BC:
(*pr)("bc0%c%c\t",
i.RType.rt & COPz_BC_TF_MASK ? 't' : 'f',
i.RType.rt & COPz_BCL_TF_MASK ? 'l' : ' ');
goto pr_displ;
case OP_C0MISC:
if (i.FRType.func < nitems(cop0_miscname))
insn = cop0_miscname[i.FRType.func];
else
insn = NULL;
if (insn == NULL)
goto unknown;
else
(*pr)("%s", insn);
break;
case OP_TFP_C0MISC:
if (i.FRType.func < nitems(cop0_tfp_miscname))
insn = cop0_tfp_miscname[i.FRType.func];
else
insn = NULL;
if (insn == NULL)
goto unknown;
else
(*pr)("%s", insn);
break;
default:
goto unknown;
}
break;
case OP_COP1:
switch (i.RType.rs) {
case OP_MF:
case OP_DMF:
case OP_CF:
case OP_MFH:
case OP_MT:
case OP_DMT:
case OP_CT:
case OP_MTH:
insn = cop_std[i.RType.rs];
(*pr)("%s1\t%s,f%d", insn,
reg_name[i.RType.rt], i.RType.rd);
break;
case OP_BC:
(*pr)("bc1%c%c\t",
i.RType.rt & COPz_BC_TF_MASK ? 't' : 'f',
i.RType.rt & COPz_BCL_TF_MASK ? 'l' : ' ');
goto pr_displ;
default:
if (fmt_name[i.FRType.fmt] == NULL)
goto unknown;
if (i.FRType.func == 0x11) {
insn = i.FRType.ft & 1 ? "movt" : "movf";
(*pr)("%s.%s\tf%d,f%d,%d",
insn, fmt_name[i.FRType.fmt],
i.FRType.fd, i.FRType.fs, i.FRType.ft >> 2);
break;
}
insn = cop1_name[i.FRType.func];
if (insn == NULL)
goto unknown;
(*pr)("%s.%s\tf%d,f%d,f%d",
insn, fmt_name[i.FRType.fmt],
i.FRType.fd, i.FRType.fs, i.FRType.ft);
}
break;
case OP_COP2:
switch (i.RType.rs) {
case OP_MF:
case OP_DMF:
case OP_CF:
case OP_MFH:
case OP_MT:
case OP_DMT:
case OP_CT:
case OP_MTH:
insn = cop_std[i.RType.rs];
(*pr)("%s2\t%s,f%d", insn,
reg_name[i.RType.rt], i.RType.rd);
break;
case OP_BC:
(*pr)("bc2%c%c\t",
i.RType.rt & COPz_BC_TF_MASK ? 't' : 'f',
i.RType.rt & COPz_BCL_TF_MASK ? 'l' : ' ');
goto pr_displ;
default:
goto unknown;
}
break;
case OP_COP1X:
switch (i.FQType.op4) {
case OP_MADD:
case OP_MSUB:
case OP_NMADD:
case OP_NMSUB:
if (fmt_name[i.FQType.fmt3] == NULL)
goto unknown;
insn = cop1x_op4[i.FQType.op4];
(*pr)("%s.%s\tf%d,f%d,f%d,f%d",
insn, fmt_name[i.FQType.fmt3],
i.FQType.fd, i.FQType.fr,
i.FQType.fs, i.FQType.ft);
break;
default:
insn = cop1x_std[i.FRType.func];
switch (i.FRType.func) {
case OP_LWXC1:
case OP_LDXC1:
(*pr)("%s\tf%d,%s(%s)", insn,
i.FQType.fd, reg_name[i.FQType.ft],
reg_name[i.FQType.fr]);
break;
case OP_SWXC1:
case OP_SDXC1:
(*pr)("%s\tf%d,%s(%s)", insn,
i.FQType.fs, reg_name[i.FQType.ft],
reg_name[i.FQType.fr]);
break;
case OP_PREFX:
(*pr)("%s\t%d,%s(%s)", insn,
i.FQType.fs, reg_name[i.FQType.ft],
reg_name[i.FQType.fr]);
break;
}
break;
}
break;
case OP_LDL:
case OP_LDR:
case OP_LB:
case OP_LH:
case OP_LWL:
case OP_LW:
case OP_LBU:
case OP_LHU:
case OP_LWR:
case OP_LWU:
case OP_SB:
case OP_SH:
case OP_SWL:
case OP_SW:
case OP_SDL:
case OP_SDR:
case OP_SWR:
case OP_LL:
case OP_LLD:
case OP_LD:
case OP_SC:
case OP_SCD:
case OP_SD:
(*pr)("%s\t%s,", insn, reg_name[i.IType.rt]);
loadstore:
(*pr)("%d(%s)", (int16_t)i.IType.imm, reg_name[i.IType.rs]);
break;
case OP_CACHE:
(*pr)("%s\t0x%x,", insn, i.IType.rt);
goto loadstore;
break;
case OP_LWC1:
case OP_LWC2:
case OP_LDC1:
case OP_LDC2:
case OP_SWC1:
case OP_SWC2:
case OP_SWC3:
case OP_SDC1:
case OP_SDC2:
(*pr)("%s\tf%d,", insn, i.IType.rt);
goto loadstore;
case OP_PREF:
(*pr)("%s\t%d,", insn, i.IType.rt);
goto loadstore;
}
(*pr)("\n");
return delay;
}
#ifdef _KERNEL
vaddr_t
db_disasm(vaddr_t loc, int altfmt)
{
extern uint32_t kdbpeek(vaddr_t);
if (dbmd_print_insn(kdbpeek(loc), loc, db_printf)) {
loc += 4;
db_printsym(loc, DB_STGY_ANY, db_printf);
db_printf(":\t ");
dbmd_print_insn(kdbpeek(loc), loc, db_printf);
}
loc += 4;
return loc;
}
#else
int
main()
{
uint32_t insn = 0;
do {
printf("%08x\t", insn);
dbmd_print_insn(insn, 0, printf);
insn++;
if ((insn & 0x00ffffff) == 0)
fprintf(stderr, "%08x\n", insn);
} while (insn != 0);
return 0;
}
#endif