diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libmach/vdb.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libmach/vdb.c')
-rwxr-xr-x | sys/src/libmach/vdb.c | 1166 |
1 files changed, 1166 insertions, 0 deletions
diff --git a/sys/src/libmach/vdb.c b/sys/src/libmach/vdb.c new file mode 100755 index 000000000..d62521fcd --- /dev/null +++ b/sys/src/libmach/vdb.c @@ -0,0 +1,1166 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +/* + * Mips-specific debugger interface + */ + +static char *mipsexcep(Map*, Rgetter); +static int mipsfoll(Map*, uvlong, Rgetter, uvlong*); +static int mipsinst(Map*, uvlong, char, char*, int); +static int mipsdas(Map*, uvlong, char*, int); +static int mipsinstlen(Map*, uvlong); + +/* + * Debugger interface + */ +Machdata mipsmach = +{ + {0, 0, 0, 0xD}, /* break point */ + 4, /* break point size */ + + beswab, /* short to local byte order */ + beswal, /* long to local byte order */ + beswav, /* vlong to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + mipsexcep, /* print exception */ + 0, /* breakpoint fixup */ + beieeesftos, /* single precision float printer */ + beieeedftos, /* double precisioin float printer */ + mipsfoll, /* following addresses */ + mipsinst, /* print instruction */ + mipsdas, /* dissembler */ + mipsinstlen, /* instruction size */ +}; + +Machdata mipsmachle = +{ + {0, 0, 0, 0xD}, /* break point */ + 4, /* break point size */ + + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* vlong to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + mipsexcep, /* print exception */ + 0, /* breakpoint fixup */ + leieeesftos, /* single precision float printer */ + leieeedftos, /* double precisioin float printer */ + mipsfoll, /* following addresses */ + mipsinst, /* print instruction */ + mipsdas, /* dissembler */ + mipsinstlen, /* instruction size */ +}; + +/* + * mips r4k little-endian + */ +Machdata mipsmach2le = +{ + {0, 0, 0, 0xD}, /* break point */ + 4, /* break point size */ + + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* vlong to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + mipsexcep, /* print exception */ + 0, /* breakpoint fixup */ + leieeesftos, /* single precision float printer */ + leieeedftos, /* double precisioin float printer */ + mipsfoll, /* following addresses */ + mipsinst, /* print instruction */ + mipsdas, /* dissembler */ + mipsinstlen, /* instruction size */ +}; + +/* + * mips r4k big-endian + */ +Machdata mipsmach2be = +{ + {0, 0, 0, 0xD}, /* break point */ + 4, /* break point size */ + + beswab, /* short to local byte order */ + beswal, /* long to local byte order */ + beswav, /* vlong to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + mipsexcep, /* print exception */ + 0, /* breakpoint fixup */ + beieeesftos, /* single precision float printer */ + beieeedftos, /* double precisioin float printer */ + mipsfoll, /* following addresses */ + mipsinst, /* print instruction */ + mipsdas, /* dissembler */ + mipsinstlen, /* instruction size */ +}; + + +static char *excname[] = +{ + "external interrupt", + "TLB modification", + "TLB miss (load or fetch)", + "TLB miss (store)", + "address error (load or fetch)", + "address error (store)", + "bus error (fetch)", + "bus error (data load or store)", + "system call", + "breakpoint", + "reserved instruction", + "coprocessor unusable", + "arithmetic overflow", + "undefined 13", + "undefined 14", + "system call", + /* the following is made up */ + "floating point exception" /* FPEXC */ +}; + +static char* +mipsexcep(Map *map, Rgetter rget) +{ + int e; + long c; + + c = (*rget)(map, "CAUSE"); + if(c & 0x00002000) /* INTR3 */ + e = 16; /* Floating point exception */ + else + e = (c>>2)&0x0F; + return excname[e]; +} + + /* mips disassembler and related functions */ + +static char FRAMENAME[] = ".frame"; + +typedef struct { + uvlong addr; + uchar op; /* bits 31-26 */ + uchar rs; /* bits 25-21 */ + uchar rt; /* bits 20-16 */ + uchar rd; /* bits 15-11 */ + uchar sa; /* bits 10-6 */ + uchar function; /* bits 5-0 */ + long immediate; /* bits 15-0 */ + ulong cofun; /* bits 24-0 */ + ulong target; /* bits 25-0 */ + long w0; + long w1; + int size; /* instruction size */ + char *curr; /* fill point in buffer */ + char *end; /* end of buffer */ + char *err; /* error message */ +} Instr; + +static Map *mymap; + +static int +decode(uvlong pc, Instr *i) +{ + ulong w; + + if (get4(mymap, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + + i->addr = pc; + i->size = 1; + i->op = (w >> 26) & 0x3F; + i->rs = (w >> 21) & 0x1F; + i->rt = (w >> 16) & 0x1F; + i->rd = (w >> 11) & 0x1F; + i->sa = (w >> 6) & 0x1F; + i->function = w & 0x3F; + i->immediate = w & 0x0000FFFF; + if (i->immediate & 0x8000) + i->immediate |= ~0x0000FFFF; + i->cofun = w & 0x01FFFFFF; + i->target = w & 0x03FFFFFF; + i->w0 = w; + return 1; +} + +static int +mkinstr(uvlong pc, Instr *i) +{ + Instr x; + + if (decode(pc, i) < 0) + return -1; + /* + * if it's a LUI followed by an ORI, + * it's an immediate load of a large constant. + * fix the LUI immediate in any case. + */ + if (i->op == 0x0F) { + if (decode(pc+4, &x) < 0) + return 0; + i->immediate <<= 16; + if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) { + i->immediate |= (x.immediate & 0xFFFF); + i->w1 = x.w0; + i->size++; + return 1; + } + } + /* + * if it's a LWC1 followed by another LWC1 + * into an adjacent register, it's a load of + * a floating point double. + */ + else if (i->op == 0x31 && (i->rt & 0x01)) { + if (decode(pc+4, &x) < 0) + return 0; + if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) { + i->rt -= 1; + i->w1 = x.w0; + i->size++; + return 1; + } + } + /* + * similarly for double stores + */ + else if (i->op == 0x39 && (i->rt & 0x01)) { + if (decode(pc+4, &x) < 0) + return 0; + if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) { + i->rt -= 1; + i->w1 = x.w0; + i->size++; + } + } + return 1; +} + +#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); +} + +typedef struct Opcode Opcode; + +struct Opcode { + char *mnemonic; + void (*f)(Opcode *, Instr *); + char *ken; +}; + +static void format(char *, Instr *, char *); + +static void +branch(Opcode *o, Instr *i) +{ + if (i->rs == 0 && i->rt == 0) + format("JMP", i, "%b"); + else if (i->rs == 0) + format(o->mnemonic, i, "R%t,%b"); + else if (i->rt < 2) + format(o->mnemonic, i, "R%s,%b"); + else + format(o->mnemonic, i, "R%s,R%t,%b"); +} + +static void +addi(Opcode *o, Instr *i) +{ + if (i->rs == i->rt) + format(o->mnemonic, i, "%i,R%t"); + else if (i->rs == 0) + format("MOVW", i, "%i,R%t"); + else if (i->rs == 30) { + bprint(i, "MOVW\t$"); + i->curr += symoff(i->curr, i->end-i->curr, + i->immediate+mach->sb, CANY); + bprint(i, "(SB),R%d", i->rt); + } + else + format(o->mnemonic, i, o->ken); +} + +static void +andi(Opcode *o, Instr *i) +{ + if (i->rs == i->rt) + format(o->mnemonic, i, "%i,R%t"); + else + format(o->mnemonic, i, o->ken); +} + +static int +plocal(Instr *i, char *m, char r, int store) +{ + int offset; + char *reg; + Symbol s; + + if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) + return 0; + if (s.value > i->immediate) { + if(!getauto(&s, s.value-i->immediate, CAUTO, &s)) + return 0; + reg = "(SP)"; + offset = i->immediate; + } else { + offset = i->immediate-s.value; + if (!getauto(&s, offset-4, CPARAM, &s)) + return 0; + reg = "(FP)"; + } + if (store) + bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg); + else + bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt); + return 1; +} + +static void +lw(Opcode *o, Instr *i, char r) +{ + char *m; + + if (r == 'F') { + if (i->size == 2) + m = "MOVD"; + else + m = "MOVF"; + } + else + m = o->mnemonic; + if (i->rs == 29 && plocal(i, m, r, 0)) + return; + + if (i->rs == 30 && mach->sb) { + bprint(i, "%s\t", m); + i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY); + bprint(i, "(SB),%c%d", r, i->rt); + return; + } + if (r == 'F') + format(m, i, "%l,F%t"); + else + format(m, i, o->ken); +} + +static void +load(Opcode *o, Instr *i) +{ + lw(o, i, 'R'); +} + +static void +lwc1(Opcode *o, Instr *i) +{ + lw(o, i, 'F'); +} + +static void +sw(Opcode *o, Instr *i, char r) +{ + char *m; + + if (r == 'F') { + if (i->size == 2) + m = "MOVD"; + else + m = "MOVF"; + } + else + m = o->mnemonic; + if (i->rs == 29 && plocal(i, m, r, 1)) + return; + + if (i->rs == 30 && mach->sb) { + bprint(i, "%s\t%c%d,", m, r, i->rt); + i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY); + bprint(i, "(SB)"); + return; + } + if (r == 'F') + format(m, i, "F%t,%l"); + else + format(m, i, o->ken); +} + +static void +store(Opcode *o, Instr *i) +{ + sw(o, i, 'R'); +} + +static void +swc1(Opcode *o, Instr *i) +{ + sw(o, i, 'F'); +} + +static void +sll(Opcode *o, Instr *i) +{ + if (i->w0 == 0) + bprint(i, "NOOP"); + else if (i->rd == i->rt) + format(o->mnemonic, i, "$%a,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +sl32(Opcode *o, Instr *i) +{ + i->sa += 32; + if (i->rd == i->rt) + format(o->mnemonic, i, "$%a,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +sllv(Opcode *o, Instr *i) +{ + if (i->rd == i->rt) + format(o->mnemonic, i, "R%s,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +jal(Opcode *o, Instr *i) +{ + if (i->rd == 31) + format("JAL", i, "(R%s)"); + else + format(o->mnemonic, i, o->ken); +} + +static void +add(Opcode *o, Instr *i) +{ + if (i->rd == i->rs) + format(o->mnemonic, i, "R%t,R%d"); + else if (i->rd == i->rt) + format(o->mnemonic, i, "R%s,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +sub(Opcode *o, Instr *i) +{ + if (i->rd == i->rs) + format(o->mnemonic, i, "R%t,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +or(Opcode *o, Instr *i) +{ + if (i->rs == 0 && i->rt == 0) + format("MOVW", i, "$0,R%d"); + else if (i->rs == 0) + format("MOVW", i, "R%t,R%d"); + else if (i->rt == 0) + format("MOVW", i, "R%s,R%d"); + else + add(o, i); +} + +static void +nor(Opcode *o, Instr *i) +{ + if (i->rs == 0 && i->rt == 0 && i->rd == 0) + format("NOP", i, 0); + else + add(o, i); +} + +static char mipscoload[] = "r%t,%l"; +static char mipsload[] = "%l,R%t"; +static char mipsstore[] = "R%t,%l"; +static char mipsalui[] = "%i,R%s,R%t"; +static char mipsalu3op[] = "R%t,R%s,R%d"; +static char mipsrtrs[] = "R%t,R%s"; +static char mipscorsrt[] = "r%s,r%t"; +static char mipscorsi[] = "r%s,%i"; +static char mipscoxxx[] = "%w"; +static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */ +static char mipsfp3[] = "F%t,F%d,F%a"; +static char mipscofp2[] = "f%a,f%d"; /* fd,fs */ +static char mipsfp2[] = "F%d,F%a"; +static char mipscofpc[] = "f%d,f%t"; /* fs,ft */ +static char mipsfpc[] = "F%t,F%d"; + +static Opcode opcodes[64] = { + 0, 0, 0, + 0, 0, 0, + "JMP", 0, "%j", + "JAL", 0, "%j", + "BEQ", branch, 0, + "BNE", branch, 0, + "BLEZ", branch, 0, + "BGTZ", branch, 0, + "ADD", addi, mipsalui, + "ADDU", addi, mipsalui, + "SGT", 0, mipsalui, + "SGTU", 0, mipsalui, + "AND", andi, mipsalui, + "OR", andi, mipsalui, + "XOR", andi, mipsalui, + "MOVW", 0, "$%u,R%t", + "cop0", 0, 0, + "cop1", 0, 0, + "cop2", 0, 0, + "cop3", 0, 0, + "BEQL", branch, 0, + "BNEL", branch, 0, + "BLEZL", branch, 0, + "BGTZL", branch, 0, + "instr18", 0, mipscoxxx, + "instr19", 0, mipscoxxx, + "MOVVL", load, mipsload, + "MOVVR", load, mipsload, + "instr1C", 0, mipscoxxx, + "instr1D", 0, mipscoxxx, + "instr1E", 0, mipscoxxx, + "instr1F", 0, mipscoxxx, + "MOVB", load, mipsload, + "MOVH", load, mipsload, + "lwl", 0, mipscoload, + "MOVW", load, mipsload, + "MOVBU", load, mipsload, + "MOVHU", load, mipsload, + "lwr", 0, mipscoload, + "instr27", 0, mipscoxxx, + "MOVB", store, mipsstore, + "MOVH", store, mipsstore, + "swl", 0, mipscoload, + "MOVW", store, mipsstore, + "MOVVL", store, mipsstore, + "MOVVR", store, mipsstore, + "swr", 0, mipscoload, + "CACHE", 0, "%C,%l", + "ll", 0, mipscoload, + "MOVW", lwc1, mipscoload, + "lwc2", 0, mipscoload, + "lwc3", 0, mipscoload, + "instr34", 0, mipscoxxx, + "ldc1", 0, mipscoload, + "ldc2", 0, mipscoload, + "MOVV", load, mipsload, + "sc", 0, mipscoload, + "swc1", swc1, mipscoload, + "swc2", 0, mipscoload, + "swc3", 0, mipscoload, + "instr3C", 0, mipscoxxx, + "sdc1", 0, mipscoload, + "sdc2", 0, mipscoload, + "MOVV", store, mipsstore, +}; + +static Opcode sopcodes[64] = { + "SLL", sll, "$%a,R%t,R%d", + "special01", 0, mipscoxxx, + "SRL", sll, "$%a,R%t,R%d", + "SRA", sll, "$%a,R%t,R%d", + "SLL", sllv, "R%s,R%t,R%d", + "special05", 0, mipscoxxx, + "SRL", sllv, "R%s,R%t,R%d", + "SRA", sllv, "R%s,R%t,R%d", + "JMP", 0, "(R%s)", + "jal", jal, "r%d,r%s", + "special0A", 0, mipscoxxx, + "special0B", 0, mipscoxxx, + "SYSCALL", 0, 0, + "BREAK", 0, 0, + "special0E", 0, mipscoxxx, + "SYNC", 0, 0, + "MOVW", 0, "HI,R%d", + "MOVW", 0, "R%s,HI", + "MOVW", 0, "LO,R%d", + "MOVW", 0, "R%s,LO", + "SLLV", sllv, "R%s,R%t,R%d", + "special15", 0, mipscoxxx, + "SRLV", sllv, "R%s,R%t,R%d", + "SRAV", sllv, "R%s,R%t,R%d", + "MUL", 0, mipsrtrs, + "MULU", 0, mipsrtrs, + "DIV", 0, mipsrtrs, + "DIVU", 0, mipsrtrs, + "special1C", 0, mipscoxxx, + "special1D", 0, mipscoxxx, + "DDIV", 0, "R%s,R%t", + "special1F", 0, mipscoxxx, + "ADD", add, mipsalu3op, + "ADDU", add, mipsalu3op, + "SUB", sub, mipsalu3op, + "SUBU", sub, mipsalu3op, + "AND", add, mipsalu3op, + "OR", or, mipsalu3op, + "XOR", add, mipsalu3op, + "NOR", nor, mipsalu3op, + "special28", 0, mipscoxxx, + "special29", 0, mipscoxxx, + "SGT", 0, mipsalu3op, + "SGTU", 0, mipsalu3op, + "special2C", 0, mipscoxxx, + "special2D", 0, mipscoxxx, + "special2E", 0, mipscoxxx, + "DSUBU", 0, "R%s,R%t,R%d", + "tge", 0, mipscorsrt, + "tgeu", 0, mipscorsrt, + "tlt", 0, mipscorsrt, + "tltu", 0, mipscorsrt, + "teq", 0, mipscorsrt, + "special35", 0, mipscoxxx, + "tne", 0, mipscorsrt, + "special37", 0, mipscoxxx, + "SLLV", sll, "$%a,R%t,R%d", + "special39", 0, mipscoxxx, + "SRLV", sll, "$%a,R%t,R%d", + "SRAV", sll, "$%a,R%t,R%d", + "SLLV", sl32, "$%a,R%t,R%d", + "special3D", 0, mipscoxxx, + "SRLV", sl32, "$%a,R%t,R%d", + "SRAV", sl32, "$%a,R%t,R%d", +}; + +static Opcode ropcodes[32] = { + "BLTZ", branch, 0, + "BGEZ", branch, 0, + "BLTZL", branch, 0, + "BGEZL", branch, 0, + "regimm04", 0, mipscoxxx, + "regimm05", 0, mipscoxxx, + "regimm06", 0, mipscoxxx, + "regimm07", 0, mipscoxxx, + "tgei", 0, mipscorsi, + "tgeiu", 0, mipscorsi, + "tlti", 0, mipscorsi, + "tltiu", 0, mipscorsi, + "teqi", 0, mipscorsi, + "regimm0D", 0, mipscoxxx, + "tnei", 0, mipscorsi, + "regimm0F", 0, mipscoxxx, + "BLTZAL", branch, 0, + "BGEZAL", branch, 0, + "BLTZALL", branch, 0, + "BGEZALL", branch, 0, + "regimm14", 0, mipscoxxx, + "regimm15", 0, mipscoxxx, + "regimm16", 0, mipscoxxx, + "regimm17", 0, mipscoxxx, + "regimm18", 0, mipscoxxx, + "regimm19", 0, mipscoxxx, + "regimm1A", 0, mipscoxxx, + "regimm1B", 0, mipscoxxx, + "regimm1C", 0, mipscoxxx, + "regimm1D", 0, mipscoxxx, + "regimm1E", 0, mipscoxxx, + "regimm1F", 0, mipscoxxx, +}; + +static Opcode fopcodes[64] = { + "ADD%f", 0, mipsfp3, + "SUB%f", 0, mipsfp3, + "MUL%f", 0, mipsfp3, + "DIV%f", 0, mipsfp3, + "sqrt.%f", 0, mipscofp2, + "ABS%f", 0, mipsfp2, + "MOV%f", 0, mipsfp2, + "NEG%f", 0, mipsfp2, + "finstr08", 0, mipscoxxx, + "finstr09", 0, mipscoxxx, + "finstr0A", 0, mipscoxxx, + "finstr0B", 0, mipscoxxx, + "round.w.%f", 0, mipscofp2, + "trunc.w%f", 0, mipscofp2, + "ceil.w%f", 0, mipscofp2, + "floor.w%f", 0, mipscofp2, + "finstr10", 0, mipscoxxx, + "finstr11", 0, mipscoxxx, + "finstr12", 0, mipscoxxx, + "finstr13", 0, mipscoxxx, + "finstr14", 0, mipscoxxx, + "finstr15", 0, mipscoxxx, + "finstr16", 0, mipscoxxx, + "finstr17", 0, mipscoxxx, + "finstr18", 0, mipscoxxx, + "finstr19", 0, mipscoxxx, + "finstr1A", 0, mipscoxxx, + "finstr1B", 0, mipscoxxx, + "finstr1C", 0, mipscoxxx, + "finstr1D", 0, mipscoxxx, + "finstr1E", 0, mipscoxxx, + "finstr1F", 0, mipscoxxx, + "cvt.s.%f", 0, mipscofp2, + "cvt.d.%f", 0, mipscofp2, + "cvt.e.%f", 0, mipscofp2, + "cvt.q.%f", 0, mipscofp2, + "cvt.w.%f", 0, mipscofp2, + "finstr25", 0, mipscoxxx, + "finstr26", 0, mipscoxxx, + "finstr27", 0, mipscoxxx, + "finstr28", 0, mipscoxxx, + "finstr29", 0, mipscoxxx, + "finstr2A", 0, mipscoxxx, + "finstr2B", 0, mipscoxxx, + "finstr2C", 0, mipscoxxx, + "finstr2D", 0, mipscoxxx, + "finstr2E", 0, mipscoxxx, + "finstr2F", 0, mipscoxxx, + "c.f.%f", 0, mipscofpc, + "c.un.%f", 0, mipscofpc, + "CMPEQ%f", 0, mipsfpc, + "c.ueq.%f", 0, mipscofpc, + "c.olt.%f", 0, mipscofpc, + "c.ult.%f", 0, mipscofpc, + "c.ole.%f", 0, mipscofpc, + "c.ule.%f", 0, mipscofpc, + "c.sf.%f", 0, mipscofpc, + "c.ngle.%f", 0, mipscofpc, + "c.seq.%f", 0, mipscofpc, + "c.ngl.%f", 0, mipscofpc, + "CMPGT%f", 0, mipsfpc, + "c.nge.%f", 0, mipscofpc, + "CMPGE%f", 0, mipsfpc, + "c.ngt.%f", 0, mipscofpc, +}; + +static char *cop0regs[32] = { + "INDEX", "RANDOM", "TLBPHYS", "EntryLo0", + "CONTEXT", "PageMask", "Wired", "Error", + "BADVADDR", "Count", "TLBVIRT", "Compare", + "STATUS", "CAUSE", "EPC", "PRID", + "Config", "LLadr", "WatchLo", "WatchHi", + "20", "21", "22", "23", + "24", "25", "26", "CacheErr", + "TagLo", "TagHi", "ErrorEPC", "31" +}; + +static char fsub[16] = { + 'F', 'D', 'e', 'q', 'W', '?', '?', '?', + '?', '?', '?', '?', '?', '?', '?', '?' +}; + +static char *cacheps[] = { + "I", "D", "SI", "SD" +}; + +static char *cacheop[] = { + "IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV" +}; + +static void +format(char *mnemonic, Instr *i, char *f) +{ + if (mnemonic) + format(0, i, mnemonic); + if (f == 0) + return; + if (mnemonic) + if (i->curr < i->end) + *i->curr++ = '\t'; + for ( ; *f && i->curr < i->end; f++) { + if (*f != '%') { + *i->curr++ = *f; + continue; + } + switch (*++f) { + + case 's': + bprint(i, "%d", i->rs); + break; + + case 't': + bprint(i, "%d", i->rt); + break; + + case 'd': + bprint(i, "%d", i->rd); + break; + + case 'a': + bprint(i, "%d", i->sa); + break; + + case 'l': + bprint(i, "%lx(R%d)",i->immediate, i->rs); + break; + + case 'i': + bprint(i, "$%lx", i->immediate); + break; + + case 'u': + i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY); + bprint(i, "(SB)"); + break; + + case 'j': + i->curr += symoff(i->curr, i->end-i->curr, + (i->target<<2)|(i->addr & 0xF0000000), CANY); + bprint(i, "(SB)"); + break; + + case 'b': + i->curr += symoff(i->curr, i->end-i->curr, + (i->immediate<<2)+i->addr+4, CANY); + break; + + case 'c': + bprint(i, "$%lx", i->cofun); + break; + + case 'w': + bprint(i, "[%lux]", i->w0); + break; + + case 'm': + bprint(i, "M(%s)", cop0regs[i->rd]); + break; + + case 'f': + *i->curr++ = fsub[i->rs & 0x0F]; + break; + + case 'C': + bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]); + break; + + case '\0': + *i->curr++ = '%'; + return; + + default: + bprint(i, "%%%c", *f); + break; + } + } + *i->curr = 0; +} + +static void +copz(int cop, Instr *i) +{ + char *f, *m, buf[16]; + + m = buf; + f = "%t,%d"; + switch (i->rs) { + + case 0: + sprint(buf, "mfc%d", cop); + break; + + case 2: + sprint(buf, "cfc%d", cop); + break; + + case 4: + sprint(buf, "mtc%d", cop); + break; + + case 6: + sprint(buf, "ctc%d", cop); + break; + + case 8: + f = "%b"; + switch (i->rt) { + + case 0: + sprint(buf, "bc%df", cop); + break; + + case 1: + sprint(buf, "bc%dt", cop); + break; + + case 2: + sprint(buf, "bc%dfl", cop); + break; + + case 3: + sprint(buf, "bc%dtl", cop); + break; + + default: + sprint(buf, "cop%d", cop); + f = mipscoxxx; + break; + } + break; + + default: + sprint(buf, "cop%d", cop); + if (i->rs & 0x10) + f = "function %c"; + else + f = mipscoxxx; + break; + } + format(m, i, f); +} + +static void +cop0(Instr *i) +{ + char *m = 0; + + if (i->rs < 8) { + switch (i->rs) { + + case 0: + case 1: + format("MOVW", i, "%m,R%t"); + return; + + case 4: + case 5: + format("MOVW", i, "R%t,%m"); + return; + } + } + else if (i->rs >= 0x10) { + switch (i->cofun) { + + case 1: + m = "TLBR"; + break; + + case 2: + m = "TLBWI"; + break; + + case 6: + m = "TLBWR"; + break; + + case 8: + m = "TLBP"; + break; + + case 16: + m = "RFE"; + break; + + case 32: + m = "ERET"; + break; + } + if (m) { + format(m, i, 0); + return; + } + } + copz(0, i); +} + +static void +cop1(Instr *i) +{ + char *m = "MOVW"; + + switch (i->rs) { + + case 0: + format(m, i, "F%d,R%t"); + return; + + case 2: + format(m, i, "FCR%d,R%t"); + return; + + case 4: + format(m, i, "R%t,F%d"); + return; + + case 6: + format(m, i, "R%t,FCR%d"); + return; + + case 8: + switch (i->rt) { + + case 0: + format("BFPF", i, "%b"); + return; + + case 1: + format("BFPT", i, "%b"); + return; + } + break; + } + copz(1, i); +} + +static int +printins(Map *map, uvlong pc, char *buf, int n) +{ + Instr i; + Opcode *o; + uchar op; + + i.curr = buf; + i.end = buf+n-1; + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + switch (i.op) { + + case 0x00: /* SPECIAL */ + o = sopcodes; + op = i.function; + break; + + case 0x01: /* REGIMM */ + o = ropcodes; + op = i.rt; + break; + + case 0x10: /* COP0 */ + cop0(&i); + return i.size*4; + + case 0x11: /* COP1 */ + if (i.rs & 0x10) { + o = fopcodes; + op = i.function; + break; + } + cop1(&i); + return i.size*4; + + case 0x12: /* COP2 */ + case 0x13: /* COP3 */ + copz(i.op-0x10, &i); + return i.size*4; + + default: + o = opcodes; + op = i.op; + break; + } + if (o[op].f) + (*o[op].f)(&o[op], &i); + else + format(o[op].mnemonic, &i, o[op].ken); + return i.size*4; +} + +extern int _mipscoinst(Map *, uvlong, char*, int); + + /* modifier 'I' toggles the default disassembler type */ +static int +mipsinst(Map *map, uvlong pc, char modifier, char *buf, int n) +{ + if ((asstype == AMIPSCO && modifier == 'i') + || (asstype == AMIPS && modifier == 'I')) + return _mipscoinst(map, pc, buf, n); + else + return printins(map, pc, buf, n); +} + +static int +mipsdas(Map *map, uvlong pc, char *buf, int n) +{ + Instr i; + + i.curr = buf; + i.end = buf+n; + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + if (i.end-i.curr > 8) + i.curr = _hexify(buf, i.w0, 7); + if (i.size == 2 && i.end-i.curr > 9) { + *i.curr++ = ' '; + i.curr = _hexify(i.curr, i.w1, 7); + } + *i.curr = 0; + return i.size*4; +} + +static int +mipsinstlen(Map *map, uvlong pc) +{ + Instr i; + + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + return i.size*4; +} + +static int +mipsfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll) +{ + ulong w, l; + char buf[8]; + Instr i; + + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + w = i.w0; + if((w&0xF3600000) == 0x41000000){ /* branch on coprocessor */ + Conditional: + foll[0] = pc+8; + l = ((w&0xFFFF)<<2); + if(w & 0x8000) + l |= 0xFFFC0000; + foll[1] = pc+4 + l; + return 2; + } + + l = (w&0xFC000000)>>26; + switch(l){ + case 0: /* SPECIAL */ + if((w&0x3E) == 0x08){ /* JR, JALR */ + sprint(buf, "R%ld", (w>>21)&0x1F); + foll[0] = (*rget)(map, buf); + return 1; + } + foll[0] = pc+i.size*4; + return 1; + case 0x30: /* Load-Linked followed by NOP, STC */ + foll[0] = pc+12; + return 1; + case 1: /* BCOND */ + case 4: /* BEQ */ + case 20: /* BEQL */ + case 5: /* BNE */ + case 21: /* BNEL */ + case 6: /* BLEZ */ + case 22: /* BLEZL */ + case 7: /* BGTZ */ + case 23: /* BGTZL */ + goto Conditional; + case 2: /* J */ + case 3: /* JAL */ + foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2); + return 1; + } + + foll[0] = pc+i.size*4; + return 1; +} |