Skip to content

Commit

Permalink
Merge be00705 into 2347b21
Browse files Browse the repository at this point in the history
  • Loading branch information
ekilmer authored Aug 5, 2020
2 parents 2347b21 + be00705 commit de9b21b
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 99 deletions.
11 changes: 11 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,14 @@
source = manticore
omit =
*__init__.py

[report]
# Regexes for lines to exclude from consideration
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover

# Don't complain if tests don't hit defensive assertion code:
raise AssertionError
raise NotImplementedError
raise Aarch64InvalidInstruction
78 changes: 16 additions & 62 deletions manticore/native/cpu/aarch64.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import warnings
from typing import NamedTuple
from inspect import signature as inspect_signature

import capstone as cs
import collections
Expand All @@ -16,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 @@ -299,45 +299,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 @@ -2366,13 +2328,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 @@ -3648,17 +3612,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 @@ -3851,7 +3804,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 @@ -3877,7 +3830,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 @@ -5168,18 +5121,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 @@ -5339,6 +5292,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 @@ -5386,7 +5340,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 @@ -5399,7 +5353,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 @@ -754,14 +754,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
48 changes: 20 additions & 28 deletions manticore/native/cpu/x86.py
Original file line number Diff line number Diff line change
Expand Up @@ -1095,11 +1095,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 @@ -1154,7 +1150,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 @@ -1171,20 +1167,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 @@ -1210,12 +1196,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 @@ -1245,11 +1226,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 @@ -5493,6 +5470,21 @@ def NOP(cpu, arg0=None):
:param cpu: current CPU.
:param arg0: this argument is ignored.
"""
pass

@instruction
def ENDBR64(cpu):
"""
The ENDBRANCH is a new instruction that is used to mark valid jump target
addresses of indirect calls and jumps in the program. This instruction
opcode is selected to be one that is a NOP on legacy machines such that
programs compiled with ENDBRANCH new instruction continue to function on
old machines without the CET enforcement. On processors that support CET
the ENDBRANCH is still a NOP and is primarily used as a marker instruction
by the processor pipeline to detect control flow violations.
:param cpu: current CPU.
"""
pass

@instruction
def MOVD(cpu, op0, op1):
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.1", "pyelftools", "unicorn==1.0.2rc2"]
native_deps = [
"capstone @ git+https://github.com/aquynh/capstone.git@1766485c0c32419e9a17d6ad31f9e218ef4f018f#subdirectory=bindings/python",
"pyelftools",
"unicorn==1.0.2rc2",
]

lint_deps = ["black==19.10b0", "mypy==0.770"]

Expand Down
Loading

0 comments on commit de9b21b

Please sign in to comment.