Skip to content

Commit

Permalink
Capstone 5 updates (5.0.0rc2) (#1701)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
3 people authored May 18, 2022
1 parent f8ad2df commit 9e11bc9
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 99 deletions.
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ exclude_lines =

# We don't bother testing code that's explicitly unimplemented
raise NotImplementedError
raise AssertionError
raise Aarch64InvalidInstruction
77 changes: 15 additions & 62 deletions manticore/native/cpu/aarch64.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import warnings
from typing import NamedTuple
from copy import copy

import capstone as cs
Expand All @@ -17,7 +17,6 @@
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
Expand Down Expand Up @@ -306,45 +305,7 @@ def canonicalize_instruction_name(insn):
# 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):
Expand Down Expand Up @@ -2373,13 +2334,15 @@ def _CMEQ_zero(cpu, res_op, reg_op, imm_op):
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
Expand Down Expand Up @@ -3655,17 +3618,6 @@ def _MOV_to_general(cpu, res_op, reg_op):

# 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)
Expand Down Expand Up @@ -3858,7 +3810,7 @@ def MRS(cpu, res_op, reg_op):
: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
Expand All @@ -3884,7 +3836,7 @@ def MSR(cpu, res_op, reg_op):
: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"
Expand Down Expand Up @@ -5175,18 +5127,18 @@ def UMOV(cpu, res_op, reg_op):

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:
Expand Down Expand Up @@ -5352,6 +5304,7 @@ def __init__(self, cpu, op, **kwargs):
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}'")
Expand Down Expand Up @@ -5399,7 +5352,7 @@ def is_extended(self):
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}'")
Expand All @@ -5412,7 +5365,7 @@ def read(self):
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}'")
Expand Down
13 changes: 5 additions & 8 deletions manticore/native/cpu/arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,14 +764,11 @@ def set_arm_tls(self, data):
@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):
Expand Down
34 changes: 6 additions & 28 deletions manticore/native/cpu/x86.py
Original file line number Diff line number Diff line change
Expand Up @@ -1167,11 +1167,7 @@ def XOR(cpu, dest, src):
: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)

Expand Down Expand Up @@ -1226,7 +1222,7 @@ def AAA(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;
Expand All @@ -1243,20 +1239,10 @@ def AAA(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.
Expand All @@ -1282,12 +1268,7 @@ def AAD(cpu, imm=None):
: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.
Expand Down Expand Up @@ -1317,11 +1298,7 @@ def AAM(cpu, imm=None):
: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)

Expand Down Expand Up @@ -5570,6 +5547,7 @@ def NOP(cpu, arg0=None):
:param cpu: current CPU.
:param arg0: this argument is ignored.
"""
pass

@instruction
def ENDBR32(cpu):
Expand Down
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand Down
Loading

0 comments on commit 9e11bc9

Please sign in to comment.