v3 candidate
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user