Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Capstone 5 development and updates (release-candidate) #1701

Merged
merged 21 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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