145 lines
4.6 KiB
Go
145 lines
4.6 KiB
Go
package disasm
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
)
|
|
|
|
func diMIPS32(buf []byte, base int64, little bool, maxInstr int) []map[string]any {
|
|
out := []map[string]any{}
|
|
for i := 0; i+4 <= len(buf) && len(out) < maxInstr; i += 4 {
|
|
var w uint32
|
|
if little {
|
|
w = binary.LittleEndian.Uint32(buf[i : i+4])
|
|
} else {
|
|
w = binary.BigEndian.Uint32(buf[i : i+4])
|
|
}
|
|
mn, ops, conf := decodeMIPS32(w, base+int64(i))
|
|
out = append(out, map[string]any{
|
|
"offset": base + int64(i),
|
|
"bytes": hexStr(buf[i : i+4]),
|
|
"mnemonic": mn,
|
|
"operands": ops,
|
|
"confident": conf,
|
|
})
|
|
}
|
|
for i := len(buf) - len(buf)%4; i < len(buf) && len(out) < maxInstr; i++ {
|
|
out = append(out, map[string]any{
|
|
"offset": base + int64(i),
|
|
"bytes": hexStr(buf[i : i+1]),
|
|
"mnemonic": "db",
|
|
"operands": hexCommaList(buf[i : i+1]),
|
|
"confident": false,
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func decodeMIPS32(w uint32, pc int64) (string, string, bool) {
|
|
if w == 0 {
|
|
return "nop", "", true
|
|
}
|
|
op := (w >> 26) & 0x3f
|
|
rs := (w >> 21) & 0x1f
|
|
rt := (w >> 16) & 0x1f
|
|
rd := (w >> 11) & 0x1f
|
|
shamt := (w >> 6) & 0x1f
|
|
funct := w & 0x3f
|
|
imm := uint16(w)
|
|
simm := int16(imm)
|
|
target26 := w & 0x03ffffff
|
|
|
|
switch op {
|
|
case 0x00:
|
|
switch funct {
|
|
case 0x00:
|
|
return "sll", fmt.Sprintf("%s, %s, %d", mipsReg(rd), mipsReg(rt), shamt), true
|
|
case 0x02:
|
|
return "srl", fmt.Sprintf("%s, %s, %d", mipsReg(rd), mipsReg(rt), shamt), true
|
|
case 0x03:
|
|
return "sra", fmt.Sprintf("%s, %s, %d", mipsReg(rd), mipsReg(rt), shamt), true
|
|
case 0x08:
|
|
return "jr", mipsReg(rs), true
|
|
case 0x09:
|
|
return "jalr", fmt.Sprintf("%s, %s", mipsReg(rd), mipsReg(rs)), true
|
|
case 0x0c:
|
|
return "syscall", fmt.Sprintf("0x%x", (w>>6)&0xfffff), true
|
|
case 0x20:
|
|
return "add", fmt.Sprintf("%s, %s, %s", mipsReg(rd), mipsReg(rs), mipsReg(rt)), true
|
|
case 0x21:
|
|
return "addu", fmt.Sprintf("%s, %s, %s", mipsReg(rd), mipsReg(rs), mipsReg(rt)), true
|
|
case 0x22:
|
|
return "sub", fmt.Sprintf("%s, %s, %s", mipsReg(rd), mipsReg(rs), mipsReg(rt)), true
|
|
case 0x23:
|
|
return "subu", fmt.Sprintf("%s, %s, %s", mipsReg(rd), mipsReg(rs), mipsReg(rt)), true
|
|
case 0x24:
|
|
return "and", fmt.Sprintf("%s, %s, %s", mipsReg(rd), mipsReg(rs), mipsReg(rt)), true
|
|
case 0x25:
|
|
return "or", fmt.Sprintf("%s, %s, %s", mipsReg(rd), mipsReg(rs), mipsReg(rt)), true
|
|
case 0x26:
|
|
return "xor", fmt.Sprintf("%s, %s, %s", mipsReg(rd), mipsReg(rs), mipsReg(rt)), true
|
|
case 0x27:
|
|
return "nor", fmt.Sprintf("%s, %s, %s", mipsReg(rd), mipsReg(rs), mipsReg(rt)), true
|
|
case 0x2a:
|
|
return "slt", fmt.Sprintf("%s, %s, %s", mipsReg(rd), mipsReg(rs), mipsReg(rt)), true
|
|
}
|
|
case 0x02:
|
|
return "j", fmt.Sprintf("0x%x", mipsJumpTarget(pc, target26)), true
|
|
case 0x03:
|
|
return "jal", fmt.Sprintf("0x%x", mipsJumpTarget(pc, target26)), true
|
|
case 0x04:
|
|
return "beq", fmt.Sprintf("%s, %s, 0x%x", mipsReg(rs), mipsReg(rt), mipsBranchTarget(pc, simm)), true
|
|
case 0x05:
|
|
return "bne", fmt.Sprintf("%s, %s, 0x%x", mipsReg(rs), mipsReg(rt), mipsBranchTarget(pc, simm)), true
|
|
case 0x08:
|
|
return "addi", fmt.Sprintf("%s, %s, %d", mipsReg(rt), mipsReg(rs), simm), true
|
|
case 0x09:
|
|
return "addiu", fmt.Sprintf("%s, %s, %d", mipsReg(rt), mipsReg(rs), simm), true
|
|
case 0x0a:
|
|
return "slti", fmt.Sprintf("%s, %s, %d", mipsReg(rt), mipsReg(rs), simm), true
|
|
case 0x0c:
|
|
return "andi", fmt.Sprintf("%s, %s, 0x%x", mipsReg(rt), mipsReg(rs), imm), true
|
|
case 0x0d:
|
|
return "ori", fmt.Sprintf("%s, %s, 0x%x", mipsReg(rt), mipsReg(rs), imm), true
|
|
case 0x0e:
|
|
return "xori", fmt.Sprintf("%s, %s, 0x%x", mipsReg(rt), mipsReg(rs), imm), true
|
|
case 0x0f:
|
|
return "lui", fmt.Sprintf("%s, 0x%x", mipsReg(rt), imm), true
|
|
case 0x20:
|
|
return "lb", mipsMem(rt, rs, simm), true
|
|
case 0x21:
|
|
return "lh", mipsMem(rt, rs, simm), true
|
|
case 0x23:
|
|
return "lw", mipsMem(rt, rs, simm), true
|
|
case 0x28:
|
|
return "sb", mipsMem(rt, rs, simm), true
|
|
case 0x29:
|
|
return "sh", mipsMem(rt, rs, simm), true
|
|
case 0x2b:
|
|
return "sw", mipsMem(rt, rs, simm), true
|
|
}
|
|
return ".word", fmt.Sprintf("0x%08x", w), false
|
|
}
|
|
|
|
func mipsJumpTarget(pc int64, target uint32) int64 {
|
|
upper := uint64(pc+4) & 0xfffffffff0000000
|
|
return int64(upper | uint64(target<<2))
|
|
}
|
|
|
|
func mipsBranchTarget(pc int64, imm int16) int64 {
|
|
return pc + 4 + int64(imm)*4
|
|
}
|
|
|
|
func mipsMem(rt, rs uint32, off int16) string {
|
|
return fmt.Sprintf("%s, %d(%s)", mipsReg(rt), off, mipsReg(rs))
|
|
}
|
|
|
|
func mipsReg(r uint32) string {
|
|
return [...]string{
|
|
"$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
|
|
"$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
|
|
"$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
|
|
"$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
|
|
}[r&0x1f]
|
|
}
|