118 lines
3.3 KiB
Go
118 lines
3.3 KiB
Go
package disasm
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
)
|
|
|
|
func diThumb16(buf []byte, base int64, maxInstr int) []map[string]any {
|
|
out := []map[string]any{}
|
|
for i := 0; i+2 <= len(buf) && len(out) < maxInstr; i += 2 {
|
|
h := binary.LittleEndian.Uint16(buf[i : i+2])
|
|
mn, ops, conf := decodeThumb16(h, base+int64(i))
|
|
out = append(out, map[string]any{
|
|
"offset": base + int64(i),
|
|
"bytes": hexStr(buf[i : i+2]),
|
|
"mnemonic": mn,
|
|
"operands": ops,
|
|
"confident": conf,
|
|
})
|
|
}
|
|
for i := len(buf) - len(buf)%2; 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 decodeThumb16(h uint16, pc int64) (string, string, bool) {
|
|
switch {
|
|
case h == 0xbf00:
|
|
return "nop", "", true
|
|
case h&0xff87 == 0x4700:
|
|
return "bx", thumbHighReg((h >> 3) & 0xf), true
|
|
case h&0xff87 == 0x4780:
|
|
return "blx", thumbHighReg((h >> 3) & 0xf), true
|
|
case h&0xf800 == 0xe000:
|
|
imm := signExtend64(uint64(h&0x07ff)<<1, 12)
|
|
return "b", fmt.Sprintf("0x%x", pc+4+imm), true
|
|
case h&0xf000 == 0xd000 && h&0x0f00 != 0x0f00:
|
|
cond := uint32((h >> 8) & 0xf)
|
|
imm := signExtend64(uint64(h&0x00ff)<<1, 9)
|
|
return "b" + armCondSuffix(cond), fmt.Sprintf("0x%x", pc+4+imm), true
|
|
case h&0xff00 == 0xdf00:
|
|
return "svc", fmt.Sprintf("#0x%x", h&0x00ff), true
|
|
case h&0xfe00 == 0xb400:
|
|
mask := uint32(h & 0x00ff)
|
|
if h&0x0100 != 0 {
|
|
mask |= 1 << 14
|
|
}
|
|
return "push", armRegList(mask), true
|
|
case h&0xfe00 == 0xbc00:
|
|
mask := uint32(h & 0x00ff)
|
|
if h&0x0100 != 0 {
|
|
mask |= 1 << 15
|
|
}
|
|
return "pop", armRegList(mask), true
|
|
case h&0xf800 == 0x2000:
|
|
rd := uint32((h >> 8) & 0x7)
|
|
return "movs", fmt.Sprintf("%s, #0x%x", armReg(rd), h&0x00ff), true
|
|
case h&0xf800 == 0x2800:
|
|
rn := uint32((h >> 8) & 0x7)
|
|
return "cmp", fmt.Sprintf("%s, #0x%x", armReg(rn), h&0x00ff), true
|
|
case h&0xf800 == 0x3000:
|
|
rd := uint32((h >> 8) & 0x7)
|
|
return "adds", fmt.Sprintf("%s, #0x%x", armReg(rd), h&0x00ff), true
|
|
case h&0xf800 == 0x3800:
|
|
rd := uint32((h >> 8) & 0x7)
|
|
return "subs", fmt.Sprintf("%s, #0x%x", armReg(rd), h&0x00ff), true
|
|
case h&0xfc00 == 0x4000:
|
|
op := (h >> 6) & 0xf
|
|
rs := uint32((h >> 3) & 0x7)
|
|
rd := uint32(h & 0x7)
|
|
names := [...]string{"ands", "eors", "lsls", "lsrs", "asrs", "adcs", "sbcs", "rors", "tst", "rsbs", "cmp", "cmn", "orrs", "muls", "bics", "mvns"}
|
|
mn := names[op]
|
|
if op == 8 || op == 10 || op == 11 {
|
|
return mn, fmt.Sprintf("%s, %s", armReg(rd), armReg(rs)), true
|
|
}
|
|
return mn, fmt.Sprintf("%s, %s", armReg(rd), armReg(rs)), true
|
|
case h&0xfe00 == 0x1800:
|
|
rm := uint32((h >> 6) & 0x7)
|
|
rn := uint32((h >> 3) & 0x7)
|
|
rd := uint32(h & 0x7)
|
|
mn := "adds"
|
|
if h&0x0200 != 0 {
|
|
mn = "subs"
|
|
}
|
|
return mn, fmt.Sprintf("%s, %s, %s", armReg(rd), armReg(rn), armReg(rm)), true
|
|
case h&0xe000 == 0x6000:
|
|
imm := uint32((h>>6)&0x1f) * 4
|
|
rn := uint32((h >> 3) & 0x7)
|
|
rd := uint32(h & 0x7)
|
|
mn := "str"
|
|
if h&0x0800 != 0 {
|
|
mn = "ldr"
|
|
}
|
|
return mn, fmt.Sprintf("%s, [%s, #0x%x]", armReg(rd), armReg(rn), imm), true
|
|
}
|
|
return ".hword", fmt.Sprintf("0x%04x", h), false
|
|
}
|
|
|
|
func thumbHighReg(r uint16) string {
|
|
if r == 13 {
|
|
return "sp"
|
|
}
|
|
if r == 14 {
|
|
return "lr"
|
|
}
|
|
if r == 15 {
|
|
return "pc"
|
|
}
|
|
return fmt.Sprintf("r%d", r)
|
|
}
|