v3 candidate
This commit is contained in:
@@ -0,0 +1,288 @@
|
||||
package disasm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// diAArch64 is a heuristic AArch64 (ARMv8 A64) decoder. It recognises a
|
||||
// subset of instructions commonly seen in disassembly and falls back to
|
||||
// ".word 0x…" for everything else. 32-bit fixed-width little-endian.
|
||||
func diAArch64(buf []byte, base int64, maxInstr int) []map[string]any {
|
||||
out := []map[string]any{}
|
||||
i := 0
|
||||
for i+4 <= len(buf) && len(out) < maxInstr {
|
||||
w := binary.LittleEndian.Uint32(buf[i : i+4])
|
||||
mn, ops, conf := decodeA64(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,
|
||||
})
|
||||
i += 4
|
||||
}
|
||||
// Tail bytes (not multiple of 4).
|
||||
for i < len(buf) && len(out) < maxInstr {
|
||||
end := i + 1
|
||||
out = append(out, map[string]any{
|
||||
"offset": base + int64(i),
|
||||
"bytes": hexStr(buf[i:end]),
|
||||
"mnemonic": "db",
|
||||
"operands": hexCommaList(buf[i:end]),
|
||||
"confident": false,
|
||||
})
|
||||
i++
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func decodeA64(w uint32, pc int64) (string, string, bool) {
|
||||
// NOP
|
||||
if w == 0xd503201f {
|
||||
return "nop", "", true
|
||||
}
|
||||
// RET Xn (default x30)
|
||||
if w&0xfffffc1f == 0xd65f0000 {
|
||||
rn := (w >> 5) & 0x1f
|
||||
if rn == 30 {
|
||||
return "ret", "", true
|
||||
}
|
||||
return "ret", regX(rn), true
|
||||
}
|
||||
// BR Xn
|
||||
if w&0xfffffc1f == 0xd61f0000 {
|
||||
return "br", regX((w >> 5) & 0x1f), true
|
||||
}
|
||||
// BLR Xn
|
||||
if w&0xfffffc1f == 0xd63f0000 {
|
||||
return "blr", regX((w >> 5) & 0x1f), true
|
||||
}
|
||||
// B / BL (unconditional branch, imm26 * 4, signed)
|
||||
if w&0x7c000000 == 0x14000000 {
|
||||
imm := signExtend64(uint64(w&0x03ffffff)<<2, 28)
|
||||
target := pc + int64(imm)
|
||||
if w&0x80000000 != 0 {
|
||||
return "bl", fmt.Sprintf("0x%x", target), true
|
||||
}
|
||||
return "b", fmt.Sprintf("0x%x", target), true
|
||||
}
|
||||
// B.cond (conditional branch, imm19*4)
|
||||
if w&0xff000010 == 0x54000000 {
|
||||
cond := int(w & 0xf)
|
||||
imm := signExtend64(uint64((w>>5)&0x7ffff)<<2, 21)
|
||||
return "b." + condName(cond), fmt.Sprintf("0x%x", pc+int64(imm)), true
|
||||
}
|
||||
// CBZ / CBNZ
|
||||
if w&0x7e000000 == 0x34000000 {
|
||||
sf := (w >> 31) & 1
|
||||
op := (w >> 24) & 1
|
||||
rt := w & 0x1f
|
||||
imm := signExtend64(uint64((w>>5)&0x7ffff)<<2, 21)
|
||||
mn := "cbz"
|
||||
if op == 1 {
|
||||
mn = "cbnz"
|
||||
}
|
||||
r := regX(rt)
|
||||
if sf == 0 {
|
||||
r = regW(rt)
|
||||
}
|
||||
return mn, fmt.Sprintf("%s, 0x%x", r, pc+int64(imm)), true
|
||||
}
|
||||
// MOVZ / MOVN / MOVK (wide immediate)
|
||||
if w&0x1f800000 == 0x12800000 {
|
||||
sf := (w >> 31) & 1
|
||||
opc := (w >> 29) & 0x3
|
||||
hw := (w >> 21) & 0x3
|
||||
imm16 := (w >> 5) & 0xffff
|
||||
rd := w & 0x1f
|
||||
mn := "movn"
|
||||
switch opc {
|
||||
case 0b10:
|
||||
mn = "movz"
|
||||
case 0b11:
|
||||
mn = "movk"
|
||||
}
|
||||
shift := hw * 16
|
||||
r := regX(rd)
|
||||
if sf == 0 {
|
||||
r = regW(rd)
|
||||
}
|
||||
if shift == 0 {
|
||||
return mn, fmt.Sprintf("%s, #0x%x", r, imm16), true
|
||||
}
|
||||
return mn, fmt.Sprintf("%s, #0x%x, lsl #%d", r, imm16, shift), true
|
||||
}
|
||||
// ADR / ADRP
|
||||
if w&0x1f000000 == 0x10000000 {
|
||||
page := (w >> 31) & 1
|
||||
rd := w & 0x1f
|
||||
immlo := uint64((w >> 29) & 0x3)
|
||||
immhi := uint64((w >> 5) & 0x7ffff)
|
||||
imm := (immhi << 2) | immlo
|
||||
mn := "adr"
|
||||
shift := uint(21)
|
||||
signed := signExtend64(imm, shift)
|
||||
if page == 1 {
|
||||
mn = "adrp"
|
||||
signed = signExtend64(imm<<12, 33)
|
||||
// adrp target is page-aligned: pc & ~0xFFF
|
||||
return mn, fmt.Sprintf("%s, 0x%x", regX(rd), (pc & ^int64(0xfff))+int64(signed)), true
|
||||
}
|
||||
return mn, fmt.Sprintf("%s, 0x%x", regX(rd), pc+int64(signed)), true
|
||||
}
|
||||
// ADD / SUB (immediate)
|
||||
if w&0x1f000000 == 0x11000000 {
|
||||
sf := (w >> 31) & 1
|
||||
op := (w >> 30) & 1
|
||||
sh := (w >> 22) & 1
|
||||
imm12 := (w >> 10) & 0xfff
|
||||
rn := (w >> 5) & 0x1f
|
||||
rd := w & 0x1f
|
||||
mn := "add"
|
||||
if op == 1 {
|
||||
mn = "sub"
|
||||
}
|
||||
lhs := regX(rd)
|
||||
mid := regX(rn)
|
||||
if sf == 0 {
|
||||
lhs = regW(rd)
|
||||
mid = regW(rn)
|
||||
}
|
||||
if sh == 1 {
|
||||
return mn, fmt.Sprintf("%s, %s, #0x%x, lsl #12", lhs, mid, imm12), true
|
||||
}
|
||||
return mn, fmt.Sprintf("%s, %s, #0x%x", lhs, mid, imm12), true
|
||||
}
|
||||
// LDR / STR (unsigned offset, 32/64-bit int)
|
||||
if w&0x3fc00000 == 0x39400000 || w&0x3fc00000 == 0x39000000 {
|
||||
size := (w >> 30) & 0x3
|
||||
l := (w >> 22) & 1
|
||||
imm12 := (w >> 10) & 0xfff
|
||||
rn := (w >> 5) & 0x1f
|
||||
rt := w & 0x1f
|
||||
var mn string
|
||||
if l == 1 {
|
||||
mn = "ldr"
|
||||
} else {
|
||||
mn = "str"
|
||||
}
|
||||
scale := int(1 << size)
|
||||
imm := int(imm12) * scale
|
||||
var reg string
|
||||
if size == 3 {
|
||||
reg = regX(rt)
|
||||
} else {
|
||||
reg = regW(rt)
|
||||
}
|
||||
base := regXorSP(rn)
|
||||
if imm == 0 {
|
||||
return mn, fmt.Sprintf("%s, [%s]", reg, base), true
|
||||
}
|
||||
return mn, fmt.Sprintf("%s, [%s, #0x%x]", reg, base, imm), true
|
||||
}
|
||||
// LDR (literal / PC-rel)
|
||||
if w&0xbf000000 == 0x18000000 {
|
||||
sf := (w >> 30) & 1
|
||||
imm := signExtend64(uint64((w>>5)&0x7ffff)<<2, 21)
|
||||
rt := w & 0x1f
|
||||
reg := regW(rt)
|
||||
if sf == 1 {
|
||||
reg = regX(rt)
|
||||
}
|
||||
return "ldr", fmt.Sprintf("%s, 0x%x", reg, pc+int64(imm)), true
|
||||
}
|
||||
// ORR / AND / EOR (shifted reg) — simplified detection, no shifts reported.
|
||||
if w&0x7f200000 == 0x2a000000 { // ORR (32/64) w/ shift=0
|
||||
sf := (w >> 31) & 1
|
||||
rm := (w >> 16) & 0x1f
|
||||
rn := (w >> 5) & 0x1f
|
||||
rd := w & 0x1f
|
||||
// MOV (register) alias: ORR Xd, XZR, Xm → MOV Xd, Xm (when Rn==31 and shift==0)
|
||||
if rn == 31 && ((w>>10)&0x3f) == 0 && ((w>>22)&0x3) == 0 {
|
||||
if sf == 1 {
|
||||
return "mov", fmt.Sprintf("%s, %s", regX(rd), regX(rm)), true
|
||||
}
|
||||
return "mov", fmt.Sprintf("%s, %s", regW(rd), regW(rm)), true
|
||||
}
|
||||
if sf == 1 {
|
||||
return "orr", fmt.Sprintf("%s, %s, %s", regX(rd), regX(rn), regX(rm)), true
|
||||
}
|
||||
return "orr", fmt.Sprintf("%s, %s, %s", regW(rd), regW(rn), regW(rm)), true
|
||||
}
|
||||
// SVC #imm16
|
||||
if w&0xffe0001f == 0xd4000001 {
|
||||
imm16 := (w >> 5) & 0xffff
|
||||
return "svc", fmt.Sprintf("#0x%x", imm16), true
|
||||
}
|
||||
// BRK #imm16
|
||||
if w&0xffe0001f == 0xd4200000 {
|
||||
imm16 := (w >> 5) & 0xffff
|
||||
return "brk", fmt.Sprintf("#0x%x", imm16), true
|
||||
}
|
||||
// HINT family → treat common ones
|
||||
if w&0xfffff01f == 0xd503201f {
|
||||
op := (w >> 5) & 0x7f
|
||||
switch op {
|
||||
case 0:
|
||||
return "nop", "", true
|
||||
case 1:
|
||||
return "yield", "", true
|
||||
case 2:
|
||||
return "wfe", "", true
|
||||
case 3:
|
||||
return "wfi", "", true
|
||||
case 4:
|
||||
return "sev", "", true
|
||||
case 5:
|
||||
return "sevl", "", true
|
||||
}
|
||||
return "hint", fmt.Sprintf("#0x%x", op), true
|
||||
}
|
||||
// Fallback
|
||||
return ".word", fmt.Sprintf("0x%08x", w), false
|
||||
}
|
||||
|
||||
func regX(r uint32) string {
|
||||
r &= 0x1f
|
||||
if r == 31 {
|
||||
return "xzr"
|
||||
}
|
||||
return fmt.Sprintf("x%d", r)
|
||||
}
|
||||
func regW(r uint32) string {
|
||||
r &= 0x1f
|
||||
if r == 31 {
|
||||
return "wzr"
|
||||
}
|
||||
return fmt.Sprintf("w%d", r)
|
||||
}
|
||||
|
||||
// regXorSP is used for the "Rn" slot in memory ops where 31 means SP, not XZR.
|
||||
func regXorSP(r uint32) string {
|
||||
r &= 0x1f
|
||||
if r == 31 {
|
||||
return "sp"
|
||||
}
|
||||
return fmt.Sprintf("x%d", r)
|
||||
}
|
||||
|
||||
func condName(c int) string {
|
||||
names := []string{
|
||||
"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt", "gt", "le", "al", "nv",
|
||||
}
|
||||
if c >= 0 && c < 16 {
|
||||
return names[c]
|
||||
}
|
||||
return fmt.Sprintf("c%d", c)
|
||||
}
|
||||
|
||||
func signExtend64(v uint64, bits uint) int64 {
|
||||
mask := uint64(1) << (bits - 1)
|
||||
if v&mask != 0 {
|
||||
v |= ^uint64(0) << bits
|
||||
}
|
||||
return int64(v)
|
||||
}
|
||||
Reference in New Issue
Block a user