Capstone 5 updates (5.0.0rc2) (#1701)

* Use latest tagged capstone==5.0.0rc2

* Fix aarch64

* Fix ARM

* New x86 instrution test

Co-authored-by: feliam <[email protected]>
Co-authored-by: Boyan MILANOV <[email protected]>
This commit is contained in:
Eric Kilmer
2022-05-18 10:31:28 -04:00
committed by GitHub
co-authored by feliam Boyan MILANOV
parent f8ad2dfdb1
commit 9e11bc9ae9
6 changed files with 197 additions and 99 deletions
+2
View File
@@ -17,3 +17,5 @@ exclude_lines =
# We don't bother testing code that's explicitly unimplemented
raise NotImplementedError
raise AssertionError
raise Aarch64InvalidInstruction
+15 -62
View File
@@ -1,4 +1,4 @@
import warnings
from typing import NamedTuple
from copy import copy
import capstone as cs
@@ -17,7 +17,6 @@ from .abstractcpu import (
Operand,
instruction,
)
from .arm import HighBit, Armv7Operand
from .bitwise import SInt, UInt, ASR, LSL, LSR, ROR, Mask, GetNBits
from .register import Register
from ...core.smtlib import Operators
@@ -306,45 +305,7 @@ class Aarch64Cpu(Cpu):
# work for B.cond. Instead of being set to something like 'b.eq',
# it just returns 'b'.
name = insn.mnemonic.upper()
name = OP_NAME_MAP.get(name, name)
ops = insn.operands
name_list = name.split(".")
# Make sure MOV (bitmask immediate) and MOV (register) go through 'MOV'.
if (
name == "ORR"
and len(ops) == 3
and ops[1].type == cs.arm64.ARM64_OP_REG
and ops[1].reg in ["WZR", "XZR"]
and not ops[2].is_shifted()
):
name = "MOV"
insn._raw.mnemonic = name.lower().encode("ascii")
del ops[1]
# Map all B.cond variants to a single implementation.
elif len(name_list) == 2 and name_list[0] == "B" and insn.cc != cs.arm64.ARM64_CC_INVALID:
name = "B_cond"
# XXX: BFI is only valid when Rn != 11111:
# https://github.com/aquynh/capstone/issues/1441
elif (
name == "BFI"
and len(ops) == 4
and ops[1].type == cs.arm64.ARM64_OP_REG
and ops[1].reg in ["WZR", "XZR"]
):
name = "BFC"
insn._raw.mnemonic = name.lower().encode("ascii")
del ops[1]
# XXX: CMEQ incorrectly sets the type to 'ARM64_OP_FP' for
# 'cmeq v0.16b, v1.16b, #0':
# https://github.com/aquynh/capstone/issues/1443
elif name == "CMEQ" and len(ops) == 3 and ops[2].type == cs.arm64.ARM64_OP_FP:
ops[2]._type = cs.arm64.ARM64_OP_IMM
return name
return OP_NAME_MAP.get(name, name)
@property
def insn_bit_str(self):
@@ -2373,13 +2334,15 @@ class Aarch64Cpu(Cpu):
cpu._cmeq(res_op, reg_op, imm_op, register=False)
@instruction
def CMEQ(cpu, res_op, reg_op, reg_imm_op):
def CMEQ(cpu, res_op, reg_op, reg_imm_op, _bug=0):
"""
Combines CMEQ (register) and CMEQ (zero).
:param res_op: destination register.
:param reg_op: source register.
:param reg_imm_op: source register or immediate (zero).
:param bug: Buggy extra operand https://github.com/aquynh/capstone/issues/1629
"""
assert res_op.type is cs.arm64.ARM64_OP_REG
assert reg_op.type is cs.arm64.ARM64_OP_REG
@@ -3655,17 +3618,6 @@ class Aarch64Cpu(Cpu):
# XXX: Check if trapped.
# XXX: Capstone doesn't set 'vess' for this alias:
# https://github.com/aquynh/capstone/issues/1452
if res_op.size == 32:
reg_op.op.vess = cs.arm64.ARM64_VESS_S
elif res_op.size == 64:
reg_op.op.vess = cs.arm64.ARM64_VESS_D
else:
raise Aarch64InvalidInstruction
# The 'instruction' decorator advances PC, so call the original
# method.
cpu.UMOV.__wrapped__(cpu, res_op, reg_op)
@@ -3858,7 +3810,7 @@ class Aarch64Cpu(Cpu):
:param reg_op: source system register.
"""
assert res_op.type is cs.arm64.ARM64_OP_REG
assert reg_op.type is cs.arm64.ARM64_OP_REG_MRS
assert reg_op.type is cs.arm64.ARM64_OP_SYS
insn_rx = "1101010100"
insn_rx += "1" # L
@@ -3884,7 +3836,7 @@ class Aarch64Cpu(Cpu):
:param res_op: destination system register.
:param reg_op: source register.
"""
assert res_op.type is cs.arm64.ARM64_OP_REG_MSR
assert res_op.type is cs.arm64.ARM64_OP_SYS
assert reg_op.type is cs.arm64.ARM64_OP_REG
insn_rx = "1101010100"
@@ -5175,18 +5127,18 @@ class Aarch64Cpu(Cpu):
reg = reg_op.read()
index = reg_op.op.vector_index
vess = reg_op.op.vess
vas = reg_op.op.vas
if vess == cs.arm64.ARM64_VESS_B:
if vas == cs.arm64.ARM64_VAS_1B:
elem_size = 8
elif vess == cs.arm64.ARM64_VESS_H:
elif vas == cs.arm64.ARM64_VAS_1H:
elem_size = 16
elif vess == cs.arm64.ARM64_VESS_S:
elif vas == cs.arm64.ARM64_VAS_1S:
elem_size = 32
elif vess == cs.arm64.ARM64_VESS_D:
elif vas == cs.arm64.ARM64_VAS_1D:
elem_size = 64
else:
@@ -5352,6 +5304,7 @@ class Aarch64Operand(Operand):
cs.arm64.ARM64_OP_MEM,
cs.arm64.ARM64_OP_IMM,
cs.arm64.ARM64_OP_FP,
cs.arm64.ARM64_OP_SYS,
cs.arm64.ARM64_OP_BARRIER,
):
raise NotImplementedError(f"Unsupported operand type: '{self.op.type}'")
@@ -5399,7 +5352,7 @@ class Aarch64Operand(Operand):
def read(self):
if self.type == cs.arm64.ARM64_OP_REG:
return self.cpu.regfile.read(self.reg)
elif self.type == cs.arm64.ARM64_OP_REG_MRS:
elif self.type == cs.arm64.ARM64_OP_REG_MRS or self.type == cs.arm64.ARM64_OP_SYS:
name = SYS_REG_MAP.get(self.op.sys)
if not name:
raise NotImplementedError(f"Unsupported system register: '0x{self.op.sys:x}'")
@@ -5412,7 +5365,7 @@ class Aarch64Operand(Operand):
def write(self, value):
if self.type == cs.arm64.ARM64_OP_REG:
self.cpu.regfile.write(self.reg, value)
elif self.type == cs.arm64.ARM64_OP_REG_MSR:
elif self.type == cs.arm64.ARM64_OP_REG_MSR or cs.arm64.ARM64_OP_SYS:
name = SYS_REG_MAP.get(self.op.sys)
if not name:
raise NotImplementedError(f"Unsupported system register: '0x{self.op.sys:x}'")
+5 -8
View File
@@ -764,14 +764,11 @@ class Armv7Cpu(Cpu):
@staticmethod
def canonicalize_instruction_name(instr):
name = instr.insn_name().upper()
# XXX bypass a capstone bug that incorrectly labels some insns as mov
if name == "MOV":
if instr.mnemonic.startswith("lsr"):
return "LSR"
elif instr.mnemonic.startswith("lsl"):
return "LSL"
elif instr.mnemonic.startswith("asr"):
return "ASR"
# FIXME: Workaround https://github.com/aquynh/capstone/issues/1630
if instr.mnemonic == "addw":
return "ADDW"
elif instr.mnemonic == "subw":
return "SUBW"
return OP_NAME_MAP.get(name, name)
def _wrap_operands(self, operands):
+6 -28
View File
@@ -1167,11 +1167,7 @@ class X86Cpu(Cpu):
:param dest: destination operand.
:param src: source operand.
"""
if dest == src:
# if the operands are the same write zero
res = dest.write(0)
else:
res = dest.write(dest.read() ^ src.read())
res = dest.write(dest.read() ^ src.read())
# Defined Flags: szp
cpu._calculate_logic_flags(dest.size, res)
@@ -1226,7 +1222,7 @@ class X86Cpu(Cpu):
This instruction executes as described in compatibility mode and legacy mode.
It is not valid in 64-bit mode.
::
IF ((AL AND 0FH) > 9) Operators.OR(AF = 1)
IF ((AL AND 0FH) > 9) OR (AF = 1)
THEN
AL = (AL + 6);
AH = AH + 1;
@@ -1243,20 +1239,10 @@ class X86Cpu(Cpu):
cpu.CF = cpu.AF
cpu.AH = Operators.ITEBV(8, cpu.AF, cpu.AH + 1, cpu.AH)
cpu.AL = Operators.ITEBV(8, cpu.AF, cpu.AL + 6, cpu.AL)
"""
if (cpu.AL & 0x0F > 9) or cpu.AF == 1:
cpu.AL = cpu.AL + 6
cpu.AH = cpu.AH + 1
cpu.AF = True
cpu.CF = True
else:
cpu.AF = False
cpu.CF = False
"""
cpu.AL = cpu.AL & 0x0F
@instruction
def AAD(cpu, imm=None):
def AAD(cpu, imm):
"""
ASCII adjust AX before division.
@@ -1282,12 +1268,7 @@ class X86Cpu(Cpu):
:param cpu: current CPU.
"""
if imm is None:
imm = 10
else:
imm = imm.read()
cpu.AL += cpu.AH * imm
cpu.AL += cpu.AH * imm.read()
cpu.AH = 0
# Defined flags: ...sz.p.
@@ -1317,11 +1298,7 @@ class X86Cpu(Cpu):
:param cpu: current CPU.
"""
if imm is None:
imm = 10
else:
imm = imm.read()
imm = imm.read()
cpu.AH = Operators.UDIV(cpu.AL, imm)
cpu.AL = Operators.UREM(cpu.AL, imm)
@@ -5570,6 +5547,7 @@ class X86Cpu(Cpu):
:param cpu: current CPU.
:param arg0: this argument is ignored.
"""
pass
@instruction
def ENDBR32(cpu):
+5 -1
View File
@@ -16,7 +16,11 @@ def rtd_dependent_deps():
# If you update native_deps please update the `REQUIREMENTS_TO_IMPORTS` dict in `utils/install_helper.py`
# (we need to know how to import a given native dependency so we can check if native dependencies are installed)
native_deps = ["capstone==4.0.2", "pyelftools", "unicorn==1.0.2"]
native_deps = [
"capstone==5.0.0rc2",
"pyelftools",
"unicorn==1.0.2",
]
lint_deps = ["black~=22.0", "mypy==0.790"]
+164
View File
@@ -1300,6 +1300,170 @@ class SymCPUTest(unittest.TestCase):
self.assertEqual(cpu.EIP, code + 1)
def test_AAA_0(self):
"""ASCII Adjust AL after subtraction."""
cs = ConstraintSet()
mem = SMemory32(cs)
cpu = I386Cpu(mem)
# alloc/map a little mem
code = mem.mmap(0x1000, 0x1000, "rwx")
stack = mem.mmap(0xF000, 0x1000, "rw")
# 37 AAA
mem[code] = BitVecConstant(size=8, value=0x37)
cpu.EIP = code
AL = 10
AH = 0x41
AF = False
cpu.AL = AL
cpu.AH = AH
cpu.AF = False
cpu.execute()
self.assertEqual(cpu.AL, 0)
self.assertEqual(cpu.AH, AH + 1)
self.assertEqual(cpu.AF, True)
self.assertEqual(cpu.CF, True)
def test_AAA_1(self):
"""ASCII Adjust AL after subtraction."""
cs = ConstraintSet()
mem = SMemory32(cs)
cpu = I386Cpu(mem)
# alloc/map a little mem
code = mem.mmap(0x1000, 0x1000, "rwx")
stack = mem.mmap(0xF000, 0x1000, "rw")
# 37 AAA
mem[code] = BitVecConstant(size=8, value=0x37)
cpu.EIP = code
AL = 18
AH = 0x41
AF = False
cpu.AL = AL
cpu.AH = AH
cpu.AF = False
cpu.execute()
self.assertEqual(cpu.AL, AL & 0xF)
self.assertEqual(cpu.AF, False)
self.assertEqual(cpu.CF, False)
def test_AAS_0(self):
"""ASCII Adjust AL after subtraction."""
cs = ConstraintSet()
mem = SMemory32(cs)
cpu = I386Cpu(mem)
# alloc/map a little mem
code = mem.mmap(0x1000, 0x1000, "rwx")
stack = mem.mmap(0xF000, 0x1000, "rw")
# 3F AAS
mem[code] = BitVecConstant(size=8, value=0x3F)
cpu.EIP = code
AL = 10
AH = 0x41
AF = False
cpu.AL = AL
cpu.AH = AH
cpu.AF = False
cpu.execute()
self.assertEqual(cpu.AL, (AL - 6) & 0xF)
self.assertEqual(cpu.AH, AH - 1)
self.assertEqual(cpu.AF, True)
self.assertEqual(cpu.CF, True)
def test_AAS_1(self):
"""ASCII Adjust AL after subtraction."""
cs = ConstraintSet()
mem = SMemory32(cs)
cpu = I386Cpu(mem)
# alloc/map a little mem
code = mem.mmap(0x1000, 0x1000, "rwx")
stack = mem.mmap(0xF000, 0x1000, "rw")
# 3F AAS
mem[code] = BitVecConstant(size=8, value=0x3F)
cpu.EIP = code
AL = 18
AH = 0x41
AF = False
cpu.AL = AL
cpu.AH = AH
cpu.AF = False
cpu.execute()
self.assertEqual(cpu.AL, AL & 0xF)
self.assertEqual(cpu.AF, False)
self.assertEqual(cpu.CF, False)
def test_DAA_0(self):
"""Decimal Adjust AL after Addition."""
cs = ConstraintSet()
mem = SMemory32(cs)
cpu = I386Cpu(mem)
# alloc/map a little mem
code = mem.mmap(0x1000, 0x1000, "rwx")
stack = mem.mmap(0xF000, 0x1000, "rw")
# 27 DAA
mem[code] = BitVecConstant(size=8, value=0x27)
cpu.EIP = code
cpu.AL = 0xAE
cpu.BL = 0x35
cpu.OF = True
cpu.SF = True
cpu.ZF = False
cpu.AF = False
cpu.PF = False
cpu.CF = False
cpu.execute()
self.assertEqual(cpu.AL, 0x14)
self.assertEqual(cpu.BL, 0x35)
self.assertEqual(cpu.SF, False)
self.assertEqual(cpu.ZF, False)
self.assertEqual(cpu.AF, True)
self.assertEqual(cpu.PF, True)
self.assertEqual(cpu.CF, True)
def test_DAS_0(self):
"""Decimal Adjust AL after Subtraction."""
cs = ConstraintSet()
mem = SMemory32(cs)
cpu = I386Cpu(mem)
# alloc/map a little mem
code = mem.mmap(0x1000, 0x1000, "rwx")
stack = mem.mmap(0xF000, 0x1000, "rw")
# 2F DAS
mem[code] = BitVecConstant(size=8, value=0x2F)
cpu.EIP = code
cpu.AL = 0xAE
cpu.OF = True
cpu.SF = True
cpu.ZF = False
cpu.AF = False
cpu.PF = False
cpu.CF = False
cpu.execute()
self.assertEqual(cpu.AL, 0x48)
self.assertEqual(cpu.SF, False)
self.assertEqual(cpu.ZF, False)
self.assertEqual(cpu.AF, True)
self.assertEqual(cpu.PF, True)
self.assertEqual(cpu.CF, True)
if __name__ == "__main__":
unittest.main()