diff options
Diffstat (limited to 'src/miasm/arch')
55 files changed, 33288 insertions, 0 deletions
diff --git a/src/miasm/arch/__init__.py b/src/miasm/arch/__init__.py new file mode 100644 index 00000000..78e2dd3c --- /dev/null +++ b/src/miasm/arch/__init__.py @@ -0,0 +1 @@ +"Architecture implementations" diff --git a/src/miasm/arch/aarch64/__init__.py b/src/miasm/arch/aarch64/__init__.py new file mode 100644 index 00000000..bbad893b --- /dev/null +++ b/src/miasm/arch/aarch64/__init__.py @@ -0,0 +1 @@ +__all__ = ["arch", "disasm", "regs", "sem"] diff --git a/src/miasm/arch/aarch64/arch.py b/src/miasm/arch/aarch64/arch.py new file mode 100644 index 00000000..ab6b7528 --- /dev/null +++ b/src/miasm/arch/aarch64/arch.py @@ -0,0 +1,2309 @@ +#-*- coding:utf-8 -*- + +from builtins import range +from future.utils import viewitems, viewvalues + +import logging +from pyparsing import * +from miasm.expression import expression as m2_expr +from miasm.core.cpu import * +from collections import defaultdict +from miasm.core.bin_stream import bin_stream +from miasm.arch.aarch64 import regs as regs_module +from miasm.arch.aarch64.regs import * +from miasm.core.cpu import log as log_cpu +from miasm.core.modint import mod_size2int +from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html +from miasm.core import utils +from miasm.core.utils import BRACKET_O, BRACKET_C + +log = logging.getLogger("aarch64dis") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.DEBUG) + +# refs from A_e_armv8_arm.pdf + +# log_cpu.setLevel(logging.DEBUG) + + +replace_regs = { + W0: X0[:32], + W1: X1[:32], + W2: X2[:32], + W3: X3[:32], + W4: X4[:32], + W5: X5[:32], + W6: X6[:32], + W7: X7[:32], + W8: X8[:32], + W9: X9[:32], + + W10: X10[:32], + W11: X11[:32], + W12: X12[:32], + W13: X13[:32], + W14: X14[:32], + W15: X15[:32], + W16: X16[:32], + W17: X17[:32], + W18: X18[:32], + W19: X19[:32], + + W20: X20[:32], + W21: X21[:32], + W22: X22[:32], + W23: X23[:32], + W24: X24[:32], + W25: X25[:32], + W26: X26[:32], + W27: X27[:32], + W28: X28[:32], + W29: X29[:32], + + W30: LR[:32], + + WSP: SP[:32], + + WZR: m2_expr.ExprInt(0, 32), + XZR: m2_expr.ExprInt(0, 64), + +} + + + + +shift2expr_dct = {'LSL': '<<', 'LSR': '>>', 'ASR': 'a>>', 'ROR': '>>>'} +shift_str = ["LSL", "LSR", "ASR", "ROR"] +shift_expr = ["<<", ">>", "a>>", '>>>'] + + +def cb_shift(tokens): + return shift2expr_dct[tokens[0]] + + +def cb_extreg(tokens): + return tokens[0] + + +def cb_shiftreg(tokens): + if len(tokens) == 1: + return tokens[0] + elif len(tokens) == 3: + result = AstOp(tokens[1], tokens[0], tokens[2]) + return result + else: + raise ValueError('bad string') + + +def cb_shift_sc(tokens): + if len(tokens) == 1: + return tokens[0] + elif len(tokens) == 3: + if tokens[1] != '<<': + raise ValueError('bad op') + result = AstOp("slice_at", tokens[0], tokens[2]) + return result + else: + raise ValueError('bad string') + + +def cb_extend(tokens): + if len(tokens) == 1: + return tokens[0] + result = AstOp(tokens[1], tokens[0], tokens[2]) + return result + + +def cb_deref_pc_off(tokens): + if len(tokens) == 2 and tokens[0] == "PC": + result = AstOp('preinc', AstId(ExprId('PC', 64)), tokens[1]) + return result + raise ValueError('bad string') + +def cb_deref_pc_nooff(tokens): + if len(tokens) == 1 and tokens[0] == "PC": + result = AstOp('preinc', AstId(PC)) + return result + raise ValueError('bad string') + +all_binaryop_lsl_t = literal_list(shift_str).setParseAction(cb_shift) + +all_binaryop_shiftleft_t = literal_list(["LSL"]).setParseAction(cb_shift) + +extend_lst = ['UXTB', 'UXTH', 'UXTW', 'UXTX', 'SXTB', 'SXTH', 'SXTW', 'SXTX'] +extend2_lst = ['UXTW', 'LSL', 'SXTW', 'SXTX'] + +all_extend_t = literal_list(extend_lst).setParseAction(cb_extreg) +all_extend2_t = literal_list(extend2_lst).setParseAction(cb_extreg) + + +gpregz32_extend = (gpregsz32_info.parser + Optional(all_extend_t + base_expr)).setParseAction(cb_extend) +gpregz64_extend = (gpregsz64_info.parser + Optional(all_extend_t + base_expr)).setParseAction(cb_extend) + + +shift32_off = (gpregsz32_info.parser + Optional(all_binaryop_lsl_t + base_expr)).setParseAction(cb_shiftreg) +shift64_off = (gpregsz64_info.parser + Optional(all_binaryop_lsl_t + base_expr)).setParseAction(cb_shiftreg) + + +shiftimm_imm_sc = (base_expr + all_binaryop_shiftleft_t + base_expr).setParseAction(cb_shift_sc) + +shiftimm_off_sc = shiftimm_imm_sc | base_expr + + +shift_off = (shift32_off | shift64_off) +reg_ext_off = (gpregz32_extend | gpregz64_extend) + +gpregs_32_64 = (gpregs32_info.parser | gpregs64_info.parser) +gpregsz_32_64 = (gpregsz32_info.parser | gpregsz64_info.parser | base_expr) + +gpregs_32_64_nosp = (gpregs32_nosp_info.parser | gpregs64_nosp_info.parser) + + +simdregs = (simd08_info.parser | simd16_info.parser | simd32_info.parser | simd64_info.parser) +simdregs_h = (simd32_info.parser | simd64_info.parser | simd128_info.parser) + +simdregs_h_zero = (simd32_info.parser | simd64_info.parser | simd128_info.parser | base_expr) + + +gpregs_info = {32: gpregs32_info, + 64: gpregs64_info} +gpregsz_info = {32: gpregsz32_info, + 64: gpregsz64_info} + + +gpregs_nosp_info = { + 32: gpregs32_nosp_info, + 64: gpregs64_nosp_info +} + +simds_info = {8: simd08_info, + 16: simd16_info, + 32: simd32_info, + 64: simd64_info, + 128: simd128_info} + + + +def cb_deref_nooff(t): + # XXX default + result = AstOp("preinc", t[0], AstInt(0)) + return result + + +def cb_deref_post(t): + assert len(t) == 2 + if isinstance(t[1], AstId) and isinstance(t[1].name, ExprId): + return + result = AstOp("postinc", *t) + return result + + +def cb_deref_pre(t): + assert len(t) == 2 + if isinstance(t[1], AstId) and isinstance(t[1].name, ExprId): + return + result = AstOp("preinc", *t) + return result + + +def cb_deref_pre_wb(t): + assert len(t) == 2 + if isinstance(t[1], AstId) and isinstance(t[1].name, ExprId): + return + result = AstOp("preinc_wb", *t) + return result + + +LBRACK = Suppress("[") +RBRACK = Suppress("]") +COMMA = Suppress(",") +POSTINC = Suppress("!") + +deref_nooff = (LBRACK + gpregs64_info.parser + RBRACK).setParseAction(cb_deref_nooff) +deref_off_post = (LBRACK + gpregs64_info.parser + RBRACK + COMMA + base_expr).setParseAction(cb_deref_post) +deref_off_pre = (LBRACK + gpregs64_info.parser + COMMA + base_expr + RBRACK).setParseAction(cb_deref_pre) +deref_off_pre_wb = (LBRACK + gpregs64_info.parser + COMMA + base_expr + RBRACK + POSTINC).setParseAction(cb_deref_pre_wb) + +deref = (deref_off_post | deref_off_pre_wb | deref_off_pre | deref_nooff) + + +deref_pc_off = (LBRACK + Literal("PC") + COMMA + base_expr + RBRACK).setParseAction(cb_deref_pc_off) +deref_pc_nooff = (LBRACK + Literal("PC") + RBRACK).setParseAction(cb_deref_pc_nooff) + +deref_pc = (deref_pc_off | deref_pc_nooff) + +def cb_deref_ext2op(t): + if len(t) == 4: + result = AstOp('segm', t[0], AstOp(t[2], t[1], t[3])) + return result + elif len(t) == 2: + result = AstOp('segm', *t) + return result + + raise ValueError("cad deref") + +deref_ext2 = (LBRACK + gpregs_32_64 + COMMA + gpregs_32_64 + Optional(all_extend2_t + base_expr) + RBRACK).setParseAction(cb_deref_ext2op) + + +class additional_info(object): + + def __init__(self): + self.except_on_instr = False + self.lnk = None + self.cond = None + +CONDS = [ + 'EQ', 'NE', 'CS', 'CC', + 'MI', 'PL', 'VS', 'VC', + 'HI', 'LS', 'GE', 'LT', + 'GT', 'LE', 'AL', 'NV'] + +CONDS_INV = [ + 'NE', 'EQ', 'CC', 'CS', + 'PL', 'MI', 'VC', 'VS', + 'LS', 'HI', 'LT', 'GE', + 'LE', 'GT', 'NV', 'AL'] + +BRCOND = ['B.' + cond for cond in CONDS] + ['CBZ', 'CBNZ', 'TBZ', 'TBNZ'] + +# for conditional selec +conds_expr, _, conds_info = gen_regs(CONDS, {}) +conds_inv_expr, _, conds_inv_info = gen_regs(CONDS_INV, {}) + + + +class aarch64_arg(m_arg): + def asm_ast_to_expr(self, value, loc_db, size_hint=None, fixed_size=None): + if size_hint is None: + size_hint = 64 + if fixed_size is None: + fixed_size = set() + if isinstance(value, AstId): + if value.name in all_regs_ids_byname: + reg = all_regs_ids_byname[value.name] + fixed_size.add(reg.size) + return reg + if isinstance(value.name, ExprId): + fixed_size.add(value.name.size) + return value.name + loc_key = loc_db.get_or_create_name_location(value.name) + return m2_expr.ExprLoc(loc_key, size_hint) + if isinstance(value, AstInt): + assert size_hint is not None + return m2_expr.ExprInt(value.value, size_hint) + if isinstance(value, AstOp): + if value.op == "segm": + segm = self.asm_ast_to_expr(value.args[0], loc_db) + ptr = self.asm_ast_to_expr(value.args[1], loc_db, None, fixed_size) + return m2_expr.ExprOp('segm', segm, ptr) + + args = [self.asm_ast_to_expr(arg, loc_db, None, fixed_size) for arg in value.args] + if len(fixed_size) == 0: + # No fixed size + pass + elif len(fixed_size) == 1: + # One fixed size, regen all + size = list(fixed_size)[0] + args = [self.asm_ast_to_expr(arg, loc_db, size, fixed_size) for arg in value.args] + else: + raise ValueError("Size conflict") + + return m2_expr.ExprOp(value.op, *args) + return None + + +class instruction_aarch64(instruction): + __slots__ = [] + + def __init__(self, *args, **kargs): + super(instruction_aarch64, self).__init__(*args, **kargs) + + @staticmethod + def arg2str(expr, index=None, loc_db=None): + wb = False + if expr.is_id() or expr.is_int(): + return str(expr) + elif expr.is_loc(): + if loc_db is not None: + return loc_db.pretty_str(expr.loc_key) + else: + return str(expr) + elif isinstance(expr, m2_expr.ExprOp) and expr.op in shift_expr: + op_str = shift_str[shift_expr.index(expr.op)] + return "%s %s %s" % (expr.args[0], op_str, expr.args[1]) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "slice_at": + return "%s LSL %s" % (expr.args[0], expr.args[1]) + elif isinstance(expr, m2_expr.ExprOp) and expr.op in extend_lst: + op_str = expr.op + return "%s %s %s" % (expr.args[0], op_str, expr.args[1]) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "postinc": + if int(expr.args[1]) != 0: + return "[%s], %s" % (expr.args[0], expr.args[1]) + else: + return "[%s]" % (expr.args[0]) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc_wb": + if int(expr.args[1]) != 0: + return "[%s, %s]!" % (expr.args[0], expr.args[1]) + else: + return "[%s]" % (expr.args[0]) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc": + if len(expr.args) == 1: + return "[%s]" % (expr.args[0]) + elif not isinstance(expr.args[1], m2_expr.ExprInt) or int(expr.args[1]) != 0: + return "[%s, %s]" % (expr.args[0], expr.args[1]) + else: + return "[%s]" % (expr.args[0]) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == 'segm': + arg = expr.args[1] + if isinstance(arg, m2_expr.ExprId): + arg = str(arg) + elif arg.op == 'LSL' and int(arg.args[1]) == 0: + arg = str(arg.args[0]) + else: + arg = "%s %s %s" % (arg.args[0], arg.op, arg.args[1]) + return '[%s, %s]' % (expr.args[0], arg) + + else: + raise NotImplementedError("bad op") + + @staticmethod + def arg2html(expr, index=None, loc_db=None): + wb = False + if expr.is_id() or expr.is_int() or expr.is_loc(): + return color_expr_html(expr, loc_db) + elif isinstance(expr, m2_expr.ExprOp) and expr.op in shift_expr: + op_str = shift_str[shift_expr.index(expr.op)] + return "%s %s %s" % ( + color_expr_html(expr.args[0], loc_db), + utils.set_html_text_color(op_str, utils.COLOR_OP), + color_expr_html(expr.args[1], loc_db) + ) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "slice_at": + return "%s LSL %s" % ( + color_expr_html(expr.args[0], loc_db), + color_expr_html(expr.args[1], loc_db) + ) + elif isinstance(expr, m2_expr.ExprOp) and expr.op in extend_lst: + op_str = expr.op + return "%s %s %s" % ( + color_expr_html(expr.args[0], loc_db), + op_str, + color_expr_html(expr.args[1], loc_db) + ) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "postinc": + if int(expr.args[1]) != 0: + return BRACKET_O + color_expr_html(expr.args[0], loc_db) + BRACKET_C + ", " + color_expr_html(expr.args[1], loc_db) + else: + return BRACKET_O + color_expr_html(expr.args[0], loc_db) + BRACKET_C + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc_wb": + if int(expr.args[1]) != 0: + return BRACKET_O + color_expr_html(expr.args[0], loc_db) + ", " + color_expr_html(expr.args[1], loc_db) + BRACKET_C + '!' + else: + return BRACKET_O + color_expr_html(expr.args[0], loc_db) + BRACKET_C + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc": + if len(expr.args) == 1: + return BRACKET_O + color_expr_html(expr.args[0], loc_db) + BRACKET_C + elif not isinstance(expr.args[1], m2_expr.ExprInt) or int(expr.args[1]) != 0: + return BRACKET_O + color_expr_html(expr.args[0], loc_db) + ", " + color_expr_html(expr.args[1], loc_db) + BRACKET_C + else: + return BRACKET_O + color_expr_html(expr.args[0], loc_db) + BRACKET_C + elif isinstance(expr, m2_expr.ExprOp) and expr.op == 'segm': + arg = expr.args[1] + if isinstance(arg, m2_expr.ExprId): + arg = str(arg) + elif arg.op == 'LSL' and int(arg.args[1]) == 0: + arg = str(arg.args[0]) + else: + arg = "%s %s %s" % ( + color_expr_html(arg.args[0], loc_db), + utils.set_html_text_color(arg.op, utils.COLOR_OP), + color_expr_html(arg.args[1], loc_db) + ) + return BRACKET_O + color_expr_html(expr.args[0], loc_db) + ', ' + arg + BRACKET_C + + else: + raise NotImplementedError("bad op") + + def dstflow(self): + return self.name in BRCOND + ["B", "BL", "BR", "BLR"] + + def mnemo_flow_to_dst_index(self, name): + if self.name in ['CBZ', 'CBNZ']: + return 1 + elif self.name in ['TBZ', 'TBNZ']: + return 2 + else: + return 0 + + def dstflow2label(self, loc_db): + index = self.mnemo_flow_to_dst_index(self.name) + expr = self.args[index] + if not expr.is_int(): + return + addr = (int(expr) + self.offset) & int(expr.mask) + loc_key = loc_db.get_or_create_offset_location(addr) + self.args[index] = m2_expr.ExprLoc(loc_key, expr.size) + + def breakflow(self): + return self.name in BRCOND + ["BR", "BLR", "RET", "ERET", "DRPS", "B", "BL"] + + def is_subcall(self): + return self.name in ["BLR", "BL"] + + def getdstflow(self, loc_db): + index = self.mnemo_flow_to_dst_index(self.name) + return [self.args[index]] + + def splitflow(self): + return self.name in BRCOND + ["BLR", "BL"] + + def get_symbol_size(self, symbol, loc_db): + return 64 + + def fixDstOffset(self): + index = self.mnemo_flow_to_dst_index(self.name) + e = self.args[index] + if self.offset is None: + raise ValueError('symbol not resolved %s' % l) + if not isinstance(e, m2_expr.ExprInt): + log.debug('dyn dst %r', e) + return + off = (int(e) - self.offset) & int(e.mask) + if int(off % 4): + raise ValueError('strange offset! %r' % off) + self.args[index] = m2_expr.ExprInt(int(off), 64) + + + +class mn_aarch64(cls_mn): + delayslot = 0 + name = "aarch64" + regs = regs_module + bintree = {} + num = 0 + all_mn = [] + all_mn_mode = defaultdict(list) + all_mn_name = defaultdict(list) + all_mn_inst = defaultdict(list) + pc = {'l': PC, 'b': PC} + sp = {'l': SP, 'b': SP} + instruction = instruction_aarch64 + max_instruction_len = 4 + alignment = 4 + + @classmethod + def getpc(cls, attrib=None): + return PC + + @classmethod + def getsp(cls, attrib=None): + return SP + + def additional_info(self): + info = additional_info() + info.lnk = False + if hasattr(self, "lnk"): + info.lnk = self.lnk.value != 0 + return info + + @classmethod + def getbits(cls, bs, attrib, start, n): + if not n: + return 0 + o = 0 + if n > bs.getlen() * 8: + raise ValueError('not enough bits %r %r' % (n, len(bs.bin) * 8)) + while n: + offset = start // 8 + n_offset = cls.endian_offset(attrib, offset) + c = cls.getbytes(bs, n_offset, 1) + if not c: + raise IOError + c = ord(c) + r = 8 - start % 8 + c &= (1 << r) - 1 + l = min(r, n) + c >>= (r - l) + o <<= l + o |= c + n -= l + start += l + return o + + @classmethod + def endian_offset(cls, attrib, offset): + if attrib == "l": + return (offset & ~3) + 3 - offset % 4 + elif attrib == "b": + return offset + else: + raise NotImplementedError('bad attrib') + + @classmethod + def check_mnemo(cls, fields): + l = sum([x.l for x in fields]) + assert l == 32, "len %r" % l + + @classmethod + def getmn(cls, name): + return name.upper() + + @classmethod + def mod_fields(cls, fields): + l = sum([x.l for x in fields]) + if l == 32: + return fields + return fields + + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + dct['mode'] = None + return [(subcls, name, bases, dct, fields)] + + def value(self, mode): + v = super(mn_aarch64, self).value(mode) + if mode == 'l': + return [x[::-1] for x in v] + elif mode == 'b': + return [x for x in v] + else: + raise NotImplementedError('bad attrib') + + def get_symbol_size(self, symbol, loc_db, mode): + return 32 + + def reset_class(self): + super(mn_aarch64, self).reset_class() + if hasattr(self, "sf"): + self.sf.value = None + + +def aarch64op(name, fields, args=None, alias=False): + dct = {"fields": fields, "alias":alias} + if args is not None: + dct['args'] = args + type(name, (mn_aarch64,), dct) + + +class aarch64_gpreg_noarg(reg_noarg): + parser = gpregs_32_64 + gpregs_info = gpregs_info + + def decode(self, v): + size = 64 if self.parent.sf.value else 32 + self.expr = self.gpregs_info[size].expr[v] + return True + + def encode(self): + if not test_set_sf(self.parent, self.expr.size): + return False + if not self.expr.size in self.gpregs_info: + return False + if not self.expr in self.gpregs_info[self.expr.size].expr: + return False + self.value = self.gpregs_info[self.expr.size].expr.index(self.expr) + return True + +class aarch64_gpreg_noarg_nosp(aarch64_gpreg_noarg): + parser = gpregs_32_64_nosp + gpregs_info = gpregs_nosp_info + + def decode(self, v): + size = 64 if self.parent.sf.value else 32 + if v >= len(self.gpregs_info[size].expr): + return False + self.expr = self.gpregs_info[size].expr[v] + return True + + def encode(self): + if not test_set_sf(self.parent, self.expr.size): + return False + if not self.expr.size in self.gpregs_info: + return False + if not self.expr in self.gpregs_info[self.expr.size].expr: + return False + if self.expr not in self.gpregs_info[self.expr.size].expr: + return False + self.value = self.gpregs_info[self.expr.size].expr.index(self.expr) + return True + + +class aarch64_simdreg(reg_noarg, aarch64_arg): + parser = simdregs + simd_size = [8, 16, 32, 64] + + def decode(self, v): + if self.parent.size.value > len(self.simd_size): + return False + size = self.simd_size[self.parent.size.value] + self.expr = simds_info[size].expr[v] + return True + + def encode(self): + if not self.expr.size in self.simd_size: + return False + if not self.expr in simds_info[self.expr.size].expr: + return False + self.value = simds_info[self.expr.size].expr.index(self.expr) + self.parent.size.value = self.simd_size.index(self.expr.size) + return True + + +class aarch64_simdreg_h(aarch64_simdreg): + parser = simdregs_h + simd_size = [32, 64, 128] + + +class aarch64_simdreg_32_64(aarch64_simdreg): + parser = simdregs_h + simd_size = [32, 64] + + +class aarch64_simdreg_32_64_zero(aarch64_simdreg_32_64): + parser = simdregs_h_zero + + def decode(self, v): + if v == 0 and self.parent.opc.value == 1: + size = 64 if self.parent.size.value else 32 + self.expr = m2_expr.ExprInt(0, size) + return True + else: + return super(aarch64_simdreg_32_64_zero, self).decode(v) + + def encode(self): + if isinstance(self.expr, m2_expr.ExprInt): + self.parent.opc.value = 1 + self.value = 0 + return True + else: + self.parent.opc.value = 0 + return super(aarch64_simdreg_32_64_zero, self).encode() + + +class aarch64_gpreg_isf(reg_noarg, aarch64_arg): + parser = gpregs_32_64 + + def decode(self, v): + size = 32 if self.parent.sf.value else 64 + self.expr = gpregs_info[size].expr[v] + return True + + def encode(self): + if not self.expr in gpregs_info[self.expr.size].expr: + return False + self.value = gpregs_info[self.expr.size].expr.index(self.expr) + self.parent.sf.value = 1 if self.expr.size == 32 else 0 + return True + + +class aarch64_gpreg(aarch64_gpreg_noarg, aarch64_arg): + pass + + +class aarch64_gpreg_n1(aarch64_gpreg): + + def decode(self, v): + if v == 0b11111: + return False + return super(aarch64_gpreg_n1, self).decode(v) + + def encode(self): + super(aarch64_gpreg_n1, self).encode() + return self.value != 0b11111 + + +class aarch64_gpregz(aarch64_gpreg_noarg, aarch64_arg): + parser = gpregsz_32_64 + gpregs_info = gpregsz_info + + +class aarch64_gpreg0(bsi, aarch64_arg): + parser = gpregsz_32_64 + gpregs_info = gpregsz_info + + def decode(self, v): + size = 64 if self.parent.sf.value else 32 + if v == 0x1F: + self.expr = m2_expr.ExprInt(0, size) + else: + self.expr = self.gpregs_info[size].expr[v] + return True + + def encode(self): + if isinstance(self.expr, m2_expr.ExprInt): + if int(self.expr) == 0: + self.value = 0x1F + return True + return False + if not self.expr.size in self.gpregs_info: + return False + if not test_set_sf(self.parent, self.expr.size): + return False + if not self.expr in self.gpregs_info[self.expr.size].expr: + return False + self.value = self.gpregs_info[self.expr.size].expr.index(self.expr) + return True + + +class aarch64_crreg(reg_noarg, aarch64_arg): + reg_info = cr_info + parser = reg_info.parser + + +class aarch64_gpreg32_nodec(bsi): + reg_info = gpregs32_info + + +class aarch64_gpreg64_nodec(bsi): + reg_info = gpregs64_info + + +class aarch64_gpreg32_noarg(reg_noarg): + reg_info = gpregs32_info + parser = reg_info.parser + + +class aarch64_gpreg32(aarch64_gpreg32_noarg, aarch64_arg): + reg_info = gpregs32_info + parser = reg_info.parser + + +class aarch64_gpreg64_noarg(reg_noarg): + reg_info = gpregs64_info + parser = reg_info.parser + + +class aarch64_gpreg64(reg_noarg, aarch64_arg): + reg_info = gpregs64_info + parser = reg_info.parser + + +class aarch64_gpregz32_noarg(reg_noarg): + reg_info = gpregsz32_info + parser = reg_info.parser + + +class aarch64_gpregz32(aarch64_gpreg32_noarg, aarch64_arg): + reg_info = gpregsz32_info + parser = reg_info.parser + + +class aarch64_gpregz64_noarg(reg_noarg): + reg_info = gpregsz64_info + parser = reg_info.parser + + +class aarch64_gpregz64(reg_noarg, aarch64_arg): + reg_info = gpregsz64_info + parser = reg_info.parser + + +class aarch64_simd08_noarg(reg_noarg): + reg_info = simd08_info + parser = reg_info.parser + + +class aarch64_simd08(aarch64_simd08_noarg, aarch64_arg): + reg_info = simd08_info + parser = reg_info.parser + + +class aarch64_simd16_noarg(reg_noarg): + reg_info = simd16_info + parser = reg_info.parser + + +class aarch64_simd16(aarch64_simd16_noarg, aarch64_arg): + reg_info = simd16_info + parser = reg_info.parser + + +class aarch64_simd32_noarg(reg_noarg): + reg_info = simd32_info + parser = reg_info.parser + + +class aarch64_simd32(aarch64_simd32_noarg, aarch64_arg): + reg_info = simd32_info + parser = reg_info.parser + + +class aarch64_simd64_noarg(reg_noarg): + reg_info = simd64_info + parser = reg_info.parser + + +class aarch64_simd64(aarch64_simd64_noarg, aarch64_arg): + reg_info = simd64_info + parser = reg_info.parser + + +class aarch64_simd128_noarg(reg_noarg): + reg_info = simd128_info + parser = reg_info.parser + + +class aarch64_simd128(aarch64_simd128_noarg, aarch64_arg): + reg_info = simd128_info + parser = reg_info.parser + + +class aarch64_imm_32(imm_noarg, aarch64_arg): + parser = base_expr + + +class aarch64_imm_64(aarch64_imm_32): + parser = base_expr + + +class aarch64_int64_noarg(int32_noarg): + parser = base_expr + intsize = 64 + intmask = (1 << intsize) - 1 + int2expr = lambda self, x: m2_expr.ExprInt( + sign_ext(x, self.l, self.intsize), 64) + + +class aarch64_uint64_noarg(imm_noarg): + parser = base_expr + intsize = 64 + intmask = (1 << intsize) - 1 + int2expr = lambda self, x: m2_expr.ExprInt(x, 64) + + +class aarch64_uint64(aarch64_uint64_noarg, aarch64_arg): + parser = base_expr + + +def set_imm_to_size(size, expr): + if size == expr.size: + return expr + if size > expr.size: + expr = m2_expr.ExprInt(int(expr), size) + else: + if int(expr) > (1 << size) - 1: + return None + expr = m2_expr.ExprInt(int(expr), size) + return expr + + +class aarch64_imm_sf(imm_noarg): + parser = base_expr + + def fromstring(self, text, loc_db, parser_result=None): + start, stop = super(aarch64_imm_sf, self).fromstring(text, loc_db, parser_result) + if start is None: + return start, stop + size = self.parent.args[0].expr.size + if self.expr in gpregs64_info.expr + gpregs32_info.expr: + return None, None + if isinstance(self.expr, m2_expr.ExprOp): + return False + expr = set_imm_to_size(size, self.expr) + if expr is None: + return None, None + self.expr = expr + return start, stop + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + if not test_set_sf(self.parent, self.expr.size): + return False + value = int(self.expr) + if value >= 1 << self.l: + return False + self.value = value + return True + + def decode(self, v): + size = 64 if self.parent.sf.value else 32 + self.expr = m2_expr.ExprInt(v, size) + return True + + +class aarch64_imm_sft(aarch64_imm_sf, aarch64_arg): + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + if not test_set_sf(self.parent, self.expr.size): + return False + value = int(self.expr) + if value < 1 << self.l: + self.parent.shift.value = 0 + else: + if value & 0xFFF: + return False + value >>= 12 + if value >= 1 << self.l: + return False + self.parent.shift.value = 1 + self.value = value + return True + + def decode(self, v): + size = 64 if self.parent.sf.value else 32 + if self.parent.shift.value == 0: + self.expr = m2_expr.ExprInt(v, size) + elif self.parent.shift.value == 1: + self.expr = m2_expr.ExprInt(v << 12, size) + else: + return False + return True + +OPTION2SIZE = [32, 32, 32, 64, + 32, 32, 32, 64] + + +class aarch64_gpreg_ext(reg_noarg, aarch64_arg): + parser = reg_ext_off + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprOp): + return False + if self.expr.op not in extend_lst: + return False + reg, amount = self.expr.args + + if not reg in gpregsz_info[self.expr.size].expr: + return False + self.value = gpregsz_info[self.expr.size].expr.index(reg) + option = extend_lst.index(self.expr.op) + if self.expr.size != OPTION2SIZE[option]: + if not test_set_sf(self.parent, self.expr.size): + return False + self.parent.option.value = option + self.parent.imm.value = int(amount) + return True + + def decode(self, v): + if self.parent.sf.value == 0: + size = 64 if self.parent.sf.value else 32 + else: + size = OPTION2SIZE[self.parent.option.value] + reg = gpregsz_info[size].expr[v] + + self.expr = m2_expr.ExprOp(extend_lst[self.parent.option.value], + reg, m2_expr.ExprInt(self.parent.imm.value, reg.size)) + return True + +EXT2_OP = { + 0b010: 'UXTW', + 0b011: 'LSL', + 0b110: 'SXTW', + 0b111: 'SXTX' +} + +EXT2_OP_INV = dict((value, key) for key, value in viewitems(EXT2_OP)) + + +class aarch64_gpreg_ext2(reg_noarg, aarch64_arg): + parser = deref_ext2 + + def get_size(self): + return self.parent.size.value + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprOp): + return False + if len(self.expr.args) != 2: + return False + arg0, arg1 = self.expr.args + if (self.expr.is_op("preinc") and arg0.is_id() and arg1.is_id()): + self.parent.shift.value = 0 + self.parent.rn.value = self.parent.rn.reg_info.expr.index(arg0) + self.value = gpregs_info[arg1.size].expr.index(arg1) + self.parent.option.value = 0b011 + return True + if not (isinstance(self.expr, m2_expr.ExprOp) and self.expr.op == 'segm'): + return False + if not arg0 in self.parent.rn.reg_info.expr: + return False + self.parent.rn.value = self.parent.rn.reg_info.expr.index(arg0) + is_reg = False + self.parent.shift.value = 0 + if isinstance(arg1, m2_expr.ExprId): + reg = arg1 + self.parent.option.value = 0b011 + is_reg = True + elif isinstance(arg1, m2_expr.ExprOp) and arg1.op in viewvalues(EXT2_OP): + reg = arg1.args[0] + else: + return False + if not (reg.size in gpregs_info and + reg in gpregs_info[reg.size].expr): + return False + self.value = gpregs_info[reg.size].expr.index(reg) + if is_reg: + return True + if not (isinstance(arg1.args[1], m2_expr.ExprInt)): + return False + if arg1.op not in EXT2_OP_INV: + return False + self.parent.option.value = EXT2_OP_INV[arg1.op] + if int(arg1.args[1]) == 0: + self.parent.shift.value = 0 + return True + + if int(arg1.args[1]) != self.get_size(): + return False + + self.parent.shift.value = 1 + + return True + + def decode(self, v): + opt = self.parent.option.value + if opt in [0, 1, 4, 5]: + return False + elif opt in [2, 6]: + reg_expr = gpregsz32_info.expr + elif opt in [3, 7]: + reg_expr = gpregsz64_info.expr + arg = reg_expr[v] + + if opt in EXT2_OP: + if self.parent.shift.value == 1: + arg = m2_expr.ExprOp(EXT2_OP[opt], arg, + m2_expr.ExprInt(self.get_size(), arg.size)) + else: + arg = m2_expr.ExprOp(EXT2_OP[opt], arg, + m2_expr.ExprInt(0, arg.size)) + + reg = self.parent.rn.reg_info.expr[self.parent.rn.value] + self.expr = m2_expr.ExprOp('segm', reg, arg) + return True + + +class aarch64_gpreg_ext2_128(aarch64_gpreg_ext2): + + def get_size(self): + return 4 + + +def test_set_sf(parent, size): + if not hasattr(parent, 'sf'): + return False + if parent.sf.value == None: + parent.sf.value = 1 if size == 64 else 0 + return True + psize = 64 if parent.sf.value else 32 + return psize == size + + +class aarch64_gpreg_sftimm(reg_noarg, aarch64_arg): + reg_info = gpregsz_info + parser = shift_off + + def encode(self): + size = self.expr.size + if not test_set_sf(self.parent, size): + return False + if isinstance(self.expr, m2_expr.ExprId): + if not size in gpregs_info: + return False + if not self.expr in self.reg_info[size].expr: + return False + self.parent.shift.value = 0 + self.parent.imm.value = 0 + self.value = self.reg_info[size].expr.index(self.expr) + return True + + if not isinstance(self.expr, m2_expr.ExprOp): + return False + if not self.expr.op in shift_expr: + return False + args = self.expr.args + if not args[0] in self.reg_info[size].expr: + return False + if not isinstance(args[1], m2_expr.ExprInt): + return False + self.parent.shift.value = shift_expr.index(self.expr.op) + self.parent.imm.value = int(args[1]) + self.value = self.reg_info[size].expr.index(args[0]) + return True + + def decode(self, v): + size = 64 if self.parent.sf.value else 32 + e = self.reg_info[size].expr[v] + amount = self.parent.imm.value + if amount != 0: + e = m2_expr.ExprOp( + shift_expr[self.parent.shift.value], e, m2_expr.ExprInt(amount, e.size)) + self.expr = e + return True + + +def ror(value, amount, size): + mask = (1 << size) - 1 + return ((value >> amount) | (value << (size - amount))) & mask + + +def rol(value, amount, size): + mask = (1 << size) - 1 + return ((value << amount) | (value >> (size - amount)) & mask) + +# This implementation is inspired from ARM ISA v8.2 +# Exact Reference name: +# "ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile" + +class ReservedValue(Exception): + """Reserved Value, should not happen""" + pass + +class NotEncodable(Exception): + """Instruction is not encodable""" + pass + +class bits(object): + """Stand for ARM ASL 'bits' type, ie. a bit vector""" + + __slots__ = ["size", "value"] + + def __init__(self, size, value): + """Instantiate a bitvector of size @size with value @value""" + value = int(value) + self.size = int(size) + if value & self.mask != value: + raise ValueError( + "Value %r is too large for %r bits (mask %r)", + value, + size, + self.mask + ) + self.value = value + + def concat_left(self, other_bits): + """Return a new bits instance for @other_bits . self""" + return bits(self.size + other_bits.size, + self.value | (other_bits.value << self.size)) + + @property + def mask(self): + return (1 << self.size) - 1 + + def __invert__(self): + return bits(self.size, self.value ^ self.mask) + + def __int__(self): + return self.value + + def __and__(self, other_bits): + assert other_bits.size == self.size + return bits(self.size, self.value & other_bits.value) + + def __eq__(self, other_bits): + return all((self.size == other_bits.size, + self.value == other_bits.value)) + + def __getitem__(self, info): + if isinstance(info, slice): + start = info.start if info.start else 0 + stop = info.stop if info.stop else self.value + if info.step is not None: + raise RuntimeError("Not implemented") + mask = (1 << stop) - 1 + return bits(stop - start, + (self.value >> start) & mask) + else: + raise RuntimeError("Not implemented") + + @property + def pop_count(self): + "Population count: number of bit set" + count = 0 + value = self.value + while (value > 0): + if value & 1 == 1: + count += 1 + value >>= 1 + return count + + def __str__(self): + return "'%s'" % "".join('1' if self.value & (1 << i) else '0' + for i in reversed(range(self.size))) + +# From J1-6035 +def HighestSetBit(x): + for i in reversed(range(x.size)): + if x.value & (1 << i): + return i + return - 1 + +# From J1-6037 +def Ones(N): + return bits(N, (1 << N) - 1) + +# From J1-6038 +def ROR(x, shift): + if shift == 0: + return x + return bits(x.size, ror(UInt(x), shift, x.size)) + +# From J1-6038 +def Replicate(x, N): + assert N % x.size == 0 + new = x + while new.size < N: + new = new.concat_left(x) + return new + +# From J1-6039 +def UInt(x): + return int(x) + +# From J1-6039 +def ZeroExtend(x, N): + assert N >= x.size + return bits(N, x.value) + +# From J1-5906 +def DecodeBitMasks(M, immN, imms, immr, immediate): + """ + @M: 32 or 64 + @immN: 1-bit + @imms: 6-bit + @immr: 6-bit + @immediate: boolean + """ + len_ = HighestSetBit((~imms).concat_left(immN)) + if len_ < 1: + raise ReservedValue() + assert M >= (1 << len_) + + levels = ZeroExtend(Ones(len_), 6) + + if immediate and (imms & levels) == levels: + raise ReservedValue() + S = UInt(imms & levels); + R = UInt(immr & levels); + + esize = 1 << len_ + welem = ZeroExtend(Ones(S + 1), esize) + wmask = Replicate(ROR(welem, R), M) + + # For now, 'tmask' is unused: + # + # diff = S - R; + # d = UInt(bits(len_, diff)) + # telem = ZeroExtend(Ones(d + 1), esize) + # tmask = Replicate(telem, M) + + return wmask, None + +# EncodeBitMasks doesn't have any equivalent in ARM ASL shared functions +# This implementation "reverses" DecodeBitMasks flow +def EncodeBitMasks(wmask): + # Find replicate + M = wmask.size + for i in range(1, M + 1): + if M % i != 0: + continue + if wmask == Replicate(wmask[:i], M): + break + else: + raise NotEncodable + + # Find ROR value: welem is only '1's + welem_after_ror = wmask[:i] + esize = welem_after_ror.size + S = welem_after_ror.pop_count - 1 + welem = ZeroExtend(Ones(S + 1), esize) + for i in range(welem_after_ror.size): + if ROR(welem, i) == welem_after_ror: + break + else: + raise NotEncodable + R = i + + # Find len value + for i in range(M): + if (1 << i) == esize: + break + else: + raise NotEncodable + len_ = i + levels = ZeroExtend(Ones(len_), 6) + levels = UInt(levels) + + if len_ == 6: + # N = 1 + immn = 1 + imms = S + else: + # N = 0, NOT(imms) have to be considered + immn = 0 + mask = (1 << ((6 - len_ - 1))) - 1 + mask <<= (len_ + 1) + imms = S | mask + immr = R + return immr, imms, immn + + +class aarch64_imm_nsr(aarch64_imm_sf, aarch64_arg): + parser = base_expr + + def decode(self, v): + size = 64 if self.parent.sf.value else 32 + bitmask, _ = DecodeBitMasks(size, + bits(1, self.parent.immn.value), + bits(6, v), + bits(6, self.parent.immr.value), + True + ) + self.expr = m2_expr.ExprInt(UInt(bitmask), + size) + return True + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + if not test_set_sf(self.parent, self.expr.size): + return False + value = int(self.expr) + if value == 0: + return False + + try: + immr, imms, immn = EncodeBitMasks(bits(self.expr.size, value)) + except NotEncodable: + return False + self.parent.immr.value = immr + self.parent.immn.value = immn + self.value = imms + return True + + +class aarch64_pcoff(aarch64_imm_32): + parser = base_expr + + +class aarch64_immhip_page(aarch64_imm_32): + parser = base_expr + + def decode(self, v): + v = ((v << 2) | self.parent.immlo.value) << 12 + v = sign_ext(v, 33, 64) + self.expr = m2_expr.ExprInt(v, 64) + return True + + def encode(self): + v = int(self.expr) + if v & (1 << 63): + v &= (1 << 33) - 1 + if v & 0xfff: + return False + v >>= 12 + self.parent.immlo.value = v & 3 + v >>= 2 + self.value = v + return True + + +class aarch64_immhi_page(aarch64_imm_32): + parser = base_expr + + def decode(self, v): + v = ((v << 2) | self.parent.immlo.value) + v = sign_ext(v, 21, 64) + self.expr = m2_expr.ExprInt(v, 64) + return True + + def encode(self): + v = int(self.expr) + if v & (1 << 63): + v &= (1 << 21) - 1 + self.parent.immlo.value = v & 3 + v >>= 2 + if v > (1 << 19) - 1: + return False + self.value = v & ((1 << 19) - 1) + return True + + +class aarch64_imm_hw(aarch64_arg): + parser = base_expr + shift_op = '<<' + + def decode(self, v): + size = 64 if self.parent.sf.value else 32 + self.expr = m2_expr.ExprInt(v << (16 * self.parent.hw.value), size) + return True + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + size = self.parent.args[0].expr.size + if set_imm_to_size(size, self.expr) is None: + return False + value = int(self.expr) + mask = (1 << size) - 1 + for i in range(size // 16): + if ((0xffff << (i * 16)) ^ mask) & value: + continue + self.parent.hw.value = i + self.value = value >> (i * 16) + return True + return False + + +class aarch64_imm_hw_sc(aarch64_arg): + parser = shiftimm_off_sc + shift_op = 'slice_at' + + def decode(self, v): + size = 64 if self.parent.sf.value else 32 + expr = m2_expr.ExprInt(v, size) + amount = m2_expr.ExprInt(16 * self.parent.hw.value, size) + if self.parent.hw.value: + self.expr = m2_expr.ExprOp(self.shift_op, expr, amount) + else: + self.expr = expr + return True + + def encode(self): + if isinstance(self.expr, m2_expr.ExprInt): + if int(self.expr) > 0xFFFF: + return False + self.value = int(self.expr) + self.parent.hw.value = 0 + return True + + if not (isinstance(self.expr, m2_expr.ExprOp) and + self.expr.op == self.shift_op and + len(self.expr.args) == 2 and + isinstance(self.expr.args[0], m2_expr.ExprInt) and + isinstance(self.expr.args[1], m2_expr.ExprInt)): + return False + if set_imm_to_size(self.parent.args[0].expr.size, self.expr.args[0]) is None: + return False + if set_imm_to_size(self.parent.args[0].expr.size, self.expr.args[1]) is None: + return False + arg, amount = [int(arg) for arg in self.expr.args] + if arg > 0xFFFF: + return False + if amount % 16 or amount // 16 > 4: + return False + self.value = arg + self.parent.hw.value = amount // 16 + return True + + +class aarch64_offs(imm_noarg, aarch64_arg): + parser = base_expr + + def decode(self, v): + v = v & self.lmask + v = (v << 2) + v = sign_ext(v, (self.l + 2), 64) + self.expr = m2_expr.ExprInt(v, 64) + return True + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + v = int(self.expr) + if v & (1 << 63): + v &= (1 << (self.l + 2)) - 1 + self.value = v >> 2 + return True + + + +class aarch64_offs_pc(imm_noarg, aarch64_arg): + parser = deref_pc + + def decode(self, v): + v = v & self.lmask + v = (v << 2) + v = sign_ext(v, (self.l + 2), 64) + self.expr = m2_expr.ExprOp("preinc", PC, m2_expr.ExprInt(v, 64)) + return True + + def encode(self): + if not self.expr.is_op('preinc'): + return False + if self.expr.args == (PC,): + v = 0 + elif (len(self.expr.args) == 2 and + self.expr.args[0] == PC and + self.expr.args[1].is_int()): + v = int(self.expr.args[1]) + else: + return None + if v & (1 << 63): + v &= (1 << (self.l + 2)) - 1 + self.value = v >> 2 + return True + + + +def set_mem_off(parent, imm): + if hasattr(parent, 'simm'): + mask = (1 << parent.simm.l) - 1 + if imm != sign_ext(imm & mask, parent.simm.l, 64): + return False + parent.simm.value = imm & mask + elif hasattr(parent, 'uimm'): + mask = (1 << parent.uimm.l) - 1 + if imm > mask: + return False + parent.uimm.value = imm + else: + raise ValueError('unknown imm') + return True + + +def get_size(parent): + if not hasattr(parent, "size"): + return 0 + if hasattr(parent.size, "amount"): + size = parent.size.amount + else: + size = parent.size.value + return size + + +class aarch64_deref(aarch64_arg): + parser = deref + + def decode_w_size(self, off): + return off + + def encode_w_size(self, off): + return off + + def get_postpre(self, parent): + if hasattr(self.parent, "postpre"): + if self.parent.postpre.value == 0: + op = 'postinc' + else: + op = 'preinc_wb' + else: + op = 'preinc' + return op + + def decode(self, v): + reg = gpregs64_info.expr[v] + off = int(self.parent.imm.expr) + op = self.get_postpre(self.parent) + off = self.decode_w_size(off) + self.expr = m2_expr.ExprOp(op, reg, m2_expr.ExprInt(off, 64)) + return True + + def encode(self): + expr = self.expr + if not isinstance(expr, m2_expr.ExprOp): + return False + if not expr.op in ['postinc', 'preinc_wb', 'preinc']: + return False + if hasattr(self.parent, "postpre"): + if expr.op == 'postinc': + self.parent.postpre.value = 0 + else: + self.parent.postpre.value = 1 + if len(expr.args) != 2: + return False + reg, off = expr.args + if not reg in gpregs64_info.expr: + return False + if not isinstance(off, m2_expr.ExprInt): + return False + imm = int(off) + imm = self.encode_w_size(imm) + if imm is False: + return False + self.parent.imm.expr = m2_expr.ExprInt(imm, 64) + if not self.parent.imm.encode(): + return False + self.value = gpregs64_info.expr.index(reg) + return True + + +class aarch64_deref_size(aarch64_deref): + + def decode_w_size(self, off): + size = get_size(self.parent) + return off << size + + def encode_w_size(self, off): + size = get_size(self.parent) + if size: + if off & ((1 << size) - 1): + return False + off >>= size + return off + + +class aarch64_deref_nooff(aarch64_deref): + parser = deref_nooff + + def decode(self, v): + reg = gpregs64_info.expr[v] + self.expr = m2_expr.ExprOp('preinc', reg) + return True + + def encode(self): + expr = self.expr + if not isinstance(expr, m2_expr.ExprOp): + return False + if expr.op != 'preinc': + return False + if len(expr.args) == 1: + reg = expr.args[0] + elif len(expr.args) == 2: + reg, off = expr.args + if not isinstance(off, m2_expr.ExprInt): + return False + if int(off) != 0: + return False + else: + return False + + if not reg in gpregs64_info.expr: + return False + self.value = gpregs64_info.expr.index(reg) + return True + + +class aarch64_sf_scale(aarch64_deref): + size2scale = {32: 2, 64: 3} + + def decode_w_size(self, off): + size = 2 + self.parent.sf.value + return off << size + + def encode_w_size(self, off): + size = self.parent.args[0].expr.size + if not size in self.size2scale: + return False + scale = self.size2scale[size] + off = int(mod_size2int[size](off) >> scale) + return off + + +class aarch64_sd_scale(aarch64_sf_scale): + size2scale = {32: 2, 64: 3, 128: 4} + + def decode_w_size(self, off): + size = 2 + self.parent.size.value + return off << size + + +class aarch64_eq(bsi): + + def decode(self, v): + return getattr(self.parent, self.ref).value == v + + def encode(self): + self.value = getattr(self.parent, self.ref).value + return True +modf = bs_mod_name(l=1, fname='modf', mn_mod=['', 'S']) +sf = bs(l=1, fname='sf', order=-1) + + +class aarch64_cond_arg(reg_noarg, aarch64_arg): + reg_info = conds_info + parser = reg_info.parser + + +class aarch64_cond_inv_arg(reg_noarg, aarch64_arg): + reg_info = conds_inv_info + parser = reg_info.parser + + +class aarch64_b40(aarch64_arg): + parser = base_expr + + def decode(self, v): + self.expr = m2_expr.ExprInt( + (self.parent.sf.value << self.l) | v, self.parent.rt.expr.size) + return True + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + size = self.parent.args[0].expr.size + value = int(self.expr) + self.value = value & self.lmask + if self.parent.sf.value is None: + self.parent.sf.value = value >> self.l + return True + else: + return value >> self.l == self.parent.sf.value + + +shift = bs(l=2, fname='shift') + +shiftb = bs(l=1, fname='shift', order=-1) + + +rn64_v = bs(l=5, cls=(aarch64_gpreg64_nodec,), fname='rn', order=-1) + +rn = bs(l=5, cls=(aarch64_gpreg,), fname="rn") +rs = bs(l=5, cls=(aarch64_gpreg,), fname="rs") +rm = bs(l=5, cls=(aarch64_gpreg,), fname="rm") +rd = bs(l=5, cls=(aarch64_gpreg,), fname="rd") +ra = bs(l=5, cls=(aarch64_gpregz,), fname="ra") +rt = bs(l=5, cls=(aarch64_gpregz,), fname="rt") +rt2 = bs(l=5, cls=(aarch64_gpregz,), fname="rt2") +rn0 = bs(l=5, cls=(aarch64_gpreg0,), fname="rn") + +rmz = bs(l=5, cls=(aarch64_gpregz,), fname="rm") +rnz = bs(l=5, cls=(aarch64_gpregz,), fname="rn") +rdz = bs(l=5, cls=(aarch64_gpregz,), fname="rd") + +rd_nosp = bs(l=5, cls=(aarch64_gpreg_noarg_nosp, aarch64_arg), fname="rd") + + +rn_n1 = bs(l=5, cls=(aarch64_gpreg_n1,), fname="rn") +rm_n1 = bs(l=5, cls=(aarch64_gpreg_n1,), fname="rm") + + +rn_na = bs(l=5, cls=(aarch64_gpreg_noarg,), fname="rn", order=-1) +rn32_na = bs(l=5, cls=(aarch64_gpreg32_noarg,), fname="rn", order=-1) +rn64_na = bs(l=5, cls=(aarch64_gpreg64_noarg,), fname="rn", order=-1) + +sd1 = bs(l=5, cls=(aarch64_simdreg_h,), fname="rt") +sd2 = bs(l=5, cls=(aarch64_simdreg_h,), fname="rt2") + +sdn_32_64 = bs(l=5, cls=(aarch64_simdreg_32_64,), fname="rn") +sdd_32_64 = bs(l=5, cls=(aarch64_simdreg_32_64,), fname="rd") +sdm_32_64 = bs(l=5, cls=(aarch64_simdreg_32_64,), fname="rm") +sda_32_64 = bs(l=5, cls=(aarch64_simdreg_32_64,), fname="ra") + + +sdm_32_64_zero = bs(l=5, cls=(aarch64_simdreg_32_64_zero,), fname="rm") + +crn = bs(l=4, cls=(aarch64_crreg,), fname="crn") +crm = bs(l=4, cls=(aarch64_crreg,), fname="crm") + + +rn64 = bs(l=5, cls=(aarch64_gpreg64,), fname="rn") +rs64 = bs(l=5, cls=(aarch64_gpreg64,), fname="rs") +rm64 = bs(l=5, cls=(aarch64_gpreg64,), fname="rm") +rd64 = bs(l=5, cls=(aarch64_gpreg64,), fname="rd") +rt64 = bs(l=5, cls=(aarch64_gpregz64,), fname="rt") +ra64 = bs(l=5, cls=(aarch64_gpregz64,), fname="ra") + +rn32 = bs(l=5, cls=(aarch64_gpreg32,), fname="rn") +rm32 = bs(l=5, cls=(aarch64_gpreg32,), fname="rm") +rd32 = bs(l=5, cls=(aarch64_gpreg32,), fname="rd") +rs32 = bs(l=5, cls=(aarch64_gpreg32,), fname="rs") + +sd08 = bs(l=5, cls=(aarch64_simd08,), fname="rd") +sd16 = bs(l=5, cls=(aarch64_simd16,), fname="rd") +sd32 = bs(l=5, cls=(aarch64_simd32,), fname="rd") +sd64 = bs(l=5, cls=(aarch64_simd64,), fname="rd") +sd128 = bs(l=5, cls=(aarch64_simd128,), fname="rd") + +sn08 = bs(l=5, cls=(aarch64_simd08,), fname="rn") +sn16 = bs(l=5, cls=(aarch64_simd16,), fname="rn") +sn32 = bs(l=5, cls=(aarch64_simd32,), fname="rn") +sn64 = bs(l=5, cls=(aarch64_simd64,), fname="rn") +sn128 = bs(l=5, cls=(aarch64_simd128,), fname="rn") + + +rt32 = bs(l=5, cls=(aarch64_gpregz32,), fname="rt") + +rt_isf = bs(l=5, cls=(aarch64_gpreg_isf,), fname="rt") + +rn64_deref = bs(l=5, cls=(aarch64_deref,), fname="rn") +rn64_deref_sz = bs(l=5, cls=(aarch64_deref_size,), fname="rn") +rn64_deref_sf = bs(l=5, cls=(aarch64_sf_scale,), fname="rn") +rn64_deref_sd = bs(l=5, cls=(aarch64_sd_scale,), fname="rn") + +rn64_deref_nooff = bs(l=5, cls=(aarch64_deref_nooff,), fname="rn") + +imm_sft_12 = bs(l=12, cls=(aarch64_imm_sft,)) + +# imm32_3 = bs(l=3, cls=(aarch64_imm_32,)) +imm32_3 = bs(l=3, fname="imm") +imm6 = bs(l=6, fname="imm", order=-1) +imm3 = bs(l=3, fname="imm", order=-1) +simm6 = bs(l=6, cls=(aarch64_int64_noarg, aarch64_arg), fname="imm", order=-1) +simm9 = bs(l=9, cls=(aarch64_int64_noarg,), fname="imm", order=-1) +simm7 = bs(l=7, cls=(aarch64_int64_noarg,), fname="imm", order=-1) +nzcv = bs(l=4, cls=(aarch64_uint64_noarg, aarch64_arg), fname="nzcv", order=-1) +uimm4 = bs(l=4, cls=(aarch64_uint64_noarg, aarch64_arg), fname="imm", order=-1) +uimm5 = bs(l=5, cls=(aarch64_uint64_noarg, aarch64_arg), fname="imm", order=-1) +uimm6 = bs(l=6, cls=(aarch64_uint64_noarg, aarch64_arg), fname="imm", order=-1) +uimm12 = bs(l=12, cls=(aarch64_uint64_noarg,), fname="imm", order=-1) +uimm16 = bs(l=16, cls=(aarch64_uint64_noarg, aarch64_arg), fname="imm", order=-1) +uimm7 = bs(l=7, cls=(aarch64_uint64_noarg,), fname="imm", order=-1) + +uimm8 = bs(l=8, cls=(aarch64_uint64,), fname="imm", order=-1) + +class op0_value(aarch64_uint64): + def decode(self, v): + v = v & self.lmask + v = self.decodeval(v) + v += 2 + e = self.int2expr(v) + if not e: + return False + self.expr = e + return True + + def encode(self): + v = self.expr2int(self.expr) + if v is None: + return False + v -= 2 + v = self.encodeval(v) + if v is False: + return False + self.value = v + return True + +op0 = bs(l=1, cls=(op0_value, aarch64_arg), fname="op0") +op1 = bs(l=3, cls=(aarch64_uint64, aarch64_arg), fname="op1") +op2 = bs(l=3, cls=(aarch64_uint64, aarch64_arg), fname="op2") + + +imm16 = bs(l=16, fname="imm", order=-1) + + +immlo = bs(l=2, fname='immlo') +immhip = bs(l=19, cls=(aarch64_immhip_page,)) +immhi = bs(l=19, cls=(aarch64_immhi_page,)) + +option = bs(l=3, fname='option', order=-1) + + +rm_ext = bs(l=5, cls=(aarch64_gpreg_ext,), fname="rm") +rm_sft = bs(l=5, cls=(aarch64_gpreg_sftimm,), fname="rm") + +rm_ext2 = bs(l=5, cls=(aarch64_gpreg_ext2,), fname="rm") +rm_ext2_128 = bs(l=5, cls=(aarch64_gpreg_ext2_128,), fname="rm") + + +imms = bs(l=6, cls=(aarch64_imm_nsr,), fname='imms') +immr = bs(l=6, fname='immr') +immn = bs(l=1, fname='immn') + + +imm16_hw = bs(l=16, cls=(aarch64_imm_hw,), fname='imm') +imm16_hw_sc = bs(l=16, cls=(aarch64_imm_hw_sc,), fname='imm') +hw = bs(l=2, fname='hw') + + +a_imms = bs(l=6, cls=(aarch64_imm_sf, aarch64_arg), fname="imm1", order=-1) +a_immr = bs(l=6, cls=(aarch64_imm_sf, aarch64_arg), fname="imm1", order=-1) + + + +adsu_name = {'ADD': 0, 'SUB': 1} +bs_adsu_name = bs_name(l=1, name=adsu_name) + + +adsus_name = {'ADDS': 0, 'SUBS': 1} +bs_adsus_name = bs_name(l=1, name=adsus_name) + + +offs19 = bs(l=19, cls=(aarch64_offs,), fname='off') +offs19pc = bs(l=19, cls=(aarch64_offs_pc,), fname='off') + +offs26 = bs(l=26, cls=(aarch64_offs,), fname='off') +offs14 = bs(l=14, cls=(aarch64_offs,), fname='off') + +b40 = bs(l=5, cls=(aarch64_b40,), fname='b40', order=1) + +sdsize1 = bs(l=1, fname="size") + +sdsize = bs(l=2, fname="size") +opsize = bs(l=2, fname="size") +sd = bs(l=5, cls=(aarch64_simdreg,), fname='sd') + +opc = bs(l=1, fname='opc', order=-1) + +# add/sub (imm) +aarch64op("addsub", [sf, bs_adsu_name, modf, bs('10001'), shift, imm_sft_12, rn, rd], [rd, rn, imm_sft_12]) +aarch64op("cmp", [sf, bs('1'), bs('1'), bs('10001'), shift, imm_sft_12, rn, bs('11111')], [rn, imm_sft_12], alias=True) +aarch64op("cmn", [sf, bs('0'), bs('1'), bs('10001'), shift, imm_sft_12, rn, bs('11111')], [rn, imm_sft_12], alias=True) + +aarch64op("adrp", [bs('1'), immlo, bs('10000'), immhip, rd64], [rd64, immhip]) +aarch64op("adr", [bs('0'), immlo, bs('10000'), immhi, rd64], [rd64, immhi]) + +# add/sub (reg shift) +aarch64op("addsub", [sf, bs_adsu_name, modf, bs('01011'), shift, bs('0'), rm_sft, imm6, rn, rd_nosp], [rd_nosp, rn, rm_sft]) +aarch64op("CMN", [sf, bs('0'), bs('1'), bs('01011'), shift, bs('0'), rm_sft, imm6, rn, bs('11111')], [rn, rm_sft]) + +aarch64op("cmp", [sf, bs('1'), bs('1'), bs('01011'), shift, bs('0'), rm_sft, imm6, rn, bs('11111')], [rn, rm_sft], alias=True) +# add/sub (reg ext) +aarch64op("addsub", [sf, bs_adsu_name, bs('0'), bs('01011'), bs('00'), bs('1'), rm_ext, option, imm3, rn, rd], [rd, rn, rm_ext]) +aarch64op("addssubs", [sf, bs_adsus_name, bs('1'), bs('01011'), bs('00'), bs('1'), rm_ext, option, imm3, rn, rd_nosp], [rd_nosp, rn, rm_ext]) +aarch64op("cmp", [sf, bs('1'), bs('1'), bs('01011'), bs('00'), bs('1'), rm_ext, option, imm3, rn, bs('11111')], [rn, rm_ext], alias=True) + + +aarch64op("neg", [sf, bs('1'), modf, bs('01011'), shift, bs('0'), rm_sft, imm6, bs('11111'), rd], [rd, rm_sft], alias=True) + + +logic_name = {'AND': 0, 'ORR': 1, 'EOR': 2} +bs_logic_name = bs_name(l=2, name=logic_name) +# logical (imm) +aarch64op("logic", [sf, bs_logic_name, bs('100100'), immn, immr, imms, rn0, rd], [rd, rn0, imms]) +# ANDS +aarch64op("ands", [sf, bs('11'), bs('100100'), immn, immr, imms, rn0, rdz], [rdz, rn0, imms]) +aarch64op("tst", [sf, bs('11'), bs('100100'), immn, immr, imms, rn0, bs('11111')], [rn0, imms], alias=True) + + +# bitfield move p.149 +logicbf_name = {'SBFM': 0b00, 'BFM': 0b01, 'UBFM': 0b10} +bs_logicbf_name = bs_name(l=2, name=logicbf_name) +aarch64op("logic", [sf, bs_logicbf_name, bs('100110'), bs(l=1, cls=(aarch64_eq,), ref="sf"), a_immr, a_imms, rn, rd], [rd, rn, a_immr, a_imms]) + + +# logical (reg shift) +aarch64op("and", [sf, bs('00'), bs('01010'), shift, bs('0'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft]) +aarch64op("bic", [sf, bs('00'), bs('01010'), shift, bs('1'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft]) +aarch64op("orr", [sf, bs('01'), bs('01010'), shift, bs('0'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft]) +aarch64op("orn", [sf, bs('01'), bs('01010'), shift, bs('1'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft]) +aarch64op("mvn", [sf, bs('01'), bs('01010'), shift, bs('1'), rm_sft, imm6, bs('11111'), rd], [rd, rm_sft], alias=True) +aarch64op("eor", [sf, bs('10'), bs('01010'), shift, bs('0'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft]) +aarch64op("eon", [sf, bs('10'), bs('01010'), shift, bs('1'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft]) +aarch64op("ands", [sf, bs('11'), bs('01010'), shift, bs('0'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft]) +aarch64op("tst", [sf, bs('11'), bs('01010'), shift, bs('0'), rm_sft, imm6, rn, bs('11111')], [rn, rm_sft], alias=True) +aarch64op("bics", [sf, bs('11'), bs('01010'), shift, bs('1'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft]) + +# move reg +aarch64op("mov", [sf, bs('01'), bs('01010'), bs('00'), bs('0'), rmz, bs('000000'), bs('11111'), rd], [rd, rmz], alias=True) + + +aarch64op("adc", [sf, bs('00'), bs('11010000'), rm, bs('000000'), rn, rd], [rd, rn, rm]) +aarch64op("adcs", [sf, bs('01'), bs('11010000'), rm, bs('000000'), rn, rd], [rd, rn, rm]) + + +aarch64op("sbc", [sf, bs('10'), bs('11010000'), rm, bs('000000'), rn, rd], [rd, rn, rm]) +aarch64op("sbcs", [sf, bs('11'), bs('11010000'), rm, bs('000000'), rn, rd], [rd, rn, rm]) + + + +bcond = bs_mod_name(l=4, fname='cond', mn_mod=['EQ', 'NE', 'CS', 'CC', + 'MI', 'PL', 'VS', 'VC', + 'HI', 'LS', 'GE', 'LT', + 'GT', 'LE', 'AL', 'NV']) + +cond_arg = bs(l=4, cls=(aarch64_cond_arg,), fname="cond") +cond_inv_arg = bs(l=4, cls=(aarch64_cond_inv_arg,), fname="cond") +# unconditional branch (ret) +aarch64op("br", [bs('1101011'), bs('0000'), bs('11111'), bs('000000'), rn64, bs('00000')], [rn64]) +aarch64op("blr", [bs('1101011'), bs('0001'), bs('11111'), bs('000000'), rn64, bs('00000')], [rn64]) +aarch64op("ret", [bs('1101011'), bs('0010'), bs('11111'), bs('000000'), rn64, bs('00000')], [rn64]) +aarch64op("eret", [bs('1101011'), bs('0100'), bs('11111'), bs('000000'), bs('11111'), bs('00000')]) +aarch64op("drps", [bs('1101011'), bs('0101'), bs('11111'), bs('000000'), bs('11111'), bs('00000')]) + +# unconditional branch (imm) +aarch64op("b", [bs('0'), bs('00101'), offs26], [offs26]) +aarch64op("bl", [bs('1'), bs('00101'), offs26], [offs26]) + + +post_pre = bs(l=1, order=-1, fname='postpre') + +# conditional compare (imm) p.158 +ccmp_name = {'CCMN': 0, 'CCMP': 1} +bs_ccmp_name = bs_name(l=1, name=ccmp_name) +aarch64op("condcmp", [sf, bs_ccmp_name, bs('1'), bs('11010010'), uimm5, cond_arg, bs('1'), bs('0'), rn, bs('0'), nzcv], [rn, uimm5, nzcv, cond_arg]) +aarch64op("condcmp", [sf, bs_ccmp_name, bs('1'), bs('11010010'), rm, cond_arg, bs('0'), bs('0'), rn, bs('0'), nzcv], [rn, rm, nzcv, cond_arg]) + +ldst_b_name = {'STRB': 0, 'LDRB': 1} +bs_ldst_b_name = bs_name(l=1, name=ldst_b_name) +ldst_name = {'STR': 0, 'LDR': 1} +bs_ldst_name = bs_name(l=1, name=ldst_name) +ldst_h_name = {'STRH': 0, 'LDRH': 1} +bs_ldst_h_name = bs_name(l=1, name=ldst_h_name) + +ldst_tb_name = {'STTRB': 0, 'LDTRB': 1} +bs_ldst_tb_name = bs_name(l=1, name=ldst_tb_name) + +ldst_th_name = {'STTRH': 0, 'LDTRH': 1} +bs_ldst_th_name = bs_name(l=1, name=ldst_th_name) + +ldst_ub_name = {'STURB': 0, 'LDURB': 1} +bs_ldst_ub_name = bs_name(l=1, name=ldst_ub_name) +ldst_u_name = {'STUR': 0, 'LDUR': 1} +bs_ldst_u_name = bs_name(l=1, name=ldst_u_name) + +ldst_t_name = {'STTR': 0, 'LDTR': 1} +bs_ldst_st_name = bs_name(l=1, name=ldst_t_name) + +ldst_1u_name = {'STUR': 0b0, 'LDUR': 0b1} +bs_ldst_1u_name = bs_name(l=1, name=ldst_1u_name) + +ldst_uh_name = {'STURH': 0, 'LDURH': 1} +bs_ldst_uh_name = bs_name(l=1, name=ldst_uh_name) + + +ldst_sw_name = {'STRSW': 0, 'LDRSW': 1} +bs_ldst_sw_name = bs_name(l=1, name=ldst_sw_name) + +# load/store register (imm post index) +aarch64op("ldst", [bs('00'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_b_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt32], [rt32, rn64_deref ]) +aarch64op("ldrsb", [bs('00'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt_isf], [rt_isf, rn64_deref ]) +aarch64op("ldrsh", [bs('01'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt_isf], [rt_isf, rn64_deref ]) +aarch64op("ldst", [bs('01'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_h_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt32], [rt32, rn64_deref ]) +aarch64op("ldst", [bs('10'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt32], [rt32, rn64_deref ]) +aarch64op("ldrsw", [bs('10'), bs('111'), bs('0'), bs('00'), bs('10'), bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt64], [rt64, rn64_deref ]) +aarch64op("ldst", [bs('11'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt64], [rt64, rn64_deref ]) + +aarch64op("ldst", [sdsize, bs('111'), bs('1'), bs('00'), bs('0'), bs_ldst_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, sd], [sd, rn64_deref ]) +aarch64op("ldst", [bs('00'), bs('111'), bs('1'), bs('00'), bs('1'), bs_ldst_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, sd128], [sd128, rn64_deref ]) + +# load/store register (unsigned imm) +aarch64op("ldst", [bs('00', fname="size"), bs('111'), bs('0'), bs('01'), bs('0'), bs_ldst_b_name, uimm12, rn64_deref_sz, rt32], [rt32, rn64_deref_sz ]) +aarch64op("ldrsb", [bs('00', fname="size"), bs('111'), bs('0'), bs('01'), bs('1'), sf, uimm12, rn64_deref_sz, rt_isf], [rt_isf, rn64_deref_sz ]) +aarch64op("ldrsh", [bs('01', fname="size"), bs('111'), bs('0'), bs('01'), bs('1'), sf, uimm12, rn64_deref_sz, rt_isf], [rt_isf, rn64_deref_sz ]) +aarch64op("ldst", [bs('01', fname="size"), bs('111'), bs('0'), bs('01'), bs('0'), bs_ldst_h_name, uimm12, rn64_deref_sz, rt32], [rt32, rn64_deref_sz ]) +aarch64op("ldst", [bs('10', fname="size"), bs('111'), bs('0'), bs('01'), bs('0'), bs_ldst_name, uimm12, rn64_deref_sz, rt32], [rt32, rn64_deref_sz ]) +aarch64op("ldrsw", [bs('10', fname="size"), bs('111'), bs('0'), bs('01'), bs('10'), uimm12, rn64_deref_sz, rt64], [rt64, rn64_deref_sz ]) +aarch64op("ldst", [bs('11', fname="size"), bs('111'), bs('0'), bs('01'), bs('0'), bs_ldst_name, uimm12, rn64_deref_sz, rt64], [rt64, rn64_deref_sz ]) + +aarch64op("ldst", [sdsize, bs('111'), bs('1'), bs('01'), bs('0'), bs_ldst_name, uimm12, rn64_deref_sz, sd], [sd, rn64_deref_sz ]) +aarch64op("ldst", [bs('00'), bs('111'), bs('1'), bs('01'), bs('1', fname='size', amount=4), bs_ldst_name, uimm12, rn64_deref_sz, sd128], [sd128, rn64_deref_sz ]) + +# load/store register (unp) +aarch64op("ldst", [bs('00'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_tb_name, bs('0'), simm9, bs('10'), rn64_deref, rt32], [rt32, rn64_deref ]) +aarch64op("ldtrsb", [bs('00'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, bs('10'), rn64_deref, rt_isf], [rt_isf, rn64_deref ]) +aarch64op("ldtrsh", [bs('01'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, bs('10'), rn64_deref, rt_isf], [rt_isf, rn64_deref ]) +aarch64op("ldsttrh",[bs('01'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_th_name, bs('0'), simm9, bs('10'), rn64_deref, rt32], [rt32, rn64_deref ]) +aarch64op("ldtrsw", [bs('10'), bs('111'), bs('0'), bs('00'), bs('10'), bs('0'), simm9, bs('10'), rn64_deref, rt64], [rt64, rn64_deref ]) +aarch64op("ldstt", [bs('1'), sf, bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_st_name, bs('0'), simm9, bs('10'), rn64_deref, rt], [rt, rn64_deref ]) + +aarch64op("ldstt", [sdsize, bs('111'), bs('1'), bs('00'), bs('0'), bs_ldst_st_name, bs('0'), simm9, bs('10'), rn64_deref, sd], [sd, rn64_deref ]) +aarch64op("ldst", [bs('00'), bs('111'), bs('1'), bs('00'), bs('1'), bs_ldst_st_name, bs('0'), simm9, bs('10'), rn64_deref, sd128], [sd128, rn64_deref ]) + +# load/store register (unscaled imm) +aarch64op("ldst", [bs('00'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_ub_name, bs('0'), simm9, bs('00'), rn64_deref, rt32], [rt32, rn64_deref ]) +aarch64op("ldursb", [bs('00'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, bs('00'), rn64_deref, rt_isf], [rt_isf, rn64_deref ]) +aarch64op("ldstuh", [bs('01'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_uh_name, bs('0'), simm9, bs('00'), rn64_deref, rt32], [rt32, rn64_deref ]) +aarch64op("ldursh", [bs('01'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, bs('00'), rn64_deref, rt_isf], [rt_isf, rn64_deref ]) +aarch64op("ldursw", [bs('10'), bs('111'), bs('0'), bs('00'), bs('10'), bs('0'), simm9, bs('00'), rn64_deref, rt64], [rt64, rn64_deref ]) +aarch64op("ldst", [bs('1'), sf, bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_u_name, bs('0'), simm9, bs('00'), rn64_deref, rt], [rt, rn64_deref ]) + +aarch64op("ldstu", [sdsize, bs('111'), bs('1'), bs('00'), bs('0'), bs_ldst_u_name, bs('0'), simm9, bs('00'), rn64_deref, sd], [sd, rn64_deref ]) +aarch64op("ldst", [bs('00'), bs('111'), bs('1'), bs('00'), bs('1'), bs_ldst_1u_name, bs('0'), simm9, bs('00'), rn64_deref, sd128], [sd128, rn64_deref ]) + +# load/store (register) p.728 + +aarch64op("ldstrb",[bs('00', fname="size"), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_b_name, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt32], [rt32, rm_ext2]) + +aarch64op("ldstrh",[bs('01', fname="size"), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_h_name, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt32], [rt32, rm_ext2]) + +aarch64op("ldrsb", [bs('00', fname="size"), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt_isf], [rt_isf, rm_ext2]) + +aarch64op("ldrsh", [bs('01', fname="size"), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt_isf], [rt_isf, rm_ext2]) + +aarch64op("ldst", [sdsize, bs('111'), bs('1'), bs('00'), bs('0'), bs_ldst_name, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, sd], [sd, rm_ext2]) +aarch64op("ldst", [bs('00', fname="size"), bs('111'), bs('1'), bs('00'), bs('1'), bs_ldst_name, bs('1'), rm_ext2_128, option, shiftb, bs('10'), rn64_v, sd128], [sd128, rm_ext2_128]) + +aarch64op("str", [bs('10', fname="size"), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_name, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt32], [rt32, rm_ext2]) + +aarch64op("ldrsw", [bs('10', fname="size"), bs('111'), bs('0'), bs('00'), bs('10'), bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt64], [rt64, rm_ext2]) + +aarch64op("ldst", [bs('11', fname="size"), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_name, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt64], [rt64, rm_ext2]) + +# load/store literal p.137 +aarch64op("ldr", [bs('0'), sf, bs('011'), bs('0'), bs('00'), offs19pc, rt], [rt, offs19pc]) +aarch64op("ldrsw", [bs('10'), bs('011'), bs('0'), bs('00'), offs19pc, rt64], [rt64, offs19pc]) + +# load/store simd literal p.142 +aarch64op("ldr", [sdsize, bs('011'), bs('1'), bs('00'), offs19pc, sd1], [sd1, offs19pc]) + + +# move wide p.203 +movwide_name = {'MOVN': 0b00, 'MOVZ': 0b10} +bs_movwide_name = bs_name(l=2, name=movwide_name) +# mov wide (imm) +aarch64op("mov", [sf, bs_movwide_name, bs('100101'), hw, imm16_hw, rd], [rd, imm16_hw]) +aarch64op("movk", [sf, bs('11'), bs('100101'), hw, imm16_hw_sc, rd], [rd, imm16_hw_sc]) + +# stp/ldp p.139 +ldstp_name = {'STP': 0b0, 'LDP': 0b1} +bs_ldstp_name = bs_name(l=1, name=ldstp_name) +aarch64op("ldstp", [sf, bs('0'), bs('101'), bs('0'), bs('0'), post_pre, bs('1'), bs_ldstp_name, simm7, rt2, rn64_deref_sf, rt], [rt, rt2, rn64_deref_sf]) +aarch64op("ldstp", [sf, bs('0'), bs('101'), bs('0'), bs('0'), bs('1'), bs('0'), bs_ldstp_name, simm7, rt2, rn64_deref_sf, rt], [rt, rt2, rn64_deref_sf]) + +aarch64op("ldstp", [sdsize, bs('101'), bs('1'), bs('0'), post_pre, bs('1'), bs_ldstp_name, simm7, sd2, rn64_deref_sd, sd1], [sd1, sd2, rn64_deref_sd]) +aarch64op("ldstp", [sdsize, bs('101'), bs('1'), bs('0'), bs('1'), bs('0'), bs_ldstp_name, simm7, sd2, rn64_deref_sd, sd1], [sd1, sd2, rn64_deref_sd]) + + +# data process p.207 +datap0_name = {'RBIT': 0b000000, 'REV16': 0b000001, + 'REV': 0b000010, + 'CLZ': 0b000100, 'CLS': 0b000101} +bs_datap0_name = bs_name(l=6, name=datap0_name) +aarch64op("ldstp", [bs('0', fname='sf'), bs('1'), modf, bs('11010110'), bs('00000'), bs_datap0_name, rn, rd]) +datap1_name = {'RBIT': 0b000000, 'REV16': 0b000001, + 'REV32': 0b000010, 'REV': 0b000011, + 'CLZ': 0b000100, 'CLS': 0b000101} +bs_datap1_name = bs_name(l=6, name=datap1_name) +aarch64op("ldstp", [bs('1', fname='sf'), bs('1'), modf, bs('11010110'), bs('00000'), bs_datap1_name, rn, rd]) + + +# conditional branch p.132 +aarch64op("b.", [bs('0101010'), bs('0'), offs19, bs('0'), bcond], [offs19]) +aarch64op("cbnz", [sf, bs('011010'), bs('1'), offs19, rt], [rt, offs19]) +aarch64op("cbz", [sf, bs('011010'), bs('0'), offs19, rt], [rt, offs19]) +aarch64op("tbnz", [sf, bs('011011'), bs('1'), b40, offs14, rt], [rt, b40, offs14]) +aarch64op("tbz", [sf, bs('011011'), bs('0'), b40, offs14, rt], [rt, b40, offs14]) + + +# fmov register p.160 +aarch64op("fmov", [bs('000'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('0000'), bs('00'), bs('10000'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64]) +# fmov scalar imm p.160 +aarch64op("fmov", [bs('000'), bs('11110'), bs('0'), sdsize1, bs('1'), uimm8, bs('100'), bs('00000'), sdd_32_64], [sdd_32_64, uimm8]) +# floating point comparison p.164 +aarch64op("fcmp", [bs('000'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64_zero, bs('00'), bs('1000'), sdn_32_64, bs('0'), opc, bs('000')], [sdn_32_64, sdm_32_64_zero]) +aarch64op("fcmpe", [bs('000'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64_zero, bs('00'), bs('1000'), sdn_32_64, bs('1'), opc, bs('000')], [sdn_32_64, sdm_32_64_zero]) +# floating point convert p.161 +aarch64op("fcvtas",[sf, bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('00'), bs('100'), bs('000000'), sdn_32_64, rd], [rd, sdn_32_64]) +aarch64op("fcvtzu",[sf, bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('11'), bs('001'), bs('000000'), sdn_32_64, rd], [rd, sdn_32_64]) +aarch64op("fcvtzs",[sf, bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('11'), bs('000'), bs('000000'), sdn_32_64, rd], [rd, sdn_32_64]) + +aarch64op("fcvt", [bs('000'), bs('11110'), bs('11'), bs('1'), bs('0001'), bs('00'), bs('10000'), sn16, sd32], [sd32, sn16]) +aarch64op("fcvt", [bs('000'), bs('11110'), bs('11'), bs('1'), bs('0001'), bs('01'), bs('10000'), sn16, sd64], [sd64, sn16]) +aarch64op("fcvt", [bs('000'), bs('11110'), bs('00'), bs('1'), bs('0001'), bs('11'), bs('10000'), sn32, sd16], [sd16, sn32]) +aarch64op("fcvt", [bs('000'), bs('11110'), bs('00'), bs('1'), bs('0001'), bs('01'), bs('10000'), sn32, sd64], [sd64, sn32]) +aarch64op("fcvt", [bs('000'), bs('11110'), bs('01'), bs('1'), bs('0001'), bs('11'), bs('10000'), sn64, sd16], [sd16, sn64]) +aarch64op("fcvt", [bs('000'), bs('11110'), bs('01'), bs('1'), bs('0001'), bs('00'), bs('10000'), sn64, sd32], [sd32, sn64]) + + + +swapargs = bs_swapargs(l=1, fname="swap", mn_mod=list(range(1 << 1))) + +aarch64op("fmov", [bs('0'), bs('00'), bs('11110'), bs('00'), bs('1'), bs('00'), bs('110'), bs('000000'), sn32, rd32], [rd32, sn32]) +aarch64op("fmov", [bs('0'), bs('00'), bs('11110'), bs('00'), bs('1'), bs('00'), bs('111'), bs('000000'), rn32, sd32], [sd32, rn32]) +aarch64op("fmov", [bs('1'), bs('00'), bs('11110'), bs('00'), bs('1'), bs('00'), bs('110'), bs('000000'), sd32, rd32], [rd32, sd32]) +aarch64op("fmov", [bs('1'), bs('00'), bs('11110'), bs('01'), bs('1'), bs('00'), bs('111'), bs('000000'), rd64, sd64], [sd64, rd64]) +aarch64op("fmov", [bs('1'), bs('00'), bs('11110'), bs('01'), bs('1'), bs('00'), bs('110'), bs('000000'), sd64, rd64], [rd64, sd64]) + + + +# floating point arith p.163 +aarch64op("fsub", [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('001'), bs('1'), bs('10'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64]) +aarch64op("fadd", [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('001'), bs('0'), bs('10'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64]) +aarch64op("fdiv", [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('000'), bs('1'), bs('10'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64]) +aarch64op("fmul", [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('000'), bs('0'), bs('10'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64]) +aarch64op("fnmul", [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('100'), bs('0'), bs('10'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64]) + +aarch64op("fabs", [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('0000'), bs('01'), bs('10000'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64]) +aarch64op("fneg", [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('0000'), bs('10'), bs('10000'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64]) +aarch64op("fsqrt", [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('0000'), bs('11'), bs('10000'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64]) + + +# floating point multiply add p.163 +aarch64op("fmadd", [bs('0'), bs('00'), bs('11111'), bs('0'), sdsize1, bs('0'), sdm_32_64, bs('0'), sda_32_64, sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64, sda_32_64]) +aarch64op("fmsub", [bs('0'), bs('00'), bs('11111'), bs('0'), sdsize1, bs('0'), sdm_32_64, bs('1'), sda_32_64, sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64, sda_32_64]) +aarch64op("fnmadd",[bs('0'), bs('00'), bs('11111'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('0'), sda_32_64, sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64, sda_32_64]) +aarch64op("fnmsub",[bs('0'), bs('00'), bs('11111'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('1'), sda_32_64, sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64, sda_32_64]) + +# conversion float integer p.235 +aarch64op("scvtf", [sf, bs('0'), bs('0'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('00'), bs('010'), bs('000000'), rn, sdd_32_64], [sdd_32_64, rn]) +aarch64op("ucvtf", [sf, bs('0'), bs('0'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('00'), bs('011'), bs('000000'), rn, sdd_32_64], [sdd_32_64, rn]) + + + +# conditional select p.158 +aarch64op("csel", [sf, bs('0'), bs('0'), bs('11010100'), rmz, cond_arg, bs('00'), rnz, rd], [rd, rnz, rmz, cond_arg]) +aarch64op("csinc", [sf, bs('0'), bs('0'), bs('11010100'), rmz, cond_arg, bs('01'), rnz, rd], [rd, rnz, rmz, cond_arg]) +aarch64op("csinv", [sf, bs('1'), bs('0'), bs('11010100'), rmz, cond_arg, bs('00'), rnz, rd], [rd, rnz, rmz, cond_arg]) +aarch64op("csneg", [sf, bs('1'), bs('0'), bs('11010100'), rmz, cond_arg, bs('01'), rnz, rd], [rd, rnz, rmz, cond_arg]) +aarch64op("cset", [sf, bs('0'), bs('0'), bs('11010100'), bs('11111'), cond_inv_arg, bs('01'), bs('11111'), rd], [rd, cond_inv_arg], alias=True) +aarch64op("csetm", [sf, bs('1'), bs('0'), bs('11010100'), bs('11111'), cond_inv_arg, bs('00'), bs('11111'), rd], [rd, cond_inv_arg], alias=True) + + +# multiply p.156 +aarch64op("madd", [sf, bs('00'), bs('11011'), bs('000'), rm, bs('0'), ra, rn, rd], [rd, rn, rm, ra]) +aarch64op("msub", [sf, bs('00'), bs('11011'), bs('000'), rm, bs('1'), ra, rn, rd], [rd, rn, rm, ra]) + +aarch64op("umulh", [bs('1'), bs('00'), bs('11011'), bs('110'), rm64, bs('0'), bs('11111'), rn64, rd64], [rd64, rn64, rm64]) +aarch64op("smulh", [bs('1'), bs('00'), bs('11011'), bs('010'), rm64, bs('0'), bs('11111'), rn64, rd64], [rd64, rn64, rm64]) + +aarch64op("smaddl",[bs('1'), bs('00'), bs('11011'), bs('001'), rm32, bs('0'), ra64, rn32, rd64], [rd64, rn32, rm32, ra64]) +aarch64op("umaddl",[bs('1'), bs('00'), bs('11011'), bs('101'), rm32, bs('0'), ra64, rn32, rd64], [rd64, rn32, rm32, ra64]) + +aarch64op("smsubl",[bs('1'), bs('00'), bs('11011'), bs('001'), rm32, bs('1'), ra64, rn32, rd64], [rd64, rn32, rm32, ra64]) +aarch64op("umsubl",[bs('1'), bs('00'), bs('11011'), bs('101'), rm32, bs('1'), ra64, rn32, rd64], [rd64, rn32, rm32, ra64]) + +# division p.156 +aarch64op("sdiv", [sf, bs('0'), bs('0'), bs('11010110'), rm, bs('00001'), bs('1'), rn, rd], [rd, rn, rm]) +aarch64op("udiv", [sf, bs('0'), bs('0'), bs('11010110'), rm, bs('00001'), bs('0'), rn, rd], [rd, rn, rm]) + + +# extract register p.150 +aarch64op("extr", [sf, bs('00100111'), bs(l=1, cls=(aarch64_eq,), ref="sf"), bs('0'), rm, uimm6, rn, rd], [rd, rn, rm, uimm6]) + +# shift reg p.155 +shiftr_name = {'LSL': 0b00, 'LSR': 0b01, 'ASR': 0b10, 'ROR': 0b11} +bs_shiftr_name = bs_name(l=2, name=shiftr_name) + +aarch64op("shiftr", [sf, bs('0'), bs('0'), bs('11010110'), rm, bs('0010'), bs_shiftr_name, rn, rd], [rd, rn, rm]) + +# +aarch64op("NOP", [bs('11010101000000110010000000011111')]) + +# exception p.133 +aarch64op("brk", [bs('11010100'), bs('001'), uimm16, bs('000'), bs('00')], [uimm16]) +aarch64op("hlt", [bs('11010100'), bs('010'), uimm16, bs('000'), bs('00')], [uimm16]) +aarch64op("svc", [bs('11010100'), bs('000'), uimm16, bs('000'), bs('01')], [uimm16]) +aarch64op("hvc", [bs('11010100'), bs('000'), uimm16, bs('000'), bs('10')], [uimm16]) +aarch64op("smc", [bs('11010100'), bs('000'), uimm16, bs('000'), bs('11')], [uimm16]) + +# msr p.631 +msr_name = {'MSR': 0b0, 'MRS': 0b1} +bs_msr_name = bs_name(l=1, name=msr_name) +aarch64op("mrs", [bs('1101010100'), bs('1'), bs('1'), op0, op1, crn, crm, op2, rt64], [rt64, op0, op1, crn, crm, op2]) +aarch64op("msr", [bs('1101010100'), bs('0'), bs('1'), op0, op1, crn, crm, op2, rt64], [op0, op1, crn, crm, op2, rt64]) + + +# load/store exclusive p.140 +aarch64op("stxr", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('0'), bs('11111'), rn64_deref_nooff, rt], [rs32, rt, rn64_deref_nooff]) +aarch64op("ldxr", [bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('0'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff]) + + +aarch64op("stxrb", [bs('0'), bs('0'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('0'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff]) +aarch64op("ldxrb", [bs('0'), bs('0'), bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('0'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff]) + +aarch64op("stxrb", [bs('0'), bs('1'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('0'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff]) +aarch64op("ldxrh", [bs('0'), bs('1'), bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('0'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff]) + +aarch64op("stxp", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('1'), rs32, bs('0'), rt2, rn64_deref_nooff, rt], [rs32, rt, rt2, rn64_deref_nooff]) +aarch64op("ldxp", [bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('1'), bs('11111'), bs('0'), rt2, rn64_deref_nooff, rt], [rt, rt2, rn64_deref_nooff]) + +# load acquire/store release p.141 +aarch64op("ldar", [bs('1'), sf, bs('001000'), bs('1'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff]) +aarch64op("ldarb",[bs('0'), bs('0'), bs('001000'), bs('1'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff]) +aarch64op("ldarh",[bs('0'), bs('1'), bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff]) +aarch64op("ldaxp",[bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('1'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff]) +aarch64op("ldaxr",[bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff]) + +aarch64op("stlr", [bs('1'), sf, bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff]) +aarch64op("stlrb",[bs('0'), bs('0'), bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff]) +aarch64op("stlrh",[bs('0'), bs('1'), bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff]) + +aarch64op("stlxr", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt], [rs32, rt, rn64_deref_nooff]) +aarch64op("stlxrb",[bs('0'), bs('0'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff]) +aarch64op("stlxrh",[bs('0'), bs('1'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff]) +aarch64op("stlxp", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('1'), rs32, bs('1'), rt2, rn64_deref_nooff, rt], [rs32, rt, rt2, rn64_deref_nooff]) + + +# barriers p.135 +aarch64op("dsb", [bs('1101010100'), bs('0000110011'), crm, bs('1'), bs('00'), bs('11111')], [crm]) +aarch64op("dmb", [bs('1101010100'), bs('0000110011'), crm, bs('1'), bs('01'), bs('11111')], [crm]) +aarch64op("isb", [bs('1101010100'), bs('0000110011'), crm, bs('1'), bs('10'), bs('11111')], [crm]) +aarch64op("ic", [bs('1101010100'), bs('0'), bs('01'), op1, bs('0111'), crm, op2, rt64], [op1, crm, op2, rt64]) +aarch64op('clrex', [bs('1101010100'), bs('0'), bs('00'), bs('011'), bs('0011'), uimm4, bs('010'), bs('11111')], [uimm4]) +aarch64op("tlbi", [bs('1101010100'), bs('0'), bs('01'), op1, bs('1000'), crm, op2, rt64], [op1, crm, op2, rt64]) +aarch64op('yield', [bs('1101010100'), bs('0'), bs('00'), bs('011'), bs('0010'), bs('0000'), bs('001'), bs('11111')], []) + + +stacctype = bs_mod_name(l=1, fname='order', mn_mod=['', 'L']) +ltacctype = bs_mod_name(l=1, fname='order', mn_mod=['', 'A']) + + +aarch64op("casp", [bs('0'), sf, bs('001000'), bs('0'), ltacctype, bs('1'), rs, stacctype, bs('11111'), rn64_deref_nooff, rt], [rs, rt, rn64_deref_nooff]) +aarch64op("ldaxrb", [bs('00'), bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff]) diff --git a/src/miasm/arch/aarch64/disasm.py b/src/miasm/arch/aarch64/disasm.py new file mode 100644 index 00000000..c4ad9181 --- /dev/null +++ b/src/miasm/arch/aarch64/disasm.py @@ -0,0 +1,27 @@ +from miasm.core.asmblock import disasmEngine +from miasm.arch.aarch64.arch import mn_aarch64 + +cb_aarch64_funcs = [] + + +def cb_aarch64_disasm(*args, **kwargs): + for func in cb_aarch64_funcs: + func(*args, **kwargs) + + +class dis_aarch64b(disasmEngine): + attrib = "b" + def __init__(self, bs=None, **kwargs): + super(dis_aarch64b, self).__init__( + mn_aarch64, self.attrib, bs, + dis_block_callback = cb_aarch64_disasm, + **kwargs) + + +class dis_aarch64l(disasmEngine): + attrib = "l" + def __init__(self, bs=None, **kwargs): + super(dis_aarch64l, self).__init__( + mn_aarch64, self.attrib, bs, + dis_block_callback = cb_aarch64_disasm, + **kwargs) diff --git a/src/miasm/arch/aarch64/jit.py b/src/miasm/arch/aarch64/jit.py new file mode 100644 index 00000000..f71ecae4 --- /dev/null +++ b/src/miasm/arch/aarch64/jit.py @@ -0,0 +1,79 @@ +from builtins import range +import logging + +from miasm.jitter.jitload import Jitter, named_arguments +from miasm.core.utils import pck64, upck64 +from miasm.arch.aarch64.sem import Lifter_Aarch64b, Lifter_Aarch64l + +log = logging.getLogger('jit_aarch64') +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) + +class jitter_aarch64l(Jitter): + max_reg_arg = 8 + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_Aarch64l(loc_db), *args, **kwargs) + self.vm.set_little_endian() + + def push_uint64_t(self, value): + self.cpu.SP -= 8 + self.vm.set_mem(self.cpu.SP, pck64(value)) + + def pop_uint64_t(self): + value = self.vm.get_u64(self.cpu.SP) + self.cpu.SP += 8 + return value + + def get_stack_arg(self, index): + return self.vm.get_u64(self.cpu.SP + 8 * index) + + # calling conventions + + @named_arguments + def func_args_stdcall(self, n_args): + args = [] + for i in range(min(n_args, self.max_reg_arg)): + args.append(getattr(self.cpu, 'X%d' % i)) + for i in range(max(0, n_args - self.max_reg_arg)): + args.append(self.get_stack_arg(i)) + ret_ad = self.cpu.LR + return ret_ad, args + + def func_ret_stdcall(self, ret_addr, ret_value=None): + self.pc = self.cpu.PC = ret_addr + if ret_value is not None: + self.cpu.X0 = ret_value + return True + + def get_arg_n_stdcall(self, index): + if index < self.max_reg_arg: + arg = self.cpu.get_gpreg()['X%d' % index] + else: + arg = self.get_stack_arg(index - self.max_reg_arg) + return arg + + def func_prepare_stdcall(self, ret_addr, *args): + for index in range(min(len(args), 4)): + setattr(self.cpu, 'X%d' % index, args[index]) + for index in range(4, len(args)): + self.vm.set_mem(self.cpu.SP + 8 * (index - 4), pck64(args[index])) + self.cpu.LR = ret_addr + + func_args_systemv = func_args_stdcall + func_ret_systemv = func_ret_stdcall + get_arg_n_systemv = get_arg_n_stdcall + func_prepare_systemv = func_prepare_stdcall + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.PC = self.pc + + +class jitter_aarch64b(jitter_aarch64l): + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_Aarch64b(loc_db), *args, **kwargs) + self.vm.set_big_endian() diff --git a/src/miasm/arch/aarch64/lifter_model_call.py b/src/miasm/arch/aarch64/lifter_model_call.py new file mode 100644 index 00000000..74f25969 --- /dev/null +++ b/src/miasm/arch/aarch64/lifter_model_call.py @@ -0,0 +1,50 @@ +#-*- coding:utf-8 -*- + +from miasm.ir.analysis import LifterModelCall +from miasm.arch.aarch64.sem import Lifter_Aarch64l, Lifter_Aarch64b + + +class LifterModelCallAarch64lBase(Lifter_Aarch64l, LifterModelCall): + + def __init__(self, loc_db): + Lifter_Aarch64l.__init__(self, loc_db) + self.ret_reg = self.arch.regs.X0 + + +class LifterModelCallAarch64bBase(Lifter_Aarch64b, LifterModelCall): + + def __init__(self, loc_db): + Lifter_Aarch64b.__init__(self, loc_db) + self.ret_reg = self.arch.regs.X0 + + +class LifterModelCallAarch64l(LifterModelCallAarch64lBase): + + def __init__(self, loc_db): + LifterModelCallAarch64lBase.__init__(self, loc_db) + self.ret_reg = self.arch.regs.X0 + + def get_out_regs(self, _): + return set([self.ret_reg, self.sp]) + + def sizeof_char(self): + return 8 + + def sizeof_short(self): + return 16 + + def sizeof_int(self): + return 32 + + def sizeof_long(self): + return 32 + + def sizeof_pointer(self): + return 32 + + +class LifterModelCallAarch64b(LifterModelCallAarch64bBase, LifterModelCallAarch64l): + + def __init__(self, loc_db): + LifterModelCallAarch64bBase.__init__(self, loc_db) + self.ret_reg = self.arch.regs.X0 diff --git a/src/miasm/arch/aarch64/regs.py b/src/miasm/arch/aarch64/regs.py new file mode 100644 index 00000000..9dee726b --- /dev/null +++ b/src/miasm/arch/aarch64/regs.py @@ -0,0 +1,251 @@ +#-*- coding:utf-8 -*- + +from builtins import range +from miasm.expression.expression import ExprId +from miasm.core.cpu import gen_reg, gen_regs, reg_info + +exception_flags = ExprId('exception_flags', 32) +interrupt_num = ExprId('interrupt_num', 32) + + +gpregs32_str = ["W%d" % i for i in range(0x1f)] + ["WSP"] +gpregs32_expr, gpregs32_init, gpregs32_info = gen_regs( + gpregs32_str, globals(), 32) + +gpregs64_str = ["X%d" % i for i in range(0x1E)] + ["LR", "SP"] +gpregs64_expr, gpregs64_init, gpregs64_info = gen_regs( + gpregs64_str, globals(), 64) + + +gpregsz32_str = ["W%d" % i for i in range(0x1f)] + ["WZR"] +gpregsz32_expr, gpregsz32_init, gpregsz32_info = gen_regs( + gpregsz32_str, globals(), 32) + +gpregsz64_str = ["X%d" % i for i in range(0x1e)] + ["LR", "XZR"] +gpregsz64_expr, gpregsz64_init, gpregsz64_info = gen_regs( + gpregsz64_str, globals(), 64) + +gpregs32_nosp, _, gpregs32_nosp_info = gen_regs(gpregs32_str[:-1], globals(), 32) +gpregs64_nosp, _, gpregs64_nosp_info = gen_regs(gpregs64_str[:-1], globals(), 64) + + +cr_str = ["c%d" % i for i in range(0x10)] +cr_expr, cr_init, cr_info = gen_regs(cr_str, globals(), 32) + + +simd08_str = ["B%d" % i for i in range(0x20)] +simd08_expr, simd08_init, simd08_info = gen_regs(simd08_str, globals(), 8) + +simd16_str = ["H%d" % i for i in range(0x20)] +simd16_expr, simd16_init, simd16_info = gen_regs(simd16_str, globals(), 16) + +simd32_str = ["S%d" % i for i in range(0x20)] +simd32_expr, simd32_init, simd32_info = gen_regs(simd32_str, globals(), 32) + +simd64_str = ["D%d" % i for i in range(0x20)] +simd64_expr, simd64_init, simd64_info = gen_regs(simd64_str, globals(), 64) + +simd128_str = ["Q%d" % i for i in range(0x20)] +simd128_expr, simd128_init, simd128_info = gen_regs( + simd128_str, globals(), 128) + +sysregs_str = ['ACTLR_EL1', 'ACTLR_EL2', 'ACTLR_EL3', 'AFSR0_EL1', + 'AFSR0_EL2', 'AFSR0_EL3', 'AFSR1_EL1', 'AFSR1_EL2', 'AFSR1_EL3', + 'AIDR_EL1', 'AMAIR_EL1', 'AMAIR_EL2', 'AMAIR_EL3', 'AMCFGR_EL0', + 'AMCG1IDR_EL0', 'AMCGCR_EL0', 'AMCNTENCLR0_EL0', 'AMCNTENCLR1_EL0', + 'AMCNTENSET0_EL0', 'AMCNTENSET1_EL0', 'AMCR_EL0'] + \ + ['AMEVCNTR%d%d_EL0' % (i, j) for i in range(2) for j in range(16)] + \ + ['AMEVCNTVOFF%d%d_EL2' % (i, j) for i in range(2) for j in range(16)] + \ + ['AMEVTYPER%d%d_EL0' % (i, j) for i in range(2) for j in range(16)] + \ + ['AMUSERENR_EL0', 'APDAKeyHi_EL1', 'APDAKeyLo_EL1', 'APDBKeyHi_EL1', + 'APDBKeyLo_EL1', 'APGAKeyHi_EL1', 'APGAKeyLo_EL1', 'APIAKeyHi_EL1', + 'APIAKeyLo_EL1', 'APIBKeyHi_EL1', 'APIBKeyLo_EL1', 'CCSIDR2_EL1', + 'CCSIDR_EL1', 'CLIDR_EL1', 'CNTFRQ_EL0', 'CNTHCTL_EL2', + 'CNTHPS_CTL_EL2', 'CNTHPS_CVAL_EL2', 'CNTHPS_TVAL_EL2', 'CNTHP_CTL_EL2', + 'CNTHP_CVAL_EL2', 'CNTHP_TVAL_EL2', 'CNTHVS_CTL_EL2', 'CNTHVS_CVAL_EL2', + 'CNTHVS_TVAL_EL2', 'CNTHV_CTL_EL2', 'CNTHV_CVAL_EL2', 'CNTHV_TVAL_EL2', + 'CNTKCTL_EL1', 'CNTPCTSS_EL0', 'CNTPCT_EL0', 'CNTPOFF_EL2', + 'CNTPS_CTL_EL1', 'CNTPS_CVAL_EL1', 'CNTPS_TVAL_EL1', 'CNTP_CTL_EL0', + 'CNTP_CVAL_EL0', 'CNTP_TVAL_EL0', 'CNTVCTSS_EL0', 'CNTVCT_EL0', + 'CNTVOFF_EL2', 'CNTV_CTL_EL0', 'CNTV_CVAL_EL0', 'CNTV_TVAL_EL0', + 'CONTEXTIDR_EL1', 'CONTEXTIDR_EL2', 'CPACR_EL1', 'CPTR_EL2', + 'CPTR_EL3', 'CSSELR_EL1', 'CTR_EL0', 'DACR32_EL2', 'DBGAUTHSTATUS_EL1'] + \ + ['DBGBCR%d_EL1' % i for i in range(16)] + \ + ['DBGBVR%d_EL1' % i for i in range(16)] + \ + ['DBGCLAIMCLR_EL1', 'DBGCLAIMSET_EL1', 'DBGDTRRX_EL0', 'DBGDTRTX_EL0', + 'DBGDTR_EL0', 'DBGPRCR_EL1', 'DBGVCR32_EL2'] + \ + ['DBGWCR%d_EL1' % i for i in range(16)] + \ + ['DBGWVR%d_EL1' % i for i in range(16)] + \ + ['DCZID_EL0', 'DISR_EL1', 'ELR_EL1', 'ERRIDR_EL1', + 'ERRSELR_EL1','ERXADDR_EL1', 'ERXCTLR_EL1', 'ERXFR_EL1', + 'ERXMISC0_EL1', 'ERXMISC1_EL1', 'ERXMISC2_EL1', 'ERXMISC3_EL1', + 'ERXPFGCDN_EL1', 'ERXPFGCTL_EL1', 'ERXPFGF_EL1', 'ERXSTATUS_EL1', + 'ESR_EL1', 'ESR_EL2', 'ESR_EL3', 'FAR_EL1', + 'FAR_EL2', 'FAR_EL3', 'FPEXC32_EL2', 'HACR_EL2', + 'HAFGRTR_EL2', 'HCR_EL2', 'HDFGRTR_EL2', 'HDFGWTR_EL2', + 'HFGITR_EL2', 'HFGRTR_EL2', 'HFGWTR_EL2', 'HPFAR_EL2', + 'HSTR_EL2', 'ICC_AP0R0_EL1', 'ICC_AP0R1_EL1', 'ICC_AP0R2_EL1', + 'ICC_AP0R3_EL1', 'ICC_AP1R0_EL1', 'ICC_AP1R1_EL1', 'ICC_AP1R2_EL1', + 'ICC_AP1R3_EL1', 'ICC_ASGI1R_EL1', 'ICC_BPR0_EL1', 'ICC_BPR1_EL1', + 'ICC_CTLR_EL1', 'ICC_CTLR_EL3', 'ICC_DIR_EL1', 'ICC_EOIR0_EL1', + 'ICC_EOIR1_EL1', 'ICC_HPPIR0_EL1', 'ICC_HPPIR1_EL1', 'ICC_IAR0_EL1', + 'ICC_IAR1_EL1', 'ICC_IGRPEN0_EL1', 'ICC_IGRPEN1_EL1', 'ICC_IGRPEN1_EL3', + 'ICC_PMR_EL1', 'ICC_RPR_EL1', 'ICC_SGI0R_EL1', 'ICC_SGI1R_EL1', + 'ICC_SRE_EL1', 'ICC_SRE_EL2', 'ICC_SRE_EL3', 'ICH_AP0R0_EL2', + 'ICH_AP0R1_EL2', 'ICH_AP0R2_EL2', 'ICH_AP0R3_EL2', 'ICH_AP1R0_EL2', + 'ICH_AP1R1_EL2', 'ICH_AP1R2_EL2', 'ICH_AP1R3_EL2', 'ICH_EISR_EL2', + 'ICH_ELRSR_EL2', 'ICH_HCR_EL2'] + \ + ['ICH_LR%d_EL2' % i for i in range(16)] + \ + ['ICH_MISR_EL2', 'ICH_VMCR_EL2', 'ICH_VTR_EL2', 'ID_AA64AFR0_EL1', + 'ID_AA64AFR1_EL1', 'ID_AA64DFR0_EL1', 'ID_AA64DFR1_EL1', 'ID_AA64ISAR0_EL1', + 'ID_AA64ISAR1_EL1', 'ID_AA64MMFR0_EL1','ID_AA64MMFR1_EL1', 'ID_AA64MMFR2_EL1', + 'ID_AA64PFR0_EL1', 'ID_AA64PFR1_EL1', 'ID_AA64ZFR0_EL1', 'ID_AFR0_EL1', + 'ID_DFR0_EL1', 'ID_ISAR0_EL1', 'ID_ISAR1_EL1', 'ID_ISAR2_EL1', + 'ID_ISAR3_EL1', 'ID_ISAR4_EL1', 'ID_ISAR5_EL1', 'ID_MMFR0_EL1', + 'ID_MMFR1_EL1', 'ID_MMFR2_EL1', 'ID_MMFR3_EL1', 'ID_MMFR4_EL1', + 'ID_MMFR5_EL1', 'ID_PFR0_EL1', 'ID_PFR1_EL1', 'ID_PFR2_EL1', + 'IFSR32_EL2', 'ISR_EL1', 'LORC_EL1', 'LOREA_EL1', + 'LORID_EL1', 'LORN_EL1', 'LORSA_EL1', 'MAIR_EL1', + 'MAIR_EL2', 'MAIR_EL3', 'MDCCINT_EL1', 'MDCCSR_EL0', + 'MDCR_EL2', 'MDCR_EL3', 'MDRAR_EL1', 'MDSCR_EL1', + 'MIDR_EL1', 'MPIDR_EL1', 'MVFR0_EL1', 'MVFR1_EL1', + 'MVFR2_EL1', 'OSDLR_EL1', 'OSDTRRX_EL1', 'OSDTRTX_EL1', + 'OSECCR_EL1', 'OSLAR_EL1', 'OSLSR_EL1', 'PAR_EL1', + 'PMBIDR_EL1', 'PMBLIMITR_EL1', 'PMBPTR_EL1', 'PMBSR_EL1', + 'PMCCFILTR_EL0', 'PMCCNTR_EL0', 'PMCEID0_EL0', 'PMCEID1_EL0', + 'PMCNTENCLR_EL0', 'PMCNTENSET_EL0', 'PMCR_EL0'] + \ + ['PMEVCNTR%d_EL0' % i for i in range(32)] + \ + ['PMEVTYPER%d_EL0' % i for i in range(32)] + \ + ['PMINTENCLR_EL1', 'PMINTENSET_EL1', 'PMMIR_EL1', 'PMOVSCLR_EL0', + 'PMOVSSET_EL0', 'PMSCR_EL1', 'PMSCR_EL2', 'PMSELR_EL0', + 'PMSEVFR_EL1', 'PMSFCR_EL1', 'PMSICR_EL1', 'PMSIDR_EL1', + 'PMSIRR_EL1', 'PMSLATFR_EL1', 'PMSWINC_EL0', 'PMUSERENR_EL0', + 'PMXEVCNTR_EL0', 'PMXEVTYPER_EL0', 'REVIDR_EL1', 'RMR_EL1', + 'RMR_EL2', 'RMR_EL3', 'RVBAR_EL1', 'RVBAR_EL2', + 'RVBAR_EL3', 'SCRLR_EL1', 'SCR_EL3', 'SCTLR_EL1', + 'SCTLR_EL2', 'SCTLR_EL3', 'SDER32_EL2', 'SDER32_EL3', + 'SPSR_EL1', 'TCR_EL1', 'TCR_EL2', 'TCR_EL3', + 'TPIDRRO_EL0', 'TPIDR_EL0', 'TPIDR_EL1', 'TPIDR_EL2', + 'TPIDR_EL3', 'TRFCR_EL1', 'TRFCR_EL2', 'TTBR0_EL1', + 'TTBR0_EL2', 'TTBR0_EL3', 'TTBR1_EL1', 'VBAR_EL1', + 'VBAR_EL2', 'VBAR_EL3', 'VDISR_EL2', 'VMPIDR_EL2', + 'VNCR_EL2', 'VPIDR_EL2', 'VSESR_EL2', 'VSTCR_EL2', + 'VSTTBR_EL2', 'VTCR_EL2', 'VTTBR_EL2', 'ZCR_EL1', + 'ZCR_EL2', 'ZCR_EL3', 'ELR_EL2', 'ELR_EL3', + 'FPCR', 'FPSR', 'SP_EL0', 'SP_EL1', + 'SP_EL2', 'SPSR_abt', 'SPSR_EL2', + 'SPSR_EL3', 'SPSR_fiq', 'SPSR_irq', 'SPSR_und', + 'DLR_EL0', 'DSPSR_EL0'] +sysregs_expr, sysregs_init, sysregs_info = gen_regs(sysregs_str, globals(), 64) + +PC, _ = gen_reg("PC", 64) +WZR, _ = gen_reg("WZR", 32) +XZR, _ = gen_reg("XZR", 64) + +PC_init = ExprId("PC_init", 64) +WZR_init = ExprId("WZR_init", 32) +XZR_init = ExprId("XZR_init", 64) + +reg_zf = 'zf' +reg_nf = 'nf' +reg_of = 'of' +reg_cf = 'cf' + +reg_df = 'df' +reg_af = 'af' +reg_iff = 'if' +reg_ff = 'ff' + +reg_cur_el = 'cur_el' +reg_dit = 'dit' +reg_pan = 'pan' +reg_spsel = 'spsel' +reg_ssbs = 'ssbs' +reg_tco = 'tco' +reg_uao = 'uao' + +zf = ExprId(reg_zf, size=1) +nf = ExprId(reg_nf, size=1) +of = ExprId(reg_of, size=1) +cf = ExprId(reg_cf, size=1) + +df = ExprId(reg_df, size=1) +af = ExprId(reg_af, size=1) +iff = ExprId(reg_iff, size=1) +ff = ExprId(reg_ff, size=1) + +cur_el = ExprId(reg_cur_el, size=2) +dit = ExprId(reg_dit, size=1) +pan = ExprId(reg_pan, size=1) +spsel = ExprId(reg_spsel, size=1) +ssbs = ExprId(reg_ssbs, size=1) +tco = ExprId(reg_tco, size=1) +uao = ExprId(reg_uao, size=1) + + +zf_init = ExprId("zf_init", size=1) +nf_init = ExprId("nf_init", size=1) +of_init = ExprId("of_init", size=1) +cf_init = ExprId("cf_init", size=1) +df_init = ExprId("df_init", size=1) +af_init = ExprId("af_init", size=1) +iff_init = ExprId("if_init", size=1) +ff_init = ExprId("ff_init", size=1) +cur_el_init = ExprId("cur_el_init", size=2) +dit_init = ExprId("dit_init", size=1) +pan_init = ExprId("pan_init", size=1) +spsel_init = ExprId("spsel_init", size=1) +ssbs_init = ExprId("ssbs_init", size=1) +tco_init = ExprId("tco_init", size=1) +uao_init = ExprId("uao_init", size=1) + + +all_regs_ids = [ + B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16, + B17, B18, B19, B20, B21, B22, B23, B24, B25, B26, B27, B28, B29, B30, B31, + + H0, H1, H2, H3, H4, H5, H6, H7, H8, H9, H10, H11, H12, H13, H14, H15, H16, + H17, H18, H19, H20, H21, H22, H23, H24, H25, H26, H27, H28, H29, H30, H31, + + S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15, S16, + S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31, + + D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, + D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, + + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, Q16, + Q17, Q18, Q19, Q20, Q21, Q22, Q23, Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31, + + W0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15, W16, + W17, W18, W19, W20, W21, W22, W23, W24, W25, W26, W27, W28, W29, W30, WSP, + + X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, + X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, LR, SP, + + exception_flags, + interrupt_num, + PC, + WZR, + XZR, + zf, nf, of, cf, + df, af, iff, ff, + cur_el, dit, pan, spsel, ssbs, tco, uao, +] + sysregs_expr + + +all_regs_ids_no_alias = all_regs_ids + +attrib_to_regs = { + 'l': all_regs_ids_no_alias, + 'b': all_regs_ids_no_alias, +} + +all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) + +all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids] + +regs_init = {} +for i, r in enumerate(all_regs_ids): + regs_init[r] = all_regs_ids_init[i] + +regs_flt_expr = [] diff --git a/src/miasm/arch/aarch64/sem.py b/src/miasm/arch/aarch64/sem.py new file mode 100644 index 00000000..eaa01228 --- /dev/null +++ b/src/miasm/arch/aarch64/sem.py @@ -0,0 +1,2386 @@ +from builtins import range +from future.utils import viewitems + +from miasm.expression.expression import ExprId, ExprInt, ExprLoc, ExprMem, \ + ExprCond, ExprCompose, ExprOp, ExprAssign +from miasm.ir.ir import Lifter, IRBlock, AssignBlock +from miasm.arch.aarch64.arch import mn_aarch64, conds_expr, replace_regs +from miasm.arch.aarch64.regs import * +from miasm.core.sembuilder import SemBuilder +from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO, EXCEPT_INT_XX + +# System register for ARM64-A 8.6 +system_regs = { + # op0 op1 crn crm op2 + (2, 0, 0, 0, 2): OSDTRRX_EL1, + + (2, 0, 0, 2, 0): MDCCINT_EL1, + (2, 0, 0, 2, 2): MDSCR_EL1, + + (2, 0, 0, 3, 2): OSDTRTX_EL1, + + (2, 0, 0, 6, 2): OSECCR_EL1, + + (2, 0, 0, 0, 4): DBGBVR0_EL1, + (2, 0, 0, 1, 4): DBGBVR1_EL1, + (2, 0, 0, 2, 4): DBGBVR2_EL1, + (2, 0, 0, 3, 4): DBGBVR3_EL1, + (2, 0, 0, 4, 4): DBGBVR4_EL1, + (2, 0, 0, 5, 4): DBGBVR5_EL1, + (2, 0, 0, 6, 4): DBGBVR6_EL1, + (2, 0, 0, 7, 4): DBGBVR7_EL1, + (2, 0, 0, 8, 4): DBGBVR8_EL1, + (2, 0, 0, 9, 4): DBGBVR9_EL1, + (2, 0, 0, 10, 4): DBGBVR10_EL1, + (2, 0, 0, 11, 4): DBGBVR11_EL1, + (2, 0, 0, 12, 4): DBGBVR12_EL1, + (2, 0, 0, 13, 4): DBGBVR13_EL1, + (2, 0, 0, 14, 4): DBGBVR14_EL1, + (2, 0, 0, 15, 4): DBGBVR15_EL1, + + (2, 0, 0, 0, 5): DBGBCR0_EL1, + (2, 0, 0, 1, 5): DBGBCR1_EL1, + (2, 0, 0, 2, 5): DBGBCR2_EL1, + (2, 0, 0, 3, 5): DBGBCR3_EL1, + (2, 0, 0, 4, 5): DBGBCR4_EL1, + (2, 0, 0, 5, 5): DBGBCR5_EL1, + (2, 0, 0, 6, 5): DBGBCR6_EL1, + (2, 0, 0, 7, 5): DBGBCR7_EL1, + (2, 0, 0, 8, 5): DBGBCR8_EL1, + (2, 0, 0, 9, 5): DBGBCR9_EL1, + (2, 0, 0, 10, 5): DBGBCR10_EL1, + (2, 0, 0, 11, 5): DBGBCR11_EL1, + (2, 0, 0, 12, 5): DBGBCR12_EL1, + (2, 0, 0, 13, 5): DBGBCR13_EL1, + (2, 0, 0, 14, 5): DBGBCR14_EL1, + (2, 0, 0, 15, 5): DBGBCR15_EL1, + + (2, 0, 0, 0, 6): DBGWVR0_EL1, + (2, 0, 0, 1, 6): DBGWVR1_EL1, + (2, 0, 0, 2, 6): DBGWVR2_EL1, + (2, 0, 0, 3, 6): DBGWVR3_EL1, + (2, 0, 0, 4, 6): DBGWVR4_EL1, + (2, 0, 0, 5, 6): DBGWVR5_EL1, + (2, 0, 0, 6, 6): DBGWVR6_EL1, + (2, 0, 0, 7, 6): DBGWVR7_EL1, + (2, 0, 0, 8, 6): DBGWVR8_EL1, + (2, 0, 0, 9, 6): DBGWVR9_EL1, + (2, 0, 0, 10, 6): DBGWVR10_EL1, + (2, 0, 0, 11, 6): DBGWVR11_EL1, + (2, 0, 0, 12, 6): DBGWVR12_EL1, + (2, 0, 0, 13, 6): DBGWVR13_EL1, + (2, 0, 0, 14, 6): DBGWVR14_EL1, + (2, 0, 0, 15, 6): DBGWVR15_EL1, + + (2, 0, 0, 0, 7): DBGWCR0_EL1, + (2, 0, 0, 1, 7): DBGWCR1_EL1, + (2, 0, 0, 2, 7): DBGWCR2_EL1, + (2, 0, 0, 3, 7): DBGWCR3_EL1, + (2, 0, 0, 4, 7): DBGWCR4_EL1, + (2, 0, 0, 5, 7): DBGWCR5_EL1, + (2, 0, 0, 6, 7): DBGWCR6_EL1, + (2, 0, 0, 7, 7): DBGWCR7_EL1, + (2, 0, 0, 8, 7): DBGWCR8_EL1, + (2, 0, 0, 9, 7): DBGWCR9_EL1, + (2, 0, 0, 10, 7): DBGWCR10_EL1, + (2, 0, 0, 11, 7): DBGWCR11_EL1, + (2, 0, 0, 12, 7): DBGWCR12_EL1, + (2, 0, 0, 13, 7): DBGWCR13_EL1, + (2, 0, 0, 14, 7): DBGWCR14_EL1, + (2, 0, 0, 15, 7): DBGWCR15_EL1, + + (2, 0, 1, 0, 0): MDRAR_EL1, + (2, 0, 1, 0, 4): OSLAR_EL1, + + (2, 0, 1, 1, 4): OSLSR_EL1, + + (2, 0, 1, 3, 4): OSDLR_EL1, + + (2, 0, 1, 4, 4): DBGPRCR_EL1, + + (2, 0, 7, 8, 6): DBGCLAIMSET_EL1, + + (2, 0, 7, 9, 6): DBGCLAIMCLR_EL1, + + (2, 0, 7, 14, 6): DBGAUTHSTATUS_EL1, + + (2, 3, 0, 1, 0): MDCCSR_EL0, + + (2, 3, 0, 4, 0): DBGDTR_EL0, + + (2, 3, 0, 5, 0): DBGDTRRX_EL0, + (2, 3, 0, 5, 1): DBGDTRTX_EL0, + + (2, 4, 0, 7, 0): DBGVCR32_EL2, + + (3, 0, 0, 0, 0): MIDR_EL1, + (3, 0, 0, 0, 5): MPIDR_EL1, + (3, 0, 0, 0, 6): REVIDR_EL1, + + (3, 0, 0, 1, 0): ID_PFR0_EL1, + (3, 0, 0, 1, 1): ID_PFR1_EL1, + (3, 0, 0, 1, 2): ID_DFR0_EL1, + (3, 0, 0, 1, 3): ID_AFR0_EL1, + (3, 0, 0, 1, 4): ID_MMFR0_EL1, + (3, 0, 0, 1, 5): ID_MMFR1_EL1, + (3, 0, 0, 1, 6): ID_MMFR2_EL1, + (3, 0, 0, 1, 7): ID_MMFR3_EL1, + + (3, 0, 0, 2, 0): ID_ISAR0_EL1, + (3, 0, 0, 2, 1): ID_ISAR1_EL1, + (3, 0, 0, 2, 2): ID_ISAR2_EL1, + (3, 0, 0, 2, 3): ID_ISAR3_EL1, + (3, 0, 0, 2, 4): ID_ISAR4_EL1, + (3, 0, 0, 2, 5): ID_ISAR5_EL1, + (3, 0, 0, 2, 6): ID_MMFR4_EL1, + + (3, 0, 0, 3, 0): MVFR0_EL1, + (3, 0, 0, 3, 1): MVFR1_EL1, + (3, 0, 0, 3, 2): MVFR2_EL1, + (3, 0, 0, 3, 4): ID_PFR2_EL1, + (3, 0, 0, 3, 6): ID_MMFR5_EL1, + + (3, 0, 0, 4, 0): ID_AA64PFR0_EL1, + (3, 0, 0, 4, 1): ID_AA64PFR1_EL1, + (3, 0, 0, 4, 4): ID_AA64ZFR0_EL1, + + (3, 0, 0, 5, 0): ID_AA64DFR0_EL1, + (3, 0, 0, 5, 1): ID_AA64DFR1_EL1, + (3, 0, 0, 5, 4): ID_AA64AFR0_EL1, + (3, 0, 0, 5, 5): ID_AA64AFR1_EL1, + + (3, 0, 0, 6, 0): ID_AA64ISAR0_EL1, + (3, 0, 0, 6, 1): ID_AA64ISAR1_EL1, + + (3, 0, 0, 7, 0): ID_AA64MMFR0_EL1, + (3, 0, 0, 7, 1): ID_AA64MMFR1_EL1, + (3, 0, 0, 7, 2): ID_AA64MMFR2_EL1, + + (3, 0, 1, 0, 0): SCRLR_EL1, + (3, 0, 1, 0, 1): ACTLR_EL1, + (3, 0, 1, 0, 2): CPACR_EL1, + + (3, 0, 1, 2, 0): ZCR_EL1, + (3, 0, 1, 2, 1): TRFCR_EL1, + + (3, 0, 2, 0, 0): TTBR0_EL1, + (3, 0, 2, 0, 1): TTBR1_EL1, + (3, 0, 2, 0, 2): TCR_EL1, + + (3, 0, 2, 1, 0): APIAKeyLo_EL1, + (3, 0, 2, 1, 1): APIAKeyHi_EL1, + (3, 0, 2, 1, 2): APIBKeyLo_EL1, + (3, 0, 2, 1, 3): APIBKeyHi_EL1, + + (3, 0, 2, 2, 0): APDAKeyLo_EL1, + (3, 0, 2, 2, 1): APDAKeyHi_EL1, + (3, 0, 2, 2, 2): APDBKeyLo_EL1, + (3, 0, 2, 2, 3): APDBKeyHi_EL1, + + (3, 0, 2, 3, 0): APGAKeyLo_EL1, + (3, 0, 2, 3, 1): APGAKeyHi_EL1, + + (3, 0, 4, 1, 0): SP_EL0, + (3, 0, 4, 6, 0): ICC_PMR_EL1, # Alias ICV_PMR_EL1 + + (3, 0, 5, 1, 0): AFSR0_EL1, + (3, 0, 5, 1, 1): AFSR1_EL1, + + (3, 0, 5, 2, 0): ESR_EL1, + + (3, 0, 5, 3, 0): ERRIDR_EL1, + (3, 0, 5, 3, 1): ERRSELR_EL1, + + (3, 0, 5, 4, 0): ERXFR_EL1, + (3, 0, 5, 4, 1): ERXCTLR_EL1, + (3, 0, 5, 4, 2): ERXSTATUS_EL1, + (3, 0, 5, 4, 3): ERXADDR_EL1, + (3, 0, 5, 4, 4): ERXPFGF_EL1, + (3, 0, 5, 4, 5): ERXPFGCTL_EL1, + (3, 0, 5, 4, 6): ERXPFGCDN_EL1, + + (3, 0, 5, 5, 0): ERXMISC0_EL1, + (3, 0, 5, 5, 1): ERXMISC1_EL1, + (3, 0, 5, 5, 2): ERXMISC2_EL1, + (3, 0, 5, 5, 3): ERXMISC3_EL1, + + (3, 0, 6, 0, 0): FAR_EL1, + + (3, 0, 7, 4, 0): PAR_EL1, + + (3, 0, 9, 9, 0): PMSCR_EL1, + (3, 0, 9, 9, 2): PMSICR_EL1, + (3, 0, 9, 9, 3): PMSIRR_EL1, + (3, 0, 9, 9, 4): PMSFCR_EL1, + (3, 0, 9, 9, 5): PMSEVFR_EL1, + (3, 0, 9, 9, 6): PMSLATFR_EL1, + (3, 0, 9, 9, 7): PMSIDR_EL1, + + (3, 0, 9, 10, 0): PMBLIMITR_EL1, + (3, 0, 9, 10, 1): PMBPTR_EL1, + (3, 0, 9, 10, 3): PMBSR_EL1, + (3, 0, 9, 10, 7): PMBIDR_EL1, + + (3, 0, 9, 14, 1): PMINTENSET_EL1, + (3, 0, 9, 14, 2): PMINTENCLR_EL1, + (3, 0, 9, 14, 6): PMMIR_EL1, + + (3, 0, 10, 2, 0): MAIR_EL1, + + (3, 0, 10, 3, 0): AMAIR_EL1, + + (3, 0, 10, 4, 0): LORSA_EL1, + (3, 0, 10, 4, 1): LOREA_EL1, + (3, 0, 10, 4, 2): LORN_EL1, + (3, 0, 10, 4, 3): LORC_EL1, + (3, 0, 10, 4, 7): LORID_EL1, + + (3, 0, 12, 0, 0): VBAR_EL1, + (3, 0, 12, 0, 1): RVBAR_EL1, + (3, 0, 12, 0, 2): RMR_EL1, + + (3, 0, 12, 1, 0): ISR_EL1, + (3, 0, 12, 1, 1): DISR_EL1, + + (3, 0, 12, 8, 0): ICC_IAR0_EL1, # Alias ICV_IAR0_EL1 + (3, 0, 12, 8, 1): ICC_EOIR0_EL1, # Alias ICV_EOIR0_EL1 + (3, 0, 12, 8, 2): ICC_HPPIR0_EL1, # Alias ICV_HPPIR0_EL1 + (3, 0, 12, 8, 3): ICC_BPR0_EL1, # Alias ICV_BPR0_EL1 + (3, 0, 12, 8, 4): ICC_AP0R0_EL1, # Alias ICV_AP0R0_EL1 + (3, 0, 12, 8, 5): ICC_AP0R1_EL1, # Alias ICV_AP0R1_EL1 + (3, 0, 12, 8, 6): ICC_AP0R2_EL1, # Alias ICV_AP0R2_EL1 + (3, 0, 12, 8, 7): ICC_AP0R3_EL1, # Alias ICV_AP0R3_EL1 + + (3, 0, 12, 9, 0): ICC_AP1R0_EL1, # Alias ICV_AP1R0_EL1 + (3, 0, 12, 9, 1): ICC_AP1R1_EL1, # Alias ICV_AP1R1_EL1 + (3, 0, 12, 9, 2): ICC_AP1R2_EL1, # Alias ICV_AP1R2_EL1 + (3, 0, 12, 9, 3): ICC_AP1R3_EL1, # Alias ICV_AP1R3_EL1 + + (3, 0, 12, 11, 1): ICC_DIR_EL1, # Alias ICV_DIR_EL1 + (3, 0, 12, 11, 3): ICC_RPR_EL1, # Alias ICV_RPR_EL1 + (3, 0, 12, 11, 5): ICC_SGI1R_EL1, + (3, 0, 12, 11, 6): ICC_ASGI1R_EL1, + (3, 0, 12, 11, 7): ICC_SGI0R_EL1, + + (3, 0, 12, 12, 0): ICC_IAR1_EL1, # Alias ICV_IAR1_EL1 + (3, 0, 12, 12, 1): ICC_EOIR1_EL1, # Alias ICV_EOIR1_EL1 + (3, 0, 12, 12, 2): ICC_HPPIR1_EL1, # Alias ICV_HPPIR1_EL1 + (3, 0, 12, 12, 3): ICC_BPR1_EL1, # Alias ICV_BPR1_EL1 + (3, 0, 12, 12, 4): ICC_CTLR_EL1, # Alias ICV_CTLR_EL1 + (3, 0, 12, 12, 5): ICC_SRE_EL1, + (3, 0, 12, 12, 6): ICC_IGRPEN0_EL1, # Alias ICV_IGRPEN0_EL1 + (3, 0, 12, 12, 7): ICC_IGRPEN1_EL1, # Alias ICV_IGRPEN1_EL1 + + (3, 0, 13, 0, 1): CONTEXTIDR_EL1, + (3, 0, 13, 0, 4): TPIDR_EL1, + + (3, 0, 14, 1, 0): CNTKCTL_EL1, + + (3, 1, 0, 0, 0): CCSIDR_EL1, + (3, 1, 0, 0, 1): CLIDR_EL1, + (3, 1, 0, 0, 2): CCSIDR2_EL1, + (3, 1, 0, 0, 7): AIDR_EL1, + + (3, 2, 0, 0, 0): CSSELR_EL1, + (3, 0, 0, 0, 1): CTR_EL0, + + (3, 3, 0, 0, 7): DCZID_EL0, + + (3, 3, 4, 4, 0): FPCR, + (3, 3, 4, 4, 1): FPSR, + + (3, 3, 4, 5, 0): DSPSR_EL0, + (3, 3, 4, 5, 1): DLR_EL0, + + (3, 4, 4, 0, 0): SPSR_EL2, + (3, 4 ,4, 0, 1): ELR_EL2, + + (3, 4, 4, 1, 0): SP_EL1, + + (3, 4, 4, 3, 0): SPSR_irq, + (3, 4, 4, 3, 1): SPSR_abt, + (3, 4, 4, 3, 2): SPSR_und, + (3, 4, 4, 3, 3): SPSR_fiq, + + (3, 3, 9, 12, 0): PMCR_EL0, + (3, 3, 9, 12, 1): PMCNTENSET_EL0, + (3, 3, 9, 12, 2): PMCNTENCLR_EL0, + (3, 3, 9, 12, 3): PMOVSCLR_EL0, + (3, 3, 9, 12, 4): PMSWINC_EL0, + (3, 3, 9, 12, 5): PMSELR_EL0, + (3, 3, 9, 12, 6): PMCEID0_EL0, + (3, 3, 9, 12, 7): PMCEID1_EL0, + + (3, 3, 9, 13, 0): PMCCNTR_EL0, + (3, 3, 9, 13, 1): PMXEVTYPER_EL0, + (3, 3, 9, 13, 2): PMXEVCNTR_EL0, + + (3, 3, 9, 14, 0): PMUSERENR_EL0, + (3, 3, 9, 14, 3): PMOVSSET_EL0, + + (3, 3, 13, 0, 2): TPIDR_EL0, + (3, 3, 13, 0, 3): TPIDRRO_EL0, + + (3, 3, 13, 2, 0): AMCR_EL0, + (3, 3, 13, 2, 1): AMCFGR_EL0, + (3, 3, 13, 2, 2): AMCGCR_EL0, + (3, 3, 13, 2, 3): AMUSERENR_EL0, + (3, 3, 13, 2, 4): AMCNTENCLR0_EL0, + (3, 3, 13, 2, 5): AMCNTENSET0_EL0, + (3, 3, 13, 2, 6): AMCG1IDR_EL0, + + (3, 3, 13, 3, 0): AMCNTENCLR1_EL0, + (3, 3, 13, 3, 1): AMCNTENSET1_EL0, + + (3, 3, 13, 4, 0): AMEVCNTR00_EL0, + (3, 3, 13, 4, 1): AMEVCNTR01_EL0, + (3, 3, 13, 4, 2): AMEVCNTR02_EL0, + (3, 3, 13, 4, 3): AMEVCNTR03_EL0, + (3, 3, 13, 4, 4): AMEVCNTR04_EL0, + (3, 3, 13, 4, 5): AMEVCNTR05_EL0, + (3, 3, 13, 4, 6): AMEVCNTR06_EL0, + (3, 3, 13, 4, 7): AMEVCNTR07_EL0, + + (3, 3, 13, 5, 0): AMEVCNTR08_EL0, + (3, 3, 13, 5, 1): AMEVCNTR09_EL0, + (3, 3, 13, 5, 2): AMEVCNTR010_EL0, + (3, 3, 13, 5, 3): AMEVCNTR011_EL0, + (3, 3, 13, 5, 4): AMEVCNTR012_EL0, + (3, 3, 13, 5, 5): AMEVCNTR013_EL0, + (3, 3, 13, 5, 6): AMEVCNTR014_EL0, + (3, 3, 13, 5, 7): AMEVCNTR015_EL0, + + (3, 3, 13, 6, 0): AMEVTYPER00_EL0, + (3, 3, 13, 6, 1): AMEVTYPER01_EL0, + (3, 3, 13, 6, 2): AMEVTYPER02_EL0, + (3, 3, 13, 6, 3): AMEVTYPER03_EL0, + (3, 3, 13, 6, 4): AMEVTYPER04_EL0, + (3, 3, 13, 6, 5): AMEVTYPER05_EL0, + (3, 3, 13, 6, 6): AMEVTYPER06_EL0, + (3, 3, 13, 6, 7): AMEVTYPER07_EL0, + + (3, 3, 13, 7, 0): AMEVTYPER08_EL0, + (3, 3, 13, 7, 1): AMEVTYPER09_EL0, + (3, 3, 13, 7, 2): AMEVTYPER010_EL0, + (3, 3, 13, 7, 3): AMEVTYPER011_EL0, + (3, 3, 13, 7, 4): AMEVTYPER012_EL0, + (3, 3, 13, 7, 5): AMEVTYPER013_EL0, + (3, 3, 13, 7, 6): AMEVTYPER014_EL0, + (3, 3, 13, 7, 7): AMEVTYPER015_EL0, + + (3, 3, 13, 12, 0): AMEVCNTR10_EL0, + (3, 3, 13, 12, 1): AMEVCNTR11_EL0, + (3, 3, 13, 12, 2): AMEVCNTR12_EL0, + (3, 3, 13, 12, 3): AMEVCNTR13_EL0, + (3, 3, 13, 12, 4): AMEVCNTR14_EL0, + (3, 3, 13, 12, 5): AMEVCNTR15_EL0, + (3, 3, 13, 12, 6): AMEVCNTR16_EL0, + (3, 3, 13, 12, 7): AMEVCNTR17_EL0, + + (3, 3, 13, 13, 0): AMEVCNTR18_EL0, + (3, 3, 13, 13, 1): AMEVCNTR19_EL0, + (3, 3, 13, 13, 2): AMEVCNTR110_EL0, + (3, 3, 13, 13, 3): AMEVCNTR111_EL0, + (3, 3, 13, 13, 4): AMEVCNTR112_EL0, + (3, 3, 13, 13, 5): AMEVCNTR113_EL0, + (3, 3, 13, 13, 6): AMEVCNTR114_EL0, + (3, 3, 13, 13, 7): AMEVCNTR115_EL0, + + (3, 3, 13, 14, 0): AMEVTYPER10_EL0, + (3, 3, 13, 14, 1): AMEVTYPER11_EL0, + (3, 3, 13, 14, 2): AMEVTYPER12_EL0, + (3, 3, 13, 14, 3): AMEVTYPER13_EL0, + (3, 3, 13, 14, 4): AMEVTYPER14_EL0, + (3, 3, 13, 14, 5): AMEVTYPER15_EL0, + (3, 3, 13, 14, 6): AMEVTYPER16_EL0, + (3, 3, 13, 14, 7): AMEVTYPER17_EL0, + + (3, 3, 13, 15, 0): AMEVTYPER18_EL0, + (3, 3, 13, 15, 1): AMEVTYPER19_EL0, + (3, 3, 13, 15, 2): AMEVTYPER110_EL0, + (3, 3, 13, 15, 3): AMEVTYPER111_EL0, + (3, 3, 13, 15, 4): AMEVTYPER112_EL0, + (3, 3, 13, 15, 5): AMEVTYPER113_EL0, + (3, 3, 13, 15, 6): AMEVTYPER114_EL0, + (3, 3, 13, 15, 7): AMEVTYPER115_EL0, + + (3, 3, 14, 0, 0): CNTFRQ_EL0, + (3, 3, 14, 0, 1): CNTPCT_EL0, + (3, 3, 14, 0, 2): CNTVCT_EL0, + (3, 3, 14, 0, 5): CNTPCTSS_EL0, + (3, 3, 14, 0, 6): CNTVCTSS_EL0, + + (3, 3, 14, 2, 0): CNTP_TVAL_EL0, + (3, 3, 14, 2, 1): CNTP_CTL_EL0, + (3, 3, 14, 2, 2): CNTP_CVAL_EL0, + + (3, 3, 14, 3, 0): CNTV_TVAL_EL0, + (3, 3, 14, 3, 1): CNTV_CTL_EL0, + (3, 3, 14, 3, 2): CNTV_CVAL_EL0, + + (3, 3, 14, 8, 0): PMEVCNTR0_EL0, + (3, 3, 14, 8, 1): PMEVCNTR1_EL0, + (3, 3, 14, 8, 2): PMEVCNTR2_EL0, + (3, 3, 14, 8, 3): PMEVCNTR3_EL0, + (3, 3, 14, 8, 4): PMEVCNTR4_EL0, + (3, 3, 14, 8, 5): PMEVCNTR5_EL0, + (3, 3, 14, 8, 6): PMEVCNTR6_EL0, + (3, 3, 14, 8, 7): PMEVCNTR7_EL0, + + (3, 3, 14, 9, 0): PMEVCNTR8_EL0, + (3, 3, 14, 9, 1): PMEVCNTR9_EL0, + (3, 3, 14, 9, 2): PMEVCNTR10_EL0, + (3, 3, 14, 9, 3): PMEVCNTR11_EL0, + (3, 3, 14, 9, 4): PMEVCNTR12_EL0, + (3, 3, 14, 9, 5): PMEVCNTR13_EL0, + (3, 3, 14, 9, 6): PMEVCNTR14_EL0, + (3, 3, 14, 9, 7): PMEVCNTR15_EL0, + + (3, 3, 14, 10, 0): PMEVCNTR16_EL0, + (3, 3, 14, 10, 1): PMEVCNTR17_EL0, + (3, 3, 14, 10, 2): PMEVCNTR18_EL0, + (3, 3, 14, 10, 3): PMEVCNTR19_EL0, + (3, 3, 14, 10, 4): PMEVCNTR20_EL0, + (3, 3, 14, 10, 5): PMEVCNTR21_EL0, + (3, 3, 14, 10, 6): PMEVCNTR22_EL0, + (3, 3, 14, 10, 7): PMEVCNTR23_EL0, + + (3, 3, 14, 11, 0): PMEVCNTR24_EL0, + (3, 3, 14, 11, 1): PMEVCNTR25_EL0, + (3, 3, 14, 11, 2): PMEVCNTR26_EL0, + (3, 3, 14, 11, 3): PMEVCNTR27_EL0, + (3, 3, 14, 11, 4): PMEVCNTR28_EL0, + (3, 3, 14, 11, 5): PMEVCNTR29_EL0, + (3, 3, 14, 11, 6): PMEVCNTR30_EL0, + + (3, 3, 14, 12, 0): PMEVTYPER0_EL0, + (3, 3, 14, 12, 1): PMEVTYPER1_EL0, + (3, 3, 14, 12, 2): PMEVTYPER2_EL0, + (3, 3, 14, 12, 3): PMEVTYPER3_EL0, + (3, 3, 14, 12, 4): PMEVTYPER4_EL0, + (3, 3, 14, 12, 5): PMEVTYPER5_EL0, + (3, 3, 14, 12, 6): PMEVTYPER6_EL0, + (3, 3, 14, 12, 7): PMEVTYPER7_EL0, + + (3, 3, 14, 13, 0): PMEVTYPER8_EL0, + (3, 3, 14, 13, 1): PMEVTYPER9_EL0, + (3, 3, 14, 13, 2): PMEVTYPER10_EL0, + (3, 3, 14, 13, 3): PMEVTYPER11_EL0, + (3, 3, 14, 13, 4): PMEVTYPER12_EL0, + (3, 3, 14, 13, 5): PMEVTYPER13_EL0, + (3, 3, 14, 13, 6): PMEVTYPER14_EL0, + (3, 3, 14, 13, 7): PMEVTYPER15_EL0, + + (3, 3, 14, 14, 0): PMEVTYPER16_EL0, + (3, 3, 14, 14, 1): PMEVTYPER17_EL0, + (3, 3, 14, 14, 2): PMEVTYPER18_EL0, + (3, 3, 14, 14, 3): PMEVTYPER19_EL0, + (3, 3, 14, 14, 4): PMEVTYPER20_EL0, + (3, 3, 14, 14, 5): PMEVTYPER21_EL0, + (3, 3, 14, 14, 6): PMEVTYPER22_EL0, + (3, 3, 14, 14, 7): PMEVTYPER23_EL0, + + (3, 3, 14, 15, 0): PMEVTYPER24_EL0, + (3, 3, 14, 15, 1): PMEVTYPER25_EL0, + (3, 3, 14, 15, 2): PMEVTYPER26_EL0, + (3, 3, 14, 15, 3): PMEVTYPER27_EL0, + (3, 3, 14, 15, 4): PMEVTYPER28_EL0, + (3, 3, 14, 15, 5): PMEVTYPER29_EL0, + (3, 3, 14, 15, 6): PMEVTYPER30_EL0, + (3, 3, 14, 15, 7): PMCCFILTR_EL0, + + (3, 4, 0, 0, 0): VPIDR_EL2, + (3, 4, 0, 0, 5): VMPIDR_EL2, + + (3, 4, 1, 0, 0): SCTLR_EL2, + (3, 4, 1, 0, 5): ACTLR_EL2, + + (3, 4, 1, 1, 0): HCR_EL2, + (3, 4, 1, 1, 1): MDCR_EL2, + (3, 4, 1, 1, 2): CPTR_EL2, + (3, 4, 1, 1, 3): HSTR_EL2, + (3, 4, 1, 1, 4): HFGRTR_EL2, + (3, 4, 1, 1, 5): HFGWTR_EL2, + (3, 4, 1, 1, 6): HFGITR_EL2, + (3, 4, 1, 1, 7): HACR_EL2, + + (3, 4, 1, 2, 0): ZCR_EL2, + + (3, 4, 1, 2, 1): TRFCR_EL2, + + (3, 4, 1, 3, 1): SDER32_EL2, + + (3, 4, 2, 0, 0): TTBR0_EL2, + (3, 4, 2, 0, 2): TCR_EL2, + + (3, 4, 2, 1, 0): VTTBR_EL2, + (3, 4, 2, 1, 2): VTCR_EL2, + + (3, 4, 2, 2, 0): VNCR_EL2, + + (3, 4, 2, 6, 0): VSTTBR_EL2, + (3, 4, 2, 6, 2): VSTCR_EL2, + + (3, 4, 3, 0, 0): DACR32_EL2, + + (3, 4, 3, 1, 4): HDFGRTR_EL2, + (3, 4, 3, 1, 5): HDFGWTR_EL2, + (3, 4, 3, 1, 6): HAFGRTR_EL2, + + (3, 4, 5, 0, 1): IFSR32_EL2, + + (3, 4, 5, 1, 0): AFSR0_EL2, + (3, 4, 5, 1, 1): AFSR1_EL2, + + (3, 4, 5, 2, 0): ESR_EL2, + (3, 4, 5, 2, 3): VSESR_EL2, + + (3, 4, 5, 3, 0): FPEXC32_EL2, + + (3, 4, 6, 0, 0): FAR_EL2, + (3, 4, 6, 0, 4): HPFAR_EL2, + + (3, 4, 9, 9, 0): PMSCR_EL2, + + (3, 4, 10, 2, 0): MAIR_EL2, + + (3, 4, 10, 3, 0): AMAIR_EL2, + + (3, 4, 12, 0, 0): VBAR_EL2, + (3, 4, 12, 0, 1): RVBAR_EL2, + (3, 4, 12, 0, 2): RMR_EL2, + + (3, 4, 12, 1, 1): VDISR_EL2, + + (3, 4, 12, 8, 0): ICH_AP0R0_EL2, + (3, 4, 12, 8, 1): ICH_AP0R1_EL2, + (3, 4, 12, 8, 2): ICH_AP0R2_EL2, + (3, 4, 12, 8, 3): ICH_AP0R3_EL2, + + (3, 4, 12, 9, 0): ICH_AP1R0_EL2, + (3, 4, 12, 9, 1): ICH_AP1R1_EL2, + (3, 4, 12, 9, 2): ICH_AP1R2_EL2, + (3, 4, 12, 9, 3): ICH_AP1R3_EL2, + (3, 4, 12, 9, 5): ICC_SRE_EL2, + + (3, 4, 12, 11, 0): ICH_HCR_EL2, + (3, 4, 12, 11, 1): ICH_VTR_EL2, + (3, 4, 12, 11, 2): ICH_MISR_EL2, + (3, 4, 12, 11, 3): ICH_EISR_EL2, + (3, 4, 12, 11, 5): ICH_ELRSR_EL2, + (3, 4, 12, 11, 7): ICH_VMCR_EL2, + + (3, 4, 12, 12, 0): ICH_LR0_EL2, + (3, 4, 12, 12, 1): ICH_LR1_EL2, + (3, 4, 12, 12, 2): ICH_LR2_EL2, + (3, 4, 12, 12, 3): ICH_LR3_EL2, + (3, 4, 12, 12, 4): ICH_LR4_EL2, + (3, 4, 12, 12, 5): ICH_LR5_EL2, + (3, 4, 12, 12, 6): ICH_LR6_EL2, + (3, 4, 12, 12, 7): ICH_LR7_EL2, + + (3, 4, 12, 13, 0): ICH_LR8_EL2, + (3, 4, 12, 13, 1): ICH_LR9_EL2, + (3, 4, 12, 13, 2): ICH_LR10_EL2, + (3, 4, 12, 13, 3): ICH_LR11_EL2, + (3, 4, 12, 13, 4): ICH_LR12_EL2, + (3, 4, 12, 13, 5): ICH_LR13_EL2, + (3, 4, 12, 13, 6): ICH_LR14_EL2, + (3, 4, 12, 13, 7): ICH_LR15_EL2, + + (3, 4, 13, 0, 1): CONTEXTIDR_EL2, + (3, 4, 13, 0, 2): TPIDR_EL2, + + (3, 4, 13, 8, 0): AMEVCNTVOFF00_EL2, + (3, 4, 13, 8, 1): AMEVCNTVOFF01_EL2, + (3, 4, 13, 8, 2): AMEVCNTVOFF02_EL2, + (3, 4, 13, 8, 3): AMEVCNTVOFF03_EL2, + (3, 4, 13, 8, 4): AMEVCNTVOFF04_EL2, + (3, 4, 13, 8, 5): AMEVCNTVOFF05_EL2, + (3, 4, 13, 8, 6): AMEVCNTVOFF06_EL2, + (3, 4, 13, 8, 7): AMEVCNTVOFF07_EL2, + + (3, 4, 13, 9, 0): AMEVCNTVOFF08_EL2, + (3, 4, 13, 9, 1): AMEVCNTVOFF09_EL2, + (3, 4, 13, 9, 2): AMEVCNTVOFF010_EL2, + (3, 4, 13, 9, 3): AMEVCNTVOFF011_EL2, + (3, 4, 13, 9, 4): AMEVCNTVOFF012_EL2, + (3, 4, 13, 9, 5): AMEVCNTVOFF013_EL2, + (3, 4, 13, 9, 6): AMEVCNTVOFF014_EL2, + (3, 4, 13, 9, 7): AMEVCNTVOFF015_EL2, + + (3, 4, 13, 10, 0): AMEVCNTVOFF10_EL2, + (3, 4, 13, 10, 1): AMEVCNTVOFF11_EL2, + (3, 4, 13, 10, 2): AMEVCNTVOFF12_EL2, + (3, 4, 13, 10, 3): AMEVCNTVOFF13_EL2, + (3, 4, 13, 10, 4): AMEVCNTVOFF14_EL2, + (3, 4, 13, 10, 5): AMEVCNTVOFF15_EL2, + (3, 4, 13, 10, 6): AMEVCNTVOFF16_EL2, + (3, 4, 13, 10, 7): AMEVCNTVOFF17_EL2, + + (3, 4, 13, 11, 0): AMEVCNTVOFF18_EL2, + (3, 4, 13, 11, 1): AMEVCNTVOFF19_EL2, + (3, 4, 13, 11, 2): AMEVCNTVOFF110_EL2, + (3, 4, 13, 11, 3): AMEVCNTVOFF111_EL2, + (3, 4, 13, 11, 4): AMEVCNTVOFF112_EL2, + (3, 4, 13, 11, 5): AMEVCNTVOFF113_EL2, + (3, 4, 13, 11, 6): AMEVCNTVOFF114_EL2, + (3, 4, 13, 11, 7): AMEVCNTVOFF115_EL2, + + (3, 4, 14, 0, 3): CNTVOFF_EL2, + (3, 4, 14, 0, 6): CNTPOFF_EL2, + + (3, 4, 14, 1, 0): CNTHCTL_EL2, + + (3, 4, 14, 2, 0): CNTHP_TVAL_EL2, + (3, 4, 14, 2, 1): CNTHP_CTL_EL2, + (3, 4, 14, 2, 2): CNTHP_CVAL_EL2, + + (3, 4, 14, 3, 0): CNTHV_TVAL_EL2, + (3, 4, 14, 3, 1): CNTHV_CTL_EL2, + (3, 4, 14, 3, 2): CNTHV_CVAL_EL2, + + (3, 4, 14, 4, 0): CNTHVS_TVAL_EL2, + (3, 4, 14, 4, 1): CNTHVS_CTL_EL2, + (3, 4, 14, 4, 2): CNTHVS_CVAL_EL2, + + (3, 4, 14, 5, 0): CNTHPS_TVAL_EL2, + (3, 4, 14, 5, 1): CNTHPS_CTL_EL2, + (3, 4, 14, 5, 2): CNTHPS_CVAL_EL2, + + # Aliases for *_EL02 *_EL12 + # see page 2864 of "Arm Architecture Reference Manual Armv8, + # for Armv8-A architecture profile" Release 31 March 2020 + (3, 5, 1, 0, 0): SCTLR_EL1, + (3, 5, 1, 0, 2): CPACR_EL1, + + (3, 5, 1, 2, 0): ZCR_EL1, + (3, 5, 1, 2, 1): TRFCR_EL1, + + (3, 5, 2, 0, 0): TTBR0_EL1, + (3, 5, 2, 0, 1): TTBR1_EL1, + (3, 5, 2, 0, 2): TCR_EL1, + + (3, 5, 4, 0, 0): SPSR_EL1, + (3, 5, 4, 0, 1): ELR_EL1, + + (3, 5, 5, 1, 0): AFSR0_EL1, + (3, 5, 5, 1, 1): AFSR1_EL1, + + (3, 5, 5, 2, 0): ESR_EL1, + + (3, 5, 6, 0, 0): FAR_EL1, + + (3, 5, 9, 9, 0): PMSCR_EL1, + + (3, 5, 10, 2, 0): MAIR_EL1, + + (3, 5, 10, 3, 0): AMAIR_EL1, + + (3, 5, 12, 0, 0): VBAR_EL1, + + (3, 5, 13, 0, 0): CONTEXTIDR_EL1, + + (3, 5, 14, 1, 0): CNTKCTL_EL1, + + (3, 5, 14, 2, 0): CNTP_TVAL_EL0, + (3, 5, 14, 2, 1): CNTP_CTL_EL0, + (3, 5, 14, 2, 2): CNTP_CVAL_EL0, + + (3, 5, 14, 3, 0): CNTV_TVAL_EL0, + (3, 5, 14, 3, 1): CNTV_CTL_EL0, + (3, 5, 14, 3, 2): CNTV_CVAL_EL0, + # End of aliases + + (3, 6, 1, 0, 0): SCTLR_EL3, + (3, 6, 1, 0, 1): ACTLR_EL3, + + (3, 6, 1, 1, 0): SCR_EL3, + (3, 6, 1, 1, 1): SDER32_EL3, + (3, 6, 1, 1, 2): CPTR_EL3, + + (3, 6, 1, 2, 0): ZCR_EL3, + + (3, 6, 1, 3, 1): MDCR_EL3, + + (3, 6, 2, 0, 0): TTBR0_EL3, + (3, 6, 2, 0, 2): TCR_EL3, + + (3, 6, 4, 0, 0): SPSR_EL3, + (3, 6, 4, 0, 1): ELR_EL3, + + (3, 6, 4, 1, 0): SP_EL2, + + (3, 6, 5, 1, 0): AFSR0_EL3, + (3, 6, 5, 1, 1): AFSR1_EL3, + + (3, 6, 5, 2, 0): ESR_EL3, + + (3, 6, 6, 0, 0): FAR_EL3, + + (3, 6, 10, 2, 0): MAIR_EL3, + + (3, 6, 10, 3, 0): AMAIR_EL3, + + (3, 6, 12, 0, 0): VBAR_EL3, + (3, 6, 12, 0, 1): RVBAR_EL3, + (3, 6, 12, 0, 2): RMR_EL3, + + (3, 6, 12, 12, 4): ICC_CTLR_EL3, + (3, 6, 12, 12, 5): ICC_SRE_EL3, + (3, 6, 12, 12, 7): ICC_IGRPEN1_EL3, + + (3, 6, 13, 0, 2): TPIDR_EL3, + + (3, 7, 14, 2, 0): CNTPS_TVAL_EL1, + (3, 7, 14, 2, 1): CNTPS_CTL_EL1, + (3, 7, 14, 2, 2): CNTPS_CVAL_EL1, +} + +# CPSR: N Z C V + + +def update_flag_zf(a): + return [ExprAssign(zf, ExprOp("FLAG_EQ", a))] + + +def update_flag_zf_eq(a, b): + return [ExprAssign(zf, ExprOp("FLAG_EQ_CMP", a, b))] + + +def update_flag_nf(arg): + return [ + ExprAssign( + nf, + ExprOp("FLAG_SIGN_SUB", arg, ExprInt(0, arg.size)) + ) + ] + + +def update_flag_zn(a): + e = [] + e += update_flag_zf(a) + e += update_flag_nf(a) + return e + + +def check_ops_msb(a, b, c): + if not a or not b or not c or a != b or a != c: + raise ValueError('bad ops size %s %s %s' % (a, b, c)) + + +def update_flag_add_cf(op1, op2): + "Compute cf in @op1 + @op2" + return [ExprAssign(cf, ExprOp("FLAG_ADD_CF", op1, op2))] + + +def update_flag_add_of(op1, op2): + "Compute of in @op1 + @op2" + return [ExprAssign(of, ExprOp("FLAG_ADD_OF", op1, op2))] + + +def update_flag_sub_cf(op1, op2): + "Compote CF in @op1 - @op2" + return [ExprAssign(cf, ExprOp("FLAG_SUB_CF", op1, op2) ^ ExprInt(1, 1))] + + +def update_flag_sub_of(op1, op2): + "Compote OF in @op1 - @op2" + return [ExprAssign(of, ExprOp("FLAG_SUB_OF", op1, op2))] + + +def update_flag_arith_add_co(arg1, arg2): + e = [] + e += update_flag_add_cf(arg1, arg2) + e += update_flag_add_of(arg1, arg2) + return e + + +def update_flag_arith_add_zn(arg1, arg2): + """ + Compute zf and nf flags for (arg1 + arg2) + """ + e = [] + e += update_flag_zf_eq(arg1, -arg2) + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, -arg2))] + return e + + +def update_flag_arith_sub_co(arg1, arg2): + """ + Compute cf and of flags for (arg1 - arg2) + """ + e = [] + e += update_flag_sub_cf(arg1, arg2) + e += update_flag_sub_of(arg1, arg2) + return e + + +def update_flag_arith_sub_zn(arg1, arg2): + """ + Compute zf and nf flags for (arg1 - arg2) + """ + e = [] + e += update_flag_zf_eq(arg1, arg2) + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, arg2))] + return e + + + + +def update_flag_zfaddwc_eq(arg1, arg2, arg3): + return [ExprAssign(zf, ExprOp("FLAG_EQ_ADDWC", arg1, arg2, arg3))] + +def update_flag_zfsubwc_eq(arg1, arg2, arg3): + return [ExprAssign(zf, ExprOp("FLAG_EQ_SUBWC", arg1, arg2, arg3))] + + +def update_flag_arith_addwc_zn(arg1, arg2, arg3): + """ + Compute znp flags for (arg1 + arg2 + cf) + """ + e = [] + e += update_flag_zfaddwc_eq(arg1, arg2, arg3) + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_ADDWC", arg1, arg2, arg3))] + return e + + +def update_flag_arith_subwc_zn(arg1, arg2, arg3): + """ + Compute znp flags for (arg1 - (arg2 + cf)) + """ + e = [] + e += update_flag_zfsubwc_eq(arg1, arg2, arg3) + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUBWC", arg1, arg2, arg3))] + return e + + +def update_flag_addwc_cf(op1, op2, op3): + "Compute cf in @res = @op1 + @op2 + @op3" + return [ExprAssign(cf, ExprOp("FLAG_ADDWC_CF", op1, op2, op3))] + + +def update_flag_addwc_of(op1, op2, op3): + "Compute of in @res = @op1 + @op2 + @op3" + return [ExprAssign(of, ExprOp("FLAG_ADDWC_OF", op1, op2, op3))] + + +def update_flag_arith_addwc_co(arg1, arg2, arg3): + e = [] + e += update_flag_addwc_cf(arg1, arg2, arg3) + e += update_flag_addwc_of(arg1, arg2, arg3) + return e + + + +def update_flag_subwc_cf(op1, op2, op3): + "Compute cf in @res = @op1 + @op2 + @op3" + return [ExprAssign(cf, ExprOp("FLAG_SUBWC_CF", op1, op2, op3) ^ ExprInt(1, 1))] + + +def update_flag_subwc_of(op1, op2, op3): + "Compute of in @res = @op1 + @op2 + @op3" + return [ExprAssign(of, ExprOp("FLAG_SUBWC_OF", op1, op2, op3))] + + +def update_flag_arith_subwc_co(arg1, arg2, arg3): + e = [] + e += update_flag_subwc_cf(arg1, arg2, arg3) + e += update_flag_subwc_of(arg1, arg2, arg3) + return e + + +cond2expr = {'EQ': ExprOp("CC_EQ", zf), + 'NE': ExprOp("CC_NE", zf), + 'CS': ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), # inv cf + 'CC': ExprOp("CC_U<", cf ^ ExprInt(1, 1)), # inv cf + 'MI': ExprOp("CC_NEG", nf), + 'PL': ExprOp("CC_POS", nf), + 'VS': ExprOp("CC_sOVR", of), + 'VC': ExprOp("CC_sNOOVR", of), + 'HI': ExprOp("CC_U>", cf ^ ExprInt(1, 1), zf), # inv cf + 'LS': ExprOp("CC_U<=", cf ^ ExprInt(1, 1), zf), # inv cf + 'GE': ExprOp("CC_S>=", nf, of), + 'LT': ExprOp("CC_S<", nf, of), + 'GT': ExprOp("CC_S>", nf, of, zf), + 'LE': ExprOp("CC_S<=", nf, of, zf), + 'AL': ExprInt(1, 1), + 'NV': ExprInt(0, 1) + } + + +def extend_arg(dst, arg): + if not isinstance(arg, ExprOp): + return arg + + op, (reg, shift) = arg.op, arg.args + if op == "SXTB": + base = reg[:8].signExtend(dst.size) + op = "<<" + elif op == "SXTH": + base = reg[:16].signExtend(dst.size) + op = "<<" + elif op == 'SXTW': + base = reg[:32].signExtend(dst.size) + op = "<<" + elif op == "SXTX": + base = reg.signExtend(dst.size) + op = "<<" + + elif op == "UXTB": + base = reg[:8].zeroExtend(dst.size) + op = "<<" + elif op == "UXTH": + base = reg[:16].zeroExtend(dst.size) + op = "<<" + elif op == 'UXTW': + base = reg[:32].zeroExtend(dst.size) + op = "<<" + elif op == "UXTX": + base = reg.zeroExtend(dst.size) + op = "<<" + + elif op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>']: + base = reg.zeroExtend(dst.size) + else: + raise NotImplementedError('Unknown shifter operator') + + out = ExprOp(op, base, (shift.zeroExtend(dst.size) + & ExprInt(dst.size - 1, dst.size))) + return out + + +# SemBuilder context +ctx = {"PC": PC, + "LR": LR, + "nf": nf, + "zf": zf, + "cf": cf, + "of": of, + "cond2expr": cond2expr, + "extend_arg": extend_arg, + "ExprId":ExprId, + "exception_flags": exception_flags, + "interrupt_num": interrupt_num, + "EXCEPT_DIV_BY_ZERO": EXCEPT_DIV_BY_ZERO, + "EXCEPT_INT_XX": EXCEPT_INT_XX, + } + +sbuild = SemBuilder(ctx) + + +# instruction definition ############## + +@sbuild.parse +def add(arg1, arg2, arg3): + arg1 = arg2 + extend_arg(arg2, arg3) + + +@sbuild.parse +def sub(arg1, arg2, arg3): + arg1 = arg2 - extend_arg(arg2, arg3) + + +@sbuild.parse +def neg(arg1, arg2): + arg1 = - arg2 + + +@sbuild.parse +def and_l(arg1, arg2, arg3): + arg1 = arg2 & extend_arg(arg2, arg3) + + +@sbuild.parse +def eor(arg1, arg2, arg3): + arg1 = arg2 ^ extend_arg(arg2, arg3) + + +@sbuild.parse +def eon(arg1, arg2, arg3): + arg1 = arg2 ^ (~extend_arg(arg2, arg3)) + + +@sbuild.parse +def orr(arg1, arg2, arg3): + arg1 = arg2 | extend_arg(arg2, arg3) + + +@sbuild.parse +def orn(arg1, arg2, arg3): + arg1 = arg2 | (~extend_arg(arg2, arg3)) + + +@sbuild.parse +def bic(arg1, arg2, arg3): + arg1 = arg2 & (~extend_arg(arg2, arg3)) + + +def bics(ir, instr, arg1, arg2, arg3): + e = [] + tmp1, tmp2 = arg2, (~extend_arg(arg2, arg3)) + res = tmp1 & tmp2 + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', tmp1, tmp2))] + e += update_flag_nf(res) + + e.append(ExprAssign(arg1, res)) + return e, [] + + +@sbuild.parse +def mvn(arg1, arg2): + arg1 = (~extend_arg(arg1, arg2)) + + +def adds(ir, instr, arg1, arg2, arg3): + e = [] + arg3 = extend_arg(arg2, arg3) + res = arg2 + arg3 + + e += update_flag_arith_add_zn(arg2, arg3) + e += update_flag_arith_add_co(arg2, arg3) + + e.append(ExprAssign(arg1, res)) + + return e, [] + + +def subs(ir, instr, arg1, arg2, arg3): + e = [] + arg3 = extend_arg(arg2, arg3) + res = arg2 - arg3 + + + e += update_flag_arith_sub_zn(arg2, arg3) + e += update_flag_arith_sub_co(arg2, arg3) + + e.append(ExprAssign(arg1, res)) + return e, [] + + +def cmp(ir, instr, arg1, arg2): + e = [] + arg2 = extend_arg(arg1, arg2) + + e += update_flag_arith_sub_zn(arg1, arg2) + e += update_flag_arith_sub_co(arg1, arg2) + + return e, [] + + +def cmn(ir, instr, arg1, arg2): + e = [] + arg2 = extend_arg(arg1, arg2) + + e += update_flag_arith_add_zn(arg1, arg2) + e += update_flag_arith_add_co(arg1, arg2) + + return e, [] + + +def ands(ir, instr, arg1, arg2, arg3): + e = [] + arg3 = extend_arg(arg2, arg3) + res = arg2 & arg3 + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg2, arg3))] + e += update_flag_nf(res) + + e.append(ExprAssign(arg1, res)) + return e, [] + +def tst(ir, instr, arg1, arg2): + e = [] + arg2 = extend_arg(arg1, arg2) + res = arg1 & arg2 + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))] + e += update_flag_nf(res) + + return e, [] + + +@sbuild.parse +def lsl(arg1, arg2, arg3): + arg1 = arg2 << (arg3 & ExprInt(arg3.size - 1, arg3.size)) + + +@sbuild.parse +def lsr(arg1, arg2, arg3): + arg1 = arg2 >> (arg3 & ExprInt(arg3.size - 1, arg3.size)) + + +@sbuild.parse +def asr(arg1, arg2, arg3): + arg1 = ExprOp( + 'a>>', arg2, (arg3 & ExprInt(arg3.size - 1, arg3.size))) + + +@sbuild.parse +def mov(arg1, arg2): + arg1 = arg2 + + +def movk(ir, instr, arg1, arg2): + e = [] + if isinstance(arg2, ExprOp): + assert(arg2.op == 'slice_at' and + isinstance(arg2.args[0], ExprInt) and + isinstance(arg2.args[1], ExprInt)) + value, shift = int(arg2.args[0]), int(arg2.args[1]) + e.append( + ExprAssign(arg1[shift:shift + 16], ExprInt(value, 16))) + else: + e.append(ExprAssign(arg1[:16], ExprInt(int(arg2), 16))) + + return e, [] + + +@sbuild.parse +def movz(arg1, arg2): + arg1 = arg2 + + +@sbuild.parse +def movn(arg1, arg2): + arg1 = ~arg2 + + +@sbuild.parse +def bl(arg1): + PC = arg1 + ir.IRDst = arg1 + LR = ExprInt(instr.offset + instr.l, 64) + +@sbuild.parse +def csel(arg1, arg2, arg3, arg4): + cond_expr = cond2expr[arg4.name] + arg1 = arg2 if cond_expr else arg3 + +def ccmp(ir, instr, arg1, arg2, arg3, arg4): + e = [] + if(arg2.is_int()): + arg2=ExprInt(int(arg2),arg1.size) + default_nf = arg3[0:1] + default_zf = arg3[1:2] + default_cf = arg3[2:3] + default_of = arg3[3:4] + cond_expr = cond2expr[arg4.name] + res = arg1 - arg2 + new_nf = nf + new_zf = update_flag_zf(res)[0].src + new_cf = update_flag_sub_cf(arg1, arg2)[0].src + new_of = update_flag_sub_of(arg1, arg2)[0].src + + e.append(ExprAssign(nf, ExprCond(cond_expr, + new_nf, + default_nf))) + e.append(ExprAssign(zf, ExprCond(cond_expr, + new_zf, + default_zf))) + e.append(ExprAssign(cf, ExprCond(cond_expr, + new_cf, + default_cf))) + e.append(ExprAssign(of, ExprCond(cond_expr, + new_of, + default_of))) + return e, [] + + +def csinc(ir, instr, arg1, arg2, arg3, arg4): + e = [] + cond_expr = cond2expr[arg4.name] + e.append( + ExprAssign( + arg1, + ExprCond( + cond_expr, + arg2, + arg3 + ExprInt(1, arg3.size) + ) + ) + ) + return e, [] + + +def csinv(ir, instr, arg1, arg2, arg3, arg4): + e = [] + cond_expr = cond2expr[arg4.name] + e.append( + ExprAssign( + arg1, + ExprCond( + cond_expr, + arg2, + ~arg3) + ) + ) + return e, [] + + +def csneg(ir, instr, arg1, arg2, arg3, arg4): + e = [] + cond_expr = cond2expr[arg4.name] + e.append( + ExprAssign( + arg1, + ExprCond( + cond_expr, + arg2, + -arg3) + ) + ) + return e, [] + + +def cset(ir, instr, arg1, arg2): + e = [] + cond_expr = cond2expr[arg2.name] + e.append( + ExprAssign( + arg1, + ExprCond( + cond_expr, + ExprInt(1, arg1.size), + ExprInt(0, arg1.size) + ) + ) + ) + return e, [] + + +def csetm(ir, instr, arg1, arg2): + e = [] + cond_expr = cond2expr[arg2.name] + e.append( + ExprAssign( + arg1, + ExprCond( + cond_expr, + ExprInt(-1, arg1.size), + ExprInt(0, arg1.size) + ) + ) + ) + return e, [] + + +def get_mem_access(mem): + updt = None + if isinstance(mem, ExprOp): + if mem.op == 'preinc': + if len(mem.args) == 1: + addr = mem.args[0] + else: + addr = mem.args[0] + mem.args[1] + elif mem.op == 'segm': + base = mem.args[0] + op, (reg, shift) = mem.args[1].op, mem.args[1].args + if op == 'SXTW': + off = reg.signExtend(base.size) << shift.zeroExtend(base.size) + addr = base + off + elif op == 'UXTW': + off = reg.zeroExtend(base.size) << shift.zeroExtend(base.size) + addr = base + off + elif op == 'LSL': + if isinstance(shift, ExprInt) and int(shift) == 0: + addr = base + reg.zeroExtend(base.size) + else: + addr = base + \ + (reg.zeroExtend(base.size) + << shift.zeroExtend(base.size)) + else: + raise NotImplementedError('bad op') + elif mem.op == "postinc": + addr, off = mem.args + updt = ExprAssign(addr, addr + off) + elif mem.op == "preinc_wb": + base, off = mem.args + addr = base + off + updt = ExprAssign(base, base + off) + else: + raise NotImplementedError('bad op') + else: + raise NotImplementedError('bad op') + return addr, updt + + + +def ldr(ir, instr, arg1, arg2): + e = [] + addr, updt = get_mem_access(arg2) + e.append(ExprAssign(arg1, ExprMem(addr, arg1.size))) + if updt: + e.append(updt) + return e, [] + + +def ldr_size(ir, instr, arg1, arg2, size): + e = [] + addr, updt = get_mem_access(arg2) + e.append( + ExprAssign(arg1, ExprMem(addr, size).zeroExtend(arg1.size))) + if updt: + e.append(updt) + return e, [] + + +def ldrb(ir, instr, arg1, arg2): + return ldr_size(ir, instr, arg1, arg2, 8) + + +def ldrh(ir, instr, arg1, arg2): + return ldr_size(ir, instr, arg1, arg2, 16) + + +def ldrs_size(ir, instr, arg1, arg2, size): + e = [] + addr, updt = get_mem_access(arg2) + e.append( + ExprAssign(arg1, ExprMem(addr, size).signExtend(arg1.size))) + if updt: + e.append(updt) + return e, [] + + +def ldrsb(ir, instr, arg1, arg2): + return ldrs_size(ir, instr, arg1, arg2, 8) + + +def ldrsh(ir, instr, arg1, arg2): + return ldrs_size(ir, instr, arg1, arg2, 16) + + +def ldrsw(ir, instr, arg1, arg2): + return ldrs_size(ir, instr, arg1, arg2, 32) + +def ldaxrb(ir, instr, arg1, arg2): + # TODO XXX no memory lock implemented + assert arg2.is_op('preinc') + assert len(arg2.args) == 1 + ptr = arg2.args[0] + e = [] + e.append(ExprAssign(arg1, ExprMem(ptr, 8).zeroExtend(arg1.size))) + return e, [] + +def ldxr(ir, instr, arg1, arg2): + # TODO XXX no memory lock implemented + assert arg2.is_op('preinc') + assert len(arg2.args) == 1 + ptr = arg2.args[0] + e = [] + e.append(ExprAssign(arg1, ExprMem(ptr, arg1.size).zeroExtend(arg1.size))) + return e, [] + +def stlxr(ir, instr, arg1, arg2, arg3): + assert arg3.is_op('preinc') + assert len(arg3.args) == 1 + ptr = arg3.args[0] + e = [] + e.append(ExprAssign(ExprMem(ptr, arg2.size), arg2)) + # TODO XXX here, force update success + e.append(ExprAssign(arg1, ExprInt(0, arg1.size))) + return e, [] + +def stlxrb(ir, instr, arg1, arg2, arg3): + assert arg3.is_op('preinc') + assert len(arg3.args) == 1 + ptr = arg3.args[0] + e = [] + e.append(ExprAssign(ExprMem(ptr, 8), arg2[:8])) + # TODO XXX here, force update success + e.append(ExprAssign(arg1, ExprInt(0, arg1.size))) + return e, [] + +def stlrb(ir, instr, arg1, arg2): + ptr = arg2.args[0] + e = [] + e.append(ExprAssign(ExprMem(ptr, 8), arg1[:8])) + return e, [] + +def l_str(ir, instr, arg1, arg2): + e = [] + addr, updt = get_mem_access(arg2) + e.append(ExprAssign(ExprMem(addr, arg1.size), arg1)) + if updt: + e.append(updt) + return e, [] + + +def strb(ir, instr, arg1, arg2): + e = [] + addr, updt = get_mem_access(arg2) + e.append(ExprAssign(ExprMem(addr, 8), arg1[:8])) + if updt: + e.append(updt) + return e, [] + + +def strh(ir, instr, arg1, arg2): + e = [] + addr, updt = get_mem_access(arg2) + e.append(ExprAssign(ExprMem(addr, 16), arg1[:16])) + if updt: + e.append(updt) + return e, [] + + +def stp(ir, instr, arg1, arg2, arg3): + e = [] + addr, updt = get_mem_access(arg3) + e.append(ExprAssign(ExprMem(addr, arg1.size), arg1)) + e.append( + ExprAssign(ExprMem(addr + ExprInt(arg1.size // 8, addr.size), arg2.size), arg2)) + if updt: + e.append(updt) + return e, [] + + +def ldp(ir, instr, arg1, arg2, arg3): + e = [] + addr, updt = get_mem_access(arg3) + e.append(ExprAssign(arg1, ExprMem(addr, arg1.size))) + e.append( + ExprAssign(arg2, ExprMem(addr + ExprInt(arg1.size // 8, addr.size), arg2.size))) + if updt: + e.append(updt) + return e, [] + + +def sbfm(ir, instr, arg1, arg2, arg3, arg4): + e = [] + rim, sim = int(arg3), int(arg4) + 1 + if sim > rim: + res = arg2[rim:sim].signExtend(arg1.size) + else: + shift = ExprInt(arg2.size - rim, arg2.size) + res = (arg2[:sim].signExtend(arg1.size) << shift) + e.append(ExprAssign(arg1, res)) + return e, [] + + +def ubfm(ir, instr, arg1, arg2, arg3, arg4): + e = [] + rim, sim = int(arg3), int(arg4) + 1 + if sim != arg1.size - 1 and rim == sim: + # Simple case: lsl + value = int(rim) + assert value < arg1.size + e.append(ExprAssign(arg1, arg2 << (ExprInt(arg1.size - value, arg2.size)))) + return e, [] + if sim == arg1.size: + # Simple case: lsr + value = int(rim) + assert value < arg1.size + e.append(ExprAssign(arg1, arg2 >> (ExprInt(value, arg2.size)))) + return e, [] + + if sim > rim: + res = arg2[rim:sim].zeroExtend(arg1.size) + else: + shift = ExprInt(arg2.size - rim, arg2.size) + res = (arg2[:sim].zeroExtend(arg1.size) << shift) + e.append(ExprAssign(arg1, res)) + return e, [] + +def bfm(ir, instr, arg1, arg2, arg3, arg4): + e = [] + rim, sim = int(arg3), int(arg4) + 1 + if sim > rim: + res = arg2[rim:sim] + e.append(ExprAssign(arg1[:sim-rim], res)) + else: + shift_i = arg2.size - rim + shift = ExprInt(shift_i, arg2.size) + res = arg2[:sim] + e.append(ExprAssign(arg1[shift_i:shift_i+sim], res)) + return e, [] + + + +def mrs(ir, insr, arg1, arg2, arg3, arg4, arg5, arg6): + e = [] + if arg2.is_int(3) and arg3.is_int(3) and arg4.is_id("c4") and arg5.is_id("c2") and arg6.is_int(0): + out = [] + out.append(ExprInt(0x0, 28)) + out.append(of) + out.append(cf) + out.append(zf) + out.append(nf) + e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size))) + + elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(7): + out = [] + out.append(ExprInt(0x0, 38)) + out.append(tco) + e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size))) + + elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(0): + out = [] + out.append(ExprInt(0x0, 39)) + out.append(dit) + e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size))) + + elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(4): + out = [] + out.append(ExprInt(0x0, 40)) + out.append(uao) + e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size))) + + elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(3): + out = [] + out.append(ExprInt(0x0, 41)) + out.append(pan) + e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size))) + + elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(6): + out = [] + out.append(ExprInt(0x0, 51)) + out.append(ssbs) + e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size))) + + elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(1): + out = [] + out.append(ExprInt(0x0, 54)) + out.append(df) + out.append(af) + out.append(iff) + out.append(ff) + e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size))) + + elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(2): + out = [] + out.append(ExprInt(0x0, 60)) + out.append(cur_el) + e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size))) + + elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(0): + out = [] + out.append(ExprInt(0x0, 63)) + out.append(spsel) + e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size))) + + else: + sreg = (int(arg2), int(arg3), int(str(arg4)[1:]), int(str(arg5)[1:]), int(arg6)) + if sreg in system_regs: + e.append(ExprAssign(arg1, system_regs[sreg])) + else: + raise NotImplementedError("Unknown system register: %d %d %s %s %d" % (int(arg2), int(arg3), str(arg4), str(arg5), int(arg6))) + + return e, [] + +def msr(ir, instr, arg1, arg2, arg3, arg4, arg5, arg6): + + e = [] + if arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(0): + e.append(ExprAssign(nf, arg6[31:32])) + e.append(ExprAssign(zf, arg6[30:31])) + e.append(ExprAssign(cf, arg6[29:30])) + e.append(ExprAssign(of, arg6[28:29])) + + elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(7): + e.append(ExprAssign(tco, arg6[25:26])) + + elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(0): + e.append(ExprAssign(dit, arg6[24:25])) + + elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(4): + e.append(ExprAssign(uao, arg6[23:24])) + + elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(3): + e.append(ExprAssign(pan, arg6[22:23])) + + elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(6): + e.append(ExprAssign(ssbs, arg6[12:13])) + + elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(1): + e.append(ExprAssign(df, arg6[9:10])) + e.append(ExprAssign(af, arg6[8:9])) + e.append(ExprAssign(iff, arg6[7:8])) + e.append(ExprAssign(ff, arg6[6:7])) + + elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(2): + e.append(ExprAssign(cur_el, arg6[2:4])) + + elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(0): + e.append(ExprAssign(spsel, arg6[0:1])) + + else: + sreg = (int(arg1), int(arg2), int(str(arg3)[1:]), int(str(arg4)[1:]), int(arg5)) + if sreg in system_regs: + e.append(ExprAssign(system_regs[sreg], arg6)) + else: + raise NotImplementedError("Unknown system register: %d %d %s %s %d" % (int(arg1), int(arg2), str(arg3), str(arg4), int(arg5))) + + return e, [] + + + +def adc(ir, instr, arg1, arg2, arg3): + arg3 = extend_arg(arg2, arg3) + e = [] + r = arg2 + arg3 + cf.zeroExtend(arg3.size) + e.append(ExprAssign(arg1, r)) + return e, [] + + +def adcs(ir, instr, arg1, arg2, arg3): + arg3 = extend_arg(arg2, arg3) + e = [] + r = arg2 + arg3 + cf.zeroExtend(arg3.size) + e.append(ExprAssign(arg1, r)) + e += update_flag_arith_addwc_zn(arg2, arg3, cf) + e += update_flag_arith_addwc_co(arg2, arg3, cf) + return e, [] + + +def sbc(ir, instr, arg1, arg2, arg3): + arg3 = extend_arg(arg2, arg3) + e = [] + r = arg2 - (arg3 + (~cf).zeroExtend(arg3.size)) + e.append(ExprAssign(arg1, r)) + return e, [] + + +def sbcs(ir, instr, arg1, arg2, arg3): + arg3 = extend_arg(arg2, arg3) + e = [] + r = arg2 - (arg3 + (~cf).zeroExtend(arg3.size)) + e.append(ExprAssign(arg1, r)) + e += update_flag_arith_subwc_zn(arg2, arg3, ~cf) + e += update_flag_arith_subwc_co(arg2, arg3, ~cf) + return e, [] + + +@sbuild.parse +def madd(arg1, arg2, arg3, arg4): + arg1 = arg2 * arg3 + arg4 + + +@sbuild.parse +def msub(arg1, arg2, arg3, arg4): + arg1 = arg4 - (arg2 * arg3) + + +@sbuild.parse +def udiv(arg1, arg2, arg3): + if arg3: + arg1 = ExprOp('udiv', arg2, arg3) + else: + exception_flags = ExprInt(EXCEPT_DIV_BY_ZERO, + exception_flags.size) + +@sbuild.parse +def sdiv(arg1, arg2, arg3): + if arg3: + arg1 = ExprOp('sdiv', arg2, arg3) + else: + exception_flags = ExprInt(EXCEPT_DIV_BY_ZERO, + exception_flags.size) + + + +@sbuild.parse +def smaddl(arg1, arg2, arg3, arg4): + arg1 = arg2.signExtend(arg1.size) * arg3.signExtend(arg1.size) + arg4 + + +@sbuild.parse +def cbz(arg1, arg2): + dst = ExprLoc(ir.get_next_loc_key(instr), 64) if arg1 else arg2 + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def cbnz(arg1, arg2): + dst = arg2 if arg1 else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def tbz(arg1, arg2, arg3): + bitmask = ExprInt(1, arg1.size) << arg2 + dst = ExprLoc( + ir.get_next_loc_key(instr), + 64 + ) if arg1 & bitmask else arg3 + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def tbnz(arg1, arg2, arg3): + bitmask = ExprInt(1, arg1.size) << arg2 + dst = arg3 if arg1 & bitmask else ExprLoc( + ir.get_next_loc_key(instr), + 64 + ) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_ne(arg1): + cond = cond2expr['NE'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_eq(arg1): + cond = cond2expr['EQ'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_ge(arg1): + cond = cond2expr['GE'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_mi(arg1): + cond = cond2expr['MI'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_pl(arg1): + cond = cond2expr['PL'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_gt(arg1): + cond = cond2expr['GT'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_cc(arg1): + cond = cond2expr['CC'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_cs(arg1): + cond = cond2expr['CS'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_hi(arg1): + cond = cond2expr['HI'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_le(arg1): + cond = cond2expr['LE'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_ls(arg1): + cond = cond2expr['LS'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def b_lt(arg1): + cond = cond2expr['LT'] + dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def ret(arg1): + PC = arg1 + ir.IRDst = arg1 + + +@sbuild.parse +def adrp(arg1, arg2): + arg1 = (PC & ExprInt(0xfffffffffffff000, 64)) + arg2 + + +@sbuild.parse +def adr(arg1, arg2): + arg1 = PC + arg2 + + +@sbuild.parse +def b(arg1): + PC = arg1 + ir.IRDst = arg1 + + +@sbuild.parse +def br(arg1): + PC = arg1 + ir.IRDst = arg1 + +@sbuild.parse +def blr(arg1): + PC = arg1 + ir.IRDst = arg1 + LR = ExprLoc(ir.get_next_loc_key(instr), 64) + +@sbuild.parse +def nop(): + """Do nothing""" + + +@sbuild.parse +def dsb(arg1): + """Data Synchronization Barrier""" + +@sbuild.parse +def isb(arg1): + """Instruction Synchronization Barrier""" + +@sbuild.parse +def dmb(arg1): + """Data Memory Barrier""" + +@sbuild.parse +def tlbi(arg1, arg2, arg3, arg4): + """TLB invalidate operation""" + +@sbuild.parse +def clrex(arg1): + """Clear the local monitor of the executing PE""" + +@sbuild.parse +def ic(arg1, arg2, arg3, arg4): + """Instruction/Data cache operation""" + + +def rev(ir, instr, arg1, arg2): + out = [] + for i in range(0, arg2.size, 8): + out.append(arg2[i:i+8]) + out.reverse() + e = [] + result = ExprCompose(*out) + e.append(ExprAssign(arg1, result)) + return e, [] + + +def rev16(ir, instr, arg1, arg2): + out = [] + for i in range(0, arg2.size // 8): + index = (i & ~1) + (1 - (i & 1)) + out.append(arg2[index * 8:(index + 1) * 8]) + e = [] + result = ExprCompose(*out) + e.append(ExprAssign(arg1, result)) + return e, [] + + +@sbuild.parse +def extr(arg1, arg2, arg3, arg4): + compose = ExprCompose(arg2, arg3) + arg1 = compose[int(arg4):int(arg4)+arg1.size] + + +@sbuild.parse +def svc(arg1): + exception_flags = ExprInt(EXCEPT_INT_XX, exception_flags.size) + interrupt_num = ExprInt(int(arg1), interrupt_num.size) + + +def fmov(ir, instr, arg1, arg2): + if arg2.is_int(): + # Transform int to signed floating-point constant with 3-bit exponent + # and normalized 4 bits of precision + # VFPExpandImm() of ARM Architecture Reference Manual + imm8 = int(arg2) + N = arg1.size + assert N in [32, 64] + E = 8 if N == 32 else 11 + F = N - E - 1; + # sign = imm8<7>; + sign = (imm8 >> 7) & 1; + # exp = NOT(imm8<6>):Replicate(imm8<6>,E-3):imm8<5:4>; + exp = (((imm8 >> 6) & 1) ^ 1) << (E - 3 + 2) + if (imm8 >> 6) & 1: + tmp = (1 << (E - 3)) - 1 + else: + tmp = 0 + exp |= tmp << 2 + exp |= (imm8 >> 4) & 3 + # frac = imm8<3:0>:Zeros(F-4); + frac = (imm8 & 0xf) << (F - 4) + value = frac + value |= exp << (4 + F - 4) + value |= sign << (4 + F - 4 + 1 + E - 3 + 2) + arg2 = ExprInt(value, N) + e = [ExprAssign(arg1, arg2)] + return e, [] + + +def fadd(ir, instr, arg1, arg2, arg3): + e = [] + e.append(ExprAssign(arg1, ExprOp('fadd', arg2, arg3))) + return e, [] + + +def fsub(ir, instr, arg1, arg2, arg3): + e = [] + e.append(ExprAssign(arg1, ExprOp('fsub', arg2, arg3))) + return e, [] + + +def fmul(ir, instr, arg1, arg2, arg3): + e = [] + e.append(ExprAssign(arg1, ExprOp('fmul', arg2, arg3))) + return e, [] + + +def fdiv(ir, instr, arg1, arg2, arg3): + e = [] + e.append(ExprAssign(arg1, ExprOp('fdiv', arg2, arg3))) + return e, [] + + +def fabs(ir, instr, arg1, arg2): + e = [] + e.append(ExprAssign(arg1, ExprOp('fabs', arg2))) + return e, [] + + +def fmadd(ir, instr, arg1, arg2, arg3, arg4): + e = [] + e.append( + ExprAssign( + arg1, + ExprOp( + 'fadd', + arg4, + ExprOp('fmul', arg2, arg3) + ) + ) + ) + return e, [] + + +def fmsub(ir, instr, arg1, arg2, arg3, arg4): + e = [] + e.append( + ExprAssign( + arg1, + ExprOp( + 'fsub', + arg4, + ExprOp('fmul', arg2, arg3) + ) + ) + ) + return e, [] + + +def fcvt(ir, instr, arg1, arg2): + # XXX TODO: rounding + e = [] + src = ExprOp('fpconvert_fp%d' % arg1.size, arg2) + e.append(ExprAssign(arg1, src)) + return e, [] + + +def scvtf(ir, instr, arg1, arg2): + # XXX TODO: rounding + e = [] + src = ExprOp('sint_to_fp', arg2) + if arg1.size != src.size: + src = ExprOp('fpconvert_fp%d' % arg1.size, src) + e.append(ExprAssign(arg1, src)) + return e, [] + + +def ucvtf(ir, instr, arg1, arg2): + # XXX TODO: rounding + e = [] + src = ExprOp('uint_to_fp', arg2) + if arg1.size != src.size: + src = ExprOp('fpconvert_fp%d' % arg1.size, src) + e.append(ExprAssign(arg1, src)) + return e, [] + + +def fcvtzs(ir, instr, arg1, arg2): + # XXX TODO: rounding + e = [] + e.append( + ExprAssign( + arg1, + ExprOp('fp_to_sint%d' % arg1.size, + ExprOp('fpround_towardszero', arg2) + ) + ) + ) + return e, [] + + +def fcvtzu(ir, instr, arg1, arg2): + # XXX TODO: rounding + e = [] + e.append( + ExprAssign( + arg1, + ExprOp('fp_to_uint%d' % arg1.size, + ExprOp('fpround_towardszero', arg2) + ) + ) + ) + return e, [] + + +def fcmpe(ir, instr, arg1, arg2): + e = [] + e.append( + ExprAssign( + nf, + ExprOp('fcom_c0', arg1, arg2) + ) + ) + e.append( + ExprAssign( + cf, + ~ExprOp('fcom_c0', arg1, arg2) + ) + ) + e.append( + ExprAssign( + zf, + ExprOp('fcom_c3', arg1, arg2) + ) + ) + e.append(ExprAssign(of, ExprInt(0, 1))) + return e, [] + + +def clz(ir, instr, arg1, arg2): + e = [] + e.append(ExprAssign(arg1, ExprOp('cntleadzeros', arg2))) + return e, [] + +def casp(ir, instr, arg1, arg2, arg3): + # XXX TODO: memory barrier + e = [] + if arg1.size == 32: + regs = gpregs32_expr + else: + regs = gpregs64_expr + index1 = regs.index(arg1) + index2 = regs.index(arg2) + + # TODO endianness + comp_value = ExprCompose(regs[index1], regs[index1 + 1]) + new_value = ExprCompose(regs[index2], regs[index2 + 1]) + assert arg3.is_op('preinc') + ptr = arg3.args[0] + data = ExprMem(ptr, comp_value.size) + + loc_store = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) + loc_do = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) + loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + + e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("FLAG_EQ_CMP", data, comp_value), loc_do, loc_store))) + + e_store = [] + e_store.append(ExprAssign(data, new_value)) + e_store.append(ExprAssign(ir.IRDst, loc_do)) + blk_store = IRBlock(ir.loc_db, loc_store.loc_key, [AssignBlock(e_store, instr)]) + + e_do = [] + e_do.append(ExprAssign(regs[index1], data[:data.size // 2])) + e_do.append(ExprAssign(regs[index1 + 1], data[data.size // 2:])) + e_do.append(ExprAssign(ir.IRDst, loc_next)) + blk_do = IRBlock(ir.loc_db, loc_do.loc_key, [AssignBlock(e_do, instr)]) + + return e, [blk_store, blk_do] + + +@sbuild.parse +def umaddl(arg1, arg2, arg3, arg4): + arg1 = arg2.zeroExtend(arg1.size) * arg3.zeroExtend(arg1.size) + arg4 + + +@sbuild.parse +def umsubbl(arg1, arg2, arg3, arg4): + arg1 = arg2.zeroExtend(arg1.size) * arg3.zeroExtend(arg1.size) + arg4 + + +@sbuild.parse +def umull(arg1, arg2, arg3): + arg1 = (arg2.zeroExtend(64) * arg3.zeroExtend(64)) + + +@sbuild.parse +def umulh(arg1, arg2, arg3): + arg1 = (arg2.zeroExtend(128) * arg3.zeroExtend(128))[64:] + + +@sbuild.parse +def smulh(arg1, arg2, arg3): + arg1 = (arg2.signExtend(128) * arg3.signExtend(128))[64:] + + +@sbuild.parse +def smull(arg1, arg2, arg3): + arg1 = (arg2.signExtend(64) * arg3.signExtend(64))[64:] + + + +mnemo_func = sbuild.functions +mnemo_func.update({ + 'and': and_l, + 'adds': adds, + 'ands': ands, + 'tst': tst, + 'subs': subs, + 'cmp': cmp, + 'cmn': cmn, + 'movk': movk, + 'ccmp': ccmp, + 'csinc': csinc, + 'csinv': csinv, + 'csneg': csneg, + 'cset': cset, + 'csetm': csetm, + + 'b.ne': b_ne, + 'b.eq': b_eq, + 'b.ge': b_ge, + 'b.mi': b_mi, + 'b.pl': b_pl, + 'b.gt': b_gt, + 'b.cc': b_cc, + 'b.cs': b_cs, + 'b.hi': b_hi, + 'b.le': b_le, + 'b.ls': b_ls, + 'b.lt': b_lt, + + 'bics': bics, + + 'ret': ret, + 'stp': stp, + 'ldp': ldp, + + 'ldr': ldr, + 'ldrb': ldrb, + 'ldrh': ldrh, + + 'ldur': ldr, + 'ldurb': ldrb, + 'ldursb': ldrsb, + 'ldurh': ldrh, + 'ldursh': ldrsh, + 'ldursw': ldrsw, + + 'ldrsb': ldrsb, + 'ldrsh': ldrsh, + 'ldrsw': ldrsw, + + 'ldar': ldr, # TODO memory barrier + 'ldarb': ldrb, + + 'ldaxrb': ldaxrb, + 'stlxrb': stlxrb, + + 'stlr': l_str, # TODO memory barrier + 'stlrb': stlrb, + + 'stlxr': stlxr, + 'ldxr': ldxr, + + 'str': l_str, + 'strb': strb, + 'strh': strh, + + 'stur': l_str, + 'sturb': strb, + 'sturh': strh, + + + 'bfm': bfm, + 'sbfm': sbfm, + 'ubfm': ubfm, + + 'extr': extr, + 'rev': rev, + 'rev16': rev16, + + 'msr': msr, + 'mrs': mrs, + + 'adc': adc, + 'adcs': adcs, + 'sbc': sbc, + 'sbcs': sbcs, + + 'fmov': fmov, + 'fadd': fadd, + 'fsub': fsub, + 'fmul': fmul, + 'fdiv': fdiv, + 'fabs': fabs, + 'fmadd': fmadd, + 'fmsub': fmsub, + 'fcvt': fcvt, + 'scvtf': scvtf, + 'ucvtf': ucvtf, + 'fcvtzs': fcvtzs, + 'fcvtzu': fcvtzu, + 'fcmpe': fcmpe, + 'clz': clz, + + # XXX TODO: memory barrier + 'casp':casp, + 'caspl':casp, + 'caspa':casp, + 'caspal':casp, + + 'yield': nop, + 'isb': isb, + 'dsb': dsb, + 'dmb': dmb, + 'tlbi': tlbi, + 'clrex': clrex, + 'ic': ic +}) + + +def get_mnemo_expr(ir, instr, *args): + if not instr.name.lower() in mnemo_func: + raise NotImplementedError('unknown mnemo %s' % instr) + instr, extra_ir = mnemo_func[instr.name.lower()](ir, instr, *args) + return instr, extra_ir + + +class aarch64info(object): + mode = "aarch64" + # offset + + +class Lifter_Aarch64l(Lifter): + + def __init__(self, loc_db): + Lifter.__init__(self, mn_aarch64, "l", loc_db) + self.pc = PC + self.sp = SP + self.IRDst = ExprId('IRDst', 64) + self.addrsize = 64 + + def get_ir(self, instr): + args = instr.args + if len(args) and isinstance(args[-1], ExprOp): + if (args[-1].op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>'] and + isinstance(args[-1].args[-1], ExprId)): + args[-1] = ExprOp(args[-1].op, + args[-1].args[0], + args[-1].args[-1][:8].zeroExtend(32)) + instr_ir, extra_ir = get_mnemo_expr(self, instr, *args) + self.mod_pc(instr, instr_ir, extra_ir) + instr_ir, extra_ir = self.del_dst_zr(instr, instr_ir, extra_ir) + return instr_ir, extra_ir + + def expr_fix_regs_for_mode(self, e): + return e.replace_expr(replace_regs) + + def expraff_fix_regs_for_mode(self, e): + dst = self.expr_fix_regs_for_mode(e.dst) + src = self.expr_fix_regs_for_mode(e.src) + return ExprAssign(dst, src) + + def irbloc_fix_regs_for_mode(self, irblock, mode=64): + irs = [] + for assignblk in irblock: + new_assignblk = dict(assignblk) + for dst, src in viewitems(assignblk): + del(new_assignblk[dst]) + # Special case for 64 bits: + # If destination is a 32 bit reg, zero extend the 64 bit reg + if (isinstance(dst, ExprId) and + dst.size == 32 and + dst in replace_regs): + src = src.zeroExtend(64) + dst = replace_regs[dst].arg + + dst = self.expr_fix_regs_for_mode(dst) + src = self.expr_fix_regs_for_mode(src) + new_assignblk[dst] = src + irs.append(AssignBlock(new_assignblk, assignblk.instr)) + return IRBlock(self.loc_db, irblock.loc_key, irs) + + def mod_pc(self, instr, instr_ir, extra_ir): + "Replace PC by the instruction's offset" + cur_offset = ExprInt(instr.offset, 64) + pc_fixed = {self.pc: cur_offset} + for i, expr in enumerate(instr_ir): + dst, src = expr.dst, expr.src + if dst != self.pc: + dst = dst.replace_expr(pc_fixed) + src = src.replace_expr(pc_fixed) + instr_ir[i] = ExprAssign(dst, src) + + for idx, irblock in enumerate(extra_ir): + extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \ + if expr != self.pc else expr, + lambda expr: expr.replace_expr(pc_fixed)) + + + def del_dst_zr(self, instr, instr_ir, extra_ir): + "Writes to zero register are discarded" + regs_to_fix = [WZR, XZR] + instr_ir = [expr for expr in instr_ir if expr.dst not in regs_to_fix] + + new_irblocks = [] + for irblock in extra_ir: + irs = [] + for assignblk in irblock: + new_dsts = { + dst:src for dst, src in viewitems(assignblk) + if dst not in regs_to_fix + } + irs.append(AssignBlock(new_dsts, assignblk.instr)) + new_irblocks.append(IRBlock(self.loc_db, irblock.loc_key, irs)) + + return instr_ir, new_irblocks + + +class Lifter_Aarch64b(Lifter_Aarch64l): + + def __init__(self, loc_db): + Lifter.__init__(self, mn_aarch64, "b", loc_db) + self.pc = PC + self.sp = SP + self.IRDst = ExprId('IRDst', 64) + self.addrsize = 64 diff --git a/src/miasm/arch/arm/__init__.py b/src/miasm/arch/arm/__init__.py new file mode 100644 index 00000000..bbad893b --- /dev/null +++ b/src/miasm/arch/arm/__init__.py @@ -0,0 +1 @@ +__all__ = ["arch", "disasm", "regs", "sem"] diff --git a/src/miasm/arch/arm/arch.py b/src/miasm/arch/arm/arch.py new file mode 100644 index 00000000..10551515 --- /dev/null +++ b/src/miasm/arch/arm/arch.py @@ -0,0 +1,3457 @@ +#-*- coding:utf-8 -*- + +from builtins import range +from future.utils import viewitems + +import logging +from pyparsing import * +from miasm.expression.expression import * +from miasm.core.cpu import * +from collections import defaultdict +from miasm.core.bin_stream import bin_stream +import miasm.arch.arm.regs as regs_module +from miasm.arch.arm.regs import * +from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html +from miasm.core import utils +from miasm.core.utils import BRACKET_O, BRACKET_C + +# A1 encoding + +log = logging.getLogger("armdis") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.DEBUG) + +# arm regs ############## +reg_dum = ExprId('DumReg', 32) + +PC, _ = gen_reg('PC') + +# GP +regs_str = ['R%d' % r for r in range(0x10)] +regs_str[13] = 'SP' +regs_str[14] = 'LR' +regs_str[15] = 'PC' +regs_expr = [ExprId(x, 32) for x in regs_str] + +gpregs = reg_info(regs_str, regs_expr) + +gpregs_pc = reg_info(regs_str[-1:], regs_expr[-1:]) +gpregs_sp = reg_info(regs_str[13:14], regs_expr[13:14]) + +gpregs_nosppc = reg_info(regs_str[:13] + [str(reg_dum), regs_str[14]], + regs_expr[:13] + [reg_dum, regs_expr[14]]) + +gpregs_nopc = reg_info(regs_str[:14], + regs_expr[:14]) + +gpregs_nosp = reg_info(regs_str[:13] + [str(reg_dum), regs_str[14], regs_str[15]], + regs_expr[:13] + [reg_dum, regs_expr[14], regs_expr[15]]) + + +# psr +sr_flags = "cxsf" +cpsr_regs_str = [] +spsr_regs_str = [] +for i in range(0x10): + o = "" + for j in range(4): + if i & (1 << j): + o += sr_flags[j] + cpsr_regs_str.append("CPSR_%s" % o) + spsr_regs_str.append("SPSR_%s" % o) + +# psr_regs_str = ['CPSR', 'SPSR'] +# psr_regs_expr = [ExprId(x, 32) for x in psr_regs_str] + +# psr_regs = reg_info(psr_regs_str, psr_regs_expr) + +cpsr_regs_expr = [ExprId(x, 32) for x in cpsr_regs_str] +spsr_regs_expr = [ExprId(x, 32) for x in spsr_regs_str] + +cpsr_regs = reg_info(cpsr_regs_str, cpsr_regs_expr) +spsr_regs = reg_info(spsr_regs_str, spsr_regs_expr) + +# CP +cpregs_str = ['c%d' % r for r in range(0x10)] +cpregs_expr = [ExprId(x, 32) for x in cpregs_str] + +cp_regs = reg_info(cpregs_str, cpregs_expr) + +# P +pregs_str = ['p%d' % r for r in range(0x10)] +pregs_expr = [ExprId(x, 32) for x in pregs_str] + +p_regs = reg_info(pregs_str, pregs_expr) + +conditional_branch = ["BEQ", "BNE", "BCS", "BCC", "BMI", "BPL", "BVS", + "BVC", "BHI", "BLS", "BGE", "BLT", "BGT", "BLE"] + +unconditional_branch = ["B", "BX", "BL", "BLX"] + +barrier_expr = { + 0b1111: ExprId("SY", 32), + 0b1110: ExprId("ST", 32), + 0b1101: ExprId("LD", 32), + 0b1011: ExprId("ISH", 32), + 0b1010: ExprId("ISHST", 32), + 0b1001: ExprId("ISHLD", 32), + 0b0111: ExprId("NSH", 32), + 0b0110: ExprId("NSHST", 32), + 0b0011: ExprId("OSH", 32), + 0b0010: ExprId("OSHST", 32), + 0b0001: ExprId("OSHLD", 32), +} + +barrier_info = reg_info_dct(barrier_expr) + + + +# parser helper ########### + +def cb_tok_reg_duo(tokens): + tokens = tokens[0] + i1 = gpregs.expr.index(tokens[0].name) + i2 = gpregs.expr.index(tokens[1].name) + o = [] + for i in range(i1, i2 + 1): + o.append(AstId(gpregs.expr[i])) + return o + +LPARENTHESIS = Literal("(") +RPARENTHESIS = Literal(")") + +LACC = Suppress(Literal("{")) +RACC = Suppress(Literal("}")) +MINUS = Suppress(Literal("-")) +CIRCUNFLEX = Literal("^") + + +def check_bounds(left_bound, right_bound, value): + if left_bound <= value and value <= right_bound: + return AstInt(value) + else: + raise ValueError('shift operator immediate value out of bound') + + +def check_values(values, value): + if value in values: + return AstInt(value) + else: + raise ValueError('shift operator immediate value out of bound') + +int_1_31 = str_int.copy().setParseAction(lambda v: check_bounds(1, 31, v[0])) +int_1_32 = str_int.copy().setParseAction(lambda v: check_bounds(1, 32, v[0])) + +int_8_16_24 = str_int.copy().setParseAction(lambda v: check_values([8, 16, 24], v[0])) + + +def cb_reglistparse(tokens): + tokens = tokens[0] + if tokens[-1] == "^": + return AstOp('sbit', AstOp('reglist', *tokens[:-1])) + return AstOp('reglist', *tokens) + + +allshifts = ['<<', '>>', 'a>>', '>>>', 'rrx'] +allshifts_armt = ['<<', '>>', 'a>>', '>>>', 'rrx'] + +shift2expr_dct = {'LSL': '<<', 'LSR': '>>', 'ASR': 'a>>', + 'ROR': ">>>", 'RRX': "rrx"} + +expr2shift_dct = dict((value, key) for key, value in viewitems(shift2expr_dct)) + + +def op_shift2expr(tokens): + return shift2expr_dct[tokens[0]] + +reg_duo = Group(gpregs.parser + MINUS + + gpregs.parser).setParseAction(cb_tok_reg_duo) +reg_or_duo = reg_duo | gpregs.parser +gpreg_list = Group(LACC + delimitedList( + reg_or_duo, delim=',') + RACC + Optional(CIRCUNFLEX)) +gpreg_list.setParseAction(cb_reglistparse) + +LBRACK = Suppress("[") +RBRACK = Suppress("]") +COMMA = Suppress(",") +all_binaryop_1_31_shifts_t = literal_list( + ['LSL', 'ROR']).setParseAction(op_shift2expr) +all_binaryop_1_32_shifts_t = literal_list( + ['LSR', 'ASR']).setParseAction(op_shift2expr) +all_unaryop_shifts_t = literal_list(['RRX']).setParseAction(op_shift2expr) + +ror_shifts_t = literal_list(['ROR']).setParseAction(op_shift2expr) +shl_shifts_t = literal_list(['SHL']).setParseAction(op_shift2expr) + + +allshifts_t_armt = literal_list( + ['LSL', 'LSR', 'ASR', 'ROR', 'RRX']).setParseAction(op_shift2expr) + +gpreg_p = gpregs.parser + +psr_p = cpsr_regs.parser | spsr_regs.parser + + +def cb_shift(tokens): + if len(tokens) == 1: + ret = tokens[0] + elif len(tokens) == 2: + ret = AstOp(tokens[1], tokens[0]) + elif len(tokens) == 3: + ret = AstOp(tokens[1], tokens[0], tokens[2]) + else: + raise ValueError("Bad arg") + return ret + +shift_off = (gpregs.parser + Optional( + (all_unaryop_shifts_t) | + (all_binaryop_1_31_shifts_t + (gpregs.parser | int_1_31)) | + (all_binaryop_1_32_shifts_t + (gpregs.parser | int_1_32)) +)).setParseAction(cb_shift) +shift_off |= base_expr + + +rot2_expr = (gpregs.parser + Optional( + (ror_shifts_t + (int_8_16_24)) +)).setParseAction(cb_shift) + + +rot5_expr = shift_off + +OP_LSL = Suppress("LSL") + +def cb_deref_reg_reg(tokens): + if len(tokens) != 2: + raise ValueError("Bad mem format") + return AstMem(AstOp('+', tokens[0], tokens[1]), 8) + +def cb_deref_reg_reg_lsl_1(tokens): + if len(tokens) != 3: + raise ValueError("Bad mem format") + reg1, reg2, index = tokens + if not isinstance(index, AstInt) or index.value != 1: + raise ValueError("Bad index") + ret = AstMem(AstOp('+', reg1, AstOp('<<', reg2, index)), 16) + return ret + + +deref_reg_reg = (LBRACK + gpregs.parser + COMMA + gpregs.parser + RBRACK).setParseAction(cb_deref_reg_reg) +deref_reg_reg_lsl_1 = (LBRACK + gpregs.parser + COMMA + gpregs.parser + OP_LSL + base_expr + RBRACK).setParseAction(cb_deref_reg_reg_lsl_1) + + + +(gpregs.parser + Optional( + (ror_shifts_t + (int_8_16_24)) +)).setParseAction(cb_shift) + + + +reg_or_base = gpregs.parser | base_expr + +def deref2expr_nooff(tokens): + tokens = tokens[0] + # XXX default + return ExprOp("preinc", tokens[0], ExprInt(0, 32)) + + +def cb_deref_preinc(tokens): + tokens = tokens[0] + if len(tokens) == 1: + return AstOp("preinc", tokens[0], AstInt(0)) + elif len(tokens) == 2: + return AstOp("preinc", tokens[0], tokens[1]) + else: + raise NotImplementedError('len(tokens) > 2') + + +def cb_deref_pre_mem(tokens): + tokens = tokens[0] + if len(tokens) == 1: + return AstMem(AstOp("preinc", tokens[0], AstInt(0)), 32) + elif len(tokens) == 2: + return AstMem(AstOp("preinc", tokens[0], tokens[1]), 32) + else: + raise NotImplementedError('len(tokens) > 2') + + +def cb_deref_post(tokens): + tokens = tokens[0] + return AstOp("postinc", tokens[0], tokens[1]) + + +def cb_deref_wb(tokens): + tokens = tokens[0] + if tokens[-1] == '!': + return AstMem(AstOp('wback', *tokens[:-1]), 32) + return AstMem(tokens[0], 32) + +# shift_off.setParseAction(deref_off) +deref_nooff = Group( + LBRACK + gpregs.parser + RBRACK).setParseAction(deref2expr_nooff) +deref_pre = Group(LBRACK + gpregs.parser + Optional( + COMMA + shift_off) + RBRACK).setParseAction(cb_deref_preinc) +deref_post = Group(LBRACK + gpregs.parser + RBRACK + + COMMA + shift_off).setParseAction(cb_deref_post) +deref = Group((deref_post | deref_pre | deref_nooff) + + Optional('!')).setParseAction(cb_deref_wb) + + +def cb_gpreb_wb(tokens): + assert len(tokens) == 1 + tokens = tokens[0] + if tokens[-1] == '!': + return AstOp('wback', *tokens[:-1]) + return tokens[0] + +gpregs_wb = Group(gpregs.parser + Optional('!')).setParseAction(cb_gpreb_wb) + + +cond_list_full = ['EQ', 'NE', 'CS', 'CC', 'MI', 'PL', 'VS', 'VC', + 'HI', 'LS', 'GE', 'LT', 'GT', 'LE', 'NV'] + + +cond_list = ['EQ', 'NE', 'CS', 'CC', 'MI', 'PL', 'VS', 'VC', + 'HI', 'LS', 'GE', 'LT', 'GT', 'LE', ''] # , 'NV'] +cond_dct = dict([(x[1], x[0]) for x in enumerate(cond_list)]) +bm_cond = bs_mod_name(l=4, fname='cond', mn_mod=cond_list) + + + +cond_dct_barmt = dict([(x[0], x[1]) for x in enumerate(cond_list) if x[0] & 0b1110 != 0b1110]) +bm_cond_barmt = bs_mod_name(l=4, fname='cond', mn_mod=cond_dct_barmt) + + + +def permut_args(order, args): + l = [] + for i, x in enumerate(order): + l.append((x.__class__, i)) + l = dict(l) + out = [None for x in range(len(args))] + for a in args: + out[l[a.__class__]] = a + return out + + +class additional_info(object): + + def __init__(self): + self.except_on_instr = False + self.lnk = None + self.cond = None + + +class instruction_arm(instruction): + __slots__ = [] + + def __init__(self, *args, **kargs): + super(instruction_arm, self).__init__(*args, **kargs) + + @staticmethod + def arg2str(expr, index=None, loc_db=None): + wb = False + if expr.is_id() or expr.is_int(): + return str(expr) + elif expr.is_loc(): + if loc_db is not None: + return loc_db.pretty_str(expr.loc_key) + else: + return str(expr) + if isinstance(expr, ExprOp) and expr.op in expr2shift_dct: + if len(expr.args) == 1: + return '%s %s' % (expr.args[0], expr2shift_dct[expr.op]) + elif len(expr.args) == 2: + return '%s %s %s' % (expr.args[0], expr2shift_dct[expr.op], expr.args[1]) + else: + raise NotImplementedError('zarb arg2str') + + + sb = False + if isinstance(expr, ExprOp) and expr.op == "sbit": + sb = True + expr = expr.args[0] + if isinstance(expr, ExprOp) and expr.op == "reglist": + o = [gpregs.expr.index(x) for x in expr.args] + out = reglist2str(o) + if sb: + out += "^" + return out + + + if isinstance(expr, ExprOp) and expr.op == 'wback': + wb = True + expr = expr.args[0] + if isinstance(expr, ExprId): + out = str(expr) + if wb: + out += "!" + return out + + if not isinstance(expr, ExprMem): + return str(expr) + + expr = expr.ptr + if isinstance(expr, ExprOp) and expr.op == 'wback': + wb = True + expr = expr.args[0] + + + if isinstance(expr, ExprId): + r, s = expr, None + elif len(expr.args) == 1 and isinstance(expr.args[0], ExprId): + r, s = expr.args[0], None + elif isinstance(expr.args[0], ExprId): + r, s = expr.args[0], expr.args[1] + else: + r, s = expr.args[0].args + if isinstance(s, ExprOp) and s.op in expr2shift_dct: + s = ' '.join( + str(x) + for x in (s.args[0], expr2shift_dct[s.op], s.args[1]) + ) + + if isinstance(expr, ExprOp) and expr.op == 'postinc': + o = '[' + str(r) + ']' + if s and not (isinstance(s, ExprInt) and int(s) == 0): + o += ', %s' % s + else: + if s and not (isinstance(s, ExprInt) and int(s) == 0): + o = '[' + ("%s, %s" % (r, s)) + ']' + else: + o = '[' + str(r) + ']' + + if wb: + o += "!" + return o + + @staticmethod + def arg2html(expr, index=None, loc_db=None): + wb = False + if expr.is_id() or expr.is_int() or expr.is_loc(): + return color_expr_html(expr, loc_db) + if isinstance(expr, ExprOp) and expr.op in expr2shift_dct: + if len(expr.args) == 1: + return '%s %s' % (color_expr_html(expr.args[0], loc_db), expr2shift_dct[expr.op]) + elif len(expr.args) == 2: + return '%s %s %s' % (color_expr_html(expr.args[0], loc_db), expr2shift_dct[expr.op], expr.args[1]) + else: + raise NotImplementedError('zarb arg2str') + + + sb = False + if isinstance(expr, ExprOp) and expr.op == "sbit": + sb = True + expr = expr.args[0] + if isinstance(expr, ExprOp) and expr.op == "reglist": + o = [gpregs.expr.index(x) for x in expr.args] + out = reglist2html(o) + if sb: + out += "^" + return out + + + if isinstance(expr, ExprOp) and expr.op == 'wback': + wb = True + expr = expr.args[0] + if isinstance(expr, ExprId): + out = color_expr_html(expr, loc_db) + if wb: + out += "!" + return out + + if not isinstance(expr, ExprMem): + return color_expr_html(expr, loc_db) + + expr = expr.ptr + if isinstance(expr, ExprOp) and expr.op == 'wback': + wb = True + expr = expr.args[0] + + + if isinstance(expr, ExprId): + r, s = expr, None + elif len(expr.args) == 1 and isinstance(expr.args[0], ExprId): + r, s = expr.args[0], None + elif isinstance(expr.args[0], ExprId): + r, s = expr.args[0], expr.args[1] + else: + r, s = expr.args[0].args + if isinstance(s, ExprOp) and s.op in expr2shift_dct: + s_html = ' '.join( + str(x) + for x in ( + color_expr_html(s.args[0], loc_db), + utils.set_html_text_color(expr2shift_dct[s.op], utils.COLOR_OP), + color_expr_html(s.args[1], loc_db) + ) + ) + else: + s_html = color_expr_html(s, loc_db) + + if isinstance(expr, ExprOp) and expr.op == 'postinc': + o = BRACKET_O + color_expr_html(r, loc_db) + BRACKET_C + if s and not (isinstance(s, ExprInt) and int(s) == 0): + o += ', %s' % s_html + else: + if s and not (isinstance(s, ExprInt) and int(s) == 0): + o = BRACKET_O + color_expr_html(r, loc_db) + ", " + s_html + BRACKET_C + else: + o = BRACKET_O + color_expr_html(r, loc_db) + BRACKET_C + + if wb: + o += "!" + return o + + + def dstflow(self): + if self.is_subcall(): + return True + return self.name in conditional_branch + unconditional_branch + + def dstflow2label(self, loc_db): + expr = self.args[0] + if not isinstance(expr, ExprInt): + return + if self.name == 'BLX': + addr = (int(expr) + self.offset) & int(expr.mask) + else: + addr = (int(expr) + self.offset) & int(expr.mask) + loc_key = loc_db.get_or_create_offset_location(addr) + self.args[0] = ExprLoc(loc_key, expr.size) + + def breakflow(self): + if self.is_subcall(): + return True + if self.name in conditional_branch + unconditional_branch: + return True + if self.name.startswith("LDM") and PC in self.args[1].args: + return True + if self.args and PC in self.args[0].get_r(): + return True + return False + + def is_subcall(self): + if self.name == 'BLX': + return True + return self.additional_info.lnk + + def getdstflow(self, loc_db): + return [self.args[0]] + + def splitflow(self): + if self.additional_info.lnk: + return True + if self.name == 'BLX': + return True + if self.name == 'BX': + return False + return self.breakflow() and self.additional_info.cond != 14 + + def get_symbol_size(self, symbol, loc_db): + return 32 + + def fixDstOffset(self): + e = self.args[0] + if self.offset is None: + raise ValueError('symbol not resolved %s' % l) + if not isinstance(e, ExprInt): + log.debug('dyn dst %r', e) + return + off = (int(e) - self.offset) & int(e.mask) + if int(off % 4): + raise ValueError('strange offset! %r' % off) + self.args[0] = ExprInt(off, 32) + + def get_args_expr(self): + args = [a for a in self.args] + return args + + def get_asm_offset(self, expr): + # LDR XXX, [PC, offset] => PC is self.offset+8 + return ExprInt(self.offset+8, expr.size) + +class instruction_armt(instruction_arm): + __slots__ = [] + + def __init__(self, *args, **kargs): + super(instruction_armt, self).__init__(*args, **kargs) + + def dstflow(self): + if self.name in ["CBZ", "CBNZ"]: + return True + return self.name in conditional_branch + unconditional_branch + + def dstflow2label(self, loc_db): + if self.name in ["CBZ", "CBNZ"]: + expr = self.args[1] + else: + expr = self.args[0] + if not isinstance(expr, ExprInt): + return + if self.name == 'BLX': + addr = (int(expr) + (self.offset & 0xfffffffc)) & int(expr.mask) + elif self.name == 'BL': + addr = (int(expr) + self.offset) & int(expr.mask) + elif self.name.startswith('BP'): + addr = (int(expr) + self.offset) & int(expr.mask) + elif self.name.startswith('CB'): + addr = (int(expr) + self.offset + self.l + 2) & int(expr.mask) + else: + addr = (int(expr) + self.offset) & int(expr.mask) + + loc_key = loc_db.get_or_create_offset_location(addr) + dst = ExprLoc(loc_key, expr.size) + + if self.name in ["CBZ", "CBNZ"]: + self.args[1] = dst + else: + self.args[0] = dst + + def breakflow(self): + if self.name in conditional_branch + unconditional_branch +["CBZ", "CBNZ", 'TBB', 'TBH']: + return True + if self.name.startswith("LDM") and PC in self.args[1].args: + return True + if self.args and PC in self.args[0].get_r(): + return True + return False + + def getdstflow(self, loc_db): + if self.name in ['CBZ', 'CBNZ']: + return [self.args[1]] + return [self.args[0]] + + def splitflow(self): + if self.name in conditional_branch + ['BL', 'BLX', 'CBZ', 'CBNZ']: + return True + return False + + def is_subcall(self): + return self.name in ['BL', 'BLX'] + + def fixDstOffset(self): + e = self.args[0] + if self.offset is None: + raise ValueError('symbol not resolved %s' % l) + if not isinstance(e, ExprInt): + log.debug('dyn dst %r', e) + return + # The first +2 is to compensate instruction len, but strangely, 32 bits + # thumb2 instructions len is 2... For the second +2, didn't find it in + # the doc. + off = (int(e) - self.offset) & int(e.mask) + if int(off % 2): + raise ValueError('strange offset! %r' % off) + self.args[0] = ExprInt(off, 32) + + def get_asm_offset(self, expr): + # ADR XXX, PC, imm => PC is 4 aligned + imm + new_offset = ((self.offset + self.l) // 4) * 4 + return ExprInt(new_offset, expr.size) + + +class mn_arm(cls_mn): + delayslot = 0 + name = "arm" + regs = regs_module + bintree = {} + num = 0 + all_mn = [] + all_mn_mode = defaultdict(list) + all_mn_name = defaultdict(list) + all_mn_inst = defaultdict(list) + pc = {'l':PC, 'b':PC} + sp = {'l':SP, 'b':SP} + instruction = instruction_arm + max_instruction_len = 4 + alignment = 4 + + @classmethod + def getpc(cls, attrib = None): + return PC + + @classmethod + def getsp(cls, attrib = None): + return SP + + def additional_info(self): + info = additional_info() + info.lnk = False + if hasattr(self, "lnk"): + info.lnk = self.lnk.value != 0 + if hasattr(self, "cond"): + info.cond = self.cond.value + else: + info.cond = None + return info + + @classmethod + def getbits(cls, bs, attrib, start, n): + if not n: + return 0 + o = 0 + if n > bs.getlen() * 8: + raise ValueError('not enough bits %r %r' % (n, len(bs.bin) * 8)) + while n: + offset = start // 8 + n_offset = cls.endian_offset(attrib, offset) + c = cls.getbytes(bs, n_offset, 1) + if not c: + raise IOError + c = ord(c) + r = 8 - start % 8 + c &= (1 << r) - 1 + l = min(r, n) + c >>= (r - l) + o <<= l + o |= c + n -= l + start += l + return o + + @classmethod + def endian_offset(cls, attrib, offset): + if attrib == "l": + return (offset & ~3) + 3 - offset % 4 + elif attrib == "b": + return offset + else: + raise NotImplementedError('bad attrib') + + @classmethod + def check_mnemo(cls, fields): + l = sum([x.l for x in fields]) + assert l == 32, "len %r" % l + + @classmethod + def getmn(cls, name): + return name.upper() + + @classmethod + def mod_fields(cls, fields): + l = sum([x.l for x in fields]) + if l == 32: + return fields + return [bm_cond] + fields + + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + dct['mode'] = None + return [(subcls, name, bases, dct, fields)] + + def value(self, mode): + v = super(mn_arm, self).value(mode) + if mode == 'l': + return [x[::-1] for x in v] + elif mode == 'b': + return [x for x in v] + else: + raise NotImplementedError('bad attrib') + + + def get_symbol_size(self, symbol, loc_db, mode): + return 32 + + +class mn_armt(cls_mn): + name = "armt" + regs = regs_module + delayslot = 0 + bintree = {} + num = 0 + all_mn = [] + all_mn_mode = defaultdict(list) + all_mn_name = defaultdict(list) + all_mn_inst = defaultdict(list) + pc = PC + sp = SP + instruction = instruction_armt + max_instruction_len = 4 + alignment = 4 + + @classmethod + def getpc(cls, attrib = None): + return PC + + @classmethod + def getsp(cls, attrib = None): + return SP + + def additional_info(self): + info = additional_info() + info.lnk = False + if hasattr(self, "lnk"): + info.lnk = self.lnk.value != 0 + info.cond = 14 # COND_ALWAYS + return info + + + @classmethod + def getbits(cls, bs, attrib, start, n): + if not n: + return 0 + o = 0 + if n > bs.getlen() * 8: + raise ValueError('not enough bits %r %r' % (n, len(bs.bin) * 8)) + while n: + offset = start // 8 + n_offset = cls.endian_offset(attrib, offset) + c = cls.getbytes(bs, n_offset, 1) + if not c: + raise IOError + c = ord(c) + r = 8 - start % 8 + c &= (1 << r) - 1 + l = min(r, n) + c >>= (r - l) + o <<= l + o |= c + n -= l + start += l + return o + + @classmethod + def endian_offset(cls, attrib, offset): + if attrib == "l": + return (offset & ~1) + 1 - offset % 2 + elif attrib == "b": + return offset + else: + raise NotImplementedError('bad attrib') + + @classmethod + def check_mnemo(cls, fields): + l = sum([x.l for x in fields]) + assert l in [16, 32], "len %r" % l + + @classmethod + def getmn(cls, name): + return name.upper() + + @classmethod + def mod_fields(cls, fields): + return list(fields) + + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + dct['mode'] = None + return [(subcls, name, bases, dct, fields)] + + def value(self, mode): + v = super(mn_armt, self).value(mode) + if mode == 'l': + out = [] + for x in v: + if len(x) == 2: + out.append(x[::-1]) + elif len(x) == 4: + out.append(x[:2][::-1] + x[2:4][::-1]) + return out + elif mode == 'b': + return [x for x in v] + else: + raise NotImplementedError('bad attrib') + + def get_args_expr(self): + args = [a.expr for a in self.args] + return args + + def get_symbol_size(self, symbol, loc_db, mode): + return 32 + + +class arm_arg(m_arg): + def asm_ast_to_expr(self, arg, loc_db): + if isinstance(arg, AstId): + if isinstance(arg.name, ExprId): + return arg.name + if arg.name in gpregs.str: + return None + loc_key = loc_db.get_or_create_name_location(arg.name) + return ExprLoc(loc_key, 32) + if isinstance(arg, AstOp): + args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args] + if None in args: + return None + if arg.op == "-": + assert len(args) == 2 + return args[0] - args[1] + return ExprOp(arg.op, *args) + if isinstance(arg, AstInt): + return ExprInt(arg.value, 32) + if isinstance(arg, AstMem): + ptr = self.asm_ast_to_expr(arg.ptr, loc_db) + if ptr is None: + return None + return ExprMem(ptr, arg.size) + return None + + +class arm_reg(reg_noarg, arm_arg): + pass + + +class arm_gpreg_noarg(reg_noarg): + reg_info = gpregs + parser = reg_info.parser + + +class arm_gpreg(arm_reg): + reg_info = gpregs + parser = reg_info.parser + + +class arm_reg_wb(arm_reg): + reg_info = gpregs + parser = gpregs_wb + + def decode(self, v): + v = v & self.lmask + e = self.reg_info.expr[v] + if self.parent.wback.value: + e = ExprOp('wback', e) + self.expr = e + return True + + def encode(self): + e = self.expr + self.parent.wback.value = 0 + if isinstance(e, ExprOp) and e.op == 'wback': + self.parent.wback.value = 1 + e = e.args[0] + if isinstance(e, ExprId): + self.value = self.reg_info.expr.index(e) + else: + self.parent.wback.value = 1 + self.value = self.reg_info.expr.index(e.args[0]) + return True + + +class arm_psr(arm_arg): + parser = psr_p + + def decode(self, v): + v = v & self.lmask + if self.parent.psr.value == 0: + e = cpsr_regs.expr[v] + else: + e = spsr_regs.expr[v] + self.expr = e + return True + + def encode(self): + e = self.expr + if e in spsr_regs.expr: + self.parent.psr.value = 1 + v = spsr_regs.expr.index(e) + elif e in cpsr_regs.expr: + self.parent.psr.value = 0 + v = cpsr_regs.expr.index(e) + else: + return False + self.value = v + return True + + +class arm_cpreg(arm_reg): + reg_info = cp_regs + parser = reg_info.parser + + +class arm_preg(arm_reg): + reg_info = p_regs + parser = reg_info.parser + + +class arm_imm(imm_noarg, arm_arg): + parser = base_expr + + +class arm_offs(arm_imm): + parser = base_expr + + def int2expr(self, v): + if v & ~self.intmask != 0: + return None + return ExprInt(v, self.intsize) + + def decodeval(self, v): + v <<= 2 + # Add pipeline offset + v += 8 + return v + + def encodeval(self, v): + if v%4 != 0: + return False + # Remove pipeline offset + v -= 8 + return v >> 2 + + def decode(self, v): + v = v & self.lmask + if (1 << (self.l - 1)) & v: + v |= ~0 ^ self.lmask + v = self.decodeval(v) + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if (1 << (self.l - 1)) & v: + v = -((0xffffffff ^ v) + 1) + v = self.encodeval(v) + if v is False: + return False + self.value = (v & 0xffffffff) & self.lmask + return True + + +class arm_imm8_12(arm_arg): + parser = deref + + def decode(self, v): + v = v & self.lmask + if self.parent.updown.value: + e = ExprInt(v << 2, 32) + else: + e = ExprInt(-v << 2, 32) + if self.parent.ppi.value: + e = ExprOp('preinc', self.parent.rn.expr, e) + else: + e = ExprOp('postinc', self.parent.rn.expr, e) + if self.parent.wback.value == 1: + e = ExprOp('wback', e) + self.expr = ExprMem(e, 32) + return True + + def encode(self): + self.parent.updown.value = 1 + e = self.expr + if not isinstance(e, ExprMem): + return False + e = e.ptr + if isinstance(e, ExprOp) and e.op == 'wback': + self.parent.wback.value = 1 + e = e.args[0] + else: + self.parent.wback.value = 0 + if e.op == "postinc": + self.parent.ppi.value = 0 + elif e.op == "preinc": + self.parent.ppi.value = 1 + else: + # XXX default + self.parent.ppi.value = 1 + self.parent.rn.expr = e.args[0] + if len(e.args) == 1: + self.value = 0 + return True + e = e.args[1] + if not isinstance(e, ExprInt): + log.debug('should be int %r', e) + return False + v = int(e) + if v < 0 or v & (1 << 31): + self.parent.updown.value = 0 + v = -v & 0xFFFFFFFF + if v & 0x3: + log.debug('arg should be 4 aligned') + return False + v >>= 2 + self.value = v + return True + + +class arm_imm_4_12(arm_arg): + parser = reg_or_base + + def decode(self, v): + v = v & self.lmask + imm = (self.parent.imm4.value << 12) | v + self.expr = ExprInt(imm, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if v > 0xffff: + return False + self.parent.imm4.value = v >> 12 + self.value = v & 0xfff + return True + + +class arm_imm_12_4(arm_arg): + parser = base_expr + + def decode(self, v): + v = v & self.lmask + imm = (self.parent.imm.value << 4) | v + self.expr = ExprInt(imm, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if v > 0xffff: + return False + self.parent.imm.value = (v >> 4) & 0xfff + self.value = v & 0xf + return True + + +class arm_op2(arm_arg): + parser = shift_off + + def str_to_imm_rot_form(self, s, neg=False): + if neg: + s = -s & 0xffffffff + for i in range(0, 32, 2): + v = myrol32(s, i) + if 0 <= v < 0x100: + return ((i // 2) << 8) | v + return None + + def decode(self, v): + val = v & self.lmask + if self.parent.immop.value: + rot = val >> 8 + imm = val & 0xff + imm = myror32(imm, rot * 2) + self.expr = ExprInt(imm, 32) + return True + rm = val & 0xf + shift = val >> 4 + shift_kind = shift & 1 + shift_type = (shift >> 1) & 3 + shift >>= 3 + if shift_kind: + # shift kind is reg + if shift & 1: + return False + rs = shift >> 1 + if rs == 0xf: + return False + shift_op = regs_expr[rs] + else: + # shift kind is imm + amount = shift + shift_op = ExprInt(amount, 32) + a = regs_expr[rm] + if shift_op == ExprInt(0, 32): + #rrx + if shift_type == 3: + self.expr = ExprOp(allshifts[4], a) + #asr, lsr + elif shift_type == 1 or shift_type == 2: + self.expr = ExprOp(allshifts[shift_type], a, ExprInt(32, 32)) + else: + self.expr = a + else: + self.expr = ExprOp(allshifts[shift_type], a, shift_op) + return True + + def encode(self): + e = self.expr + # pure imm + if isinstance(e, ExprInt): + val = self.str_to_imm_rot_form(int(e)) + if val is None: + return False + self.parent.immop.value = 1 + self.value = val + return True + + self.parent.immop.value = 0 + # pure reg + if isinstance(e, ExprId): + rm = gpregs.expr.index(e) + shift_kind = 0 + shift_type = 0 + amount = 0 + self.value = ( + ((((amount << 2) | shift_type) << 1) | shift_kind) << 4) | rm + return True + # rot reg + if not isinstance(e, ExprOp): + log.debug('bad reg rot1 %r', e) + return False + rm = gpregs.expr.index(e.args[0]) + shift_type = allshifts.index(e.op) + if e.op == 'rrx': + shift_kind = 0 + amount = 0 + shift_type = 3 + elif isinstance(e.args[1], ExprInt): + shift_kind = 0 + amount = int(e.args[1]) + # LSR/ASR of 32 => 0 + if amount == 32 and e.op in ['>>', 'a>>']: + amount = 0 + else: + shift_kind = 1 + amount = gpregs.expr.index(e.args[1]) << 1 + self.value = ( + ((((amount << 2) | shift_type) << 1) | shift_kind) << 4) | rm + return True + +# op2imm + rn + + +class arm_op2imm(arm_imm8_12): + parser = deref + + def str_to_imm_rot_form(self, s, neg=False): + if neg: + s = -s & 0xffffffff + if 0 <= s < (1 << 12): + return s + return None + + def decode(self, v): + val = v & self.lmask + if self.parent.immop.value == 0: + imm = val + if self.parent.updown.value == 0: + imm = -imm + if self.parent.ppi.value: + e = ExprOp('preinc', self.parent.rn.expr, ExprInt(imm, 32)) + else: + e = ExprOp('postinc', self.parent.rn.expr, ExprInt(imm, 32)) + if self.parent.wback.value == 1: + e = ExprOp('wback', e) + self.expr = ExprMem(e, 32) + return True + rm = val & 0xf + shift = val >> 4 + shift_kind = shift & 1 + shift_type = (shift >> 1) & 3 + shift >>= 3 + # print self.parent.immop.value, hex(shift), hex(shift_kind), + # hex(shift_type) + if shift_kind: + # log.debug('error in disasm xx') + return False + else: + # shift kind is imm + amount = shift + shift_op = ExprInt(amount, 32) + a = regs_expr[rm] + if shift_op == ExprInt(0, 32): + pass + else: + a = ExprOp(allshifts[shift_type], a, shift_op) + if self.parent.ppi.value: + e = ExprOp('preinc', self.parent.rn.expr, a) + else: + e = ExprOp('postinc', self.parent.rn.expr, a) + if self.parent.wback.value == 1: + e = ExprOp('wback', e) + self.expr = ExprMem(e, 32) + return True + + def encode(self): + self.parent.immop.value = 1 + self.parent.updown.value = 1 + + e = self.expr + assert(isinstance(e, ExprMem)) + e = e.ptr + if e.op == 'wback': + self.parent.wback.value = 1 + e = e.args[0] + else: + self.parent.wback.value = 0 + if e.op == "postinc": + self.parent.ppi.value = 0 + elif e.op == "preinc": + self.parent.ppi.value = 1 + else: + # XXX default + self.parent.ppi.value = 1 + + # if len(v) <1: + # raise ValueError('cannot parse', s) + self.parent.rn.expr = e.args[0] + if len(e.args) == 1: + self.parent.immop.value = 0 + self.value = 0 + return True + # pure imm + if isinstance(e.args[1], ExprInt): + self.parent.immop.value = 0 + val = self.str_to_imm_rot_form(int(e.args[1])) + if val is None: + val = self.str_to_imm_rot_form(int(e.args[1]), True) + if val is None: + log.debug('cannot encode inm') + return False + self.parent.updown.value = 0 + self.value = val + return True + # pure reg + if isinstance(e.args[1], ExprId): + rm = gpregs.expr.index(e.args[1]) + shift_kind = 0 + shift_type = 0 + amount = 0 + self.value = ( + ((((amount << 2) | shift_type) << 1) | shift_kind) << 4) | rm + return True + # rot reg + if not isinstance(e.args[1], ExprOp): + log.debug('bad reg rot2 %r', e) + return False + e = e.args[1] + rm = gpregs.expr.index(e.args[0]) + shift_type = allshifts.index(e.op) + if isinstance(e.args[1], ExprInt): + shift_kind = 0 + amount = int(e.args[1]) + else: + shift_kind = 1 + amount = gpregs.expr.index(e.args[1]) << 1 + self.value = ( + ((((amount << 2) | shift_type) << 1) | shift_kind) << 4) | rm + return True + + +def reglist2str(rlist): + out = [] + i = 0 + while i < len(rlist): + j = i + 1 + while j < len(rlist) and rlist[j] < 13 and rlist[j] == rlist[j - 1] + 1: + j += 1 + j -= 1 + if j < i + 2: + out.append(regs_str[rlist[i]]) + i += 1 + else: + out.append(regs_str[rlist[i]] + '-' + regs_str[rlist[j]]) + i = j + 1 + return "{" + ", ".join(out) + '}' + +def reglist2html(rlist): + out = [] + i = 0 + while i < len(rlist): + j = i + 1 + while j < len(rlist) and rlist[j] < 13 and rlist[j] == rlist[j - 1] + 1: + j += 1 + j -= 1 + if j < i + 2: + out.append(color_expr_html(regs_expr[rlist[i]], None)) + i += 1 + else: + out.append(color_expr_html(regs_expr[rlist[i]], None) + '-' + color_expr_html(regs_expr[rlist[j]], None)) + i = j + 1 + out = utils.fix_html_chars("{") + ", ".join(out) + utils.fix_html_chars("}") + return out + + +class arm_rlist(arm_arg): + parser = gpreg_list + + def encode(self): + self.parent.sbit.value = 0 + e = self.expr + if isinstance(e, ExprOp) and e.op == "sbit": + e = e.args[0] + self.parent.sbit.value = 1 + rlist = [gpregs.expr.index(x) for x in e.args] + v = 0 + for r in rlist: + v |= 1 << r + self.value = v + return True + + def decode(self, v): + v = v & self.lmask + out = [] + for i in range(0x10): + if 1 << i & v: + out.append(gpregs.expr[i]) + if not out: + return False + e = ExprOp('reglist', *out) + if self.parent.sbit.value == 1: + e = ExprOp('sbit', e) + self.expr = e + return True + + +class updown_b_nosp_mn(bs_mod_name): + mn_mod = ['D', 'I'] + + def modname(self, name, f_i): + return name + self.args['mn_mod'][f_i] + + +class ppi_b_nosp_mn(bs_mod_name): + prio = 5 + mn_mod = ['A', 'B'] + + +class updown_b_sp_mn(bs_mod_name): + mn_mod = ['A', 'D'] + + def modname(self, name, f_i): + if name.startswith("STM"): + f_i = [1, 0][f_i] + return name + self.args['mn_mod'][f_i] + + +class ppi_b_sp_mn(bs_mod_name): + mn_mod = ['F', 'E'] + + def modname(self, name, f_i): + if name.startswith("STM"): + f_i = [1, 0][f_i] + return name + self.args['mn_mod'][f_i] + + +class arm_reg_wb_nosp(arm_reg_wb): + + def decode(self, v): + v = v & self.lmask + if v == 13: + return False + e = self.reg_info.expr[v] + if self.parent.wback.value: + e = ExprOp('wback', e) + self.expr = e + return True + + +class arm_offs_blx(arm_imm): + + def decode(self, v): + v = v & self.lmask + v = (v << 2) + (self.parent.lowb.value << 1) + v = sign_ext(v, 26, 32) + # Add pipeline offset + v += 8 + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + # Remove pipeline offset + v = (int(self.expr) - 8) & int(self.expr.mask) + if v & 0x80000000: + v &= (1 << 26) - 1 + self.parent.lowb.value = (v >> 1) & 1 + self.value = v >> 2 + return True + + +class bs_lnk(bs_mod_name): + + def modname(self, name, i): + return name[:1] + self.args['mn_mod'][i] + name[1:] + + +class armt_rm_cp(bsi): + + def decode(self, v): + if v != gpregs.expr.index(self.parent.rm.expr): + return False + return True + + def encode(self): + self.value = gpregs.expr.index(self.parent.rm.expr) + return True + + +accum = bs(l=1) +scc = bs_mod_name(l=1, fname='scc', mn_mod=['', 'S']) +dumscc = bs("1") +rd = bs(l=4, cls=(arm_gpreg,)) +rdl = bs(l=4, cls=(arm_gpreg,)) + +rn = bs(l=4, cls=(arm_gpreg,), fname="rn") +rs = bs(l=4, cls=(arm_gpreg,)) +rm = bs(l=4, cls=(arm_gpreg,), fname='rm') +ra = bs(l=4, cls=(arm_gpreg,)) +rt = bs(l=4, cls=(arm_gpreg,), fname='rt') +rt2 = bs(l=4, cls=(arm_gpreg,)) + +rm_cp = bs(l=4, cls=(armt_rm_cp,)) + +op2 = bs(l=12, cls=(arm_op2,)) +lnk = bs_lnk(l=1, fname='lnk', mn_mod=['', 'L']) +offs = bs(l=24, cls=(arm_offs,), fname="offs") + +rn_noarg = bs(l=4, cls=(arm_gpreg_noarg,), fname="rn") +rm_noarg = bs(l=4, cls=(arm_gpreg_noarg,), fname="rm", order = -1) + +immop = bs(l=1, fname='immop') +dumr = bs(l=4, default_val="0000", fname="dumr") +# psr = bs(l=1, cls=(arm_psr,), fname="psr") + +psr = bs(l=1, fname="psr") +psr_field = bs(l=4, cls=(arm_psr,)) + +ppi = bs(l=1, fname='ppi') +updown = bs(l=1, fname='updown') +trb = bs_mod_name(l=1, fname='trb', mn_mod=['', 'B']) +wback = bs_mod_name(l=1, fname="wback", mn_mod=['', 'T']) +wback_no_t = bs(l=1, fname="wback") + +op2imm = bs(l=12, cls=(arm_op2imm,)) + +updown_b_nosp = updown_b_nosp_mn(l=1, mn_mod=['D', 'I'], fname='updown') +ppi_b_nosp = ppi_b_nosp_mn(l=1, mn_mod=['A', 'B'], fname='ppi') +updown_b_sp = updown_b_sp_mn(l=1, mn_mod=['A', 'D'], fname='updown') +ppi_b_sp = ppi_b_sp_mn(l=1, mn_mod=['F', 'E'], fname='ppi') + +sbit = bs(l=1, fname="sbit") +rn_sp = bs("1101", cls=(arm_reg_wb,), fname='rnsp') +rn_wb = bs(l=4, cls=(arm_reg_wb_nosp,), fname='rn') +rlist = bs(l=16, cls=(arm_rlist,), fname='rlist') + +swi_i = bs(l=24, cls=(arm_imm,), fname="swi_i") + +opc = bs(l=4, cls=(arm_imm, m_arg), fname='opc') +crn = bs(l=4, cls=(arm_cpreg,), fname='crn') +crd = bs(l=4, cls=(arm_cpreg,), fname='crd') +crm = bs(l=4, cls=(arm_cpreg,), fname='crm') +cpnum = bs(l=4, cls=(arm_preg,), fname='cpnum') +cp = bs(l=3, cls=(arm_imm, m_arg), fname='cp') + +imm8_12 = bs(l=8, cls=(arm_imm8_12, m_arg), fname='imm') +tl = bs_mod_name(l=1, fname="tl", mn_mod=['', 'L']) + +cpopc = bs(l=3, cls=(arm_imm, m_arg), fname='cpopc') +imm20 = bs(l=20, cls=(arm_imm, m_arg)) +imm4 = bs(l=4, cls=(arm_imm, m_arg)) +imm12 = bs(l=12, cls=(arm_imm, m_arg)) +imm16 = bs(l=16, cls=(arm_imm, m_arg)) + +imm12_off = bs(l=12, fname="imm") + +imm2_noarg = bs(l=2, fname="imm") +imm4_noarg = bs(l=4, fname="imm4") + + +imm_4_12 = bs(l=12, cls=(arm_imm_4_12,)) + +imm12_noarg = bs(l=12, fname="imm") +imm_12_4 = bs(l=4, cls=(arm_imm_12_4,)) + +lowb = bs(l=1, fname='lowb') +offs_blx = bs(l=24, cls=(arm_offs_blx,), fname="offs") + +fix_cond = bs("1111", fname="cond") + +class mul_part_x(bs_mod_name): + prio = 5 + mn_mod = ['B', 'T'] + +class mul_part_y(bs_mod_name): + prio = 6 + mn_mod = ['B', 'T'] + +mul_x = mul_part_x(l=1, fname='x', mn_mod=['B', 'T']) +mul_y = mul_part_y(l=1, fname='y', mn_mod=['B', 'T']) + +class arm_immed(arm_arg): + parser = deref + + def decode(self, v): + if self.parent.immop.value == 1: + imm = ExprInt((self.parent.immedH.value << 4) | v, 32) + else: + imm = gpregs.expr[v] + if self.parent.updown.value == 0: + imm = -imm + if self.parent.ppi.value: + e = ExprOp('preinc', self.parent.rn.expr, imm) + else: + e = ExprOp('postinc', self.parent.rn.expr, imm) + if self.parent.wback.value == 1: + e = ExprOp('wback', e) + self.expr = ExprMem(e, 32) + + return True + + def encode(self): + self.parent.immop.value = 1 + self.parent.updown.value = 1 + e = self.expr + if not isinstance(e, ExprMem): + return False + e = e.ptr + if isinstance(e, ExprOp) and e.op == 'wback': + self.parent.wback.value = 1 + e = e.args[0] + else: + self.parent.wback.value = 0 + if e.op == "postinc": + self.parent.ppi.value = 0 + elif e.op == "preinc": + self.parent.ppi.value = 1 + else: + # XXX default + self.parent.ppi.value = 1 + self.parent.rn.expr = e.args[0] + if len(e.args) == 1: + self.value = 0 + self.parent.immedH.value = 0 + return True + e = e.args[1] + if isinstance(e, ExprInt): + v = int(e) + if v < 0 or v & (1 << 31): + self.parent.updown.value = 0 + v = (-v) & 0xFFFFFFFF + if v > 0xff: + log.debug('cannot encode imm XXX') + return False + self.value = v & 0xF + self.parent.immedH.value = v >> 4 + return True + + self.parent.immop.value = 0 + if isinstance(e, ExprOp) and len(e.args) == 1 and e.op == "-": + self.parent.updown.value = 0 + e = e.args[0] + if e in gpregs.expr: + self.value = gpregs.expr.index(e) + self.parent.immedH.value = 0x0 + return True + else: + raise ValueError('e should be int: %r' % e) + +immedH = bs(l=4, fname='immedH') +immedL = bs(l=4, cls=(arm_immed, m_arg), fname='immedL') +hb = bs(l=1) + + +class armt2_rot_rm(arm_arg): + parser = shift_off + def decode(self, v): + r = self.parent.rm.expr + if v == 00: + e = r + else: + raise NotImplementedError('rotation') + self.expr = e + return True + def encode(self): + e = self.expr + if isinstance(e, ExprId): + self.value = 0 + else: + raise NotImplementedError('rotation') + return True + +rot_rm = bs(l=2, cls=(armt2_rot_rm,), fname="rot_rm") + + +class arm_mem_rn_imm(arm_arg): + parser = deref + def decode(self, v): + value = self.parent.imm.value + if self.parent.rw.value == 0: + value = -value + imm = ExprInt(value, 32) + reg = gpregs.expr[v] + if value: + expr = ExprMem(reg + imm, 32) + else: + expr = ExprMem(reg, 32) + self.expr = expr + return True + + def encode(self): + self.parent.add_imm.value = 1 + self.parent.imm.value = 0 + expr = self.expr + if not isinstance(expr, ExprMem): + return False + ptr = expr.ptr + if ptr in gpregs.expr: + self.value = gpregs.expr.index(ptr) + elif (isinstance(ptr, ExprOp) and + len(ptr.args) == 2 and + ptr.op == 'preinc'): + reg, imm = ptr.args + if not reg in gpregs.expr: + return False + self.value = gpregs.expr.index(reg) + if not isinstance(imm, ExprInt): + return False + value = int(imm) + if value & 0x80000000: + value = -value + self.parent.add_imm.value = 0 + self.parent.imm.value = value + else: + return False + return True + +mem_rn_imm = bs(l=4, cls=(arm_mem_rn_imm,), order=1) + +def armop(name, fields, args=None, alias=False): + dct = {"fields": fields} + dct["alias"] = alias + if args is not None: + dct['args'] = args + type(name, (mn_arm,), dct) + + +def armtop(name, fields, args=None, alias=False): + dct = {"fields": fields} + dct["alias"] = alias + if args is not None: + dct['args'] = args + type(name, (mn_armt,), dct) + + +op_list = ['AND', 'EOR', 'SUB', 'RSB', 'ADD', 'ADC', 'SBC', 'RSC', + 'TST', 'TEQ', 'CMP', 'CMN', 'ORR', 'MOV', 'BIC', 'MVN'] +data_mov_name = {'MOV': 13, 'MVN': 15} +data_test_name = {'TST': 8, 'TEQ': 9, 'CMP': 10, 'CMN': 11} + +data_name = {} +for i, n in enumerate(op_list): + if n in list(data_mov_name) + list(data_test_name): + continue + data_name[n] = i +bs_data_name = bs_name(l=4, name=data_name) + +bs_data_mov_name = bs_name(l=4, name=data_mov_name) + +bs_data_test_name = bs_name(l=4, name=data_test_name) + + +transfer_name = {'STR': 0, 'LDR': 1} +bs_transfer_name = bs_name(l=1, name=transfer_name) + +transferh_name = {'STRH': 0, 'LDRH': 1} +bs_transferh_name = bs_name(l=1, name=transferh_name) + + +transfer_ldr_name = {'LDRD': 0, 'LDRSB': 1} +bs_transfer_ldr_name = bs_name(l=1, name=transfer_ldr_name) + +btransfer_name = {'STM': 0, 'LDM': 1} +bs_btransfer_name = bs_name(l=1, name=btransfer_name) + +ctransfer_name = {'STC': 0, 'LDC': 1} +bs_ctransfer_name = bs_name(l=1, name=ctransfer_name) + +mr_name = {'MCR': 0, 'MRC': 1} +bs_mr_name = bs_name(l=1, name=mr_name) + + +bs_addi = bs(l=1, fname="add_imm") +bs_rw = bs_mod_name(l=1, fname='rw', mn_mod=['W', '']) + +class armt_barrier_option(reg_noarg, arm_arg): + reg_info = barrier_info + parser = reg_info.parser + + def decode(self, v): + v = v & self.lmask + if v not in self.reg_info.dct_expr: + return False + self.expr = self.reg_info.dct_expr[v] + return True + + def encode(self): + if not self.expr in self.reg_info.dct_expr_inv: + log.debug("cannot encode reg %r", self.expr) + return False + self.value = self.reg_info.dct_expr_inv[self.expr] + return True + + def check_fbits(self, v): + return v & self.fmask == self.fbits + +barrier_option = bs(l=4, cls=(armt_barrier_option,)) + +armop("mul", [bs('000000'), bs('0'), scc, rd, bs('0000'), rs, bs('1001'), rm], [rd, rm, rs]) +armop("umull", [bs('000010'), bs('0'), scc, rd, rdl, rs, bs('1001'), rm], [rdl, rd, rm, rs]) +armop("umlal", [bs('000010'), bs('1'), scc, rd, rdl, rs, bs('1001'), rm], [rdl, rd, rm, rs]) +armop("smull", [bs('000011'), bs('0'), scc, rd, rdl, rs, bs('1001'), rm], [rdl, rd, rm, rs]) +armop("smlal", [bs('000011'), bs('1'), scc, rd, rdl, rs, bs('1001'), rm], [rdl, rd, rm, rs]) +armop("mla", [bs('000000'), bs('1'), scc, rd, rn, rs, bs('1001'), rm], [rd, rm, rs, rn]) +armop("mrs", [bs('00010'), psr, bs('00'), psr_field, rd, bs('000000000000')], [rd, psr]) +armop("msr", [bs('00010'), psr, bs('10'), psr_field, bs('1111'), bs('0000'), bs('0000'), rm], [psr_field, rm]) +armop("data", [bs('00'), immop, bs_data_name, scc, rn, rd, op2], [rd, rn, op2]) +armop("data_mov", [bs('00'), immop, bs_data_mov_name, scc, bs('0000'), rd, op2], [rd, op2]) +armop("data_test", [bs('00'), immop, bs_data_test_name, dumscc, rn, dumr, op2]) +armop("b", [bs('101'), lnk, offs]) + +armop("smul", [bs('00010110'), rd, bs('0000'), rs, bs('1'), mul_y, mul_x, bs('0'), rm], [rd, rm, rs]) + +# TODO TEST +#armop("und", [bs('011'), imm20, bs('1'), imm4]) +armop("transfer", [bs('01'), immop, ppi, updown, trb, wback_no_t, bs_transfer_name, rn_noarg, rd, op2imm], [rd, op2imm]) +armop("transferh", [bs('000'), ppi, updown, immop, wback_no_t, bs_transferh_name, rn_noarg, rd, immedH, bs('1011'), immedL], [rd, immedL]) +armop("ldrd", [bs('000'), ppi, updown, immop, wback_no_t, bs_transfer_ldr_name, rn_noarg, rd, immedH, bs('1101'), immedL], [rd, immedL]) +armop("ldrsh", [bs('000'), ppi, updown, immop, wback_no_t, bs('1'), rn_noarg, rd, immedH, bs('1'), bs('1'), bs('1'), bs('1'), immedL], [rd, immedL]) +armop("strd", [bs('000'), ppi, updown, immop, wback_no_t, bs('0'), rn_noarg, rd, immedH, bs('1'), bs('1'), bs('1'), bs('1'), immedL], [rd, immedL]) +armop("btransfersp", [bs('100'), ppi_b_sp, updown_b_sp, sbit, wback_no_t, bs_btransfer_name, rn_sp, rlist]) +armop("btransfer", [bs('100'), ppi_b_nosp, updown_b_nosp, sbit, wback_no_t, bs_btransfer_name, rn_wb, rlist]) +# TODO: TEST +armop("swp", [bs('00010'), trb, bs('00'), rn, rd, bs('0000'), bs('1001'), rm]) +armop("svc", [bs('1111'), swi_i]) +armop("cdp", [bs('1110'), opc, crn, crd, cpnum, cp, bs('0'), crm], [cpnum, opc, crd, crn, crm, cp]) +armop("cdata", [bs('110'), ppi, updown, tl, wback_no_t, bs_ctransfer_name, rn_noarg, crd, cpnum, imm8_12], [cpnum, crd, imm8_12]) +armop("mr", [bs('1110'), cpopc, bs_mr_name, crn, rd, cpnum, cp, bs('1'), crm], [cpnum, cpopc, rd, crn, crm, cp]) +armop("bkpt", [bs('00010010'), imm12_noarg, bs('0111'), imm_12_4]) +armop("bx", [bs('000100101111111111110001'), rn]) +armop("mov", [bs('00110000'), imm4_noarg, rd, imm_4_12], [rd, imm_4_12]) +armop("movt", [bs('00110100'), imm4_noarg, rd, imm_4_12], [rd, imm_4_12]) +armop("blx", [bs('00010010'), bs('1111'), bs('1111'), bs('1111'), bs('0011'), rm], [rm]) +armop("blx", [fix_cond, bs('101'), lowb, offs_blx], [offs_blx]) +armop("clz", [bs('00010110'), bs('1111'), rd, bs('1111'), bs('0001'), rm], [rd, rm]) +armop("qadd", [bs('00010000'), rn, rd, bs('0000'), bs('0101'), rm], [rd, rm, rn]) + +armop("uxtb", [bs('01101110'), bs('1111'), rd, rot_rm, bs('00'), bs('0111'), rm_noarg]) +armop("uxth", [bs('01101111'), bs('1111'), rd, rot_rm, bs('00'), bs('0111'), rm_noarg]) +armop("sxtb", [bs('01101010'), bs('1111'), rd, rot_rm, bs('00'), bs('0111'), rm_noarg]) +armop("sxth", [bs('01101011'), bs('1111'), rd, rot_rm, bs('00'), bs('0111'), rm_noarg]) + +armop("rev", [bs('01101011'), bs('1111'), rd, bs('1111'), bs('0011'), rm]) +armop("rev16", [bs('01101011'), bs('1111'), rd, bs('1111'), bs('1011'), rm]) + +armop("pld", [bs8(0xF5), bs_addi, bs_rw, bs('01'), mem_rn_imm, bs('1111'), imm12_off]) + +armop("dsb", [bs('111101010111'), bs('1111'), bs('1111'), bs('0000'), bs('0100'), barrier_option]) +armop("isb", [bs('111101010111'), bs('1111'), bs('1111'), bs('0000'), bs('0110'), barrier_option]) +armop("nop", [bs8(0xE3), bs8(0x20), bs8(0xF0), bs8(0)]) + +class arm_widthm1(arm_imm, m_arg): + def decode(self, v): + self.expr = ExprInt(v+1, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + -1 + self.value = v + return True + + +class arm_rm_rot2(arm_arg): + parser = rot2_expr + def decode(self, v): + expr = gpregs.expr[v] + shift_value = self.parent.rot2.value + if shift_value: + expr = ExprOp(allshifts[3], expr, ExprInt(shift_value * 8, 32)) + self.expr = expr + return True + def encode(self): + if self.expr in gpregs.expr: + self.value = gpregs.expr.index(self.expr) + self.parent.rot2.value = 0 + elif (isinstance(self.expr, ExprOp) and + self.expr.op == allshifts[3]): + reg, value = self.expr.args + if reg not in gpregs.expr: + return False + self.value = gpregs.expr.index(reg) + if not isinstance(value, ExprInt): + return False + value = int(value) + if not value in [8, 16, 24]: + return False + self.parent.rot2.value = value // 8 + return True + + + +class arm_rm_rot5_lsl(arm_arg): + parser = rot5_expr + index_op = 0 + def decode(self, v): + expr = gpregs.expr[v] + shift_value = self.parent.rot5.value + if shift_value: + expr = ExprOp(allshifts[self.index_op], expr, ExprInt(shift_value, 32)) + self.expr = expr + return True + def encode(self): + if self.expr in gpregs.expr: + self.value = gpregs.expr.index(self.expr) + self.parent.rot5.value = 0 + elif (isinstance(self.expr, ExprOp) and + self.expr.op == allshifts[self.index_op]): + reg, value = self.expr.args + if reg not in gpregs.expr: + return False + self.value = gpregs.expr.index(reg) + if not isinstance(value, ExprInt): + return False + value = int(value) + if not 0 <= value < 32: + return False + self.parent.rot5.value = value + return True + +class arm_rm_rot5_asr(arm_rm_rot5_lsl): + parser = rot5_expr + index_op = 2 + def decode(self, v): + expr = gpregs.expr[v] + shift_value = self.parent.rot5.value + if shift_value == 0: + expr = ExprOp(allshifts[self.index_op], expr, ExprInt(32, 32)) + else: + expr = ExprOp(allshifts[self.index_op], expr, ExprInt(shift_value, 32)) + self.expr = expr + return True + def encode(self): + if (isinstance(self.expr, ExprOp) and + self.expr.op == allshifts[self.index_op]): + reg, value = self.expr.args + if reg not in gpregs.expr: + return False + self.value = gpregs.expr.index(reg) + if not isinstance(value, ExprInt): + return False + value = int(value) + if not 0 < value <= 32: + return False + if value == 32: + value = 0 + self.parent.rot5.value = value + else: + return False + return True + + +class arm_gpreg_nopc(reg_noarg): + reg_info = gpregs_nopc + parser = reg_info.parser + + + def decode(self, v): + ret = super(arm_gpreg_nopc, self).decode(v) + if ret is False: + return False + if self.expr == reg_dum: + return False + return True + + +class arm_gpreg_nosp(reg_noarg): + reg_info = gpregs_nosp + parser = reg_info.parser + + def decode(self, v): + ret = super(arm_gpreg_nosp, self).decode(v) + if ret is False: + return False + if self.expr == reg_dum: + return False + return True + + +rm_rot2 = bs(l=4, cls=(arm_rm_rot2,), fname="rm") +rot2 = bs(l=2, fname="rot2") + +rm_rot5_lsl = bs(l=4, cls=(arm_rm_rot5_lsl,), fname="rm") +rm_rot5_asr = bs(l=4, cls=(arm_rm_rot5_asr,), fname="rm") +rot5 = bs(l=5, fname="rot5") + +widthm1 = bs(l=5, cls=(arm_widthm1, m_arg)) +lsb = bs(l=5, cls=(arm_imm, m_arg)) + +rd_nopc = bs(l=4, cls=(arm_gpreg_nopc, arm_arg), fname="rd") +rn_nopc = bs(l=4, cls=(arm_gpreg_nopc, arm_arg), fname="rn") +ra_nopc = bs(l=4, cls=(arm_gpreg_nopc, arm_arg), fname="ra") +rt_nopc = bs(l=4, cls=(arm_gpreg_nopc, arm_arg), fname="rt") + +rn_nosp = bs(l=4, cls=(arm_gpreg_nosp, arm_arg), fname="rn") + +rn_nopc_noarg = bs(l=4, cls=(arm_gpreg_nopc,), fname="rn") + +armop("ubfx", [bs('0111111'), widthm1, rd, lsb, bs('101'), rn], [rd, rn, lsb, widthm1]) + +armop("bfc", [bs('0111110'), widthm1, rd, lsb, bs('001'), bs('1111')], [rd, lsb, widthm1]) + +armop("uxtab", [bs('01101110'), rn_nopc, rd, rot2, bs('000111'), rm_rot2], [rd, rn_nopc, rm_rot2]) + +armop("pkhbt", [bs('01101000'), rn, rd, rot5, bs('001'), rm_rot5_lsl], [rd, rn, rm_rot5_lsl]) +armop("pkhtb", [bs('01101000'), rn, rd, rot5, bs('101'), rm_rot5_asr], [rd, rn, rm_rot5_asr]) + + + +# +# thumnb ####################### +# +# ARM7-TDMI-manual-pt3 +gpregs_l = reg_info(regs_str[:8], regs_expr[:8]) +gpregs_h = reg_info(regs_str[8:], regs_expr[8:]) + +gpregs_sppc = reg_info(regs_str[-1:] + regs_str[13:14], + regs_expr[-1:] + regs_expr[13:14]) + +deref_reg_imm = Group(LBRACK + gpregs.parser + Optional( + COMMA + shift_off) + RBRACK).setParseAction(cb_deref_pre_mem) +deref_low = Group(LBRACK + gpregs_l.parser + Optional( + COMMA + shift_off) + RBRACK).setParseAction(cb_deref_pre_mem) +deref_pc = Group(LBRACK + gpregs_pc.parser + Optional( + COMMA + shift_off) + RBRACK).setParseAction(cb_deref_pre_mem) +deref_sp = Group(LBRACK + gpregs_sp.parser + COMMA + + shift_off + RBRACK).setParseAction(cb_deref_pre_mem) + +gpregs_l_wb = Group( + gpregs_l.parser + Optional('!')).setParseAction(cb_gpreb_wb) + + +gpregs_l_13 = reg_info(regs_str[:13], regs_expr[:13]) + + +class arm_offreg(arm_arg): + parser = deref_pc + + def decodeval(self, v): + return v + + def encodeval(self, v): + return v + + def decode(self, v): + v = v & self.lmask + v = self.decodeval(v) + if v: + self.expr = self.off_reg + ExprInt(v, 32) + else: + self.expr = self.off_reg + + e = self.expr + if isinstance(e, ExprOp) and e.op == 'wback': + self.parent.wback.value = 1 + e = e.args[0] + return True + + def encode(self): + e = self.expr + if not (isinstance(e, ExprOp) and e.op == "preinc"): + log.debug('cannot encode %r', e) + return False + if e.args[0] != self.off_reg: + log.debug('cannot encode reg %r', e.args[0]) + return False + v = int(e.args[1]) + v = self.encodeval(v) + self.value = v + return True + + +class arm_offpc(arm_offreg): + off_reg = regs_expr[15] + + def decode(self, v): + v = v & self.lmask + v <<= 2 + if v: + self.expr = ExprMem(self.off_reg + ExprInt(v, 32), 32) + else: + self.expr = ExprMem(self.off_reg, 32) + + e = self.expr.ptr + if isinstance(e, ExprOp) and e.op == 'wback': + self.parent.wback.value = 1 + e = e.args[0] + return True + + def encode(self): + e = self.expr + if not isinstance(e, ExprMem): + return False + e = e.ptr + if not (isinstance(e, ExprOp) and e.op == "preinc"): + log.debug('cannot encode %r', e) + return False + if e.args[0] != self.off_reg: + log.debug('cannot encode reg %r', e.args[0]) + return False + v = int(e.args[1]) + if v & 3: + return False + v >>= 2 + self.value = v + return True + + + + +class arm_offsp(arm_offpc): + parser = deref_sp + off_reg = regs_expr[13] + + +class arm_offspc(arm_offs): + + def decodeval(self, v): + v = v << 1 + # Add pipeline offset + v += 2 + 2 + return v + + def encodeval(self, v): + # Remove pipeline offset + v -= 2 + 2 + if v % 2 != 0: + return False + if v > (1 << (self.l - 1)) - 1: + return False + return v >> 1 + + +class arm_off8sppc(arm_imm): + + def decodeval(self, v): + return v << 2 + + def encodeval(self, v): + return v >> 2 + + +class arm_off7(arm_imm): + + def decodeval(self, v): + return v << 2 + + def encodeval(self, v): + return v >> 2 + +class arm_deref_reg_imm(arm_arg): + parser = deref_reg_imm + + def decode(self, v): + v = v & self.lmask + rbase = regs_expr[v] + e = ExprOp('preinc', rbase, self.parent.off.expr) + self.expr = ExprMem(e, 32) + return True + + def encode(self): + self.parent.off.expr = None + e = self.expr + if not isinstance(e, ExprMem): + return False + e = e.ptr + if not (isinstance(e, ExprOp) and e.op == 'preinc'): + log.debug('cannot encode %r', e) + return False + off = e.args[1] + if isinstance(off, ExprId): + self.parent.off.expr = off + elif isinstance(off, ExprInt): + self.parent.off.expr = off + else: + log.debug('cannot encode off %r', off) + return False + self.value = gpregs.expr.index(e.args[0]) + if self.value >= 1 << self.l: + log.debug('cannot encode reg %r', off) + return False + return True + +class arm_derefl(arm_deref_reg_imm): + parser = deref_low + + +class arm_offbw(imm_noarg): + + def decode(self, v): + v = v & self.lmask + if self.parent.trb.value == 0: + v <<= 2 + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if self.parent.trb.value == 0: + if v & 3: + log.debug('off must be aligned %r', v) + return False + v >>= 2 + self.value = v + return True + + + +class arm_off(imm_noarg): + + def decode(self, v): + v = v & self.lmask + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + self.value = v + return True + + +class arm_offh(imm_noarg): + + def decode(self, v): + v = v & self.lmask + v <<= 1 + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if v & 1: + log.debug('off must be aligned %r', v) + return False + v >>= 1 + self.value = v + return True + + +class armt_rlist(arm_arg): + parser = gpreg_list + + def encode(self): + e = self.expr + rlist = [gpregs_l.expr.index(x) for x in e.args] + v = 0 + for r in rlist: + v |= 1 << r + self.value = v + return True + + def decode(self, v): + v = v & self.lmask + out = [] + for i in range(0x10): + if 1 << i & v: + out.append(gpregs.expr[i]) + if not out: + return False + e = ExprOp('reglist', *out) + self.expr = e + return True + + +class armt_rlist13(armt_rlist): + parser = gpreg_list + + def encode(self): + e = self.expr + rlist = [] + reg_l = list(e.args) + + self.parent.pclr.value = 0 + if self.parent.name.startswith('PUSH'): + if regs_expr[14] in reg_l: + reg_l.remove(regs_expr[14]) + self.parent.pclr.value = 1 + else: + if regs_expr[15] in reg_l: + reg_l.remove(regs_expr[15]) + self.parent.pclr.value = 1 + + for reg in reg_l: + if reg not in gpregs_l_13.expr: + return False + rlist.append(gpregs_l_13.expr.index(reg)) + v = 0 + for r in rlist: + v |= 1 << r + self.value = v + return True + + def decode(self, v): + v = v & self.lmask + out = [] + for i in range(13): + if 1 << i & v: + out.append(gpregs_l_13.expr[i]) + + if self.parent.pclr.value == 1: + if self.parent.name.startswith("PUSH"): + out += [regs_expr[14]] + else: + out += [regs_expr[15]] + + if not out: + return False + e = ExprOp('reglist', *out) + self.expr = e + return True + + + +class armt_rlist13_pc_lr(armt_rlist): + parser = gpreg_list + + def encode(self): + e = self.expr + rlist = [] + reg_l = list(e.args) + + self.parent.pc_in.value = 0 + self.parent.lr_in.value = 0 + if regs_expr[14] in reg_l: + reg_l.remove(regs_expr[14]) + self.parent.lr_in.value = 1 + if regs_expr[15] in reg_l: + reg_l.remove(regs_expr[15]) + self.parent.pc_in.value = 1 + + for reg in reg_l: + if reg not in gpregs_l_13.expr: + return False + rlist.append(gpregs_l_13.expr.index(reg)) + v = 0 + for r in rlist: + v |= 1 << r + self.value = v + return True + + def decode(self, v): + v = v & self.lmask + out = [] + for i in range(13): + if 1 << i & v: + out.append(gpregs_l_13.expr[i]) + + if self.parent.lr_in.value == 1: + out += [regs_expr[14]] + if self.parent.pc_in.value == 1: + out += [regs_expr[15]] + + if not out: + return False + e = ExprOp('reglist', *out) + self.expr = e + return True + + + +class armt_rlist_pclr(armt_rlist): + + def encode(self): + e = self.expr + reg_l = list(e.args) + self.parent.pclr.value = 0 + if self.parent.pp.value == 0: + if regs_expr[14] in reg_l: + reg_l.remove(regs_expr[14]) + self.parent.pclr.value = 1 + else: + if regs_expr[15] in reg_l: + reg_l.remove(regs_expr[15]) + self.parent.pclr.value = 1 + rlist = [gpregs.expr.index(x) for x in reg_l] + v = 0 + for r in rlist: + v |= 1 << r + self.value = v + return True + + def decode(self, v): + v = v & self.lmask + out = [] + for i in range(0x10): + if 1 << i & v: + out.append(gpregs.expr[i]) + + if self.parent.pclr.value == 1: + if self.parent.pp.value == 0: + out += [regs_expr[14]] + else: + out += [regs_expr[15]] + if not out: + return False + e = ExprOp('reglist', *out) + self.expr = e + return True + + +class armt_reg_wb(arm_reg_wb): + reg_info = gpregs_l + parser = gpregs_l_wb + + def decode(self, v): + v = v & self.lmask + e = self.reg_info.expr[v] + if not e in self.parent.trlist.expr.args: + e = ExprOp('wback', e) + self.expr = e + return True + + def encode(self): + e = self.expr + if isinstance(e, ExprOp): + if e.op != 'wback': + return False + e = e.args[0] + self.value = self.reg_info.expr.index(e) + return True + + +class arm_gpreg_l(arm_reg): + reg_info = gpregs_l + parser = reg_info.parser + + +class arm_gpreg_h(arm_reg): + reg_info = gpregs_h + parser = reg_info.parser + + +class arm_gpreg_l_noarg(arm_gpreg_noarg): + reg_info = gpregs_l + parser = reg_info.parser + + +class arm_sppc(arm_reg): + reg_info = gpregs_sppc + parser = reg_info.parser + + +class arm_sp(arm_reg): + reg_info = gpregs_sp + parser = reg_info.parser + +off5 = bs(l=5, cls=(arm_imm,), fname="off") +off3 = bs(l=3, cls=(arm_imm,), fname="off") +off8 = bs(l=8, cls=(arm_imm,), fname="off") +off7 = bs(l=7, cls=(arm_off7,), fname="off") + +rdl = bs(l=3, cls=(arm_gpreg_l,), fname="rd") +rnl = bs(l=3, cls=(arm_gpreg_l,), fname="rn") +rsl = bs(l=3, cls=(arm_gpreg_l,), fname="rs") +rml = bs(l=3, cls=(arm_gpreg_l,), fname="rm") +rol = bs(l=3, cls=(arm_gpreg_l,), fname="ro") +rbl = bs(l=3, cls=(arm_gpreg_l,), fname="rb") +rbl_deref = bs(l=3, cls=(arm_derefl,), fname="rb") +dumrh = bs(l=3, default_val="000") + +rdh = bs(l=3, cls=(arm_gpreg_h,), fname="rd") +rsh = bs(l=3, cls=(arm_gpreg_h,), fname="rs") + +offpc8 = bs(l=8, cls=(arm_offpc,), fname="offs") +offsp8 = bs(l=8, cls=(arm_offsp,), fname="offs") +rol_noarg = bs(l=3, cls=(arm_gpreg_l_noarg,), fname="off") + +off5bw = bs(l=5, cls=(arm_offbw,), fname="off") +off5h = bs(l=5, cls=(arm_offh,), fname="off") +sppc = bs(l=1, cls=(arm_sppc,)) + +off12 = bs(l=12, cls=(arm_off,), fname="off", order=-1) +rn_deref = bs(l=4, cls=(arm_deref_reg_imm,), fname="rt") + + + +pclr = bs(l=1, fname='pclr', order=-2) + + +pc_in = bs(l=1, fname='pc_in', order=-2) +lr_in = bs(l=1, fname='lr_in', order=-2) + + +sp = bs(l=0, cls=(arm_sp,)) + + +off8s = bs(l=8, cls=(arm_offs,), fname="offs") +trlistpclr = bs(l=8, cls=(armt_rlist_pclr,)) +trlist = bs(l=8, cls=(armt_rlist,), fname="trlist", order = -1) +trlist13 = bs(l=13, cls=(armt_rlist13,), fname="trlist", order = -1) +trlist13pclr = bs(l=13, cls=(armt_rlist13_pc_lr,), fname="trlist", order = -1) + + +rbl_wb = bs(l=3, cls=(armt_reg_wb,), fname='rb') + +offs8 = bs(l=8, cls=(arm_offspc,), fname="offs") +offs11 = bs(l=11, cls=(arm_offspc,), fname="offs") + +hl = bs(l=1, prio=default_prio + 1, fname='hl') +off8sppc = bs(l=8, cls=(arm_off8sppc,), fname="off") + +imm8_d1 = bs(l=8, default_val="00000001") +imm8 = bs(l=8, cls=(arm_imm,), default_val = "00000001") + + +mshift_name = {'LSLS': 0, 'LSRS': 1, 'ASRS': 2} +bs_mshift_name = bs_name(l=2, name=mshift_name) + + +addsub_name = {'ADDS': 0, 'SUBS': 1} +bs_addsub_name = bs_name(l=1, name=addsub_name) + +mov_cmp_add_sub_name = {'MOVS': 0, 'CMP': 1, 'ADDS': 2, 'SUBS': 3} +bs_mov_cmp_add_sub_name = bs_name(l=2, name=mov_cmp_add_sub_name) + +alu_name = {'ANDS': 0, 'EORS': 1, 'LSLS': 2, 'LSRS': 3, + 'ASRS': 4, 'ADCS': 5, 'SBCS': 6, 'RORS': 7, + 'TST': 8, 'NEGS': 9, 'CMP': 10, 'CMN': 11, + 'ORRS': 12, 'MULS': 13, 'BICS': 14, 'MVNS': 15} +bs_alu_name = bs_name(l=4, name=alu_name) + +hiregop_name = {'ADDS': 0, 'CMP': 1, 'MOV': 2} +bs_hiregop_name = bs_name(l=2, name=hiregop_name) + +ldr_str_name = {'STR': 0, 'LDR': 1} +bs_ldr_str_name = bs_name(l=1, name=ldr_str_name) + +ldrh_strh_name = {'STRH': 0, 'LDRH': 1} +bs_ldrh_strh_name = bs_name(l=1, name=ldrh_strh_name) + +ldstsp_name = {'STR': 0, 'LDR': 1} +bs_ldstsp_name = bs_name(l=1, name=ldstsp_name) + +addsubsp_name = {'ADD': 0, 'SUB': 1} +bs_addsubsp_name = bs_name(l=1, name=addsubsp_name) + +pushpop_name = {'PUSH': 0, 'POP': 1} +bs_pushpop_name = bs_name(l=1, name=pushpop_name, fname='pp') + +tbtransfer_name = {'STMIA': 0, 'LDMIA': 1} +bs_tbtransfer_name = bs_name(l=1, name=tbtransfer_name) + +br_name = {'BEQ': 0, 'BNE': 1, 'BCS': 2, 'BCC': 3, 'BMI': 4, + 'BPL': 5, 'BVS': 6, 'BVC': 7, 'BHI': 8, 'BLS': 9, + 'BGE': 10, 'BLT': 11, 'BGT': 12, 'BLE': 13} +bs_br_name = bs_name(l=4, name=br_name) + + +armtop("mshift", [bs('000'), bs_mshift_name, off5, rsl, rdl], [rdl, rsl, off5]) +armtop("addsubr", [bs('000110'), bs_addsub_name, rnl, rsl, rdl], [rdl, rsl, rnl]) +armtop("addsubi", [bs('000111'), bs_addsub_name, off3, rsl, rdl], [rdl, rsl, off3]) +armtop("mcas", [bs('001'), bs_mov_cmp_add_sub_name, rnl, off8]) +armtop("alu", [bs('010000'), bs_alu_name, rsl, rdl], [rdl, rsl]) + # should not be used ?? +armtop("hiregop00", [bs('010001'), bs_hiregop_name, bs('00'), rsl, rdl], [rdl, rsl]) +armtop("hiregop01", [bs('010001'), bs_hiregop_name, bs('01'), rsh, rdl], [rdl, rsh]) +armtop("hiregop10", [bs('010001'), bs_hiregop_name, bs('10'), rsl, rdh], [rdh, rsl]) +armtop("hiregop11", [bs('010001'), bs_hiregop_name, bs('11'), rsh, rdh], [rdh, rsh]) +armtop("bx", [bs('010001'), bs('11'), bs('00'), rsl, dumrh]) +armtop("bx", [bs('010001'), bs('11'), bs('01'), rsh, dumrh]) +armtop("ldr", [bs('01001'), rdl, offpc8]) +armtop("ldrstr", [bs('0101'), bs_ldr_str_name, trb, bs('0'), rol_noarg, rbl_deref, rdl], [rdl, rbl_deref]) +armtop("strh", [bs('0101'), bs('00'), bs('1'), rol_noarg, rbl_deref, rdl], [rdl, rbl_deref]) +armtop("ldrh", [bs('0101'), bs('10'), bs('1'), rol_noarg, rbl_deref, rdl], [rdl, rbl_deref]) +armtop("ldsb", [bs('0101'), bs('01'), bs('1'), rol_noarg, rbl_deref, rdl], [rdl, rbl_deref]) +armtop("ldsh", [bs('0101'), bs('11'), bs('1'), rol_noarg, rbl_deref, rdl], [rdl, rbl_deref]) +armtop("ldst", [bs('011'), trb, bs_ldr_str_name, off5bw, rbl_deref, rdl], [rdl, rbl_deref]) +armtop("ldhsth", [bs('1000'), bs_ldrh_strh_name, off5h, rbl_deref, rdl], [rdl, rbl_deref]) +armtop("ldstsp", [bs('1001'), bs_ldstsp_name, rdl, offsp8], [rdl, offsp8]) +armtop("add", [bs('1010'), sppc, rdl, off8sppc], [rdl, sppc, off8sppc]) +armtop("addsp", [bs('10110000'), bs_addsubsp_name, sp, off7], [sp, off7]) +armtop("pushpop", [bs('1011'), bs_pushpop_name, bs('10'), pclr, trlistpclr], [trlistpclr]) +armtop("btransfersp", [bs('1100'), bs_tbtransfer_name, rbl_wb, trlist]) +armtop("br", [bs('1101'), bs_br_name, offs8]) +armtop("blx", [bs("01000111"), bs('1'), rm, bs('000')]) +armtop("svc", [bs('11011111'), imm8]) +armtop("b", [bs('11100'), offs11]) +armtop("und", [bs('1101'), bs('1110'), imm8_d1]) + +armtop("rev", [bs('10111010'), bs('00'), rsl, rdl], [rdl, rsl]) +armtop("rev16", [bs('10111010'), bs('01'), rsl, rdl], [rdl, rsl]) + +armtop("uxtb", [bs('10110010'), bs('11'), rml, rdl], [rdl, rml]) +armtop("uxth", [bs('10110010'), bs('10'), rml, rdl], [rdl, rml]) +armtop("sxtb", [bs('10110010'), bs('01'), rml, rdl], [rdl, rml]) +armtop("sxth", [bs('10110010'), bs('00'), rml, rdl], [rdl, rml]) + +armtop("uxtab", [bs('111110100'), bs('101'), rn_nopc, bs('1111'), rd, bs('10'), rot2, rm_rot2], [rd, rn_nopc, rm_rot2]) +armtop("uxtah", [bs('111110100'), bs('001'), rn_nopc, bs('1111'), rd, bs('10'), rot2, rm_rot2], [rd, rn_nopc, rm_rot2]) + +# thumb2 ###################### +# +# ARM Architecture Reference Manual Thumb-2 Supplement + +armt_gpreg_shift_off = (gpregs_nosppc.parser + allshifts_t_armt + (gpregs.parser | int_1_31)).setParseAction(cb_shift) + + +armt_gpreg_shift_off |= gpregs_nosppc.parser + + +class arm_gpreg_nosppc(arm_reg): + reg_info = gpregs_nosppc + parser = reg_info.parser + + def decode(self, v): + ret = super(arm_gpreg_nosppc, self).decode(v) + if ret is False: + return False + if self.expr == reg_dum: + return False + return True + + +class armt_gpreg_rm_shift_off(arm_reg): + parser = armt_gpreg_shift_off + + def decode(self, v): + v = v & self.lmask + if v >= len(gpregs_nosppc.expr): + return False + r = gpregs_nosppc.expr[v] + if r == reg_dum: + return False + + i = int(self.parent.imm5_3.value) << 2 + i |= int(self.parent.imm5_2.value) + + if self.parent.stype.value < 3 or i != 0: + shift = allshifts_armt[self.parent.stype.value] + else: + shift = allshifts_armt[4] + self.expr = ExprOp(shift, r, ExprInt(i, 32)) + return True + + def encode(self): + e = self.expr + if isinstance(e, ExprId): + if e not in gpregs_nosppc.expr: + return False + self.value = gpregs_nosppc.expr.index(e) + self.parent.stype.value = 0 + self.parent.imm5_3.value = 0 + self.parent.imm5_2.value = 0 + return True + if not e.is_op(): + return False + shift = e.op + r = gpregs_nosppc.expr.index(e.args[0]) + self.value = r + i = int(e.args[1]) + if shift == 'rrx': + if i != 1: + log.debug('rrx shift must be 1') + return False + self.parent.imm5_3.value = 0 + self.parent.imm5_2.value = 0 + self.parent.stype.value = 3 + return True + self.parent.stype.value = allshifts_armt.index(shift) + self.parent.imm5_2.value = i & 3 + self.parent.imm5_3.value = i >> 2 + return True + +rn_nosppc = bs(l=4, cls=(arm_gpreg_nosppc,), fname="rn") +rd_nosppc = bs(l=4, cls=(arm_gpreg_nosppc,), fname="rd") +rm_sh = bs(l=4, cls=(armt_gpreg_rm_shift_off,), fname="rm") + + +class armt2_imm12(arm_imm): + + def decode(self, v): + v = v & self.lmask + v |= int(self.parent.imm12_3.value) << 8 + v |= int(self.parent.imm12_1.value) << 11 + + # simple encoding + if 0 <= v < 0x100: + self.expr = ExprInt(v, 32) + return True + # 00XY00XY form + if v >> 8 == 1: + v &= 0xFF + self.expr = ExprInt((v << 16) | v, 32) + return True + # XY00XY00 form + if v >> 8 == 2: + v &= 0xFF + self.expr = ExprInt((v << 24) | (v << 8), 32) + return True + # XYXYXYXY + if v >> 8 == 3: + v &= 0xFF + self.expr = ExprInt((v << 24) | (v << 16) | (v << 8) | v, 32) + return True + r = v >> 7 + v = 0x80 | (v & 0x7F) + self.expr = ExprInt(myror32(v, r), 32) + return True + + def encode(self): + if not self.expr.is_int(): + return False + v = int(self.expr) + value = None + # simple encoding + if 0 <= v < 0x100: + value = v + elif v & 0xFF00FF00 == 0 and v & 0xFF == (v >> 16) & 0xff: + # 00XY00XY form + value = (1 << 8) | (v & 0xFF) + elif v & 0x00FF00FF == 0 and (v >> 8) & 0xff == (v >> 24) & 0xff: + # XY00XY00 form + value = (2 << 8) | ((v >> 8) & 0xff) + elif (v & 0xFF == + (v >> 8) & 0xFF == + (v >> 16) & 0xFF == + (v >> 24) & 0xFF): + # XYXYXYXY form + value = (3 << 8) | ((v >> 16) & 0xff) + else: + # rol encoding + for i in range(32): + o = myrol32(v, i) + if 0x80 <= o <= 0xFF: + value = (i << 7) | (o & 0x7F) + break + if value is None: + log.debug('cannot encode imm12') + return False + self.value = value & self.lmask + self.parent.imm12_3.value = (value >> 8) & self.parent.imm12_3.lmask + self.parent.imm12_1.value = (value >> 11) & self.parent.imm12_1.lmask + return True + + + + +class armt4_imm12(arm_imm): + + def decode(self, v): + v = v & self.lmask + v |= int(self.parent.imm12_3.value) << 8 + v |= int(self.parent.imm12_1.value) << 11 + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not self.expr.is_int(): + return False + value = int(self.expr) + if value >= (1 << 16): + return False + self.value = value & self.lmask + self.parent.imm12_3.value = (value >> 8) & self.parent.imm12_3.lmask + self.parent.imm12_1.value = (value >> 11) & self.parent.imm12_1.lmask + return True + + + +class armt2_imm16(arm_imm): + + def decode(self, v): + v = v & self.lmask + v |= int(self.parent.imm16_3.value) << 8 + v |= int(self.parent.imm16_1.value) << 11 + v |= int(self.parent.imm16_4.value) << 12 + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not self.expr.is_int(): + return False + value = int(self.expr) + if value >= (1 << 16): + return False + self.value = value & self.lmask + self.parent.imm16_3.value = (value >> 8) & self.parent.imm16_3.lmask + self.parent.imm16_1.value = (value >> 11) & self.parent.imm16_1.lmask + self.parent.imm16_4.value = (value >> 12) & self.parent.imm16_4.lmask + return True + + +class armt2_lsb5(arm_imm): + + def decode(self, v): + v = v & self.lmask + v |= int(self.parent.lsb5_3.value) << 2 + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not self.expr.is_int(): + return False + value = int(self.expr) + self.value = value & self.lmask + self.parent.lsb5_3.value = (value >> 2) & self.parent.lsb5_3.lmask + return True + + +class armt_widthm1(arm_imm): + parser = base_expr + + def decodeval(self, v): + return v + 1 + + def encodeval(self, v): + if v <= 0: + return False + return v - 1 + + + + +class armt2_off20(arm_imm): + + def decode(self, v): + v = v & self.lmask + v <<= 1 + v |= int(self.parent.off20_6.value) << 12 + v |= int(self.parent.off20_j1.value) << 18 + v |= int(self.parent.off20_j2.value) << 19 + v |= int(self.parent.off20_s.value) << 20 + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not self.expr.is_int(): + return False + value = int(self.expr) + if value & 1: + return False + self.value = (value >> 1) & self.lmask + self.parent.off20_6.value = (value >> 12) & self.parent.off20_6.lmask + self.parent.off20_j1.value = (value >> 18) & self.parent.off20_j1.lmask + self.parent.off20_j2.value = (value >> 19) & self.parent.off20_j2.lmask + self.parent.off20_s.value = (value >> 20) & self.parent.off20_s.lmask + return True + + + +class armt2_imm10l(arm_imm): + + def decode(self, v): + v = v & self.lmask + s = self.parent.sign.value + j1 = self.parent.j1.value + j2 = self.parent.j2.value + imm10h = self.parent.imm10h.value + imm10l = v + + i1, i2 = j1 ^ s ^ 1, j2 ^ s ^ 1 + + v = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10h << 12) | (imm10l << 2) + v = sign_ext(v, 25, 32) + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + s = 0 + if v & 0x80000000: + s = 1 + v &= (1<<26) - 1 + if v >= (1 << 26): + return False + i1, i2, imm10h, imm10l = (v >> 23) & 1, (v >> 22) & 1, (v >> 12) & 0x3ff, (v >> 2) & 0x3ff + j1, j2 = i1 ^ s ^ 1, i2 ^ s ^ 1 + self.parent.sign.value = s + self.parent.j1.value = j1 + self.parent.j2.value = j2 + self.parent.imm10h.value = imm10h + self.value = imm10l + return True + + +class armt2_imm11l(arm_imm): + + def decode(self, v): + v = v & self.lmask + s = self.parent.sign.value + j1 = self.parent.j1.value + j2 = self.parent.j2.value + imm10h = self.parent.imm10h.value + imm11l = v + + i1, i2 = j1 ^ s ^ 1, j2 ^ s ^ 1 + + v = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10h << 12) | (imm11l << 1) + v = sign_ext(v, 25, 32) + self.expr = ExprInt(v + 4, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = (int(self.expr) - 4) & int(self.expr.mask) + s = 0 + if v & 0x80000000: + s = 1 + v &= (1<<26) - 1 + if v >= (1 << 26): + return False + if v & 1: + return False + i1, i2, imm10h, imm11l = (v >> 23) & 1, (v >> 22) & 1, (v >> 12) & 0x3ff, (v >> 1) & 0x7ff + j1, j2 = i1 ^ s ^ 1, i2 ^ s ^ 1 + self.parent.sign.value = s + self.parent.j1.value = j1 + self.parent.j2.value = j2 + self.parent.imm10h.value = imm10h + self.value = imm11l + return True + + + +class armt2_imm6_11l(arm_imm): + + def decode(self, v): + v = v & self.lmask + s = self.parent.sign.value + j1 = self.parent.j1.value + j2 = self.parent.j2.value + imm6h = self.parent.imm6h.value + imm11l = v + + v = (s << 20) | (j2 << 19) | (j1 << 18) | (imm6h << 12) | (imm11l << 1) + v = sign_ext(v, 21, 32) + self.expr = ExprInt(v + 4, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = (int(self.expr) - 4) & int(self.expr.mask) + s = 0 + if v != sign_ext(v & ((1 << 22) - 1), 21, 32): + return False + if v & 0x80000000: + s = 1 + v &= (1<<22) - 1 + if v & 1: + return False + i2, i1, imm6h, imm11l = (v >> 19) & 1, (v >> 18) & 1, (v >> 12) & 0x3f, (v >> 1) & 0x7ff + self.parent.sign.value = s + self.parent.j1.value = i1 + self.parent.j2.value = i2 + self.parent.imm6h.value = imm6h + self.value = imm11l + return True + + + +imm12_1 = bs(l=1, fname="imm12_1", order=1) +imm12_3 = bs(l=3, fname="imm12_3", order=1) +imm12_8 = bs(l=8, cls=(armt2_imm12,), fname="imm", order=2) + + +imm12_8_t4 = bs(l=8, cls=(armt4_imm12,), fname="imm", order=2) + + +imm16_1 = bs(l=1, fname="imm16_1", order=1) +imm16_3 = bs(l=3, fname="imm16_3", order=1) +imm16_4 = bs(l=4, fname="imm16_4", order=1) +imm16_8 = bs(l=8, cls=(armt2_imm16,), fname="imm", order=2) + + +imm5_3 = bs(l=3, fname="imm5_3") +imm5_2 = bs(l=2, fname="imm5_2") +imm_stype = bs(l=2, fname="stype") + +imm_stype_00 = bs('00', fname="stype") +imm_stype_01 = bs('01', fname="stype") +imm_stype_11 = bs('11', fname="stype") + + +imm1 = bs(l=1, fname="imm1") + + + +off20_6 = bs(l=6, fname="off20_6", order=1) +off20_11 = bs(l=11, cls=(armt2_off20,), fname="imm", order=2) + + + +lsb5_3 = bs(l=3, fname="lsb5_3", order=1) +lsb5_2 = bs(l=2, cls=(armt2_lsb5,), fname="imm", order=2) + +widthm1 = bs(l=5, cls=(armt_widthm1,), fname="imm", order=2) + + + +class armt_imm5_1(arm_imm): + + def decode(self, v): + v = ((self.parent.imm1.value << 5) | v) << 1 + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if v & 0x1: + return False + self.parent.imm1.value = (v >> 6) & 1 + self.value = (v >> 1) & 0x1f + return True + +aif_str = ["X", "F", "I", "IF", "A", "AF", "AI", "AIF"] +aif_expr = [ExprId(x, 32) if x != None else None for x in aif_str] + +aif_reg = reg_info(aif_str, aif_expr) + +class armt_aif(reg_noarg, arm_arg): + reg_info = aif_reg + parser = reg_info.parser + + def decode(self, v): + if v == 0: + return False + return super(armt_aif, self).decode(v) + + def encode(self): + ret = super(armt_aif, self).encode() + if not ret: + return ret + return self.value != 0 + + def fromstring(self, text, loc_db, parser_result=None): + start, stop = super(armt_aif, self).fromstring(text, loc_db, parser_result) + if self.expr.name == "X": + return None, None + return start, stop + + +class armt_it_arg(arm_arg): + arg_E = ExprId('E', 1) + arg_NE = ExprId('NE', 1) + + def decode(self, v): + if v: + return self.arg_E + else: + return self.arg_NE + + def encode(self): + if self.expr == self.arg_E: + return 1 + elif self.expr == self.arg_NE: + return 0 + +class armt_itmask(bs_divert): + prio = 2 + + def divert(self, i, candidates): + out = [] + for cls, _, bases, dct, fields in candidates: + for value in range(1, 0x10): + nfields = fields[:] + s = int2bin(value, self.args['l']) + args = dict(self.args) + args.update({'strbits': s}) + f = bs(**args) + nfields[i] = f + inv = nfields[-2].value + ndct = dict(dct) + ndct['name'] = self.modname(ndct['name'], value, inv) + out.append((cls, ndct['name'], bases, ndct, nfields)) + return out + + def modname(self, name, value, inv): + count = 0 + while value & (1 << count) == 0: + count += 1 + out = [] + values = ['E', 'T'] + if inv== 1: + values.reverse() + for index in range(3 - count): + if value & (1 << (3 - index)): + out.append(values[0]) + else: + out.append(values[1]) + return name + "".join(out) + + + +class armt_cond_lsb(bs_divert): + prio = 2 + + def divert(self, i, candidates): + out = [] + for cls, _, bases, dct, fields in candidates: + for value in range(2): + nfields = fields[:] + s = int2bin(value, self.args['l']) + args = dict(self.args) + args.update({'strbits': s}) + f = bs(**args) + nfields[i] = f + ndct = dict(dct) + out.append((cls, ndct['name'], bases, ndct, nfields)) + return out + + +cond_expr = [ExprId(x, 32) for x in cond_list_full] +cond_info = reg_info(cond_list_full, cond_expr) + +class armt_cond_arg(arm_arg): + parser = cond_info.parser + + def decode(self, v): + v = (v << 1) | self.parent.condlsb.value + self.expr = ExprId(cond_list_full[v], 32) + return True + + def encode(self): + index = cond_list_full.index(self.expr.name) + self.value = index >> 1 + if index & 1 != self.parent.condlsb.value: + return False + return True + + +class armt_op2imm(arm_imm8_12): + parser = deref + + def str_to_imm_rot_form(self, s, neg=False): + if neg: + s = -s & 0xffffffff + if 0 <= s < (1 << 12): + return s + return None + + def decodeval(self, v): + return v + + def encodeval(self, v): + return v + + def decode(self, v): + val = v & self.lmask + val = self.decodeval(val) + if val is False: + return False + imm = val + if self.parent.updown.value == 0: + imm = -imm + if self.parent.ppi.value == 0 and self.parent.wback.value == 0: + return False + if self.parent.ppi.value: + e = ExprOp('preinc', self.parent.rn.expr, ExprInt(imm, 32)) + if self.parent.wback.value == 1: + e = ExprOp('wback', e) + else: + e = ExprOp('postinc', self.parent.rn.expr, ExprInt(imm, 32)) + self.expr = ExprMem(e, 32) + return True + + def encode(self): + self.parent.updown.value = 1 + self.parent.wback.value = 0 + + e = self.expr + assert(isinstance(e, ExprMem)) + e = e.ptr + if e.op == 'wback': + self.parent.wback.value = 1 + e = e.args[0] + if e.op == "postinc": + self.parent.ppi.value = 0 + self.parent.wback.value = 1 + elif e.op == "preinc": + self.parent.ppi.value = 1 + else: + # XXX default + self.parent.ppi.value = 1 + + self.parent.rn.expr = e.args[0] + + if len(e.args) == 1: + self.value = 0 + return True + # pure imm + if isinstance(e.args[1], ExprInt): + val = self.str_to_imm_rot_form(int(e.args[1])) + if val is None: + val = self.str_to_imm_rot_form(int(e.args[1]), True) + if val is None: + log.debug('cannot encode inm') + return False + self.parent.updown.value = 0 + val = self.encodeval(val) + if val is False: + return False + self.value = val + return True + # pure reg + if isinstance(e.args[1], ExprId): + rm = gpregs.expr.index(e.args[1]) + shift_kind = 0 + shift_type = 0 + amount = 0 + val = (((((amount << 2) | shift_type) << 1) | shift_kind) << 4) | rm + val = self.encodeval(val) + if val is False: + return False + self.value = val + return True + return False + + +class armt_op2imm00(armt_op2imm): + + def decodeval(self, v): + return v << 2 + + def encodeval(self, v): + if v & 3: + return False + return v >> 2 + + +class armt_deref_reg(arm_imm8_12): + parser = deref + + def decode(self, v): + base = self.parent.rn.expr + off = gpregs.expr[v] + if self.parent.imm.value != 0: + off = off << ExprInt(self.parent.imm.value, 32) + e = ExprMem(ExprOp('preinc', base, off), 8) + self.expr = e + return True + + def encode(self): + if not isinstance(self.expr, ExprMem): + return False + ptr = self.expr.ptr + if not ptr.is_op('preinc'): + return False + if len(ptr.args) != 2: + return False + base, off = ptr.args + if base.is_id() and off.is_id(): + self.parent.rn.expr = base + self.parent.imm.value = 0 + self.value = gpregs.expr.index(off) + elif off.is_int(): + return False + elif off.is_op('<<'): + if len(off.args) != 2: + return False + reg, off = off.args + self.parent.rn.expr = base + self.parent.imm.value = 0 + self.value = gpregs.expr.index(reg) + off = int(off) + if off > self.parent.imm.lmask: + return False + self.parent.imm.value = off + return True + + +class armt_deref_reg_reg(arm_arg): + parser = deref_reg_reg + reg_info = gpregs + + def decode(self, v): + expr = self.reg_info.expr[v] + expr = ExprMem(self.parent.rn.expr + expr, 8) + self.expr = expr + return True + + def encode(self): + expr = self.expr + if not expr.is_mem(): + return False + ptr = expr.ptr + if not ptr.is_op('+') or len(ptr.args) != 2: + return False + reg1, reg2 = ptr.args + self.parent.rn.expr = reg1 + self.value = self.reg_info.expr.index(reg2) + return True + + +class armt_deref_reg_reg_lsl_1(arm_reg): + parser = deref_reg_reg_lsl_1 + reg_info = gpregs + + def decode(self, v): + expr = self.reg_info.expr[v] + expr = ExprMem(self.parent.rn.expr + (expr << ExprInt(1, 32)), 16) + self.expr = expr + return True + + def encode(self): + expr = self.expr + if not expr.is_mem(): + return False + ptr = expr.ptr + if not ptr.is_op('+') or len(ptr.args) != 2: + return False + reg1, reg_shift = ptr.args + self.parent.rn.expr = reg1 + if not reg_shift.is_op('<<') or len(reg_shift.args) != 2: + return False + if reg_shift.args[1] != ExprInt(1, 32): + return False + self.value = self.reg_info.expr.index(reg_shift.args[0]) + return True + + +aif = bs(l=3, cls=(armt_aif,)) + + +imm5_off = bs(l=5, cls=(armt_imm5_1,), fname="imm5_off") + +tsign = bs(l=1, fname="sign") +tj1 = bs(l=1, fname="j1") +tj2 = bs(l=1, fname="j2") + +timm6h = bs(l=6, fname="imm6h") +timm10H = bs(l=10, fname="imm10h") +timm10L = bs(l=10, cls=(armt2_imm10l,), fname="imm10l") +timm11L = bs(l=11, cls=(armt2_imm11l,), fname="imm11l") + +timm6h11l = bs(l=11, cls=(armt2_imm6_11l,), fname="imm6h11l") + +itcond = bs(l=4, fname="itcond") +itmask = armt_itmask(l=4, fname="itmask") +bs_cond_arg_msb = bs(l=3, cls=(armt_cond_arg,)) + + +condlsb = armt_cond_lsb(l=1, fname="condlsb") + +deref_immpuw = bs(l=8, cls=(armt_op2imm,)) +deref_immpuw00 = bs(l=8, cls=(armt_op2imm00,)) + + +rm_deref_reg = bs(l=4, cls=(armt_deref_reg,)) + +bs_deref_reg_reg = bs(l=4, cls=(armt_deref_reg_reg,)) +bs_deref_reg_reg_lsl_1 = bs(l=4, cls=(armt_deref_reg_reg_lsl_1,)) + + +armtop("adc", [bs('11110'), imm12_1, bs('0'), bs('1010'), scc, rn_nosppc, bs('0'), imm12_3, rd_nosppc, imm12_8]) +armtop("adc", [bs('11101'), bs('01'), bs('1010'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh]) +armtop("bl", [bs('11110'), tsign, timm10H, bs('11'), tj1, bs('1'), tj2, timm11L]) +armtop("blx", [bs('11110'), tsign, timm10H, bs('11'), tj1, bs('0'), tj2, timm10L, bs('0')]) +armtop("cbz", [bs('101100'), imm1, bs('1'), imm5_off, rnl], [rnl, imm5_off]) +armtop("cbnz", [bs('101110'), imm1, bs('1'), imm5_off, rnl], [rnl, imm5_off]) + +armtop("bkpt", [bs('1011'), bs('1110'), imm8]) + + +armtop("it", [bs('10111111'), bs_cond_arg_msb, condlsb, itmask]) + + +armtop("nop", [bs8(0xBF),bs8(0x0)]) +armtop("wfi", [bs8(0xBF),bs8(0x30)]) +armtop("cpsid", [bs8(0xB6),bs('0111'), bs('0'), aif], [aif]) +armtop("cpsie", [bs8(0xB6),bs('0110'), bs('0'), aif], [aif]) + +armtop("push", [bs('1110100'), bs('10'), bs('0'), bs('1'), bs('0'), bs('1101'), bs('0'), pclr, bs('0'), trlist13], [trlist13]) +armtop("pop", [bs('1110100'), bs('01'), bs('0'), bs('1'), bs('1'), bs('1101'), pc_in, lr_in, bs('0'), trlist13pclr], [trlist13pclr]) +armtop("mov", [bs('11110'), imm12_1, bs('00010'), scc, bs('1111'), bs('0'), imm12_3, rd_nosppc, imm12_8]) +armtop("asr", [bs('11111010'), bs('0100'), rm, bs('1111'), rd, bs('0000'), rs], [rd, rm, rs]) +armtop("lsl", [bs('11111010'), bs('0000'), rm, bs('1111'), rd, bs('0000'), rs], [rd, rm, rs]) +armtop("sel", [bs('11111010'), bs('1010'), rm, bs('1111'), rd, bs('1000'), rs], [rd, rm, rs]) +armtop("rev", [bs('11111010'), bs('1001'), rm, bs('1111'), rd, bs('1000'), rm_cp], [rd, rm]) +armtop("uadd8", [bs('111110101000'), rn, bs('1111'), rd, bs('0100'), rm], [rd, rn, rm]) +armtop("mvn", [bs('11101010011'), scc, bs('11110'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh] ) +armtop("and", [bs('11101010000'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] ) +armtop("orr", [bs('11101010010'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] ) +armtop("bic", [bs('11101010001'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] ) +armtop("add", [bs('11101011000'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] ) +armtop("sub", [bs('11101011101'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] ) +armtop("eor", [bs('11101010100'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] ) +armtop("rsb", [bs('11101011110'), scc, rn, bs('0'), imm5_3, rd, imm5_2, imm_stype, rm_sh], [rd, rn, rm_sh] ) +armtop("orn", [bs('11101010011'), scc, rn_nopc, bs('0'), imm5_3, rd, imm5_2, imm_stype, rm_sh], [rd, rn_nopc, rm_sh] ) +# lsl +armtop("mov", [bs('11101010010'), scc, bs('1111'), bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype_00, rm_sh], [rd_nosppc, rm_sh] ) +armtop("mov", [bs('11101010010'), scc, bs('1111'), bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype_01, rm_sh], [rd_nosppc, rm_sh] ) +armtop("mov", [bs('11101010010'), scc, bs('1111'), bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype_11, rm_sh], [rd_nosppc, rm_sh] ) + + +armtop("orr", [bs('11110'), imm12_1, bs('00010'), scc, rn_nosppc, bs('0'), imm12_3, rd, imm12_8] ) +armtop("add", [bs('11110'), imm12_1, bs('01000'), bs('0'), rn, bs('0'), imm12_3, rd_nopc, imm12_8], [rd_nopc, rn, imm12_8]) +armtop("adds",[bs('11110'), imm12_1, bs('01000'), bs('1'), rn, bs('0'), imm12_3, rd_nopc, imm12_8], [rd_nopc, rn, imm12_8]) +armtop("bic", [bs('11110'), imm12_1, bs('00001'), scc, rn_nosppc, bs('0'), imm12_3, rd, imm12_8], [rd, rn_nosppc, imm12_8]) +armtop("and", [bs('11110'), imm12_1, bs('00000'), scc, rn, bs('0'), imm12_3, rd_nopc, imm12_8], [rd_nopc, rn, imm12_8]) +armtop("sub", [bs('11110'), imm12_1, bs('01101'), scc, rn, bs('0'), imm12_3, rd_nopc, imm12_8], [rd_nopc, rn, imm12_8]) +armtop("eor", [bs('11110'), imm12_1, bs('00100'), scc, rn, bs('0'), imm12_3, rd_nopc, imm12_8], [rd_nopc, rn, imm12_8]) +armtop("add", [bs('11110'), imm12_1, bs('10000'), scc, rn_nosppc, bs('0'), imm12_3, rd, imm12_8_t4], [rd, rn_nosppc, imm12_8_t4]) +armtop("cmp", [bs('11110'), imm12_1, bs('01101'), bs('1'), rn, bs('0'), imm12_3, bs('1111'), imm12_8] ) + +armtop("cmp", [bs('11101011101'), bs('1'), rn, bs('0'), imm5_3, bs('1111'), imm5_2, imm_stype, rm_sh], [rn, rm_sh] ) + +armtop("cmn", [bs('11110'), imm12_1, bs('01000'), bs('1'), rn, bs('0'), imm12_3, bs('1111'), imm12_8], [rn, imm12_8]) + + +armtop("mvn", [bs('11110'), imm12_1, bs('00011'), scc, bs('1111'), bs('0'), imm12_3, rd, imm12_8]) +armtop("rsb", [bs('11110'), imm12_1, bs('01110'), scc, rn_nosppc, bs('0'), imm12_3, rd, imm12_8], [rd, rn_nosppc, imm12_8]) +armtop("sub", [bs('11110'), imm12_1, bs('101010'), rn_nosppc, bs('0'), imm12_3, rd, imm12_8_t4], [rd, rn_nosppc, imm12_8_t4]) +armtop("tst", [bs('11110'), imm12_1, bs('000001'), rn, bs('0'), imm12_3, bs('1111'), imm12_8], [rn, imm12_8]) + +armtop("mov", [bs('11110'), imm16_1, bs('100100'), imm16_4, bs('0'), imm16_3, rd, imm16_8] ) +armtop("movt", [bs('11110'), imm16_1, bs('101100'), imm16_4, bs('0'), imm16_3, rd, imm16_8] ) + +armtop("sdiv", [bs('111110111001'), rn, bs('1111'), rd, bs('1111'), rm], [rd, rn, rm] ) +armtop("udiv", [bs('111110111011'), rn, bs('1111'), rd, bs('1111'), rm], [rd, rn, rm] ) +armtop("mls", [bs('111110110000'), rn, ra, rd, bs('0001'), rm], [rd, rn, rm, ra] ) +armtop("mla", [bs('111110110000'), rn, ra_nopc, rd, bs('0000'), rm], [rd, rn, rm, ra_nopc] ) +armtop("mul", [bs('111110110000'), rn, bs('1111'), rd, bs('0000'), rm], [rd, rn, rm] ) + +armtop("smlabb", [bs('111110110001'), rn, ra_nopc, rd, bs('00'), bs('00'), rm], [rd, rn, rm, ra_nopc]) +armtop("smlabt", [bs('111110110001'), rn, ra_nopc, rd, bs('00'), bs('01'), rm], [rd, rn, rm, ra_nopc]) +armtop("smlatb", [bs('111110110001'), rn, ra_nopc, rd, bs('00'), bs('10'), rm], [rd, rn, rm, ra_nopc]) +armtop("smlatt", [bs('111110110001'), rn, ra_nopc, rd, bs('00'), bs('11'), rm], [rd, rn, rm, ra_nopc]) + +armtop("b", [bs('11110'), tsign, bm_cond_barmt, timm6h, bs('10'), tj1, bs('0'), tj2, timm6h11l], [timm6h11l]) +armtop("b", [bs('11110'), tsign, timm10H, bs('10'), tj1, bs('1'), tj2, timm11L], [timm11L]) + +armtop("ubfx", [bs('111100111100'), rn, bs('0'), lsb5_3, rd, lsb5_2, bs('0'), widthm1], [rd, rn, lsb5_2, widthm1]) +armtop("uxth", [bs('111110100001'), bs('1111'), bs('1111'), rd, bs('10'), rot2, rm_rot2], [rd, rm_rot2]) + + + +armtop("str", [bs('111110001100'), rn_deref, rt, off12], [rt, rn_deref]) +armtop("str", [bs('111110000100'), rn_noarg, rt, bs('000000'), imm2_noarg, rm_deref_reg], [rt, rm_deref_reg]) +armtop("str", [bs('111110000100'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw]) +armtop("strb", [bs('111110001000'), rn_deref, rt, off12], [rt, rn_deref]) +armtop("strb", [bs('111110000000'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw]) +armtop("strh", [bs('111110001010'), rn_deref, rt, off12], [rt, rn_deref]) +armtop("strh", [bs('111110000010'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw]) + +armtop("strd", [bs('1110100'), ppi, updown, bs('1'), wback_no_t, bs('0'), rn_nopc_noarg, rt, rt2, deref_immpuw00], [rt, rt2, deref_immpuw00]) +armtop("ldrd", [bs('1110100'), ppi, updown, bs('1'), wback_no_t, bs('1'), rn_nopc_noarg, rt, rt2, deref_immpuw00], [rt, rt2, deref_immpuw00]) + + +armtop("ldr", [bs('111110001101'), rn_deref, rt, off12], [rt, rn_deref]) +armtop("ldr", [bs('111110000101'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw]) +armtop("ldr", [bs('111110000101'), rn_noarg, rt, bs('000000'), imm2_noarg, rm_deref_reg], [rt, rm_deref_reg]) +armtop("ldrb", [bs('111110000001'), rn_noarg, rt, bs('000000'), imm2_noarg, rm_deref_reg], [rt, rm_deref_reg]) +armtop("ldrb", [bs('111110000001'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw]) +armtop("ldrb", [bs('111110001001'), rn_deref, rt_nopc, off12], [rt_nopc, rn_deref]) +armtop("ldrsb",[bs('111110011001'), rn_deref, rt, off12], [rt, rn_deref]) +armtop("ldrsh",[bs('111110011011'), rn_deref, rt, off12], [rt, rn_deref]) +armtop("ldrh", [bs('111110001011'), rn_deref, rt, off12], [rt, rn_deref]) +armtop("ldrh", [bs('111110000011'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw]) + +armtop("pld", [bs('111110001001'), rn_deref, bs('1111'), off12], [rn_deref]) +armtop("pldw", [bs('111110001011'), rn_deref, bs('1111'), off12], [rn_deref]) + +armtop("clz", [bs('111110101011'), rm, bs('1111'), rd, bs('1000'), rm_cp], [rd, rm]) +armtop("tbb", [bs('111010001101'), rn_noarg, bs('11110000000'), bs('0'), bs_deref_reg_reg], [bs_deref_reg_reg]) +armtop("tbh", [bs('111010001101'), rn_noarg, bs('11110000000'), bs('1'), bs_deref_reg_reg_lsl_1], [bs_deref_reg_reg_lsl_1]) +armtop("dsb", [bs('111100111011'), bs('1111'), bs('1000'), bs('1111'), bs('0100'), barrier_option]) + +armtop("adr", [bs('11110'), imm12_1, bs('100000'), bs('1111'), bs('0'), imm12_3, rd, imm12_8_t4], [rd, imm12_8_t4]) diff --git a/src/miasm/arch/arm/disasm.py b/src/miasm/arch/arm/disasm.py new file mode 100644 index 00000000..e84f617d --- /dev/null +++ b/src/miasm/arch/arm/disasm.py @@ -0,0 +1,61 @@ +from future.utils import viewvalues + +from miasm.core.asmblock import AsmConstraint, disasmEngine +from miasm.arch.arm.arch import mn_arm, mn_armt + + +def cb_arm_fix_call(mdis, cur_block, offsets_to_dis): + """ + for arm: + MOV LR, PC + LDR PC, [R5, 0x14] + * is a subcall * + + """ + if len(cur_block.lines) < 2: + return + l1 = cur_block.lines[-1] + l2 = cur_block.lines[-2] + if l1.name != "LDR": + return + if l2.name != "MOV": + return + + values = viewvalues(mdis.arch.pc) + if not l1.args[0] in values: + return + if not l2.args[1] in values: + return + loc_key_cst = mdis.loc_db.get_or_create_offset_location(l1.offset + 4) + cur_block.add_cst(loc_key_cst, AsmConstraint.c_next) + offsets_to_dis.add(l1.offset + 4) + +cb_arm_funcs = [cb_arm_fix_call] + + +def cb_arm_disasm(*args, **kwargs): + for func in cb_arm_funcs: + func(*args, **kwargs) + + +class dis_armb(disasmEngine): + attrib = 'b' + def __init__(self, bs=None, **kwargs): + super(dis_armb, self).__init__(mn_arm, self.attrib, bs, **kwargs) + self.dis_block_callback = cb_arm_disasm + +class dis_arml(disasmEngine): + attrib = 'l' + def __init__(self, bs=None, **kwargs): + super(dis_arml, self).__init__(mn_arm, self.attrib, bs, **kwargs) + self.dis_block_callback = cb_arm_disasm + +class dis_armtb(disasmEngine): + attrib = 'b' + def __init__(self, bs=None, **kwargs): + super(dis_armtb, self).__init__(mn_armt, self.attrib, bs, **kwargs) + +class dis_armtl(disasmEngine): + attrib = 'l' + def __init__(self, bs=None, **kwargs): + super(dis_armtl, self).__init__(mn_armt, self.attrib, bs, **kwargs) diff --git a/src/miasm/arch/arm/jit.py b/src/miasm/arch/arm/jit.py new file mode 100644 index 00000000..27c26988 --- /dev/null +++ b/src/miasm/arch/arm/jit.py @@ -0,0 +1,144 @@ +from builtins import range +import logging + +from miasm.jitter.jitload import Jitter, named_arguments +from miasm.core.utils import pck32, upck32 +from miasm.arch.arm.sem import Lifter_Armb, Lifter_Arml, Lifter_Armtl, Lifter_Armtb, cond_dct_inv, tab_cond +from miasm.jitter.codegen import CGen +from miasm.expression.expression import ExprId, ExprAssign, ExprCond +from miasm.ir.ir import IRBlock, AssignBlock +from miasm.ir.translators.C import TranslatorC +from miasm.expression.simplifications import expr_simp_high_to_explicit + +log = logging.getLogger('jit_arm') +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) + + + +class arm_CGen(CGen): + + def block2assignblks(self, block): + """ + Return the list of irblocks for a native @block + @block: AsmBlock + """ + irblocks_list = [] + index = -1 + while index + 1 < len(block.lines): + index += 1 + instr = block.lines[index] + + if instr.name.startswith("IT"): + assignments = [] + label = self.lifter.get_instr_label(instr) + irblocks = [] + index, irblocks = self.lifter.do_it_block(label, index, block, assignments, True) + irblocks_list += irblocks + continue + + + assignblk_head, assignblks_extra = self.lifter.instr2ir(instr) + # Keep result in ordered list as first element is the assignblk head + # The remainings order is not really important + irblock_head = self.assignblk_to_irbloc(instr, assignblk_head) + irblocks = [irblock_head] + assignblks_extra + + + # Simplify high level operators + out = [] + for irblock in irblocks: + new_irblock = irblock.simplify(expr_simp_high_to_explicit)[1] + out.append(new_irblock) + irblocks = out + + + for irblock in irblocks: + assert irblock.dst is not None + irblocks_list.append(irblocks) + return irblocks_list + + +class jitter_arml(Jitter): + C_Gen = arm_CGen + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_Arml(loc_db), *args, **kwargs) + self.vm.set_little_endian() + + def push_uint32_t(self, value): + self.cpu.SP -= 4 + self.vm.set_mem(self.cpu.SP, pck32(value)) + + def pop_uint32_t(self): + value = self.vm.get_u32(self.cpu.SP) + self.cpu.SP += 4 + return value + + def get_stack_arg(self, index): + return self.vm.get_u32(self.cpu.SP + 4 * index) + + # calling conventions + + @named_arguments + def func_args_stdcall(self, n_args): + args = [self.get_arg_n_stdcall(i) for i in range(n_args)] + ret_ad = self.cpu.LR + return ret_ad, args + + def func_ret_stdcall(self, ret_addr, ret_value1=None, ret_value2=None): + self.pc = self.cpu.PC = ret_addr + if ret_value1 is not None: + self.cpu.R0 = ret_value1 + if ret_value2 is not None: + self.cpu.R1 = ret_value2 + return True + + def func_prepare_stdcall(self, ret_addr, *args): + for index in range(min(len(args), 4)): + setattr(self.cpu, 'R%d' % index, args[index]) + for index in reversed(range(4, len(args))): + self.push_uint32_t(args[index]) + self.cpu.LR = ret_addr + + def get_arg_n_stdcall(self, index): + if index < 4: + arg = getattr(self.cpu, 'R%d' % index) + else: + arg = self.get_stack_arg(index-4) + return arg + + func_args_systemv = func_args_stdcall + func_ret_systemv = func_ret_stdcall + func_prepare_systemv = func_prepare_stdcall + get_arg_n_systemv = get_arg_n_stdcall + + def syscall_args_systemv(self, n_args): + args = [self.cpu.R0, self.cpu.R1, self.cpu.R2, self.cpu.R3, + self.cpu.R4, self.cpu.R5][:n_args] + return args + + def syscall_ret_systemv(self, value): + self.cpu.R0 = value + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.PC = self.pc + + +class jitter_armb(jitter_arml): + C_Gen = arm_CGen + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_Armb(loc_db), *args, **kwargs) + self.vm.set_big_endian() + + +class jitter_armtl(jitter_arml): + C_Gen = arm_CGen + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_Armtl(loc_db), *args, **kwargs) + self.vm.set_little_endian() diff --git a/src/miasm/arch/arm/lifter_model_call.py b/src/miasm/arch/arm/lifter_model_call.py new file mode 100644 index 00000000..9aac74a4 --- /dev/null +++ b/src/miasm/arch/arm/lifter_model_call.py @@ -0,0 +1,106 @@ +#-*- coding:utf-8 -*- + +from miasm.ir.analysis import LifterModelCall +from miasm.ir.ir import IRBlock +from miasm.arch.arm.sem import Lifter_Arml, Lifter_Armtl, Lifter_Armb, Lifter_Armtb, tab_cond +from miasm.expression.expression import ExprAssign, ExprOp, ExprLoc, ExprCond +from miasm.ir.ir import AssignBlock + +class LifterModelCallArmlBase(Lifter_Arml, LifterModelCall): + def __init__(self, loc_db): + Lifter_Arml.__init__(self, loc_db) + self.ret_reg = self.arch.regs.R0 + +class LifterModelCallArmbBase(Lifter_Armb, LifterModelCall): + def __init__(self, loc_db): + Lifter_Armb.__init__(self, loc_db) + self.ret_reg = self.arch.regs.R0 + + +class LifterModelCallArml(LifterModelCallArmlBase): + + def __init__(self, loc_db): + LifterModelCallArmlBase.__init__(self, loc_db) + self.ret_reg = self.arch.regs.R0 + + def call_effects(self, ad, instr): + call_assignblk = AssignBlock( + [ + ExprAssign( + self.ret_reg, + ExprOp( + 'call_func_ret', + ad, + self.arch.regs.R0, + self.arch.regs.R1, + self.arch.regs.R2, + self.arch.regs.R3, + ) + ), + ExprAssign( + self.sp, + ExprOp('call_func_stack', ad, self.sp) + ), + ], + instr + ) + + + cond = instr.additional_info.cond + if cond == 14: # COND_ALWAYS: + return [call_assignblk], [] + + # Call is a conditional instruction + cond = tab_cond[cond] + + loc_next = self.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 32) + loc_do = self.loc_db.add_location() + loc_do_expr = ExprLoc(loc_do, 32) + dst_cond = ExprCond(cond, loc_do_expr, loc_next_expr) + + call_assignblks = [ + call_assignblk, + AssignBlock([ExprAssign(self.IRDst, loc_next_expr)], instr), + ] + e_do = IRBlock(self.loc_db, loc_do, call_assignblks) + assignblks_out = [ + AssignBlock([ExprAssign(self.IRDst, dst_cond)], instr) + ] + return assignblks_out, [e_do] + + + def get_out_regs(self, _): + return set([self.ret_reg, self.sp]) + + def sizeof_char(self): + return 8 + + def sizeof_short(self): + return 16 + + def sizeof_int(self): + return 32 + + def sizeof_long(self): + return 32 + + def sizeof_pointer(self): + return 32 + +class LifterModelCallArmb(LifterModelCallArmbBase, LifterModelCallArml): + + def __init__(self, loc_db): + LifterModelCallArmbBase.__init__(self, loc_db) + self.ret_reg = self.arch.regs.R0 + + +class LifterModelCallArmtl(Lifter_Armtl, LifterModelCallArml): + def __init__(self, loc_db): + Lifter_Armtl.__init__(self, loc_db) + self.ret_reg = self.arch.regs.R0 + +class LifterModelCallArmtb(LifterModelCallArmtl, Lifter_Armtb, LifterModelCallArmb): + def __init__(self, loc_db): + Lifter_Armtb.__init__(self, loc_db) + self.ret_reg = self.arch.regs.R0 diff --git a/src/miasm/arch/arm/regs.py b/src/miasm/arch/arm/regs.py new file mode 100644 index 00000000..2b24b0d5 --- /dev/null +++ b/src/miasm/arch/arm/regs.py @@ -0,0 +1,177 @@ +#-*- coding:utf-8 -*- + +from builtins import range +from miasm.expression.expression import * +from miasm.core.cpu import gen_reg, gen_regs + +# GP + +regs32_str = ["R%d" % i for i in range(13)] + ["SP", "LR", "PC"] +regs32_expr = [ExprId(x, 32) for x in regs32_str] + +exception_flags = ExprId('exception_flags', 32) +interrupt_num = ExprId('interrupt_num', 32) +bp_num = ExprId('bp_num', 32) + + +R0 = regs32_expr[0] +R1 = regs32_expr[1] +R2 = regs32_expr[2] +R3 = regs32_expr[3] +R4 = regs32_expr[4] +R5 = regs32_expr[5] +R6 = regs32_expr[6] +R7 = regs32_expr[7] +R8 = regs32_expr[8] +R9 = regs32_expr[9] +R10 = regs32_expr[10] +R11 = regs32_expr[11] +R12 = regs32_expr[12] +SP = regs32_expr[13] +LR = regs32_expr[14] +PC = regs32_expr[15] + +R0_init = ExprId("R0_init", 32) +R1_init = ExprId("R1_init", 32) +R2_init = ExprId("R2_init", 32) +R3_init = ExprId("R3_init", 32) +R4_init = ExprId("R4_init", 32) +R5_init = ExprId("R5_init", 32) +R6_init = ExprId("R6_init", 32) +R7_init = ExprId("R7_init", 32) +R8_init = ExprId("R8_init", 32) +R9_init = ExprId("R9_init", 32) +R10_init = ExprId("R10_init", 32) +R11_init = ExprId("R11_init", 32) +R12_init = ExprId("R12_init", 32) +SP_init = ExprId("SP_init", 32) +LR_init = ExprId("LR_init", 32) +PC_init = ExprId("PC_init", 32) + + +reg_zf = 'zf' +reg_nf = 'nf' +reg_of = 'of' +reg_cf = 'cf' + +zf = ExprId(reg_zf, size=1) +nf = ExprId(reg_nf, size=1) +of = ExprId(reg_of, size=1) +cf = ExprId(reg_cf, size=1) + +zf_init = ExprId("zf_init", size=1) +nf_init = ExprId("nf_init", size=1) +of_init = ExprId("of_init", size=1) +cf_init = ExprId("cf_init", size=1) + + +reg_ge0 = 'ge0' +reg_ge1 = 'ge1' +reg_ge2 = 'ge2' +reg_ge3 = 'ge3' + +ge0 = ExprId(reg_ge0, size=1) +ge1 = ExprId(reg_ge1, size=1) +ge2 = ExprId(reg_ge2, size=1) +ge3 = ExprId(reg_ge3, size=1) + +ge0_init = ExprId("ge0_init", size=1) +ge1_init = ExprId("ge1_init", size=1) +ge2_init = ExprId("ge2_init", size=1) +ge3_init = ExprId("ge3_init", size=1) + +ge_regs = [ge0, ge1, ge2, ge3] + +all_regs_ids = [ + R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, SP, LR, PC, + zf, nf, of, cf, + ge0, ge1, ge2, ge3, + exception_flags, interrupt_num, bp_num +] + +all_regs_ids_no_alias = all_regs_ids + +attrib_to_regs = { + 'l': all_regs_ids_no_alias, + 'b': all_regs_ids_no_alias, +} + +all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) + +all_regs_ids_init = [R0_init, R1_init, R2_init, R3_init, + R4_init, R5_init, R6_init, R7_init, + R8_init, R9_init, R10_init, R11_init, + R12_init, SP_init, LR_init, PC_init, + zf_init, nf_init, of_init, cf_init, + ge0_init, ge1_init, ge2_init, ge3_init, + ExprInt(0, 32), ExprInt(0, 32), ExprInt(0, 32) + ] + +regs_init = {} +for i, r in enumerate(all_regs_ids): + regs_init[r] = all_regs_ids_init[i] + +coproc_reg_str = [ + "MIDR", "CTR", "TCMTR", "TLBTR", "MIDR", "MPIDR", "REVIDR", + "ID_PFR0", "ID_PFR1", "ID_DFR0", "ID_AFR0", "ID_MMFR0", "ID_MMFR1", "ID_MMFR2", "ID_MMFR3", + "ID_ISAR0", "ID_ISAR1", "ID_ISAR2", "ID_ISAR3", "ID_ISAR4", "ID_ISAR5", + "CCSIDR", "CLIDR", "AIDR", + "CSSELR", + "VPIDR", "VMPIDR", + "SCTLR", "ACTLR", "CPACR", + "SCR", "SDER", "NSACR", + "HSCTLR", "HACTLR", + "HCR", "HDCR", "HCPTR", "HSTR", "HACR", + "TTBR0", "TTBR1", "TTBCR", + "HTCR", "VTCR", + "DACR", + "DFSR", "IFSR", + "ADFSR", "AIFSR", + "HADFSR", "HAIFSR", + "HSR", + "DFAR", "IFAR", + "HDFAR", "HIFAR", "HPFAR", + "ICIALLUIS", "BPIALLIS", + "PAR", + "ICIALLU", "ICIMVAU", "CP15ISB", "BPIALL", "BPIMVA", + "DCIMVAC", "DCISW", + "ATS1CPR", "ATS1CPW", "ATS1CUR", "ATS1CUW", "ATS12NSOPR", "ATS12NSOPW", "ATS12NSOUR", "ATS12NSOUW", + "DCCMVAC", "DCCSW", "CP15DSB", "CP15DMB", + "DCCMVAU", + "DCCIMVAC", "DCCISW", + "ATS1HR", "ATS1HW", + "TLBIALLIS", "TLBIMVAIS", "TLBIASIDIS", "TLBIMVAAIS", + "ITLBIALL", "ITLBIMVA", "ITLBIASID", + "DTLBIALL", "DTLBIMVA", "DTLBIASID", + "TLBIALL", "TLBIMVA", "TLBIASID", "TLBIMVAA", + "TLBIALLHIS", "TLBIMVAHIS", "TLBIALLNSNHIS", + "TLBIALLH", "TLBIMVAH", "TLBIALLNSNH", + "PMCR", "PMCNTENSET", "PMCNTENCLR", "PMOVSR", "PMSWINC", "PMSELR", "PMCEID0", "PMCEID1", + "PMCCNTR", "PMXEVTYPER", "PMXEVCNTR", + "PMUSERENR", "PMINTENSET", "PMINTENCLR", "PMOVSSET", + "PRRR", "NMRR", + "AMAIR0", "AMAIR1", + "HMAIR0", "HMAIR1", + "HAMAIR0", "HAMAIR1", + "VBAR", "MVBAR", + "ISR", + "HVBAR", + "FCSEIDR", "CONTEXTIDR", "TPIDRURW", "TPIDRURO", "TPIDRPRW", + "HTPIDR", + "CNTFRQ", + "CNTKCTL", + "CNTP_TVAL", "CNTP_CTL", + "CNTV_TVAL", "CNTV_CTL", + "CNTHCTL", + "CNTHP_TVAL", "CNTHP_CTL" + ] +coproc_reg_expr, coproc_reg_init, coproc_reg_info = gen_regs(coproc_reg_str, globals(), 32) + +all_regs_ids = all_regs_ids + coproc_reg_expr +all_regs_ids_byname.update(dict([(x.name, x) for x in coproc_reg_expr])) +all_regs_ids_init = all_regs_ids_init + coproc_reg_init + +for i, r in enumerate(coproc_reg_expr): + regs_init[r] = coproc_reg_init[i] + +regs_flt_expr = [] diff --git a/src/miasm/arch/arm/sem.py b/src/miasm/arch/arm/sem.py new file mode 100644 index 00000000..a138ef91 --- /dev/null +++ b/src/miasm/arch/arm/sem.py @@ -0,0 +1,2305 @@ +from builtins import range +from future.utils import viewitems, viewvalues + +from miasm.expression.expression import * +from miasm.expression.simplifications import expr_simp +from miasm.ir.ir import Lifter, IRBlock, AssignBlock +from miasm.arch.arm.arch import mn_arm, mn_armt +from miasm.arch.arm.regs import * + +from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO, EXCEPT_INT_XX + +coproc_reg_dict = { + ("p15", "c0", 0, "c0", 0): MIDR, + ("p15", "c0", 0, "c0", 1): CTR, + ("p15", "c0", 0, "c0", 2): TCMTR, + ("p15", "c0", 0, "c0", 3): TLBTR, + ("p15", "c0", 0, "c0", 4): MIDR, + ("p15", "c0", 0, "c0", 5): MPIDR, + ("p15", "c0", 0, "c0", 6): REVIDR, + ("p15", "c0", 0, "c0", 7): MIDR, + + ("p15", "c0", 0, "c1", 0): ID_PFR0, + ("p15", "c0", 0, "c1", 1): ID_PFR1, + ("p15", "c0", 0, "c1", 2): ID_DFR0, + ("p15", "c0", 0, "c1", 3): ID_AFR0, + ("p15", "c0", 0, "c1", 4): ID_MMFR0, + ("p15", "c0", 0, "c1", 5): ID_MMFR1, + ("p15", "c0", 0, "c1", 6): ID_MMFR2, + ("p15", "c0", 0, "c1", 7): ID_MMFR3, + + ("p15", "c0", 0, "c2", 0): ID_ISAR0, + ("p15", "c0", 0, "c2", 1): ID_ISAR1, + ("p15", "c0", 0, "c2", 2): ID_ISAR2, + ("p15", "c0", 0, "c2", 3): ID_ISAR3, + ("p15", "c0", 0, "c2", 4): ID_ISAR4, + ("p15", "c0", 0, "c2", 5): ID_ISAR5, + + ("p15", "c0", 1, "c0", 0): CCSIDR, + ("p15", "c0", 1, "c0", 1): CLIDR, + ("p15", "c0", 1, "c0", 7): AIDR, + + ("p15", "c0", 2, "c0", 0): CSSELR, + + ("p15", "c0", 4, "c0", 0): VPIDR, + ("p15", "c0", 4, "c0", 5): VMPIDR, + + ("p15", "c1", 0, "c0", 0): SCTLR, + ("p15", "c1", 0, "c0", 1): ACTLR, + ("p15", "c1", 0, "c0", 2): CPACR, + + ("p15", "c1", 0, "c1", 0): SCR, + ("p15", "c1", 0, "c1", 1): SDER, + ("p15", "c1", 0, "c1", 2): NSACR, + + ("p15", "c1", 4, "c0", 0): HSCTLR, + ("p15", "c1", 4, "c0", 1): HACTLR, + + ("p15", "c1", 4, "c1", 0): HCR, + ("p15", "c1", 4, "c1", 1): HDCR, + ("p15", "c1", 4, "c1", 2): HCPTR, + ("p15", "c1", 4, "c1", 3): HSTR, + ("p15", "c1", 4, "c1", 7): HACR, + + # TODO: TTBRO/TTBR1 64-bit + ("p15", "c2", 0, "c0", 0): TTBR0, + ("p15", "c2", 0, "c0", 1): TTBR1, + ("p15", "c2", 0, "c0", 2): TTBCR, + + ("p15", "c2", 4, "c0", 2): HTCR, + + ("p15", "c2", 4, "c1", 2): VTCR, + + # TODO: HTTBR, VTTBR + + ("p15", "c3", 0, "c0", 0): DACR, + + ("p15", "c5", 0, "c0", 0): DFSR, + ("p15", "c5", 0, "c0", 1): IFSR, + + ("p15", "c5", 0, "c1", 0): ADFSR, + ("p15", "c5", 0, "c1", 1): AIFSR, + + ("p15", "c5", 4, "c1", 0): HADFSR, + ("p15", "c5", 4, "c1", 1): HAIFSR, + + ("p15", "c5", 4, "c2", 0): HSR, + + ("p15", "c6", 0, "c1", 0): DFAR, + ("p15", "c6", 0, "c1", 2): IFAR, + + ("p15", "c6", 4, "c0", 0): HDFAR, + ("p15", "c6", 4, "c0", 2): HIFAR, + ("p15", "c6", 4, "c0", 4): HPFAR, + + ("p15", "c7", 0, "c1", 0): ICIALLUIS, + ("p15", "c7", 0, "c1", 6): BPIALLIS, + + ("p15", "c7", 0, "c4", 0): PAR, + + # TODO: PAR 64-bit + + ("p15", "c7", 0, "c5", 0): ICIALLU, + ("p15", "c7", 0, "c5", 1): ICIMVAU, + ("p15", "c7", 0, "c5", 4): CP15ISB, + ("p15", "c7", 0, "c5", 6): BPIALL, + ("p15", "c7", 0, "c5", 7): BPIMVA, + + ("p15", "c7", 0, "c6", 1): DCIMVAC, + ("p15", "c7", 0, "c6", 2): DCISW, + + ("p15", "c7", 0, "c8", 0): ATS1CPR, + ("p15", "c7", 0, "c8", 1): ATS1CPW, + ("p15", "c7", 0, "c8", 2): ATS1CUR, + ("p15", "c7", 0, "c8", 3): ATS1CUW, + ("p15", "c7", 0, "c8", 4): ATS12NSOPR, + ("p15", "c7", 0, "c8", 5): ATS12NSOPW, + ("p15", "c7", 0, "c8", 6): ATS12NSOUR, + ("p15", "c7", 0, "c8", 7): ATS12NSOUW, + + ("p15", "c7", 0, "c10", 1): DCCMVAC, + ("p15", "c7", 0, "c10", 2): DCCSW, + ("p15", "c7", 0, "c10", 4): CP15DSB, + ("p15", "c7", 0, "c10", 5): CP15DMB, + + ("p15", "c7", 0, "c11", 1): DCCMVAU, + + ("p15", "c7", 0, "c14", 1): DCCIMVAC, + ("p15", "c7", 0, "c14", 2): DCCISW, + + ("p15", "c7", 4, "c8", 0): ATS1HR, + ("p15", "c7", 4, "c8", 1): ATS1HW, + + ("p15", "c8", 0, "c3", 0): TLBIALLIS, + ("p15", "c8", 0, "c3", 1): TLBIMVAIS, + ("p15", "c8", 0, "c3", 2): TLBIASIDIS, + ("p15", "c8", 0, "c3", 3): TLBIMVAAIS, + + ("p15", "c8", 0, "c5", 0): ITLBIALL, + ("p15", "c8", 0, "c5", 1): ITLBIMVA, + ("p15", "c8", 0, "c5", 2): ITLBIASID, + + ("p15", "c8", 0, "c6", 0): DTLBIALL, + ("p15", "c8", 0, "c6", 1): DTLBIMVA, + ("p15", "c8", 0, "c6", 2): DTLBIASID, + + ("p15", "c8", 0, "c7", 0): TLBIALL, + ("p15", "c8", 0, "c7", 1): TLBIMVA, + ("p15", "c8", 0, "c7", 2): TLBIASID, + ("p15", "c8", 0, "c7", 3): TLBIMVAA, + + ("p15", "c8", 4, "c3", 0): TLBIALLHIS, + ("p15", "c8", 4, "c3", 1): TLBIMVAHIS, + ("p15", "c8", 4, "c3", 4): TLBIALLNSNHIS, + + ("p15", "c8", 4, "c7", 0): TLBIALLH, + ("p15", "c8", 4, "c7", 1): TLBIMVAH, + ("p15", "c8", 4, "c7", 2): TLBIALLNSNH, + + ("p15", "c9", 0, "c12", 0): PMCR, + ("p15", "c9", 0, "c12", 1): PMCNTENSET, + ("p15", "c9", 0, "c12", 2): PMCNTENCLR, + ("p15", "c9", 0, "c12", 3): PMOVSR, + ("p15", "c9", 0, "c12", 4): PMSWINC, + ("p15", "c9", 0, "c12", 5): PMSELR, + ("p15", "c9", 0, "c12", 6): PMCEID0, + ("p15", "c9", 0, "c12", 7): PMCEID1, + + ("p15", "c9", 0, "c13", 0): PMCCNTR, + ("p15", "c9", 0, "c13", 1): PMXEVTYPER, + ("p15", "c9", 0, "c13", 2): PMXEVCNTR, + + ("p15", "c9", 0, "c14", 0): PMUSERENR, + ("p15", "c9", 0, "c14", 1): PMINTENSET, + ("p15", "c9", 0, "c14", 2): PMINTENCLR, + ("p15", "c9", 0, "c14", 3): PMOVSSET, + + ("p15", "c10", 0, "c2", 0): PRRR, # ALIAS MAIR0 + ("p15", "c10", 0, "c2", 1): NMRR, # ALIAS MAIR1 + + ("p15", "c10", 0, "c3", 0): AMAIR0, + ("p15", "c10", 0, "c3", 1): AMAIR1, + + ("p15", "c10", 4, "c2", 0): HMAIR0, + ("p15", "c10", 4, "c2", 1): HMAIR1, + + ("p15", "c10", 4, "c3", 0): HAMAIR0, + ("p15", "c10", 4, "c3", 1): HAMAIR1, + + ("p15", "c12", 0, "c0", 0): VBAR, + ("p15", "c12", 0, "c0", 1): MVBAR, + + ("p15", "c12", 0, "c1", 0): ISR, + + ("p15", "c12", 4, "c0", 0): HVBAR, + + ("p15", "c13", 0, "c0", 0): FCSEIDR, + ("p15", "c13", 0, "c0", 1): CONTEXTIDR, + ("p15", "c13", 0, "c0", 2): TPIDRURW, + ("p15", "c13", 0, "c0", 3): TPIDRURO, + ("p15", "c13", 0, "c0", 4): TPIDRPRW, + + ("p15", "c13", 4, "c0", 2): HTPIDR, + + ("p15", "c14", 0, "c0", 0): CNTFRQ, + # TODO: CNTPCT 64-bit + + ("p15", "c14", 0, "c1", 0): CNTKCTL, + + ("p15", "c14", 0, "c2", 0): CNTP_TVAL, + ("p15", "c14", 0, "c2", 1): CNTP_CTL, + + ("p15", "c14", 0, "c3", 0): CNTV_TVAL, + ("p15", "c14", 0, "c3", 1): CNTV_CTL, + + # TODO: CNTVCT, CNTP_CVAL, CNTV_CVAL, CNTVOFF 64-bit + + ("p15", "c14", 4, "c1", 0): CNTHCTL, + + ("p15", "c14", 4, "c2", 0): CNTHP_TVAL, + ("p15", "c14", 4, "c2", 0): CNTHP_CTL + + # TODO: CNTHP_CVAL 64-bit + } + +# liris.cnrs.fr/~mmrissa/lib/exe/fetch.php?media=armv7-a-r-manual.pdf +EXCEPT_SOFT_BP = (1 << 1) + +EXCEPT_PRIV_INSN = (1 << 17) + +# CPSR: N Z C V + + +def update_flag_zf(a): + return [ExprAssign(zf, ExprOp("FLAG_EQ", a))] + + +def update_flag_zf_eq(a, b): + return [ExprAssign(zf, ExprOp("FLAG_EQ_CMP", a, b))] + + +def update_flag_nf(arg): + return [ + ExprAssign( + nf, + ExprOp("FLAG_SIGN_SUB", arg, ExprInt(0, arg.size)) + ) + ] + + +def update_flag_zn(a): + e = [] + e += update_flag_zf(a) + e += update_flag_nf(a) + return e + + +# Instructions which use shifter's carry flag: ANDS, BICS, EORS, MOVS/RRX, MVNS, ORNS (TODO), ORRS, TEQ, TST +def compute_rrx_carry(operation): + """ + Returns a tuple (result, carry) corresponding to the RRX computation + @operation: The ExprOp operation + """ + new_cf = operation.args[0][:1] + res = ExprCompose(operation.args[0][1:], cf) + return res, new_cf + +# XXX TODO: set cf if ROT imm in argument + + +def check_ops_msb(a, b, c): + if not a or not b or not c or a != b or a != c: + raise ValueError('bad ops size %s %s %s' % (a, b, c)) + +def update_flag_add_cf(op1, op2): + "Compute cf in @op1 + @op2" + return [ExprAssign(cf, ExprOp("FLAG_ADD_CF", op1, op2))] + + +def update_flag_add_of(op1, op2): + "Compute of in @op1 + @op2" + return [ExprAssign(of, ExprOp("FLAG_ADD_OF", op1, op2))] + + +def update_flag_sub_cf(op1, op2): + "Compute CF in @op1 - @op2" + return [ExprAssign(cf, ExprOp("FLAG_SUB_CF", op1, op2) ^ ExprInt(1, 1))] + + +def update_flag_sub_of(op1, op2): + "Compute OF in @op1 - @op2" + return [ExprAssign(of, ExprOp("FLAG_SUB_OF", op1, op2))] + + +def update_flag_arith_add_co(arg1, arg2): + e = [] + e += update_flag_add_cf(arg1, arg2) + e += update_flag_add_of(arg1, arg2) + return e + + +def update_flag_arith_add_zn(arg1, arg2): + """ + Compute zf and nf flags for (arg1 + arg2) + """ + e = [] + e += update_flag_zf_eq(arg1, -arg2) + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, -arg2))] + return e + + +def update_flag_arith_sub_co(arg1, arg2): + """ + Compute cf and of flags for (arg1 - arg2) + """ + e = [] + e += update_flag_sub_cf(arg1, arg2) + e += update_flag_sub_of(arg1, arg2) + return e + + +def update_flag_arith_sub_zn(arg1, arg2): + """ + Compute zf and nf flags for (arg1 - arg2) + """ + e = [] + e += update_flag_zf_eq(arg1, arg2) + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, arg2))] + return e + + + + +def update_flag_zfaddwc_eq(arg1, arg2, arg3): + return [ExprAssign(zf, ExprOp("FLAG_EQ_ADDWC", arg1, arg2, arg3))] + +def update_flag_zfsubwc_eq(arg1, arg2, arg3): + return [ExprAssign(zf, ExprOp("FLAG_EQ_SUBWC", arg1, arg2, arg3))] + + +def update_flag_arith_addwc_zn(arg1, arg2, arg3): + """ + Compute znp flags for (arg1 + arg2 + cf) + """ + e = [] + e += update_flag_zfaddwc_eq(arg1, arg2, arg3) + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_ADDWC", arg1, arg2, arg3))] + return e + + +def update_flag_arith_subwc_zn(arg1, arg2, arg3): + """ + Compute znp flags for (arg1 - (arg2 + cf)) + """ + e = [] + e += update_flag_zfsubwc_eq(arg1, arg2, arg3) + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUBWC", arg1, arg2, arg3))] + return e + + +def update_flag_addwc_cf(op1, op2, op3): + "Compute cf in @res = @op1 + @op2 + @op3" + return [ExprAssign(cf, ExprOp("FLAG_ADDWC_CF", op1, op2, op3))] + + +def update_flag_addwc_of(op1, op2, op3): + "Compute of in @res = @op1 + @op2 + @op3" + return [ExprAssign(of, ExprOp("FLAG_ADDWC_OF", op1, op2, op3))] + + +def update_flag_arith_addwc_co(arg1, arg2, arg3): + e = [] + e += update_flag_addwc_cf(arg1, arg2, arg3) + e += update_flag_addwc_of(arg1, arg2, arg3) + return e + + + +def update_flag_subwc_cf(op1, op2, op3): + "Compute cf in @res = @op1 + @op2 + @op3" + return [ExprAssign(cf, ExprOp("FLAG_SUBWC_CF", op1, op2, op3) ^ ExprInt(1, 1))] + + +def update_flag_subwc_of(op1, op2, op3): + "Compute of in @res = @op1 + @op2 + @op3" + return [ExprAssign(of, ExprOp("FLAG_SUBWC_OF", op1, op2, op3))] + + +def update_flag_arith_subwc_co(arg1, arg2, arg3): + e = [] + e += update_flag_subwc_cf(arg1, arg2, arg3) + e += update_flag_subwc_of(arg1, arg2, arg3) + return e + +# Utility function for flag computation when it depends on the mode +def isThumb(lifter): + return isinstance(lifter, (Lifter_Armtl, Lifter_Armtb)) + + +def get_dst(a): + if a == PC: + return PC + return None + +# instruction definition ############## + + +def adc(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + arg1, arg2 = b, c + r = b + c + cf.zeroExtend(32) + if instr.name == 'ADCS' and a != PC: + e += update_flag_arith_addwc_zn(arg1, arg2, cf) + e += update_flag_arith_addwc_co(arg1, arg2, cf) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def add(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + arg1, arg2 = b, c + r = b + c + if instr.name == 'ADDS' and a != PC: + e += update_flag_arith_add_zn(arg1, arg2) + e += update_flag_arith_add_co(arg1, arg2) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def l_and(ir, instr, a, b, c=None): + setflags = (instr.name == 'ANDS') and a != PC + if c is None: + b, c = a, b + if c.is_op(): + e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags) + # get back the result + c = e.pop(0).src + else: + e = [] + extra_ir = [] + r = b & c + if setflags: + e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', b, c))] + e += update_flag_nf(r) + + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, extra_ir + +def sub(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + r = b - c + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def subs(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + arg1, arg2 = b, c + r = b - c + e += update_flag_arith_sub_zn(arg1, arg2) + e += update_flag_arith_sub_co(arg1, arg2) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def eor(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + r = b ^ c + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def eors(ir, instr, a, b, c=None): + setflags = a != PC + if c is None: + b, c = a, b + if c.is_op(): + e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags) + # get back the result + c = e.pop(0).src + else: + e = [] + extra_ir = [] + arg1, arg2 = b, c + r = arg1 ^ arg2 + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_CMP', arg1, arg2))] + e += update_flag_nf(r) + + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, extra_ir + + +def rsb(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + arg1, arg2 = c, b + r = arg1 - arg2 + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def rsbs(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + arg1, arg2 = c, b + r = arg1 - arg2 + e += update_flag_arith_sub_zn(arg1, arg2) + e += update_flag_arith_sub_co(arg1, arg2) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def sbc(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + arg1, arg2 = b, c + r = arg1 - (arg2 + (~cf).zeroExtend(32)) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def sbcs(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + arg1, arg2 = b, c + r = arg1 - (arg2 + (~cf).zeroExtend(32)) + + e += update_flag_arith_subwc_zn(arg1, arg2, ~cf) + e += update_flag_arith_subwc_co(arg1, arg2, ~cf) + + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def rsc(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + arg1, arg2 = c, b + r = arg1 - (arg2 + (~cf).zeroExtend(32)) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def rscs(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + arg1, arg2 = c, b + r = arg1 - (arg2 + (~cf).zeroExtend(32)) + + e += update_flag_arith_subwc_zn(arg1, arg2, ~cf) + e += update_flag_arith_subwc_co(arg1, arg2, ~cf) + + e.append(ExprAssign(a, r)) + + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def tst(ir, instr, a, b): + setflags = a != PC + if b.is_op(): + e, extra_ir = _shift_rotate_tpl(ir, instr, a, b, onlyCarry=setflags) + # get back the result + b = e.pop(0).src + else: + e = [] + extra_ir = [] + arg1, arg2 = a, b + r = arg1 & arg2 + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))] + e += update_flag_nf(r) + + return e, extra_ir + + +def teq(ir, instr, a, b, c=None): + setflags = a != PC + if b.is_op(): + e, extra_ir = _shift_rotate_tpl(ir, instr, a, b, onlyCarry=setflags) + # get back the result + b = e.pop(0).src + else: + e = [] + extra_ir = [] + if c is None: + b, c = a, b + arg1, arg2 = b, c + r = arg1 ^ arg2 + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_CMP', arg1, arg2))] + e += update_flag_nf(r) + + return e, extra_ir + + +def l_cmp(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + arg1, arg2 = b, c + e += update_flag_arith_sub_zn(arg1, arg2) + e += update_flag_arith_sub_co(arg1, arg2) + return e, [] + + +def cmn(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + arg1, arg2 = b, c + e += update_flag_arith_add_zn(arg1, arg2) + e += update_flag_arith_add_co(arg1, arg2) + return e, [] + + +def orr(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + r = b | c + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def orn(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + r = ~(b | c) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def orrs(ir, instr, a, b, c=None): + setflags = a != PC + if c is None: + b, c = a, b + if c.is_op(): + e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags) + # get back the result + c = e.pop(0).src + else: + e = [] + extra_ir = [] + arg1, arg2 = b, c + r = arg1 | arg2 + + e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))] + e += update_flag_nf(r) + + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, extra_ir + + +def mov(ir, instr, a, b): + if b.is_op(): + return _shift_rotate_tpl(ir, instr, a, b, setflags=False) + # TODO handle cf + e = [ExprAssign(a, b)] + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, b)) + return e, [] + + +def movt(ir, instr, a, b): + r = a | b << ExprInt(16, 32) + e = [ExprAssign(a, r)] + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def _shift_rotate_tpl(ir, instr, dst, shift_operation, setflags=False, is_not=False, onlyCarry=False): + """ + Template to generate a shift/rotate + A temporary basic block is generated to handle 0-shift + @dst: destination + @shift_operation: the shift/rotate operation (ExprOp) + @setflags: (optional) if set, flags are updated (ZNC) + @onlyCarry: (optional) if set, Z and N flags won't be updated except if setflags is set. + @is_not: (optional) if set, behaves as MVN/MVNS + """ + op = shift_operation.op + # Compute carry (+ result for rrx) + if op == 'rrx': + res, new_cf = compute_rrx_carry(shift_operation) + shifter = ExprInt(1, 8) + elif op in ['<<', '>>', 'a>>']: + shifter = shift_operation.args[1] + if setflags or onlyCarry: + new_cf = ExprOp(op, shift_operation.args[0], shifter - ExprInt(1, size=shifter.size)) + left = op[-1] == '<' + new_cf = new_cf.msb() if left else new_cf[:1] + res = shift_operation + elif op == '>>>': + shifter = shift_operation.args[1] + if setflags or onlyCarry: + new_cf = shift_operation.msb() + res = shift_operation + else: + raise NotImplementedError(f"Unknown shift / rotate operation : {op}") + + # NOT the result and use it for ZN flags computations + if is_not: + res ^= ExprInt(-1, res.size) + # Build basic blocks + e_do = [] + e = [ExprAssign(dst, res)] + if setflags: + e += update_flag_zn(res) + if setflags or onlyCarry: + e_do += [ExprAssign(cf, expr_simp(new_cf))] + # Don't generate conditional shifter on constant + if shifter.is_int(): + if shifter.is_int(0): + # assignement + flags if setflags except cf + return (e, []) + else: + # assignement + flags if setflags + return (e + e_do, []) + + loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_skip = ir.get_next_loc_key(instr) + loc_skip_expr = ExprLoc(loc_skip, ir.IRDst.size) + isPC = get_dst(dst) + if isPC is not None: + # Not really a Loc in this case + loc_skip_expr = res + e_do.append(ExprAssign(ir.IRDst, loc_skip_expr)) + e.append(ExprAssign( + ir.IRDst, ExprCond(shifter, loc_do_expr, loc_skip_expr))) + return (e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])]) + + + +def movs(ir, instr, a, b): + e = [] + # handle shift / rotate + if b.is_op(): + return _shift_rotate_tpl(ir, instr, a, b, setflags=a != PC) + + + e.append(ExprAssign(a, b)) + # TODO handle cf + e += [ExprAssign(zf, ExprOp('FLAG_EQ', b))] + e += update_flag_nf(b) + + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, b)) + return e, [] + + +def mvn(ir, instr, a, b): + if b.is_op(): + return _shift_rotate_tpl(ir, instr, a, b, setflags=False, is_not=True) + r = b ^ ExprInt(-1, 32) + # TODO handle cf + e = [ExprAssign(a, r)] + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def mvns(ir, instr, a, b): + if b.is_op(): + return _shift_rotate_tpl(ir, instr, a, b, setflags= a != PC, is_not=True) + e = [] + r = b ^ ExprInt(-1, 32) + e.append(ExprAssign(a, r)) + # TODO handle cf + e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))] + e += update_flag_nf(r) + + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + + +def mrs(ir, instr, a, b): + e = [] + if b.is_id('CPSR_cxsf'): + out = [] + out.append(ExprInt(0x10, 28)) + out.append(of) + out.append(cf) + out.append(zf) + out.append(nf) + e.append(ExprAssign(a, ExprCompose(*out))) + else: + raise NotImplementedError("MRS not implemented") + return e, [] + +def msr(ir, instr, a, b): + e = [] + if a.is_id('CPSR_cf'): + e.append(ExprAssign(nf, b[31:32])) + e.append(ExprAssign(zf, b[30:31])) + e.append(ExprAssign(cf, b[29:30])) + e.append(ExprAssign(of, b[28:29])) + else: + raise NotImplementedError("MSR not implemented") + return e, [] + + +def neg(ir, instr, a, b): + e = [] + r = - b + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + +def negs(ir, instr, a, b): + return subs(ir, instr, a, ExprInt(0, b.size), b) + +def bic(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + r = b & (c ^ ExprInt(-1, 32)) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def bics(ir, instr, a, b, c=None): + setflags = a != PC + if c is None: + b, c = a, b + if c.is_op(): + e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags) + # get back the result + c = e.pop(0).src + else: + e = [] + extra_ir = [] + tmp1, tmp2 = b, ~c + r = tmp1 & tmp2 + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', tmp1, tmp2))] + e += update_flag_nf(r) + + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, extra_ir + + +def sdiv(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + + loc_div = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) + loc_except = ExprId(ir.loc_db.add_location(), ir.IRDst.size) + loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + + e.append(ExprAssign(ir.IRDst, ExprCond(c, loc_div, loc_except))) + + do_except = [] + do_except.append(ExprAssign(exception_flags, ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size))) + do_except.append(ExprAssign(ir.IRDst, loc_next)) + blk_except = IRBlock(ir.loc_db, loc_except.loc_key, [AssignBlock(do_except, instr)]) + + + + r = ExprOp("sdiv", b, c) + do_div = [] + do_div.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + do_div.append(ExprAssign(ir.IRDst, r)) + + do_div.append(ExprAssign(ir.IRDst, loc_next)) + blk_div = IRBlock(ir.loc_db, loc_div.loc_key, [AssignBlock(do_div, instr)]) + + return e, [blk_div, blk_except] + + +def udiv(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + + + + loc_div = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) + loc_except = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) + loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + + e.append(ExprAssign(ir.IRDst, ExprCond(c, loc_div, loc_except))) + + do_except = [] + do_except.append(ExprAssign(exception_flags, ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size))) + do_except.append(ExprAssign(ir.IRDst, loc_next)) + blk_except = IRBlock(ir.loc_db, loc_except.loc_key, [AssignBlock(do_except, instr)]) + + + r = ExprOp("udiv", b, c) + do_div = [] + do_div.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + do_div.append(ExprAssign(ir.IRDst, r)) + + do_div.append(ExprAssign(ir.IRDst, loc_next)) + blk_div = IRBlock(ir.loc_db, loc_div.loc_key, [AssignBlock(do_div, instr)]) + + return e, [blk_div, blk_except] + + +def mla(ir, instr, a, b, c, d): + e = [] + r = (b * c) + d + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def mlas(ir, instr, a, b, c, d): + e = [] + r = (b * c) + d + e += update_flag_zn(r) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def mls(ir, instr, a, b, c, d): + e = [] + r = d - (b * c) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def mul(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + r = b * c + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def muls(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + r = b * c + e += update_flag_zn(r) + e.append(ExprAssign(a, r)) + dst = get_dst(a) + if dst is not None: + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + +def umull(ir, instr, a, b, c, d): + e = [] + r = c.zeroExtend(64) * d.zeroExtend(64) + e.append(ExprAssign(a, r[0:32])) + e.append(ExprAssign(b, r[32:64])) + # r15/IRDst not allowed as output + return e, [] + +def umlal(ir, instr, a, b, c, d): + e = [] + r = c.zeroExtend(64) * d.zeroExtend(64) + ExprCompose(a, b) + e.append(ExprAssign(a, r[0:32])) + e.append(ExprAssign(b, r[32:64])) + # r15/IRDst not allowed as output + return e, [] + +def smull(ir, instr, a, b, c, d): + e = [] + r = c.signExtend(64) * d.signExtend(64) + e.append(ExprAssign(a, r[0:32])) + e.append(ExprAssign(b, r[32:64])) + # r15/IRDst not allowed as output + return e, [] + +def smlal(ir, instr, a, b, c, d): + e = [] + r = c.signExtend(64) * d.signExtend(64) + ExprCompose(a, b) + e.append(ExprAssign(a, r[0:32])) + e.append(ExprAssign(b, r[32:64])) + # r15/IRDst not allowed as output + return e, [] + +def b(ir, instr, a): + e = [] + e.append(ExprAssign(PC, a)) + e.append(ExprAssign(ir.IRDst, a)) + return e, [] + + +def bl(ir, instr, a): + e = [] + l = ExprInt(instr.offset + instr.l, 32) + e.append(ExprAssign(PC, a)) + e.append(ExprAssign(ir.IRDst, a)) + e.append(ExprAssign(LR, l)) + return e, [] + + +def bx(ir, instr, a): + e = [] + e.append(ExprAssign(PC, a)) + e.append(ExprAssign(ir.IRDst, a)) + return e, [] + + +def blx(ir, instr, a): + e = [] + l = ExprInt(instr.offset + instr.l, 32) + e.append(ExprAssign(PC, a)) + e.append(ExprAssign(ir.IRDst, a)) + e.append(ExprAssign(LR, l)) + return e, [] + + +def st_ld_r(ir, instr, a, a2, b, store=False, size=32, s_ext=False, z_ext=False): + e = [] + wb = False + postinc = False + b = b.ptr + if isinstance(b, ExprOp): + if b.op == "wback": + wb = True + b = b.args[0] + if b.op == "postinc": + postinc = True + if isinstance(b, ExprOp) and b.op in ["postinc", 'preinc']: + # XXX TODO CHECK + base, off = b.args[0], b.args[1] # ExprInt(size/8, 32) + else: + base, off = b, ExprInt(0, 32) + if postinc: + ad = base + else: + ad = base + off + + # PC base lookup uses PC 4 byte alignment + ad = ad.replace_expr({PC: PC & ExprInt(0xFFFFFFFC, 32)}) + + dmem = False + if size in [8, 16]: + if store: + a = a[:size] + m = ExprMem(ad, size=size) + elif s_ext: + m = ExprMem(ad, size=size).signExtend(a.size) + elif z_ext: + m = ExprMem(ad, size=size).zeroExtend(a.size) + else: + raise ValueError('unhandled case') + elif size == 32: + m = ExprMem(ad, size=size) + elif size == 64: + assert a2 is not None + m = ExprMem(ad, size=32) + dmem = True + size = 32 + else: + raise ValueError('the size DOES matter') + dst = None + + if store: + e.append(ExprAssign(m, a)) + if dmem: + e.append(ExprAssign(ExprMem(ad + ExprInt(4, 32), size=size), a2)) + else: + if a == PC: + dst = PC + e.append(ExprAssign(ir.IRDst, m)) + e.append(ExprAssign(a, m)) + if dmem: + e.append(ExprAssign(a2, ExprMem(ad + ExprInt(4, 32), size=size))) + + # XXX TODO check multiple write cause by wb + if wb or postinc: + e.append(ExprAssign(base, base + off)) + return e, [] + + +def ldr(ir, instr, a, b): + return st_ld_r(ir, instr, a, None, b, store=False) + + +def ldrd(ir, instr, a, b, c=None): + if c is None: + a2 = ir.arch.regs.all_regs_ids[ir.arch.regs.all_regs_ids.index(a) + 1] + else: + a2 = b + b = c + return st_ld_r(ir, instr, a, a2, b, store=False, size=64) + + +def l_str(ir, instr, a, b): + return st_ld_r(ir, instr, a, None, b, store=True) + + +def l_strd(ir, instr, a, b, c=None): + if c is None: + a2 = ir.arch.regs.all_regs_ids[ir.arch.regs.all_regs_ids.index(a) + 1] + else: + a2 = b + b = c + return st_ld_r(ir, instr, a, a2, b, store=True, size=64) + +def ldrb(ir, instr, a, b): + return st_ld_r(ir, instr, a, None, b, store=False, size=8, z_ext=True) + +def ldrsb(ir, instr, a, b): + return st_ld_r(ir, instr, a, None, b, store=False, size=8, s_ext=True, z_ext=False) + +def strb(ir, instr, a, b): + return st_ld_r(ir, instr, a, None, b, store=True, size=8) + +def ldrh(ir, instr, a, b): + return st_ld_r(ir, instr, a, None, b, store=False, size=16, z_ext=True) + + +def strh(ir, instr, a, b): + return st_ld_r(ir, instr, a, None, b, store=True, size=16, z_ext=True) + + +def ldrsh(ir, instr, a, b): + return st_ld_r(ir, instr, a, None, b, store=False, size=16, s_ext=True, z_ext=False) + + +def st_ld_m(ir, instr, a, b, store=False, postinc=False, updown=False): + e = [] + wb = False + dst = None + if isinstance(a, ExprOp) and a.op == 'wback': + wb = True + a = a.args[0] + if isinstance(b, ExprOp) and b.op == 'sbit': + b = b.args[0] + regs = b.args + base = a + if updown: + step = 4 + else: + step = -4 + regs = regs[::-1] + if postinc: + pass + else: + base += ExprInt(step, 32) + for i, r in enumerate(regs): + ad = base + ExprInt(i * step, 32) + if store: + e.append(ExprAssign(ExprMem(ad, 32), r)) + else: + e.append(ExprAssign(r, ExprMem(ad, 32))) + if r == PC: + e.append(ExprAssign(ir.IRDst, ExprMem(ad, 32))) + # XXX TODO check multiple write cause by wb + if wb: + if postinc: + e.append(ExprAssign(a, base + ExprInt(len(regs) * step, 32))) + else: + e.append(ExprAssign(a, base + ExprInt((len(regs) - 1) * step, 32))) + if store: + pass + else: + assert(isinstance(b, ExprOp) and b.op == "reglist") + + return e, [] + + +def ldmia(ir, instr, a, b): + return st_ld_m(ir, instr, a, b, store=False, postinc=True, updown=True) + + +def ldmib(ir, instr, a, b): + return st_ld_m(ir, instr, a, b, store=False, postinc=False, updown=True) + + +def ldmda(ir, instr, a, b): + return st_ld_m(ir, instr, a, b, store=False, postinc=True, updown=False) + + +def ldmdb(ir, instr, a, b): + return st_ld_m(ir, instr, a, b, store=False, postinc=False, updown=False) + + +def stmia(ir, instr, a, b): + return st_ld_m(ir, instr, a, b, store=True, postinc=True, updown=True) + + +def stmib(ir, instr, a, b): + return st_ld_m(ir, instr, a, b, store=True, postinc=False, updown=True) + + +def stmda(ir, instr, a, b): + return st_ld_m(ir, instr, a, b, store=True, postinc=True, updown=False) + + +def stmdb(ir, instr, a, b): + return st_ld_m(ir, instr, a, b, store=True, postinc=False, updown=False) + + +def svc(ir, instr, a): + e = [] + except_int = EXCEPT_INT_XX + e.append(ExprAssign(exception_flags, ExprInt(except_int, 32))) + e.append(ExprAssign(interrupt_num, a)) + return e, [] + + +def und(ir, instr, a, b): + # XXX TODO implement + e = [] + return e, [] + +def lsr(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + return _shift_rotate_tpl(ir, instr, a, b >> c, setflags=False) + + +def lsrs(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + return _shift_rotate_tpl(ir, instr, a, b >> c, setflags= a != PC) + +def asr(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + r = ExprOp("a>>", b, c) + return _shift_rotate_tpl(ir, instr, a, r, setflags=False) + +def asrs(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + r = ExprOp("a>>", b, c) + return _shift_rotate_tpl(ir, instr, a, r, setflags= a != PC) + +def lsl(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + return _shift_rotate_tpl(ir, instr, a, b << c, setflags=False) + + + +def lsls(ir, instr, a, b, c=None): + e = [] + if c is None: + b, c = a, b + if c.is_op('rrx'): + c, _ = compute_rrx_carry(c) + return _shift_rotate_tpl(ir, instr, a, b << c, setflags= a != PC) + + +def rors(ir, instr, a, b): + e = [] + r = ExprOp(">>>", a, b) + return _shift_rotate_tpl(ir, instr, a, r, setflags= a != PC) + + + +def push(ir, instr, a): + e = [] + regs = list(a.args) + for i in range(len(regs)): + r = SP + ExprInt(-4 * len(regs) + 4 * i, 32) + e.append(ExprAssign(ExprMem(r, 32), regs[i])) + r = SP + ExprInt(-4 * len(regs), 32) + e.append(ExprAssign(SP, r)) + return e, [] + + +def pop(ir, instr, a): + e = [] + regs = list(a.args) + dst = None + for i in range(len(regs)): + r = SP + ExprInt(4 * i, 32) + e.append(ExprAssign(regs[i], ExprMem(r, 32))) + if regs[i] == ir.pc: + dst = ExprMem(r, 32) + r = SP + ExprInt(4 * len(regs), 32) + e.append(ExprAssign(SP, r)) + if dst is not None: + e.append(ExprAssign(ir.IRDst, dst)) + return e, [] + + +def cbz(ir, instr, a, b): + e = [] + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 32) + e.append(ExprAssign(ir.IRDst, ExprCond(a, loc_next_expr, b))) + return e, [] + + +def cbnz(ir, instr, a, b): + e = [] + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 32) + e.append(ExprAssign(ir.IRDst, ExprCond(a, b, loc_next_expr))) + return e, [] + + +def uxtb(ir, instr, a, b): + e = [] + r = b[:8].zeroExtend(32) + e.append(ExprAssign(a, r)) + dst = None + if PC in a.get_r(): + dst = PC + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + +def uxth(ir, instr, a, b): + e = [] + r = b[:16].zeroExtend(32) + e.append(ExprAssign(a, r)) + dst = None + if PC in a.get_r(): + dst = PC + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + +def sxtb(ir, instr, a, b): + e = [] + r = b[:8].signExtend(32) + e.append(ExprAssign(a, r)) + dst = None + if PC in a.get_r(): + dst = PC + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + +def sxth(ir, instr, a, b): + e = [] + r = b[:16].signExtend(32) + e.append(ExprAssign(a, r)) + dst = None + if PC in a.get_r(): + dst = PC + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def ubfx(ir, instr, a, b, c, d): + e = [] + c = int(c) + d = int(d) + r = b[c:c+d].zeroExtend(32) + e.append(ExprAssign(a, r)) + dst = None + if PC in a.get_r(): + dst = PC + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + +def bfc(ir, instr, a, b, c): + e = [] + start = int(b) + stop = start + int(c) + out = [] + last = 0 + if start: + out.append(a[:start]) + last = start + if stop - start: + out.append(ExprInt(0, 32)[last:stop]) + last = stop + if last < 32: + out.append(a[last:]) + r = ExprCompose(*out) + e.append(ExprAssign(a, r)) + dst = None + if PC in a.get_r(): + dst = PC + e.append(ExprAssign(ir.IRDst, r)) + return e, [] + + +def pld(ir, instr, a): + e = [] + return e, [] + + +def pldw(ir, instr, a): + e = [] + return e, [] + + +def clz(ir, instr, a, b): + e = [] + e.append(ExprAssign(a, ExprOp('cntleadzeros', b))) + return e, [] + +def uxtab(ir, instr, a, b, c): + e = [] + e.append(ExprAssign(a, b + (c & ExprInt(0xff, 32)))) + return e, [] + + +def uxtah(ir, instr, a, b, c): + e = [] + e.append(ExprAssign(a, b + (c & ExprInt(0xffff, 32)))) + return e, [] + + +def bkpt(ir, instr, a): + e = [] + e.append(ExprAssign(exception_flags, ExprInt(EXCEPT_SOFT_BP, 32))) + e.append(ExprAssign(bp_num, a)) + return e, [] + + +def _extract_s16(arg, part): + if part == 'B': # bottom 16 bits + return arg[0:16] + elif part == 'T': # top 16 bits + return arg[16:32] + + +def smul(ir, instr, a, b, c): + e = [] + e.append(ExprAssign(a, _extract_s16(b, instr.name[4]).signExtend(32) * _extract_s16(c, instr.name[5]).signExtend(32))) + return e, [] + + +def smulw(ir, instr, a, b, c): + e = [] + prod = b.signExtend(48) * _extract_s16(c, instr.name[5]).signExtend(48) + e.append(ExprAssign(a, prod[16:48])) + return e, [] # signed most significant 32 bits of the 48-bit result + + +def tbb(ir, instr, a): + e = [] + dst = PC + ExprInt(2, 32) * a.zeroExtend(32) + e.append(ExprAssign(PC, dst)) + e.append(ExprAssign(ir.IRDst, dst)) + return e, [] + + +def tbh(ir, instr, a): + e = [] + dst = PC + ExprInt(2, 32) * a.zeroExtend(32) + e.append(ExprAssign(PC, dst)) + e.append(ExprAssign(ir.IRDst, dst)) + return e, [] + + +def smlabb(ir, instr, a, b, c, d): + e = [] + result = (b[:16].signExtend(32) * c[:16].signExtend(32)) + d + e.append(ExprAssign(a, result)) + return e, [] + + +def smlabt(ir, instr, a, b, c, d): + e = [] + result = (b[:16].signExtend(32) * c[16:32].signExtend(32)) + d + e.append(ExprAssign(a, result)) + return e, [] + + +def smlatb(ir, instr, a, b, c, d): + e = [] + result = (b[16:32].signExtend(32) * c[:16].signExtend(32)) + d + e.append(ExprAssign(a, result)) + return e, [] + + +def smlatt(ir, instr, a, b, c, d): + e = [] + result = (b[16:32].signExtend(32) * c[16:32].signExtend(32)) + d + e.append(ExprAssign(a, result)) + return e, [] + + +def uadd8(ir, instr, a, b, c): + e = [] + sums = [] + ges = [] + for i in range(0, 32, 8): + sums.append(b[i:i+8] + c[i:i+8]) + ges.append((b[i:i+8].zeroExtend(9) + c[i:i+8].zeroExtend(9))[8:9]) + + e.append(ExprAssign(a, ExprCompose(*sums))) + + for i, value in enumerate(ges): + e.append(ExprAssign(ge_regs[i], value)) + return e, [] + + +def sel(ir, instr, a, b, c): + e = [] + cond = nf ^ of ^ ExprInt(1, 1) + parts = [] + for i in range(4): + parts.append(ExprCond(ge_regs[i], b[i*8:(i+1)*8], c[i*8:(i+1)*8])) + result = ExprCompose(*parts) + e.append(ExprAssign(a, result)) + return e, [] + + +def rev(ir, instr, a, b): + e = [] + result = ExprCompose(b[24:32], b[16:24], b[8:16], b[:8]) + e.append(ExprAssign(a, result)) + return e, [] + + +def rev16(ir, instr, a, b): + e = [] + result = ExprCompose(b[8:16], b[:8], b[24:32], b[16:24]) + e.append(ExprAssign(a, result)) + return e, [] + + +def nop(ir, instr): + e = [] + return e, [] + + +def dsb(ir, instr, a): + # XXX TODO + e = [] + return e, [] + +def isb(ir, instr, a): + # XXX TODO + e = [] + return e, [] + +def cpsie(ir, instr, a): + # XXX TODO + e = [] + return e, [] + + +def cpsid(ir, instr, a): + # XXX TODO + e = [] + return e, [] + + +def wfe(ir, instr): + # XXX TODO + e = [] + return e, [] + + +def wfi(ir, instr): + # XXX TODO + e = [] + return e, [] + +def adr(ir, instr, arg1, arg2): + e = [] + e.append(ExprAssign(arg1, (PC & ExprInt(0xfffffffc, 32)) + arg2)) + return e, [] + + +def pkhbt(ir, instr, arg1, arg2, arg3): + e = [] + e.append( + ExprAssign( + arg1, + ExprCompose( + arg2[:16], + arg3[16:] + ) + ) + ) + return e, [] + + +def pkhtb(ir, instr, arg1, arg2, arg3): + e = [] + e.append( + ExprAssign( + arg1, + ExprCompose( + arg3[:16], + arg2[16:] + ) + ) + ) + return e, [] + +def mrc(ir, insr, arg1, arg2, arg3, arg4, arg5, arg6): + e = [] + sreg = (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6)) + if sreg in coproc_reg_dict: + e.append(ExprAssign(arg3, coproc_reg_dict[sreg])) + else: + raise NotImplementedError("Unknown coprocessor register: %s %s %d %s %d" % (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6))) + + return e, [] + +def mcr(ir, insr, arg1, arg2, arg3, arg4, arg5, arg6): + e = [] + sreg = (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6)) + if sreg in coproc_reg_dict: + e.append(ExprAssign(coproc_reg_dict[sreg], arg3)) + else: + raise NotImplementedError("Unknown coprocessor register: %s %s %d %s %d" % (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6))) + + return e, [] + +COND_EQ = 0 +COND_NE = 1 +COND_CS = 2 +COND_CC = 3 +COND_MI = 4 +COND_PL = 5 +COND_VS = 6 +COND_VC = 7 +COND_HI = 8 +COND_LS = 9 +COND_GE = 10 +COND_LT = 11 +COND_GT = 12 +COND_LE = 13 +COND_AL = 14 +COND_NV = 15 + +cond_dct = { + COND_EQ: "EQ", + COND_NE: "NE", + COND_CS: "CS", + COND_CC: "CC", + COND_MI: "MI", + COND_PL: "PL", + COND_VS: "VS", + COND_VC: "VC", + COND_HI: "HI", + COND_LS: "LS", + COND_GE: "GE", + COND_LT: "LT", + COND_GT: "GT", + COND_LE: "LE", + COND_AL: "AL", + # COND_NV: "NV", +} + +cond_dct_inv = dict((name, num) for num, name in viewitems(cond_dct)) + + +""" +Code Meaning (for cmp or subs) Flags Tested +eq Equal. Z==1 +ne Not equal. Z==0 +cs or hs Unsigned higher or same (or carry set). C==1 +cc or lo Unsigned lower (or carry clear). C==0 +mi Negative. The mnemonic stands for "minus". N==1 +pl Positive or zero. The mnemonic stands for "plus". N==0 +vs Signed overflow. The mnemonic stands for "V set". V==1 +vc No signed overflow. The mnemonic stands for "V clear". V==0 +hi Unsigned higher. (C==1) && (Z==0) +ls Unsigned lower or same. (C==0) || (Z==1) +ge Signed greater than or equal. N==V +lt Signed less than. N!=V +gt Signed greater than. (Z==0) && (N==V) +le Signed less than or equal. (Z==1) || (N!=V) +al (or omitted) Always executed. None tested. +""" + +tab_cond = {COND_EQ: ExprOp("CC_EQ", zf), + COND_NE: ExprOp("CC_NE", zf), + COND_CS: ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), # inv cf + COND_CC: ExprOp("CC_U<", cf ^ ExprInt(1, 1)), # inv cf + COND_MI: ExprOp("CC_NEG", nf), + COND_PL: ExprOp("CC_POS", nf), + COND_VS: ExprOp("CC_sOVR", of), + COND_VC: ExprOp("CC_sNOOVR", of), + COND_HI: ExprOp("CC_U>", cf ^ ExprInt(1, 1), zf), # inv cf + COND_LS: ExprOp("CC_U<=", cf ^ ExprInt(1, 1), zf), # inv cf + COND_GE: ExprOp("CC_S>=", nf, of), + COND_LT: ExprOp("CC_S<", nf, of), + COND_GT: ExprOp("CC_S>", nf, of, zf), + COND_LE: ExprOp("CC_S<=", nf, of, zf), + } + + + + + +def is_pc_written(ir, instr_ir): + all_pc = viewvalues(ir.mn.pc) + for ir in instr_ir: + if ir.dst in all_pc: + return True, ir.dst + return False, None + + +def add_condition_expr(ir, instr, cond, instr_ir, extra_ir): + if cond == COND_AL: + return instr_ir, extra_ir + if not cond in tab_cond: + raise ValueError('unknown condition %r' % cond) + cond = tab_cond[cond] + + + + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 32) + loc_do = ir.loc_db.add_location() + loc_do_expr = ExprLoc(loc_do, 32) + + dst_cond = ExprCond(cond, loc_do_expr, loc_next_expr) + assert(isinstance(instr_ir, list)) + + has_irdst = False + for e in instr_ir: + if e.dst == ir.IRDst: + has_irdst = True + break + if not has_irdst: + instr_ir.append(ExprAssign(ir.IRDst, loc_next_expr)) + e_do = IRBlock(ir.loc_db, loc_do, [AssignBlock(instr_ir, instr)]) + e = [ExprAssign(ir.IRDst, dst_cond)] + return e, [e_do] + extra_ir + +mnemo_func = {} +mnemo_func_cond = {} +mnemo_condm0 = {'add': add, + 'sub': sub, + 'eor': eor, + 'and': l_and, + 'rsb': rsb, + 'adc': adc, + 'sbc': sbc, + 'rsc': rsc, + + 'tst': tst, + 'teq': teq, + 'cmp': l_cmp, + 'cmn': cmn, + 'orr': orr, + 'mov': mov, + 'movt': movt, + 'bic': bic, + 'mvn': mvn, + 'neg': neg, + + 'sdiv': sdiv, + 'udiv': udiv, + + 'mrc': mrc, + 'mcr': mcr, + + 'mul': mul, + 'umull': umull, + 'umlal': umlal, + 'smull': smull, + 'smlal': smlal, + 'mla': mla, + 'ldr': ldr, + 'ldrd': ldrd, + 'ldrsb': ldrsb, + 'str': l_str, + 'strd': l_strd, + 'b': b, + 'bl': bl, + 'svc': svc, + 'und': und, + 'bx': bx, + 'ldrh': ldrh, + 'strh': strh, + 'ldrsh': ldrsh, + 'ldsh': ldrsh, + 'uxtb': uxtb, + 'uxth': uxth, + 'sxtb': sxtb, + 'sxth': sxth, + 'ubfx': ubfx, + 'bfc': bfc, + 'rev': rev, + 'rev16': rev16, + 'clz': clz, + 'uxtab': uxtab, + 'uxtah': uxtah, + 'bkpt': bkpt, + 'smulbb': smul, + 'smulbt': smul, + 'smultb': smul, + 'smultt': smul, + 'smulwt': smulw, + 'smulwb': smulw, + + 'pkhtb': pkhtb, + 'pkhbt': pkhbt, + + } + +mnemo_condm1 = {'adds': add, + 'subs': subs, + 'eors': eors, + 'ands': l_and, + 'rsbs': rsbs, + 'adcs': adc, + 'sbcs': sbcs, + 'rscs': rscs, + + 'orrs': orrs, + 'movs': movs, + 'bics': bics, + 'mvns': mvns, + + 'mrs': mrs, + 'msr': msr, + + 'negs': negs, + + 'muls': muls, + 'mls': mls, + 'mlas': mlas, + 'blx': blx, + + 'ldrb': ldrb, + 'ldsb': ldrsb, + 'strb': strb, + } + +mnemo_condm2 = {'ldmia': ldmia, + 'ldmib': ldmib, + 'ldmda': ldmda, + 'ldmdb': ldmdb, + + 'ldmfa': ldmda, + 'ldmfd': ldmia, + 'ldmea': ldmdb, + 'ldmed': ldmib, # XXX + + + 'stmia': stmia, + 'stmib': stmib, + 'stmda': stmda, + 'stmdb': stmdb, + + 'stmfa': stmib, + 'stmed': stmda, + 'stmfd': stmdb, + 'stmea': stmia, + } + + +mnemo_nocond = {'lsr': lsr, + 'lsrs': lsrs, + 'lsl': lsl, + 'lsls': lsls, + 'rors': rors, + 'push': push, + 'pop': pop, + 'asr': asr, + 'asrs': asrs, + 'cbz': cbz, + 'cbnz': cbnz, + 'pld': pld, + 'pldw': pldw, + 'tbb': tbb, + 'tbh': tbh, + 'nop': nop, + 'dsb': dsb, + 'isb': isb, + 'cpsie': cpsie, + 'cpsid': cpsid, + 'wfe': wfe, + 'wfi': wfi, + 'adr': adr, + 'orn': orn, + 'smlabb': smlabb, + 'smlabt': smlabt, + 'smlatb': smlatb, + 'smlatt': smlatt, + 'uadd8': uadd8, + 'sel': sel, + } + +mn_cond_x = [mnemo_condm0, + mnemo_condm1, + mnemo_condm2] + +for index, mn_base in enumerate(mn_cond_x): + for mn, mf in viewitems(mn_base): + for cond, cn in viewitems(cond_dct): + if cond == COND_AL: + cn = "" + cn = cn.lower() + if index == 0: + mn_mod = mn + cn + else: + mn_mod = mn[:-index] + cn + mn[-index:] + # print mn_mod + mnemo_func_cond[mn_mod] = cond, mf + +for name, mf in viewitems(mnemo_nocond): + mnemo_func_cond[name] = COND_AL, mf + + +def split_expr_dst(ir, instr_ir): + out = [] + dst = None + for i in instr_ir: + if i.dst == ir.pc: + out.append(i) + dst = ir.pc # i.src + else: + out.append(i) + return out, dst + + +def get_mnemo_expr(ir, instr, *args): + if not instr.name.lower() in mnemo_func_cond: + raise ValueError('unknown mnemo %s' % instr) + cond, mf = mnemo_func_cond[instr.name.lower()] + instr_ir, extra_ir = mf(ir, instr, *args) + instr, extra_ir = add_condition_expr(ir, instr, cond, instr_ir, extra_ir) + return instr, extra_ir + +get_arm_instr_expr = get_mnemo_expr + + +class arminfo(object): + mode = "arm" + # offset + + +class Lifter_Arml(Lifter): + def __init__(self, loc_db): + Lifter.__init__(self, mn_arm, "l", loc_db) + self.pc = PC + self.sp = SP + self.IRDst = ExprId('IRDst', 32) + self.addrsize = 32 + + + + def mod_pc(self, instr, instr_ir, extra_ir): + # fix PC (+8 for arm) + pc_fixed = {self.pc: ExprInt(instr.offset + 8, 32)} + + for i, expr in enumerate(instr_ir): + dst, src = expr.dst, expr.src + if dst != self.pc: + dst = dst.replace_expr(pc_fixed) + src = src.replace_expr(pc_fixed) + instr_ir[i] = ExprAssign(dst, src) + + for idx, irblock in enumerate(extra_ir): + extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \ + if expr != self.pc else expr, + lambda expr: expr.replace_expr(pc_fixed)) + + def get_ir(self, instr): + args = instr.args + # ir = get_mnemo_expr(self, self.name.lower(), *args) + if len(args) and isinstance(args[-1], ExprOp): + if (args[-1].op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>'] and + isinstance(args[-1].args[-1], ExprId)): + args[-1] = ExprOp(args[-1].op, + args[-1].args[0], + args[-1].args[-1][:8].zeroExtend(32)) + instr_ir, extra_ir = get_mnemo_expr(self, instr, *args) + + self.mod_pc(instr, instr_ir, extra_ir) + return instr_ir, extra_ir + + def parse_itt(self, instr): + name = instr.name + assert name.startswith('IT') + name = name[1:] + out = [] + for hint in name: + if hint == 'T': + out.append(0) + elif hint == "E": + out.append(1) + else: + raise ValueError("IT name invalid %s" % instr) + return out, instr.args[0] + + def do_it_block(self, loc, index, block, assignments, gen_pc_updt): + instr = block.lines[index] + it_hints, it_cond = self.parse_itt(instr) + cond_num = cond_dct_inv[it_cond.name] + cond_eq = tab_cond[cond_num] + + if not index + len(it_hints) <= len(block.lines): + raise NotImplementedError("Split IT block non supported yet") + + ir_blocks_all = [] + + # Gen dummy irblock for IT instr + loc_next = self.get_next_loc_key(instr) + dst = ExprAssign(self.IRDst, ExprLoc(loc_next, 32)) + dst_blk = AssignBlock([dst], instr) + assignments.append(dst_blk) + irblock = IRBlock(self.loc_db, loc, assignments) + ir_blocks_all.append([irblock]) + + loc = loc_next + assignments = [] + for hint in it_hints: + irblocks = [] + index += 1 + instr = block.lines[index] + + # Add conditional jump to current irblock + loc_do = self.loc_db.add_location() + loc_next = self.get_next_loc_key(instr) + + if hint: + local_cond = ~cond_eq + else: + local_cond = cond_eq + dst = ExprAssign(self.IRDst, ExprCond(local_cond, ExprLoc(loc_do, 32), ExprLoc(loc_next, 32))) + dst_blk = AssignBlock([dst], instr) + assignments.append(dst_blk) + irblock = IRBlock(self.loc_db, loc, assignments) + + irblocks.append(irblock) + + it_instr_irblocks = [] + assignments = [] + loc = loc_do + + split = self.add_instr_to_current_state( + instr, block, assignments, + it_instr_irblocks, gen_pc_updt + ) + if split: + raise NotImplementedError("Unsupported instr in IT block (%s)" % instr) + + if it_instr_irblocks: + assert len(it_instr_irblocks) == 1 + it_instr_irblocks = it_instr_irblocks.pop() + # Remove flags assignment if instr != [CMP, CMN, TST] + if instr.name not in ["CMP", "CMN", "TST"]: + # Fix assignments + out = [] + for assignment in assignments: + assignment = AssignBlock( + { + dst: src for (dst, src) in viewitems(assignment) + if dst not in [zf, nf, of, cf] + }, + assignment.instr + ) + out.append(assignment) + assignments = out + # Fix extra irblocksx + new_irblocks = [] + for irblock in it_instr_irblocks: + out = [] + for tmp_assignment in irblock: + assignment = AssignBlock( + { + dst: src for (dst, src) in viewitems(assignment) + if dst not in [zf, nf, of, cf] + }, + assignment.instr + ) + out.append(assignment) + new_irblock = IRBlock(self.loc_db, irblock.loc_key, out) + new_irblocks.append(new_irblock) + it_instr_irblocks = new_irblocks + + irblocks += it_instr_irblocks + dst = ExprAssign(self.IRDst, ExprLoc(loc_next, 32)) + dst_blk = AssignBlock([dst], instr) + assignments.append(dst_blk) + irblock = IRBlock(self.loc_db, loc, assignments) + irblocks.append(irblock) + loc = loc_next + assignments = [] + ir_blocks_all.append(irblocks) + return index, ir_blocks_all + + def add_asmblock_to_ircfg(self, block, ircfg, gen_pc_updt=False): + """ + Add a native block to the current IR + @block: native assembly block + @gen_pc_updt: insert PC update effects between instructions + """ + + it_hints = None + it_cond = None + label = block.loc_key + assignments = [] + ir_blocks_all = [] + index = -1 + while index + 1 < len(block.lines): + index += 1 + instr = block.lines[index] + if label is None: + assignments = [] + label = self.get_loc_key_for_instr(instr) + if instr.name.startswith("IT"): + index, irblocks_it = self.do_it_block(label, index, block, assignments, gen_pc_updt) + for irblocks in irblocks_it: + ir_blocks_all += irblocks + label = None + continue + + split = self.add_instr_to_current_state( + instr, block, assignments, + ir_blocks_all, gen_pc_updt + ) + if split: + ir_blocks_all.append(IRBlock(self.loc_db, label, assignments)) + label = None + assignments = [] + if label is not None: + ir_blocks_all.append(IRBlock(self.loc_db, label, assignments)) + + new_ir_blocks_all = self.post_add_asmblock_to_ircfg(block, ircfg, ir_blocks_all) + for irblock in new_ir_blocks_all: + ircfg.add_irblock(irblock) + return new_ir_blocks_all + + + +class Lifter_Armb(Lifter_Arml): + def __init__(self, loc_db): + Lifter.__init__(self, mn_arm, "b", loc_db) + self.pc = PC + self.sp = SP + self.IRDst = ExprId('IRDst', 32) + self.addrsize = 32 + + +class Lifter_Armtl(Lifter_Arml): + def __init__(self, loc_db): + Lifter.__init__(self, mn_armt, "l", loc_db) + self.pc = PC + self.sp = SP + self.IRDst = ExprId('IRDst', 32) + self.addrsize = 32 + + + def mod_pc(self, instr, instr_ir, extra_ir): + # fix PC (+4 for thumb) + pc_fixed = {self.pc: ExprInt(instr.offset + 4, 32)} + + for i, expr in enumerate(instr_ir): + dst, src = expr.dst, expr.src + if dst != self.pc: + dst = dst.replace_expr(pc_fixed) + src = src.replace_expr(pc_fixed) + instr_ir[i] = ExprAssign(dst, src) + + for idx, irblock in enumerate(extra_ir): + extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \ + if expr != self.pc else expr, + lambda expr: expr.replace_expr(pc_fixed)) + + +class Lifter_Armtb(Lifter_Armtl): + def __init__(self, loc_db): + Lifter.__init__(self, mn_armt, "b", loc_db) + self.pc = PC + self.sp = SP + self.IRDst = ExprId('IRDst', 32) + self.addrsize = 32 + diff --git a/src/miasm/arch/mep/__init__.py b/src/miasm/arch/mep/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/miasm/arch/mep/__init__.py diff --git a/src/miasm/arch/mep/arch.py b/src/miasm/arch/mep/arch.py new file mode 100644 index 00000000..ed7813ca --- /dev/null +++ b/src/miasm/arch/mep/arch.py @@ -0,0 +1,2080 @@ +# Toshiba MeP-c4 - miasm architecture definition +# Guillaume Valadon <guillaume@valadon.net> + +from builtins import range +from miasm.core.cpu import * +from miasm.core.utils import Disasm_Exception +from miasm.expression.expression import ExprId, ExprInt, ExprLoc, \ + ExprMem, ExprOp, is_expr +from miasm.core.asm_ast import AstId, AstMem + +from miasm.arch.mep.regs import * +import miasm.arch.mep.regs as mep_regs_module # will be used to set mn_mep.regs +from miasm.ir.ir import color_expr_html + + +# Note: pyparsing is used to alter the way special operands are parsed +from pyparsing import Literal, Group, Word, hexnums + + +# These definitions will help parsing dereferencing instructions (i.e. that uses +# parenthesis) with pyparsing +LPARENTHESIS = Literal("(") +RPARENTHESIS = Literal(")") +PLUSSIGN = Literal("+") +HEX_INTEGER = str_int_pos | str_int_neg + + +def ExprInt2SignedString(expr, pos_fmt="%d", neg_fmt="%d", size=None, offset=0): + """Return the signed string corresponding to an ExprInt + + Note: this function is only useful to mimic objdump output""" + + # Apply a mask to the integer + if size is None: + mask_length = expr.size + else: + mask_length = size + mask = (1 << mask_length) - 1 + value = int(expr) & mask + + # Return a signed integer if necessary + if (value >> mask_length - 1) == 1: + value = offset - ((value ^ mask) + 1) + if value < 0: + return "-" + neg_fmt % -value + else: + value += offset + + return pos_fmt % value + + +class instruction_mep(instruction): + """Generic MeP-c4 instruction + + Notes: + - this object is used to build internal miasm instructions based + on mnemonics + - it must be implemented ! + """ + + @staticmethod + def arg2str(expr, pos=None, loc_db=None): + """Convert mnemonics arguments into readable strings according to the + MeP-c4 architecture manual and their internal types + + Notes: + - it must be implemented ! However, a simple 'return str(expr)' + could do the trick. + - it is used to mimic objdump output + + Args: + expr: argument as a miasm expression + pos: position index in the arguments list + """ + + if isinstance(expr, ExprId) or isinstance(expr, ExprInt): + return str(expr) + + elif isinstance(expr, ExprLoc): + if loc_db is not None: + return loc_db.pretty_str(expr.loc_key) + else: + return str(expr) + + elif isinstance(expr, ExprMem) and (isinstance(expr.ptr, ExprId) or isinstance(expr.ptr, ExprInt)): + return "(%s)" % expr.ptr + + elif isinstance(expr, ExprMem) and isinstance(expr.ptr, ExprOp): + return "0x%X(%s)" % (int(expr.ptr.args[1]), expr.ptr.args[0]) + + # Raise an exception if the expression type was not processed + message = "instruction_mep.arg2str(): don't know what \ + to do with a '%s' instance." % type(expr) + raise Disasm_Exception(message) + + @staticmethod + def arg2html(expr, pos=None, loc_db=None): + """Convert mnemonics arguments into readable html strings according to the + MeP-c4 architecture manual and their internal types + + Notes: + - it must be implemented ! However, a simple 'return str(expr)' + could do the trick. + - it is used to mimic objdump output + + Args: + expr: argument as a miasm expression + pos: position index in the arguments list + """ + + if isinstance(expr, ExprId) or isinstance(expr, ExprInt) or isinstance(expr, ExprLoc): + return color_expr_html(expr, loc_db) + + elif isinstance(expr, ExprMem) and (isinstance(expr.ptr, ExprId) or isinstance(expr.ptr, ExprInt)): + return "(%s)" % color_expr_html(expr.ptr, loc_db) + + elif isinstance(expr, ExprMem) and isinstance(expr.ptr, ExprOp): + return "%s(%s)" % ( + color_expr_html(expr.ptr.args[1], loc_db), + color_expr_html(expr.ptr.args[0], loc_db) + ) + + # Raise an exception if the expression type was not processed + message = "instruction_mep.arg2str(): don't know what \ + to do with a '%s' instance." % type(expr) + raise Disasm_Exception(message) + + def __str__(self): + """Return the mnemonic as a string. + + Note: + - it is not mandatory as the instruction class already implement + it. It used to get rid of the padding between the opcode and the + arguments. + - most of this code is copied from miasm/core/cpu.py + """ + + o = "%s" % self.name + + if self.name == "SSARB": + # The first operand is displayed in decimal, not in hex + o += " %d" % int(self.args[0]) + o += self.arg2str(self.args[1]) + + elif self.name in ["MOV", "ADD"] and isinstance(self.args[1], ExprInt): + # The second operand is displayed in decimal, not in hex + o += " " + self.arg2str(self.args[0]) + o += ", %s" % ExprInt2SignedString(self.args[1]) + + elif "CPI" in self.name: + # The second operand ends with the '+' sign + o += " " + self.arg2str(self.args[0]) + deref_reg_str = self.arg2str(self.args[1]) + o += ", %s+)" % deref_reg_str[:-1] # GV: looks ugly + + elif self.name[0] in ["S", "L"] and self.name[-3:] in ["CPA", "PM0", "PM1"]: + # The second operand ends with the '+' sign + o += " " + self.arg2str(self.args[0]) + deref_reg_str = self.arg2str(self.args[1]) + o += ", %s+)" % deref_reg_str[:-1] # GV: looks ugly + # The third operand is displayed in decimal, not in hex + o += ", %s" % ExprInt2SignedString(self.args[2]) + + elif len(self.args) == 2 and self.name in ["SB", "SH", "LBU", "LB", "LH", "LW"] and \ + isinstance(self.args[1], ExprMem) and isinstance(self.args[1].ptr, ExprOp): # Major Opcodes #12 + # The second operand is an offset to a register + o += " " + self.arg2str(self.args[0]) + o += ", %s" % ExprInt2SignedString(self.args[1].ptr.args[1], "0x%X") + o += "(%s)" % self.arg2str(self.args[1].ptr.args[0]) + + elif len(self.args) == 2 and self.name in ["SWCP", "LWCP", "SMCP", "LMCP"] \ + and isinstance(self.args[1], ExprMem) and isinstance(self.args[1].ptr, ExprOp): # Major Opcodes #12 + # The second operand is an offset to a register + o += " " + self.arg2str(self.args[0]) + o += ", %s" % ExprInt2SignedString(self.args[1].ptr.args[1]) + o += "(%s)" % self.arg2str(self.args[1].ptr.args[0]) + + elif self.name == "SLL" and isinstance(self.args[1], ExprInt): # Major Opcodes #6 + # The second operand is displayed in hex, not in decimal + o += " " + self.arg2str(self.args[0]) + o += ", 0x%X" % int(self.args[1]) + + elif self.name in ["ADD3", "SLT3"] and isinstance(self.args[2], ExprInt): + o += " %s" % self.arg2str(self.args[0]) + o += ", %s" % self.arg2str(self.args[1]) + # The third operand is displayed in decimal, not in hex + o += ", %s" % ExprInt2SignedString(self.args[2], pos_fmt="0x%X") + + elif self.name == "(RI)": + return o + + else: + args = [] + if self.args: + o += " " + for i, arg in enumerate(self.args): + if not is_expr(arg): + raise ValueError('zarb arg type') + x = self.arg2str(arg, pos=i) + args.append(x) + o += self.gen_args(args) + + return o + + def breakflow(self): + """Instructions that stop a basic block.""" + + if self.name in ["BRA", "BEQZ", "BNEZ", "BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE", "BSR"]: + return True + + if self.name in ["JMP", "JSR", "RET"]: + return True + + if self.name in ["RETI", "HALT", "SLEEP"]: + return True + + return False + + def splitflow(self): + """Instructions that splits a basic block, i.e. the CPU can go somewhere else.""" + + if self.name in ["BEQZ", "BNEZ", "BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE", "BSR"]: + return True + + return False + + def dstflow(self): + """Instructions that explicitly provide the destination.""" + + if self.name in ["BRA", "BEQZ", "BNEZ", "BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE", "BSR"]: + return True + + if self.name in ["JMP"]: + return True + + return False + + def dstflow2label(self, loc_db): + """Set the label for the current destination. + + Note: it is used at disassembly""" + + if self.name == "JMP" and isinstance(self.args[0], ExprId): + # 'JMP RM' does not provide the destination + return + + # Compute the correct address + num = self.get_dst_num() + addr = int(self.args[num]) + if not self.name == "JMP": + addr += self.offset + + # Get a new label at the address + label = loc_db.get_or_create_offset_location(addr) + + # Assign the label to the correct instruction argument + self.args[num] = ExprLoc(label, self.args[num].size) + + def get_dst_num(self): + """Get the index of the argument that points to the instruction destination.""" + + if self.name[-1] == "Z": + num = 1 + elif self.name in ["BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE"]: + num = 2 + else: + num = 0 + + return num + + def getdstflow(self, loc_db): + """Get the argument that points to the instruction destination.""" + + num = self.get_dst_num() + return [self.args[num]] + + def is_subcall(self): + """Instructions used to call sub functions.""" + + return self.name in ["JSR", "BSR"] + + def fixDstOffset(self): + """Fix/correct the instruction immediate according to the current offset + + Note: - it is used at assembly + - code inspired by miasm/arch/mips32/arch.py""" + + if self.name == "JMP" and isinstance(self.args[0], ExprInt): + # 'JMP IMMEDIATE' does not need to be fixed + return + + # Get the argument that needs to be fixed + if not len(self.args): + return + num = self.get_dst_num() + expr = self.args[num] + + # Check that the argument can be fixed + if self.offset is None: + raise ValueError("Symbol not resolved %s" % self.l) + if not isinstance(expr, ExprInt): + return + + # Adjust the immediate according to the current instruction offset + off = expr.arg - self.offset + if int(off % 2): + raise ValueError("Strange offset! %r" % off) + self.args[num] = ExprInt(off, 32) + + +class mep_additional_info(object): + """Additional MeP instructions information + """ + + def __init__(self): + self.except_on_instr = False + + +class mn_mep(cls_mn): + """Toshiba MeP-c4 disassembler & assembler + """ + + # Define variables that stores information used to disassemble & assemble + # Notes: - these variables are mandatory + # - they could be moved to the cls_mn class + + num = 0 # holds the number of mnemonics + + all_mn = list() # list of mnenomnics, converted to metamn objects + + all_mn_mode = defaultdict(list) # mneomnics, converted to metamn objects + # Note: + # - the key is the mode # GV: what is it ? + # - the data is a list of mnemonics + + all_mn_name = defaultdict(list) # mnenomnics strings + # Note: + # - the key is the mnemonic string + # - the data is the corresponding + # metamn object + + all_mn_inst = defaultdict(list) # mnemonics objects + # Note: + # - the key is the mnemonic Python class + # - the data is an instantiated object + + bintree = dict() # Variable storing internal values used to guess a + # mnemonic during disassembly + + # Defines the instruction set that will be used + instruction = instruction_mep + + # Python module that stores registers information + regs = mep_regs_module + + # Default delay slot + # Note: + # - mandatory for the miasm Machine + delayslot = 0 + + # Architecture name + name = "mep" + + # PC name depending on architecture attributes (here, l or b) + pc = {'l': PC, 'b': PC} + + def additional_info(self): + """Define instruction side effects # GV: not fully understood yet + + When used, it must return an object that implements specific + variables, such as except_on_instr. + + Notes: + - it must be implemented ! + - it could be moved to the cls_mn class + """ + + return mep_additional_info() + + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + """Ease populating internal variables used to disassemble & assemble, such + as self.all_mn_mode, self.all_mn_name and self.all_mn_inst + + Notes: + - it must be implemented ! + - it could be moved to the cls_mn class. All miasm architectures + use the same code + + Args: + cls: ? + sublcs: + name: mnemonic name + bases: ? + dct: ? + fields: ? + + Returns: + a list of ? + + """ + + dct["mode"] = None + return [(subcls, name, bases, dct, fields)] + + @classmethod + def getmn(cls, name): + """Get the mnemonic name + + Notes: + - it must be implemented ! + - it could be moved to the cls_mn class. Most miasm architectures + use the same code + + Args: + cls: the mnemonic class + name: the mnemonic string + """ + + return name.upper() + + @classmethod + def getpc(cls, attrib=None): + """"Return the ExprId that represents the Program Counter. + + Notes: + - mandatory for the symbolic execution + - PC is defined in regs.py + + Args: + attrib: architecture dependent attributes (here, l or b) + """ + + return PC + + @classmethod + def getsp(cls, attrib=None): + """"Return the ExprId that represents the Stack Pointer. + + Notes: + - mandatory for the symbolic execution + - SP is defined in regs.py + + Args: + attrib: architecture dependent attributes (here, l or b) + """ + + return SP + + @classmethod + def getbits(cls, bitstream, attrib, start, n): + """Return an integer of n bits at the 'start' offset + + Note: code from miasm/arch/mips32/arch.py + """ + + # Return zero if zero bits are requested + if not n: + return 0 + + o = 0 # the returned value + while n: + # Get a byte, the offset is adjusted according to the endianness + offset = start // 8 # the offset in bytes + n_offset = cls.endian_offset(attrib, offset) # the adjusted offset + c = cls.getbytes(bitstream, n_offset, 1) + if not c: + raise IOError + + # Extract the bits value + c = ord(c) + r = 8 - start % 8 + c &= (1 << r) - 1 + l = min(r, n) + c >>= (r - l) + o <<= l + o |= c + n -= l + start += l + + return o + + @classmethod + def endian_offset(cls, attrib, offset): + """Adjust the byte offset according to the endianness""" + + if attrib == "l": # Little Endian + if offset % 2: + return offset - 1 + else: + return offset + 1 + + elif attrib == "b": # Big Endian + return offset + + else: + raise NotImplementedError("Bad MeP endianness") + + def value(self, mode): + """Adjust the assembled instruction based on the endianness + + Note: code inspired by miasm/arch/mips32/arch.py + """ + + # Get the candidated + candidates = super(mn_mep, self).value(mode) + + if mode == "l": + # Invert bytes per 16-bits + for i in range(len(candidates)): + tmp = candidates[i][1] + candidates[i][0] + if len(candidates[i]) == 4: + tmp += candidates[i][3] + candidates[i][2] + candidates[i] = tmp + return candidates + + elif mode == "b": + return candidates + + else: + raise NotImplementedError("Bad MeP endianness (%s)" % mode) + + +def addop(name, fields, args=None, alias=False): + """Dynamically create the "name" object + + Notes: + - it could be moved to a generic function such as: + addop(name, fields, cls_mn, args=None, alias=False). + - most architectures use the same code + + Args: + name: the mnemonic name + fields: used to fill the object.__dict__'fields' attribute # GV: not understood yet + args: used to fill the object.__dict__'fields' attribute # GV: not understood yet + alias: used to fill the object.__dict__'fields' attribute # GV: not understood yet + """ + + namespace = {"fields": fields, "alias": alias} + + if args is not None: + namespace["args"] = args + + # Dynamically create the "name" object + type(name, (mn_mep,), namespace) + + +# Define specific operand parsers & converters + +def deref2expr(s, l, parse_results): + """Convert a parsed dereferenced register to an ExprMem""" + + # Only use the first results + parse_results = parse_results[0] + + if type(parse_results[0]) == AstInt and isinstance(parse_results[2], AstId): + return AstMem(parse_results[2] + parse_results[0], 32) # 1 == "(" and 3 == ")" + + elif type(parse_results[0]) == int and isinstance(parse_results[2], AstId): + return AstMem(parse_results[2] + AstOp('-', AstInt(-parse_results[0])), 32) # 1 == "(" and 3 == ")" + + else: + return AstMem(parse_results[1], 32) # 0 == "(" and 2 == ")" + + +deref_reg_parser = Group(LPARENTHESIS + gpr_infos.parser + RPARENTHESIS).setParseAction(deref2expr) +deref_inc_reg_parser = Group(LPARENTHESIS + gpr_infos.parser + PLUSSIGN + RPARENTHESIS).setParseAction(deref2expr) +abs24_deref_parser = Group(LPARENTHESIS + HEX_INTEGER + RPARENTHESIS).setParseAction(deref2expr) +offset_deref_reg_parser = Group(HEX_INTEGER + LPARENTHESIS + gpr_infos.parser + RPARENTHESIS).setParseAction(deref2expr) + +# Define registers decoders and encoders + +class mep_arg(m_arg): + def asm_ast_to_expr(self, arg, loc_db): + """Convert AST to expressions + + Note: - code inspired by miasm/arch/mips32/arch.py""" + + if isinstance(arg, AstId): + if isinstance(arg.name, ExprId): + return arg.name + if isinstance(arg.name, str) and arg.name in gpr_names: + return None # GV: why? + loc_key = loc_db.get_or_create_name_location(arg.name) + return ExprLoc(loc_key, 32) + + elif isinstance(arg, AstMem): + addr = self.asm_ast_to_expr(arg.ptr, loc_db) + if addr is None: + return None + return ExprMem(addr, 32) + + elif isinstance(arg, AstInt): + return ExprInt(arg.value, 32) + + elif isinstance(arg, AstOp): + args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args] + if None in args: + return None + return ExprOp(arg.op, *args) + + # Raise an exception if the argument was not processed + message = "mep_arg.asm_ast_to_expr(): don't know what \ + to do with a '%s' instance." % type(arg) + raise Exception(message) + +class mep_reg(reg_noarg, mep_arg): + """Generic Toshiba MeP-c4 register + + Note: + - the register size will be set using bs() + """ + reg_info = gpr_infos # the list of MeP-c4 registers defined in regs.py + parser = reg_info.parser # GV: not understood yet + + +class mep_deref_reg(mep_arg): + """Generic Toshiba MeP-c4 dereferenced register + + Note: + - the arg2str() method could be defined to change the output string + """ + parser = deref_reg_parser + + def decode(self, v): + """Transform the decoded value to a ExprMem(ExprId()) expression""" + r = gpr_infos.expr[v] # get the ExprId, i.e. the register expression + self.expr = ExprMem(r, 32) + return True + + def encode(self): + """Ensure that we have a ExprMem(ExprId()) expression, and return the + register value.""" + + if not isinstance(self.expr, ExprMem): + return False + if not isinstance(self.expr.ptr, ExprId): + return False + + # Get the ExprId index, i.e. its value + self.value = gpr_exprs.index(self.expr.ptr) + return True + + +class mep_reg_sp(mep_reg): + """Dummy Toshiba MeP-c4 register that represents SP. It is used in + instructions that implicitly use SP, such as ADD3. + """ + implicit_reg = SP + + def decode(self, v): + """Always return 'implicit_reg.""" + self.expr = self.implicit_reg + return True + + def encode(self): + """Do nothing""" + return True + + +class mep_reg_tp(mep_reg_sp): + """Dummy Toshiba MeP-c4 register that represents TP. + """ + implicit_reg = TP + + +class mep_deref_reg_offset(mep_arg): + """Toshiba MeP-c4 dereferenced register that represents SP, plus an + offset. + """ + parser = offset_deref_reg_parser + + def decode(self, v): + """Modify the decoded value using the previously decoded + register id. + """ + + # Apply the immediate mask + se = sign_ext(v & 0xFFFF, 16, 32) # GV: might not belong here + int_id = ExprInt(se, 32) + + # Get the register expression + reg_id = gpr_infos.expr[self.parent.reg04_deref.value] + + # Build the internal expression + self.expr = ExprMem(reg_id + int_id, 32) + + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in reg04_deref. + """ + + # Verify the expression + if not isinstance(self.expr, ExprMem): + return False + if not isinstance(self.expr.ptr, ExprOp): + return False + + # Get the integer and check the upper bound + v = int(self.expr.ptr.args[1]) & 0xFFFF + + # Encode the values + self.parent.reg04_deref.value = gpr_exprs.index(self.expr.ptr.args[0]) + self.value = v & 0xFFFF + return True + + +class mep_deref_sp_offset(mep_deref_reg): + """Dummy Toshiba MeP-c4 dereferenced register that represents SP, plus an + offset. + Note: it is as generic as possible to ease its use in different instructions + """ + implicit_reg = SP + parser = offset_deref_reg_parser + + def decode(self, v): + """Modify the decoded value using the previously decoded + immediate. + """ + + immediate = None + if getattr(self.parent, "imm7_align4", False): + # Apply the immediate mask + v = self.parent.imm7_align4.value & 0x1F + + # Shift value such as: + # imm7=iii_ii||00 + immediate = v << 2 + + elif getattr(self.parent, "imm7", False): + # Apply the immediate mask + immediate = self.parent.imm7.value & 0x7F + + elif getattr(self.parent, "disp7_align2", False): + # Apply the immediate mask + disp7_align2 = self.parent.disp7_align2.value & 0x3F + + # Shift value such as: + # disp7 = ddd_ddd||0 + immediate = disp7_align2 << 1 + + if immediate is not None: + self.expr = ExprMem(self.implicit_reg + ExprInt(immediate, 32), 32) + return True + else: + return False + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in a parent immediate. + """ + + # Verify the expression + if not isinstance(self.expr, ExprMem): + return False + if not isinstance(self.expr.ptr, ExprOp): + return False + if self.expr.ptr.args[0] != self.implicit_reg: + return False + + if getattr(self.parent, "imm7_align4", False): + + # Get the integer and check the upper bound + v = int(self.expr.ptr.args[1].arg) + if v > 0x80: + return False + + # Encode the value + self.parent.imm7_align4.value = v >> 2 + + return True + + elif getattr(self.parent, "imm7", False): + + # Get the integer and check the upper bound + v = int(self.expr.ptr.args[1].arg) + if v > 0x80: + return False + + # Encode the value + self.parent.imm7.value = v + + return True + + elif getattr(self.parent, "disp7_align2", False): + + # Get the integer and check the upper bound + v = int(self.expr.ptr.args[1].arg) + if v > 0x80: + return False + + # Encode the value + self.parent.disp7_align2.value = v >> 1 + + return True + + return False + + +class mep_deref_tp_offset(mep_deref_sp_offset): + """Dummy Toshiba MeP-c4 dereferenced register that represents TP, plus an + offset. + """ + implicit_reg = TP + + +class mep_copro_reg(reg_noarg, mep_arg): + """Generic Toshiba MeP-c4 coprocessor register + """ + reg_info = copro_gpr_infos # the list of MeP-c4 coprocessor registers defined in regs.py + parser = reg_info.parser # GV: not understood yet + + +class mep_copro_reg_split(mep_copro_reg): + """Generic Toshiba MeP-c4 coprocessor register encode into different fields + """ + + def decode(self, v): + """Modify the decoded value using the previously decoded imm4_noarg. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift values such as: + # CRn=NNnnnn + crn = (v << 4) + (self.parent.imm4.value & 0xF) + + # Build the internal expression + self.expr = ExprId("C%d" % crn, 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm4_noarg. + """ + + if not isinstance(self.expr, ExprId): + return False + + # Get the register and check the upper bound + reg_name = self.expr.name + if reg_name[0] != "C": + return False + reg_value = copro_gpr_names.index(reg_name) + if reg_value > 0x3f: + return False + + # Encode the value into two parts + self.parent.imm4.value = (reg_value & 0xF) + self.value = (reg_value >> 4) & 0x3 + return True + + +class mep_deref_inc_reg(mep_deref_reg): + """Generic Toshiba MeP-c4 coprocess dereferenced & incremented register + """ + parser = deref_inc_reg_parser + + +# Immediate decoders and encoders + +class mep_int32_noarg(int32_noarg): + """Generic Toshiba MeP-c4 signed immediate + + Note: encode() is copied from int32_noarg.encode() and modified to allow + small (< 32 bits) signed immediate to be manipulated. + + """ + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + # Note: the following lines were commented on purpose + #if sign_ext(v & self.lmask, self.l, self.intsize) != v: + # return False + v = self.encodeval(v & self.lmask) + self.value = v & self.lmask + return True + + +class mep_imm(imm_noarg, mep_arg): + """Generic Toshiba MeP-c4 immediate + + Note: + - the immediate size will be set using bs() + """ + parser = base_expr + + +class mep_imm6(mep_int32_noarg): + """Toshiba MeP-c4 signed 6 bits immediate.""" + parser = base_expr + intsize = 6 + intmask = (1 << intsize) - 1 + int2expr = lambda self, x: ExprInt(sign_ext(x, self.l, 32), 32) + + +class mep_imm8(mep_int32_noarg): + """Toshiba MeP-c4 signed 8 bits immediate.""" + parser = base_expr + intsize = 8 + intmask = (1 << intsize) - 1 + int2expr = lambda self, x: ExprInt(sign_ext(x, self.l, 32), 32) + + +class mep_imm16(mep_int32_noarg): + """Toshiba MeP-c4 16 bits immediate.""" + parser = base_expr + intsize = 16 + intmask = (1 << intsize) - 1 + int2expr = lambda self, x: ExprInt(x, 32) + + +class mep_imm16_signed(mep_int32_noarg): + """Toshiba MeP-c4 signed 16 bits immediate.""" + parser = base_expr + intsize = 16 + intmask = (1 << intsize) - 1 + int2expr = lambda self, x: ExprInt(sign_ext(x, self.l, 32), 32) + + +class mep_target24(mep_imm): + """Toshiba MeP-c4 target24 immediate, as used in JMP + """ + + def decode(self, v): + """Modify the decoded value using the previously decoded imm7. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift values such as: + # target24=tttt_tttt_tttt_tttt||TTT_TTTT||0 + target24 = (v << 8) + ((self.parent.imm7.value & 0x7F) << 1) + + # Build the internal expression + self.expr = ExprInt(target24, 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm7. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer and apply a mask + v = int(self.expr) & 0x00FFFFFF + + # Encode the value into two parts + self.parent.imm7.value = (v & 0xFF) >> 1 + self.value = v >> 8 + return True + + +class mep_target24_signed(mep_target24): + """Toshiba MeP-c4 target24 signed immediate, as used in BSR + """ + + def decode(self, v): + """Perform sign extension + """ + + mep_target24.decode(self, v) + v = int(self.expr) + self.expr = ExprInt(sign_ext(v, 24, 32), 32) + + return True + + +class mep_code20(mep_imm): + """Toshiba MeP-c4 code20 immediate, as used in DSP1 + """ + + def decode(self, v): + """Modify the decoded value using the previously decoded imm4_noarg. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift values such as: + # code20=mmmm_cccc_cccc_cccc_cccc + code20 = v + ((self.parent.imm4.value & 0xFF) << 16) + + # Build the internal expression + self.expr = ExprInt(code20, 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm4_noarg. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer and check the upper bound + v = int(self.expr.arg) + if v > 0xffffff: + return False + + # Encode the value into two parts + self.parent.imm4 = ((v >> 16) & 0xFF) + self.value = v + return True + + +class mep_code24(mep_imm): + """Toshiba MeP-c4 code24 immediate, as used in CP + """ + + def decode(self, v): + """Modify the decoded value using the previously decoded imm8_CCCC_CCCC. + """ + + # Shift values such as: + # code24=CCCC_CCCC||cccc_cccc_cccc_cccc + code24 = v + ((self.parent.imm8_CCCC_CCCC.value & 0xFF) << 16) + + # Build the internal expression + self.expr = ExprInt(code24, 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm8_CCCC_CCCC. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer and check the upper bound + v = int(self.expr.arg) + if v > 0xFFFFFF: + return False + + # Encode the value into two parts + self.parent.imm8_CCCC_CCCC.value = ((v >> 16) & 0xFF) + self.value = v & 0xFFFF + return True + + +class mep_imm7_align4(mep_imm): + """Toshiba MeP-c4 imm7.align4 immediate, as used in Major #4 opcodes + """ + + def decode(self, v): + """Modify the decoded value. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift value such as: + # imm7=iii_ii||00 + imm7_align4 = v << 2 + + # Build the internal expression + self.expr = ExprInt(imm7_align4, 32) + return True + + def encode(self): + """Modify the encoded value. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer and check the upper bound + v = int(self.expr) + if v > 0x80: + return False + + # Encode the value + self.value = v >> 2 + return True + + +class mep_imm5_Iiiii (mep_imm): + """Toshiba MeP-c4 imm5 immediate, as used in STC & LDC. It encodes a + control/special register. + """ + + reg_info = csr_infos # the list of MeP-c4 control/special registers defined in regs.py + parser = reg_info.parser # GV: not understood yet + + def decode(self, v): + """Modify the decoded value using the previously decoded imm4_iiii + """ + + # Apply the immediate mask + I = v & self.lmask + + # Shift values such as: + # imm5=I||iiii + imm5 = (I << 4) + (self.parent.imm4_iiii.value & 0xF) + + # Build the internal register expression + self.expr = ExprId(csr_names[imm5], 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm4_iiii. + """ + + if not isinstance(self.expr, ExprId): + return False + + # Get the register number and check the upper bound + v = csr_names.index(self.expr.name) + if v > 0x1F: + return False + + # Encode the value into two parts + self.parent.imm4_iiii.value = v & 0xF # iiii + self.value = (v >> 4) & 0b1 # I + return True + + +class mep_disp7_align2(mep_imm): + """Toshiba MeP-c4 disp7.align2 immediate, as used in Major #8 opcodes + """ + upper_bound = 0x7F + bits_shift = 1 + + def decode(self, v): + """Modify the decoded value. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift value such as: + # disp7 = ddd_ddd||0 + disp7_align2 = (v << self.bits_shift) + + # Sign extension + disp7_align2 = sign_ext(disp7_align2, self.l + self.bits_shift, 32) + + # Build the internal expression + self.expr = ExprInt(disp7_align2, 32) + return True + + def encode(self): + """Modify the encoded value. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer + v = int(self.expr) & self.upper_bound + + # Encode the value + self.value = (v >> self.bits_shift) & self.upper_bound + self.value = (v & self.upper_bound) >> self.bits_shift + return True + + +class mep_disp8_align2(mep_disp7_align2): + upper_bound = 0xFF + + +class mep_disp8_align4(mep_disp7_align2): + upper_bound = 0xFF + bits_shift = 2 + + +class mep_imm8_align8(mep_disp7_align2): + upper_bound = 0xFF + bits_shift = 3 + + +class mep_disp12_align2(mep_disp7_align2): + upper_bound = 0xFFF + + +class mep_disp12_align2_signed(mep_disp12_align2): + + def decode(self, v): + """Perform sign extension. + """ + mep_disp12_align2.decode(self, v) + v = int(self.expr) + + self.expr = ExprInt(sign_ext(v, 12, 32), 32) + return True + + +class mep_disp17(mep_disp7_align2): + upper_bound = 0x1FFFF + + +class mep_imm24(mep_imm): + """Toshiba MeP-c4 imm24 immediate, as used in MOVU + """ + + def decode(self, v): + """Modify the decoded value. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift values such as: + # imm24=iiii_iiii_iiii_iiii||IIII_IIIII + imm24 = ((v & 0xFFFF) << 8) + ((v & 0xFF0000) >> 16) + + # Build the internal expression + self.expr = ExprInt(imm24, 32) + return True + + def encode(self): + """Modify the encoded value. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer and check the upper bound + v = int(self.expr) + if v > 0xFFFFFF: + return False + + # Encode the value + self.value = ((v & 0xFFFF00) >> 8) + ((v & 0xFF) << 16) + return True + + +class mep_abs24(mep_imm): + """Toshiba MeP-c4 abs24 immediate + """ + parser = abs24_deref_parser + + def decode(self, v): + """Modify the decoded value using the previously decoded imm6. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift values such as: + # abs24=dddd_dddd_dddd_dddd||DDDD_DD||00 + abs24 = (v << 8) + ((self.parent.imm6.value & 0x3F) << 2) + + # Build the internal expression + self.expr = ExprMem(ExprInt(abs24, 32), 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm6. + """ + + if not (isinstance(self.expr, ExprMem) and isinstance(self.expr.ptr, ExprInt)): + return False + + # Get the integer and check the upper bound + v = int(self.expr.ptr) + if v > 0xffffff: + return False + + # Encode the value into two parts + self.parent.imm6.value = (v & 0xFF) >> 2 + self.value = v >> 8 + return True + + +# Define MeP-c4 assembly operands + +reg04 = bs(l=4, # length in bits + cls=(mep_reg, )) # class implementing decoding & encoding + +reg04_l = bs(l=4, cls=(mep_reg, )) + +reg04_m = bs(l=4, cls=(mep_reg, )) + +reg04_n = bs(l=4, cls=(mep_reg, )) + +reg00 = bs(l=0, cls=(mep_reg, )) + +reg00_sp = bs(l=0, cls=(mep_reg_sp, )) + +reg00_tp = bs(l=0, cls=(mep_reg_tp, )) + +reg00_deref_sp = bs(l=0, cls=(mep_deref_sp_offset, )) + +reg00_deref_tp = bs(l=0, cls=(mep_deref_tp_offset, )) + +reg03 = bs(l=3, cls=(mep_reg, )) + +reg04_deref = bs(l=4, cls=(mep_deref_reg,)) + +reg04_deref_noarg = bs(l=4, fname="reg04_deref") + +reg04_inc_deref = bs(l=4, cls=(mep_deref_inc_reg,)) + +copro_reg04 = bs(l=4, cls=(mep_copro_reg,)) + +copro_reg05 = bs(l=1, cls=(mep_copro_reg_split,)) + +copro_reg06 = bs(l=2, cls=(mep_copro_reg_split,)) + +disp2 = bs(l=2, cls=(mep_imm, )) + +imm2 = disp2 + +imm3 = bs(l=3, cls=(mep_imm, )) + +imm4 = bs(l=4, cls=(mep_imm, )) + +imm4_noarg = bs(l=4, fname="imm4") + +imm4_iiii_noarg = bs(l=4, fname="imm4_iiii") + +imm5 = bs(l=5, cls=(mep_imm, )) + +imm5_Iiiii = bs(l=1, cls=(mep_imm5_Iiiii, )) # it is not an immediate, but a + # control/special register. + +imm6 = bs(l=6, cls=(mep_imm6, mep_arg)) + +imm6_noarg = bs(l=6, fname="imm6") + +imm7 = bs(l=7, cls=(mep_imm, )) + +imm7_noarg = bs(l=7, fname="imm7") # Note: + # - will be decoded as a 7 bits immediate + # - fname is used to set the operand name + # used in mep_target24 to merge operands + # values. By default, the bs class fills + # fname with an hex string compute from + # arguments passed to __init__ + +imm7_align4 = bs(l=5, cls=(mep_imm7_align4,)) + +imm7_align4_noarg = bs(l=5, fname="imm7_align4") + +disp7_align2 = bs(l=6, cls=(mep_disp7_align2,)) + +disp7_align2_noarg = bs(l=6, fname="disp7_align2") + +imm8 = bs(l=8, cls=(mep_imm8, mep_arg)) + +imm8_noarg = bs(l=8, fname="imm8_CCCC_CCCC") + +disp8 = bs(l=7, cls=(mep_disp8_align2, )) + +imm8_align2 = bs(l=7, cls=(mep_disp8_align2, )) + +imm8_align4 = bs(l=6, cls=(mep_disp8_align4, )) + +imm8_align8 = bs(l=5, cls=(mep_imm8_align8, )) + +imm12 = bs(l=12, cls=(mep_imm, )) + +disp12_signed = bs(l=11, cls=(mep_disp12_align2_signed, )) + +imm16 = bs(l=16, cls=(mep_imm16, mep_arg)) +imm16_signed = bs(l=16, cls=(mep_imm16_signed, mep_arg)) + +disp16_reg_deref = bs(l=16, cls=(mep_deref_reg_offset,)) + +disp17 = bs(l=16, cls=(mep_disp17, )) + +imm18 = bs(l=19, cls=(mep_imm, )) + +imm_code20 = bs(l=16, cls=(mep_code20, )) + +imm24 = bs(l=24, cls=(mep_imm24, )) + +imm_target24 = bs(l=16, cls=(mep_target24, )) +imm_target24_signed = bs(l=16, cls=(mep_target24_signed, )) + +imm_code24 = bs(l=16, cls=(mep_code24, )) + +abs24 = bs(l=16, cls=(mep_abs24, )) + + +# MeP-c4 mnemonics objects + +### <Major Opcode #0> + +# MOV Rn,Rm - 0000_nnnn_mmmm_0000 +addop("MOV", [bs("0000"), reg04, reg04, bs("0000")]) + +# NEG Rn,Rm - 0000_nnnn_mmmm_0001 +addop("NEG", [bs("0000"), reg04, reg04, bs("0001")]) + +# SLT3 R0,Rn,Rm - 0000_nnnn_mmmm_0010 +addop("SLT3", [bs("0000"), reg00, reg04, reg04, bs("0010")]) + +# SLTU3 R0,Rn,Rm - 0000_nnnn_mmmm_0011 +addop("SLTU3", [bs("0000"), reg00, reg04, reg04, bs("0011")]) + +# SUB Rn,Rm - 0000_nnnn_mmmm_0100 +addop("SUB", [bs("0000"), reg04, reg04, bs("0100")]) + +# SBVCK3 R0,Rn,Rm - 0000_nnnn_mmmm_0101 +addop("SBVCK3", [bs("0000"), reg00, reg04, reg04, bs("0101")]) + +# (RI) - 0000_xxxx_xxxx_0110 +addop("(RI)", [bs("0000"), reg04, reg04, bs("0110")]) + +# ADVCK3 R0,Rn,Rm - 0000_nnnn_mmmm_0111 +addop("ADVCK3", [bs("0000"), reg00, reg04, reg04, bs("0111")]) + +# SB Rn,(Rm) - 0000_nnnn_mmmm_1000 +addop("SB", [bs("0000"), reg04, reg04_deref, bs("1000")]) + +# SH Rn,(Rm) - 0000_nnnn_mmmm_1001 +addop("SH", [bs("0000"), reg04, reg04_deref, bs("1001")]) + +# SW Rn,(Rm) - 0000_nnnn_mmmm_1010 +addop("SW", [bs("0000"), reg04, reg04_deref, bs("1010")]) + +# LBU Rn,(Rm) - 0000_nnnn_mmmm_1011 +addop("LBU", [bs("0000"), reg04, reg04_deref, bs("1011")]) + +# LB Rn,(Rm) - 0000_nnnn_mmmm_1100 +addop("LB", [bs("0000"), reg04, reg04_deref, bs("1100")]) + +# LH Rn,(Rm) - 0000_nnnn_mmmm_1101 +addop("LH", [bs("0000"), reg04, reg04_deref, bs("1101")]) + +# LW Rn,(Rm) - 0000_nnnn_mmmm_1110 +addop("LW", [bs("0000"), reg04, reg04_deref, bs("1110")]) + +# LHU Rn,(Rm) - 0000_nnnn_mmmm_1111 +addop("LHU", [bs("0000"), reg04, reg04_deref, bs("1111")]) + + +### <Major Opcode #1> + +# OR Rn,Rm - 0001_nnnn_mmmm_0000 +addop("OR", [bs("0001"), reg04, reg04, bs("0000")]) + +# AND Rn,Rm - 0001_nnnn_mmmm_0001 +addop("AND", [bs("0001"), reg04, reg04, bs("0001")]) + +# XOR Rn,Rm - 0001_nnnn_mmmm_0010 +addop("XOR", [bs("0001"), reg04, reg04, bs("0010")]) + +# NOR Rn,Rm - 0001_nnnn_mmmm_0011 +addop("NOR", [bs("0001"), reg04, reg04, bs("0011")]) + +# MUL Rn,Rm - 0001_nnnn_mmmm_0100 +addop("MUL", [bs("0001"), reg04, reg04, bs("0100")]) + +# MULU Rn,Rm - 0001_nnnn_mmmm_0101 +addop("MULU", [bs("0001"), reg04, reg04, bs("0101")]) + +# MULR Rn,Rm - 0001_nnnn_mmmm_0110 +addop("MULR", [bs("0001"), reg04, reg04, bs("0110")]) + +# MULRU Rn,Rm - 0001_nnnn_mmmm_0111 +addop("MULRU", [bs("0001"), reg04, reg04, bs("0111")]) + +# DIV Rn,Rm - 0001_nnnn_mmmm_1000 +addop("DIV", [bs("0001"), reg04, reg04, bs("1000")]) + +# DIVU Rn,Rm - 0001_nnnn_mmmm_1001 +addop("DIVU", [bs("0001"), reg04, reg04, bs("1001")]) + +# (RI) - 0001_xxxx_xxxx_1010 +addop("(RI)", [bs("0001"), reg04, reg04, bs("1010")]) + +# (RI) - 0001_xxxx_xxxx_1011 +addop("(RI)", [bs("0001"), reg04, reg04, bs("1011")]) + +# SSARB disp2(Rm) - 0001_00dd_mmmm_1100 +addop("SSARB", [bs("000100"), disp2, reg04_deref, bs("1100")]) + +# EXTB Rn - 0001_nnnn_0000_1101 +addop("EXTB", [bs("0001"), reg04, bs("00001101")]) + +# EXTH Rn - 0001_nnnn_0010_1101 +addop("EXTH", [bs("0001"), reg04, bs("00101101")]) + +# EXTUB Rn - 0001_nnnn_1000_1101 +addop("EXTUB", [bs("0001"), reg04, bs("10001101")]) + +# EXTUH Rn - 0001_nnnn_1010_1101 +addop("EXTUH", [bs("0001"), reg04, bs("10101101")]) + +# JMP Rm - 0001_0000_mmmm_1110 +addop("JMP", [bs("00010000"), reg04, bs("1110")]) + +# JSR Rm - 0001_0000_mmmm_1111 +addop("JSR", [bs("00010000"), reg04, bs("1111")]) + +# JSRV Rm - 0001_1000_mmmm_1111 +addop("JSRV", [bs("00011000"), reg04, bs("1111")]) + + +### <Major Opcode #2> + +# BSETM (Rm),imm3 - 0010_0iii_mmmm_0000 +addop("BSETM", [bs("00100"), imm3, reg04_deref, bs("0000")], [reg04_deref, imm3]) + +# BCLRM (Rn),imm3 - 0010_0iii_mmmm_0001 +addop("BCLRM", [bs("00100"), imm3, reg04_deref, bs("0001")], [reg04_deref, imm3]) + +# BNOTM (Rm),imm3 - 0010_0iii_mmmm_0010 +addop("BNOTM", [bs("00100"), imm3, reg04_deref, bs("0010")], [reg04_deref, imm3]) + +# BTSTM R0,(Rm),imm3 - 0010_0iii_mmmm_0011 +addop("BTSTM", [bs("00100"), reg00, imm3, reg04_deref, bs("0011")], [reg00, reg04_deref, imm3]) + +# TAS Rn,(Rm) - 0010_nnnn_mmmm_0100 +addop("TAS", [bs("0010"), reg04, reg04_deref, bs("0100")]) + +# (RI) - 0010_xxxx_xxxx_0101 +addop("(RI)", [bs("0010"), reg04, reg04, bs("0101")]) + +# SL1AD3 R0,Rn,Rm - 0010_nnnn_mmmm_0110 +addop("SL1AD3", [bs("0010"), reg00, reg04, reg04, bs("0110")]) + +# SL2AD3 R0,Rn,Rm - 0010_nnnn_mmmm_0111 +addop("SL2AD3", [bs("0010"), reg00, reg04, reg04, bs("0111")]) + +# (RI) - 0010_xxxx_xxxx_1000 +addop("(RI)", [bs("0010"), reg04, reg04, bs("1000")]) + +# (RI) - 0010_xxxx_xxxx_1001 +addop("(RI)", [bs("0010"), reg04, reg04, bs("1001")]) + +# (RI) - 0010_xxxx_xxxx_1010 +addop("(RI)", [bs("0010"), reg04, reg04, bs("1010")]) + +# (RI) - 0010_xxxx_xxxx_1011 +addop("(RI)", [bs("0010"), reg04, reg04, bs("1011")]) + +# SRL Rn,Rm - 0010_nnnn_mmmm_1100 +addop("SRL", [bs("0010"), reg04, reg04, bs("1100")]) + +# SRA Rn,Rm - 0010_nnnn_mmmm_1101 +addop("SRA", [bs("0010"), reg04, reg04, bs("1101")]) + +# SLL Rn,Rm - 0010_nnnn_mmmm_1110 +addop("SLL", [bs("0010"), reg04, reg04, bs("1110")]) + +# FSFT Rn,Rm - 0010_nnnn_mmmm_1111 +addop("FSFT", [bs("0010"), reg04, reg04, bs("1111")]) + + +### <Major Opcode #3> + +# SWCPI CRn,(Rm+) - 0011_nnnn_mmmm_0000 +addop("SWCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0000")]) + +# LWCPI CRn,(Rm+) - 0011_nnnn_mmmm_0001 +addop("LWCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0001")]) + +# SMCPI CRn,(Rm+) - 0011_nnnn_mmmm_0010 +addop("SMCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0010")]) + +# LMCPI CRn,(Rm+) - 0011_nnnn_mmmm_0011 +addop("LMCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0011")]) + +# SWCP CRn,(Rm) - 0011_nnnn_mmmm_1000 +addop("SWCP", [bs("0011"), copro_reg04, reg04_deref, bs("1000")]) + +# LWCP CRn,(Rm) - 0011_nnnn_mmmm_1001 +addop("LWCP", [bs("0011"), copro_reg04, reg04_deref, bs("1001")]) + +# SMCP CRn,(Rm) - 0011_nnnn_mmmm_1010 +addop("SMCP", [bs("0011"), copro_reg04, reg04_deref, bs("1010")]) + +# LMCP CRn,(Rm) - 0011_nnnn_mmmm_1011 +addop("LMCP", [bs("0011"), copro_reg04, reg04_deref, bs("1011")]) + + +### <Major Opcode #4> + +# ADD3 Rn,SP,imm7.align4 - 0100_nnnn_0iii_ii00 +addop("ADD3", [bs("0100"), reg04, reg00_sp, bs("0"), imm7_align4, bs("00")]) + +# SW Rn,disp7.align4(SP) - 0100_nnnn_0ddd_dd10 +# Note: disp7.align4 is the same as imm7.align4 +addop("SW", [bs("0100"), reg04, bs("0"), imm7_align4_noarg, reg00_deref_sp, bs("10")]) + +# LW Rn,disp7.align4(SP) - 0100_nnnn_0ddd_dd11 +addop("LW", [bs("0100"), reg04, bs("0"), imm7_align4_noarg, reg00_deref_sp, bs("11")]) + +# SW Rn[0-7],disp7.align4(TP) - 0100_0nnn_1ddd_dd10 +addop("SW", [bs("01000"), reg03, bs("1"), imm7_align4_noarg, reg00_deref_tp, bs("10")]) + +# LW Rn[0-7],disp7.align4(TP) - 0100_0nnn_1ddd_dd11 +addop("LW", [bs("01000"), reg03, bs("1"), imm7_align4_noarg, reg00_deref_tp, bs("11")]) + +# LBU Rn[0-7],disp7(TP) - 0100_1nnn_1ddd_dddd +addop("LBU", [bs("01001"), reg03, bs("1"), imm7_noarg, reg00_deref_tp], [reg03, reg00_deref_tp]) + +### <Major Opcode #5> + +# MOV Rn,imm8 - 0101_nnnn_iiii_iiii +addop("MOV", [bs("0101"), reg04, imm8]) + + +### <Major Opcode #6> + +# ADD Rn,imm6 - 0110_nnnn_iiii_ii00 +addop("ADD", # mnemonic name + [bs("0110"), reg04, imm6, bs("00")]) # mnemonic description + +# SLT3 R0,Rn,imm5 - 0110_nnnn_iiii_i001 +addop("SLT3", [bs("0110"), reg00, reg04, imm5, bs("001")]) + +# SRL Rn,imm5 - 0110_nnnn_iiii_i010 +addop("SRL", [bs("0110"), reg04, imm5, bs("010")]) + +# SRA Rn,imm5 - 0110_nnnn_iiii_i011 +addop("SRA", [bs("0110"), reg04, imm5, bs("011")]) + +# SLTU3 R0,Rn,imm5 - 0110_nnnn_iiii_i101 +addop("SLTU3", [bs("0110"), reg00, reg04, imm5, bs("101")]) + +# SLL Rn,imm5 - 0110_nnnn_iiii_i110 +addop("SLL", [bs("0110"), reg04, imm5, bs("110")]) + +# SLL3 R0,Rn,imm5 - 0110_nnnn_iiii_i111 +addop("SLL3", [bs("0110"), reg00, reg04, imm5, bs("111")]) + + +### <Major Opcode #7> + +# DI - 0111_0000_0000_0000 +addop("DI", [bs("0111000000000000")]) + +# EI - 0111_0000_0001_0000 +addop("EI", [bs("0111000000010000")]) + +# SYNCM - 0111_0000_0001_0001 +addop("SYNCM", [bs("0111000000010001")]) + +# SYNCCP - 0111_0000_0010_0001 +addop("SYNCCP", [bs("0111000000100001")]) + +# RET - 0111_0000_0000_0010 +addop("RET", [bs("0111000000000010")]) + +# RETI - 0111_0000_0001_0010 +addop("RETI", [bs("0111000000010010")]) + +# HALT - 0111_0000_0010_0010 +addop("HALT", [bs("0111000000100010")]) + +# BREAK - 0111_0000_0011_0010 +addop("BREAK", [bs("0111000000110010")]) + +# SLEEP - 0111_0000_0110_0010 +addop("SLEEP", [bs("0111000001100010")]) + +# DRET - 0111_0000_0001_0011 +addop("DRET", [bs("0111000000010011")]) + +# DBREAK - 0111_0000_0011_0011 +addop("DBREAK", [bs("0111000000110011")]) + +# CACHE imm4,(Rm) - 0111_iiii_mmmm_0100 +addop("CACHE", [bs("0111"), imm4, reg04_deref, bs("0100")]) + +# (RI) - 0111_xxxx_xxxx_0101 +addop("(RI)", [bs("0111"), reg04, reg04, bs("0101")]) + +# SWI imm2 - 0111_0000_00ii_0110 +addop("SWI", [bs("0111000000"), imm2, bs("0110")]) + +# (RI) - 0111_xxxx_xxxx_0111 +addop("(RI)", [bs("0111"), reg04, reg04, bs("0111")]) + +# STC Rn,imm5 - 0111_nnnn_iiii_100I +addop("STC", [bs("0111"), reg04, imm4_iiii_noarg, bs("100"), imm5_Iiiii]) + +# LDC Rn,imm5 - 0111_nnnn_iiii_101I +addop("LDC", [bs("0111"), reg04, imm4_iiii_noarg, bs("101"), imm5_Iiiii]) + +# (RI) - 0111_xxxx_xxxx_1100 +addop("(RI)", [bs("0111"), reg04, reg04, bs("1100")]) + +# (RI) - 0111_xxxx_xxxx_1101 +addop("(RI)", [bs("0111"), reg04, reg04, bs("1101")]) + +# (RI) - 0111_xxxx_xxxx_1110 +addop("(RI)", [bs("0111"), reg04, reg04, bs("1110")]) + +# (RI) - 0111_xxxx_xxxx_1111 +addop("(RI)", [bs("0111"), reg04, reg04, bs("1111")]) + + +### <Major Opcode #8> + +# SB Rn[0-7],disp7(TP) - 1000_0nnn_0ddd_dddd +addop("SB", [bs("10000"), reg03, bs("0"), imm7_noarg, reg00_deref_tp]) + +# SH Rn[0-7],disp7.align2(TP) - 1000_0nnn_1ddd_ddd0 +# (disp7.align2 = ddd_ddd||0) +addop("SH", [bs("10000"), reg03, bs("1"), disp7_align2_noarg, bs("0"), reg00_deref_tp]) + +# LB Rn[0-7],disp7(TP) - 1000_1nnn_0ddd_dddd +addop("LB", [bs("10001"), reg03, bs("0"), imm7_noarg, reg00_deref_tp]) + +# LH Rn[0-7],disp7.align2(TP) - 1000_1nnn_1ddd_ddd0 +addop("LH", [bs("10001"), reg03, bs("1"), disp7_align2_noarg, bs("0"), reg00_deref_tp]) + +# LHU Rn[0-7],disp7.align2(TP) - 1000_1nnn_1ddd_ddd1 +addop("LHU", [bs("10001"), reg03, bs("1"), disp7_align2_noarg, bs("1"), reg00_deref_tp]) + + +### <Major Opcode #9> + +# ADD3 Rl,Rn,Rm - 1001_nnnn_mmmm_llll +addop("ADD3", [bs("1001"), reg04_n, reg04_m, reg04_l], [reg04_l, reg04_n, reg04_m]) + + +### <Major Opcode #10> + +# BEQZ Rn,disp8.align2 - 1010_nnnn_dddd_ddd0 +# (disp8=dddd_ddd||0) +addop("BEQZ", [bs("1010"), reg04, disp8, bs("0")]) + +# BNEZ Rn,disp8.align2 - 1010_nnnn_dddd_ddd1 +addop("BNEZ", [bs("1010"), reg04, disp8, bs("1")]) + + +### <Major Opcode #11> + +# BRA disp12.align2 - 1011_dddd_dddd_ddd0 +# (disp12=dddd_dddd_ddd||0) +addop("BRA", [bs("1011"), disp12_signed, bs("0")]) + +# BSR disp12.align2 - 1011_dddd_dddd_ddd1 +addop("BSR", [bs("1011"), disp12_signed, bs("1")]) + + +### <Major Opcode #12> + +# ADD3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0000 iiii_iiii_iiii_iiii +addop("ADD3", [bs("1100"), reg04, reg04, bs("0000"), imm16_signed]) + +# MOV Rn,imm16 - 1100_nnnn_0000_0001 iiii_iiii_iiii_iiii +addop("MOV", [bs("1100"), reg04, bs("00000001"), imm16]) + +# MOVU Rn,imm16 - 1100_nnnn_0001_0001 iiii_iiii_iiii_iiii +addop("MOVU", [bs("1100"), reg04, bs("00010001"), imm16]) + +# MOVH Rn,imm16 - 1100_nnnn_0010_0001 iiii_iiii_iiii_iiii +addop("MOVH", [bs("1100"), reg04, bs("00100001"), imm16]) + +# SLT3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0010 iiii_iiii_iiii_iiii +addop("SLT3", [bs("1100"), reg04, reg04, bs("0010"), imm16_signed]) + +# SLTU3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0011 iiii_iiii_iiii_iiii +addop("SLTU3", [bs("1100"), reg04, reg04, bs("0011"), imm16]) + +# OR3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0100 iiii_iiii_iiii_iiii +addop("OR3", [bs("1100"), reg04, reg04, bs("0100"), imm16]) + +# AND3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0101 iiii_iiii_iiii_iiii +addop("AND3", [bs("1100"), reg04, reg04, bs("0101"), imm16]) + +# XOR3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0110 iiii_iiii_iiii_iiii +addop("XOR3", [bs("1100"), reg04, reg04, bs("0110"), imm16]) + +# (RI) - 1100_xxxx_xxxx_0111 xxxx_xxxx_xxxx_xxxx +addop("(RI)", [bs("1100"), imm8, bs("0111"), imm16]) + +# SB Rn,disp16(Rm) - 1100_nnnn_mmmm_1000 dddd_dddd_dddd_dddd +addop("SB", [bs("1100"), reg04, reg04_deref_noarg, bs("1000"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# SH Rn,disp16(Rm) - 1100_nnnn_mmmm_1001 dddd_dddd_dddd_dddd +addop("SH", [bs("1100"), reg04, reg04_deref_noarg, bs("1001"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# SW Rn,disp16(Rm) - 1100_nnnn_mmmm_1010 dddd_dddd_dddd_dddd +addop("SW", [bs("1100"), reg04, reg04_deref_noarg, bs("1010"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# LBU Rn,disp16(Rm) - 1100_nnnn_mmmm_1011 dddd_dddd_dddd_dddd +addop("LBU", [bs("1100"), reg04, reg04_deref_noarg, bs("1011"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# LB Rn,disp16(Rm) - 1100_nnnn_mmmm_1100 dddd_dddd_dddd_dddd +addop("LB", [bs("1100"), reg04, reg04_deref_noarg, bs("1100"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# LH Rn,disp16(Rm) - 1100_nnnn_mmmm_1101 dddd_dddd_dddd_dddd +addop("LH", [bs("1100"), reg04, reg04_deref_noarg, bs("1101"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# LW Rn,disp16(Rm) - 1100_nnnn_mmmm_1110 dddd_dddd_dddd_dddd +addop("LW", [bs("1100"), reg04, reg04_deref_noarg, bs("1110"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# LHU Rn,disp16(Rm) - 1100_nnnn_mmmm_1111 dddd_dddd_dddd_dddd +addop("LHU", [bs("1100"), reg04, reg04_deref_noarg, bs("1111"), disp16_reg_deref], [reg04, disp16_reg_deref]) + + +### <Major Opcode #13> + +# MOVU Rn[0-7],imm24 - 1101_0nnn_IIII_IIII iiii_iiii_iiii_iiii +addop("MOVU", [bs("11010"), reg03, imm24]) + +# BCPEQ cccc,disp17 - 1101_1000_cccc_0100 dddd_dddd_dddd_dddd +addop("BCPEQ", [bs("11011000"), imm4, bs("0100"), disp17]) + +# BCPNE cccc,disp17 - 1101_1000_cccc_0101 dddd_dddd_dddd_dddd +addop("BCPNE", [bs("11011000"), imm4, bs("0101"), disp17]) + +# BCPAT cccc,disp17 - 1101_1000_cccc_0110 dddd_dddd_dddd_dddd +addop("BCPAT", [bs("11011000"), imm4, bs("0110"), disp17]) + +# BCPAF cccc,disp17 - 1101_1000_cccc_0111 dddd_dddd_dddd_dddd +addop("BCPAF", [bs("11011000"), imm4, bs("0111"), disp17]) + +# JMP target24 - 1101_1TTT_TTTT_1000 tttt_tttt_tttt_tttt +addop("JMP", [bs("11011"), imm7_noarg, bs("1000"), imm_target24], + [imm_target24]) # the only interesting operand is imm_target24 + +# BSR disp24 - 1101_1DDD_DDDD_1001 dddd_dddd_dddd_dddd +addop("BSR", [bs("11011"), imm7_noarg, bs("1001"), imm_target24_signed], [imm_target24_signed]) + +# BSRV disp24 1101_1DDD_DDDD_1011 dddd_dddd_dddd_dddd +addop("BSRV", [bs("11011"), imm7_noarg, bs("1011"), imm_target24], [imm_target24]) + + +### <Major Opcode #14> + +# BEQI Rn,imm4,disp17 - 1110_nnnn_iiii_0000 dddd_dddd_dddd_dddd +addop("BEQI", [bs("1110"), reg04, imm4, bs("0000"), disp17]) + +# BEQ Rn,Rm,disp17 - 1110_nnnn_mmmm_0001 dddd_dddd_dddd_dddd +addop("BEQ", [bs("1110"), reg04, reg04, bs("0001"), disp17]) + +# BNEI Rn,imm4,disp17 - 1110_nnnn_iiii_0100 dddd_dddd_dddd_dddd +addop("BNEI", [bs("1110"), reg04, imm4, bs("0100"), disp17]) + +# BNE Rn,Rm,disp17 - 1110_nnnn_mmmm_0101 dddd_dddd_dddd_dddd +addop("BNE", [bs("1110"), reg04, reg04, bs("0101"), disp17]) + +# BGEI Rn,imm4,disp17 - 1110_nnnn_iiii_1000 dddd_dddd_dddd_dddd +addop("BGEI", [bs("1110"), reg04, imm4, bs("1000"), disp17]) + +# REPEAT Rn,disp17 - 1110_nnnn_0000_1001 dddd_dddd_dddd_dddd +addop("REPEAT", [bs("1110"), reg04, bs("00001001"), disp17]) + +# EREPEAT disp17 - 1110_0000_0001_1001 dddd_dddd_dddd_dddd +addop("EREPEAT", [bs("1110000000011001"), disp17]) + +# BLTI Rn,imm4,disp17 - 1110_nnnn_iiii_1100 dddd_dddd_dddd_dddd +addop("BLTI", [bs("1110"), reg04, imm4, bs("1100"), disp17]) + +# (RI) - 1110_xxxx_xxxx_1101 xxxx_xxxx_xxxx_xxxx +addop("(RI)", [bs("1110"), imm8, bs("1101"), imm16]) + +# SW Rn,(abs24) - 1110_nnnn_DDDD_DD10 dddd_dddd_dddd_dddd +addop("SW", [bs("1110"), reg04, imm6_noarg, bs("10"), abs24]) + +# LW Rn,(abs24) - 1110_nnnn_DDDD_DD11 dddd_dddd_dddd_dddd +addop("LW", [bs("1110"), reg04, imm6_noarg, bs("11"), abs24]) + + +### <Major Opcode #15> + +# DSP Rn,Rm,code16 - 1111_nnnn_mmmm_0000 cccc_cccc_cccc_cccc +addop("DSP", [bs("1111"), reg04, reg04, bs("0000"), imm16]) + +# Note: DSP, DSP0 & DSP1 look exactly the same. This is ambiguous, and prevent +# them for being correctly disassembled. DSP0 & DSP1 are arbitrarily +# disabled. + +# DSP0 code24 - 1111_nnnn_mmmm_0000 cccc_cccc_cccc_cccc +#addop("DSP0", [bs("1111"), imm8_noarg, bs("0000"), imm_code24], [imm_code24]) + +# DSP1 Rn,code20 - 1111_nnnn_mmmm_0000 cccc_cccc_cccc_cccc +#addop("DSP1", [bs("1111"), reg04, imm4_noarg, bs("0000"), imm_code20]) + +# LDZ Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0000 +addop("LDZ", [bs("1111"), reg04, reg04, bs("00010000000000000000")]) + +# AVE Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0010 +addop("AVE", [bs("1111"), reg04, reg04, bs("00010000000000000010")]) + +# ABS Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0011 +addop("ABS", [bs("1111"), reg04, reg04, bs("00010000000000000011")]) + +# MIN Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0100 +addop("MIN", [bs("1111"), reg04, reg04, bs("00010000000000000100")]) + +# MAX Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0101 +addop("MAX", [bs("1111"), reg04, reg04, bs("00010000000000000101")]) + +# MINU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0110 +addop("MINU", [bs("1111"), reg04, reg04, bs("00010000000000000110")]) + +# MAXU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0111 +addop("MAXU", [bs("1111"), reg04, reg04, bs("00010000000000000111")]) + +# SADD Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1000 +addop("SADD", [bs("1111"), reg04, reg04, bs("00010000000000001000")]) + +# SADDU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1001 +addop("SADDU", [bs("1111"), reg04, reg04, bs("00010000000000001001")]) + +# SSUB Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1010 +addop("SSUB", [bs("1111"), reg04, reg04, bs("00010000000000001010")]) + +# SSUBU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1011 +addop("SSUBU", [bs("1111"), reg04, reg04, bs("00010000000000001011")]) + +# CLIP Rn,imm5 - 1111_nnnn_0000_0001 0001_0000_iiii_i000 +addop("CLIP", [bs("1111"), reg04, bs("0000000100010000"), imm5, bs("000")]) + +# CLIPU Rn,imm5 - 1111_nnnn_0000_0001 0001_0000_iiii_i001 +addop("CLIPU", [bs("1111"), reg04, bs("0000000100010000"), imm5, bs("001")]) + +# (RI) - 1111_xxxx_xxxx_0001 0010_xxxx_xxxx_xxxx +addop("(RI)", [bs("1111"), imm8, bs("00010010"), imm12]) + +# MADD Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0100 +addop("MADD", [bs("1111"), reg04, reg04, bs("00010011000000000100")]) + +# MADDU Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0101 +addop("MADDU", [bs("1111"), reg04, reg04, bs("00010011000000000101")]) + +# MADDR Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0110 +addop("MADDR", [bs("1111"), reg04, reg04, bs("00010011000000000110")]) + +# MADDRU Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0111 +addop("MADDRU", [bs("1111"), reg04, reg04, bs("00010011000000000111")]) + +# UCI Rn,Rm,code16 - 1111_nnnn_mmmm_0010 cccc_cccc_cccc_cccc +addop("UCI", [bs("1111"), reg04, reg04, bs("0010"), imm16]) + +# (RI) - 1111_xxxx_xxxx_0011 xxxx_xxxx_xxxx_xxxx +addop("(RI)", [bs("1111"), imm8, bs("0011"), imm16]) + +# STCB Rn,abs16 - 1111_nnnn_0000_0100 aaaa_aaaa_aaaa_aaaa +addop("STCB", [bs("1111"), reg04, bs("00000100"), imm16]) + +# LDCB Rn,abs16 - 1111_nnnn_0001_0100 aaaa_aaaa_aaaa_aaaa +addop("LDCB", [bs("1111"), reg04, bs("00010100"), imm16]) + +# SBCPA CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0000_0000_iiii_iiii +addop("SBCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100000000"), imm8]) + +# SHCPA CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0001_0000_iiii_iii0 +addop("SHCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100010000"), imm8_align2, bs("0")]) + +# SWCPA CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0010_0000_iiii_ii00 +addop("SWCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100100000"), imm8_align4, bs("00")]) + +# SMCPA CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0011_0000_iiii_i000 +addop("SMCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100110000"), imm8_align8, bs("000")]) + +# LBCPA CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0100_0000_iiii_iiii +addop("LBCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101000000"), imm8]) + +# LHCPA CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0101_0000_iiii_iii0 +addop("LHCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101010000"), imm8_align2, bs("0")]) + +# LWCPA CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0110_0000_iiii_ii00 +addop("LWCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101100000"), imm8_align4, bs("00")]) + +# LMCPA CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0111_0000_iiii_i000 +addop("LMCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101110000"), imm8_align8, bs("000")]) + +# SBCPM0 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0000_1000_iiii_iiii +addop("SBCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100001000"), imm8]) + +# SHCPM0 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0001_1000_iiii_iii0 +addop("SHCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100011000"), imm8_align2, bs("0")]) + +# SWCPM0 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0010_1000_iiii_ii00 +addop("SWCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100101000"), imm8_align4, bs("00")]) + +# SMCPM0 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0011_1000_iiii_i000 +addop("SMCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100111000"), imm8_align8, bs("000")]) + +# LBCPM0 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0100_1000_iiii_iiii +addop("LBCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101001000"), imm8]) + +# LHCPM0 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0101_1000_iiii_iii0 +addop("LHCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101011000"), imm8_align2, bs("0")]) + +# LWCPM0 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0110_1000_iiii_ii00 +addop("LWCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101101000"), imm8_align4, bs("00")]) + +# LMCPM0 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0111_1000_iiii_i000 +addop("LMCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101111000"), imm8_align8, bs("000")]) + +# SBCPM1 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0000_1100_iiii_iiii +addop("SBCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100001100"), imm8]) + +# SHCPM1 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0001_1100_iiii_iii0 +addop("SHCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100011100"), imm8_align2, bs("0")]) + +# SWCPM1 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0010_1100_iiii_ii00 +addop("SWCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100101100"), imm8_align4, bs("00")]) + +# SMCPM1 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0011_1100_iiii_i000 +addop("SMCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100111100"), imm8_align8, bs("000")]) + +# LBCPM1 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0100_1100_iiii_iiii +addop("LBCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101001100"), imm8]) + +# LHCPM1 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0101_1100_iiii_iii0 +addop("LHCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101011100"), imm8_align2, bs("0")]) + +# LWCPM1 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0110_1100_iiii_ii00 +addop("LWCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101101100"), imm8_align4, bs("00")]) + +# LMCPM1 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0111_1100_iiii_i000 +addop("LMCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101111100"), imm8_align8, bs("000")]) + +# (RI) - 1111_xxxx_xxxx_0110 xxxx_xxxx_xxxx_xxxx +addop("(RI)", [bs("1111"), imm8, bs("0110"), imm16]) + +# CP code24 - 1111_CCCC_CCCC_0111 cccc_cccc_cccc_cccc +#addop("CP", [bs("1111"), imm8_noarg, bs("0111"), imm_code24], [imm_code24]) +# Note: CP & CMOV* look exactly the same. This is ambiguous, and prevent +# them for being correctly disassembled. CP was arbitrarily disabled. + +# CP code56 - 1111_CCCC_CCCC_0111 cccc_cccc_cccc_cccc cccc_cccc_cccc_cccc +# 64-bit VLIW operation mode - not implemented + +# CMOV CRn,Rm - 1111_nnnn_mmmm_0111 1111_0000_0000_0000 +#addop("CMOV", [bs("1111"), copro_reg04, reg04, bs("01111111000000000000")]) + +# CMOV Rm,CRn - 1111_nnnn_mmmm_0111 1111_0000_0000_0001 +#addop("CMOV", [bs("1111"), copro_reg04, reg04, bs("01111111000000000001")], [reg04, copro_reg04]) + +# CMOVC CCRn,Rm - 1111_nnnn_mmmm_0111 1111_0000_0000_NN10 +# CRn=NNnnnn +addop("CMOVC", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg06, bs("10")], [copro_reg06, reg04]) + +# CMOVC Rm,CCRn - 1111_nnnn_mmmm_0111 1111_0000_0000_NN11 +# CRn=NNnnnn +addop("CMOVC", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg06, bs("11")], [reg04, copro_reg06]) + +# CMOVH CRn,Rm - 1111_nnnn_mmmm_0111 1111_0001_0000_0000 +#addop("CMOVH", [bs("1111"), copro_reg04, reg04, bs("01111111000100000000")]) + +# CMOVH Rm,CRn - 1111_nnnn_mmmm_0111 1111_0001_0000_0001 +#addop("CMOVH", [bs("1111"), copro_reg04, reg04, bs("01111111000100000001")], [reg04, copro_reg04]) + +# Note: the following CMOV* instructions are extensions used when the processor +# has more than 16 coprocessor general-purpose registers. They can be +# used to assemble and disassemble both CMOV* instructuons sets. + +# CMOV CRn,Rm - 1111_nnnn_mmmm_0111 1111_0000_0000_N000 +# CRn=Nnnnn +addop("CMOV", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg05, bs("000")], [copro_reg05, reg04]) + +# CMOV Rm,CRn - 1111_nnnn_mmmm_0111 1111_0000_0000_N001 +addop("CMOV", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg05, bs("001")], [reg04, copro_reg05]) + +# CMOVH CRn,Rm - 1111_nnnn_mmmm_0111 1111_0001_0000_N000 +addop("CMOVH", [bs("1111"), imm4_noarg, reg04, bs("0111111100010000"), copro_reg05, bs("000")], [copro_reg05, reg04]) + +# CMOVH Rm,CRn - 1111_nnnn_mmmm_0111 1111_0001_0000_N001 +addop("CMOVH", [bs("1111"), imm4_noarg, reg04, bs("0111111100010000"), copro_reg05, bs("001")], [reg04, copro_reg05]) + +# (RI) - 1111_xxxx_xxxx_10xx xxxx_xxxx_xxxx_xxxx +addop("(RI)", [bs("1111"), imm8, bs("10"), imm18]) + +# SWCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1100 dddd_dddd_dddd_dddd +addop("SWCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1100"), disp16_reg_deref], [copro_reg04, disp16_reg_deref]) + +# LWCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1101 dddd_dddd_dddd_dddd +addop("LWCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1101"), disp16_reg_deref], [copro_reg04, disp16_reg_deref, reg04_deref]) + +# SMCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1110 dddd_dddd_dddd_dddd +addop("SMCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1110"), disp16_reg_deref], [copro_reg04, disp16_reg_deref, reg04_deref]) + +# LMCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1111 dddd_dddd_dddd_dddd +addop("LMCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1111"), disp16_reg_deref], [copro_reg04, disp16_reg_deref]) diff --git a/src/miasm/arch/mep/disasm.py b/src/miasm/arch/mep/disasm.py new file mode 100644 index 00000000..0260c01d --- /dev/null +++ b/src/miasm/arch/mep/disasm.py @@ -0,0 +1,23 @@ +# Toshiba MeP-c4 - miasm disassembly engine +# Guillaume Valadon <guillaume@valadon.net> + +from miasm.core.asmblock import disasmEngine +from miasm.arch.mep.arch import mn_mep + + +class dis_mepb(disasmEngine): + """MeP miasm disassembly engine - Big Endian + + Notes: + - its is mandatory to call the miasm Machine + """ + + attrib = "b" + + def __init__(self, bs=None, **kwargs): + super(dis_mepb, self).__init__(mn_mep, self.attrib, bs, **kwargs) + + +class dis_mepl(dis_mepb): + """MeP miasm disassembly engine - Little Endian""" + attrib = "l" diff --git a/src/miasm/arch/mep/jit.py b/src/miasm/arch/mep/jit.py new file mode 100644 index 00000000..3fee2537 --- /dev/null +++ b/src/miasm/arch/mep/jit.py @@ -0,0 +1,112 @@ +# Toshiba MeP-c4 - miasm jitter +# Guillaume Valadon <guillaume@valadon.net> +# Note: inspiration from msp430/jit.py + +from miasm.jitter.jitload import Jitter +from miasm.core.utils import * +from miasm.jitter.codegen import CGen +from miasm.ir.translators.C import TranslatorC +from miasm.arch.mep.sem import Lifter_MEPl, Lifter_MEPb + +import logging + +log = logging.getLogger("jit_mep") +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) + + +class mep_CGen(CGen): + """ + Translate a block containing MeP instructions to C + + Note: it is used to emulate the *REPEAT instructions + """ + + def __init__(self, lifter): + self.lifter = lifter + self.PC = self.lifter.arch.regs.PC + self.translator = TranslatorC(self.lifter.loc_db) + self.init_arch_C() + + def gen_pre_code(self, attrib): + """Generate C code inserted before the current block""" + + # Call the base class method + out = super(mep_CGen, self).gen_pre_code(attrib) + + # Set the PC register value explicitly + out.append("mycpu->PC = 0x%X;" % attrib.instr.offset) + out.append("mycpu->last_addr = mycpu->PC;"); + + return out + + def gen_post_code(self, attrib, pc_value): + """Generate C code inserted after the current block""" + + # Call the base class method + out = super(mep_CGen, self).gen_post_code(attrib, pc_value) + + # Implement the *REPEAT instructions logics + tmp = r""" + /* *REPEAT instructions logic */ + { + uint32_t is_repeat_end = mycpu->is_repeat_end; + mycpu->is_repeat_end = !!(mycpu->last_addr == (mycpu->RPE&~0x1)); + + if (is_repeat_end && !mycpu->take_jmp && + (mycpu->in_erepeat || mycpu->RPC)) { + if (mycpu->RPC) + mycpu->RPC --; + + //printf("Go repeat %X\n", mycpu->RPB); + DST_value = mycpu->RPB; + BlockDst->address = mycpu->RPB; + return JIT_RET_NO_EXCEPTION; + } + } + """ + + out += tmp.split('`\n') + return out + + +class jitter_mepl(Jitter): + + C_Gen = mep_CGen + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_MEPl(loc_db), *args, **kwargs) + self.vm.set_little_endian() + self.lifter.jit_pc = self.lifter.arch.regs.PC + + def push_uint16_t(self, v): + regs = self.cpu.get_gpreg() + regs["SP"] -= 2 + self.cpu.set_gpreg(regs) + self.vm.set_mem(regs["SP"], pck16(v)) + + def pop_uint16_t(self): + regs = self.cpu.get_gpreg() + x = self.vm.get_u16(regs["SP"]) + regs["SP"] += 2 + self.cpu.set_gpreg(regs) + return x + + def get_stack_arg(self, n): + regs = self.cpu.get_gpreg() + x = self.vm.get_u16(regs["SP"] + 2 * n) + return x + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.PC = self.pc + + +class jitter_mepb(jitter_mepl): + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_MEPb(loc_db), *args, **kwargs) + self.vm.set_big_endian() + self.lifter.jit_pc = self.lifter.arch.regs.PC diff --git a/src/miasm/arch/mep/lifter_model_call.py b/src/miasm/arch/mep/lifter_model_call.py new file mode 100644 index 00000000..db729ba0 --- /dev/null +++ b/src/miasm/arch/mep/lifter_model_call.py @@ -0,0 +1,45 @@ +# Toshiba MeP-c4 - miasm IR analysis +# Guillaume Valadon <guillaume@valadon.net> + +from miasm.arch.mep.sem import Lifter_MEPb, Lifter_MEPl +from miasm.ir.analysis import LifterModelCall + + +class LifterModelCallMepb(Lifter_MEPb, LifterModelCall): + """MeP high level IR manipulations - Big Endian + + Notes: + - it is mandatory for symbolic execution. + """ + + def __init__(self, loc_db): + Lifter_MEPb.__init__(self, loc_db) + self.ret_reg = self.arch.regs.R0 + + # Note: the following are abstract method and must be implemented + def sizeof_char(self): + "Return the size of a char in bits" + return 8 + + def sizeof_short(self): + "Return the size of a short in bits" + return 16 + + def sizeof_int(self): + "Return the size of an int in bits" + return 32 + + def sizeof_long(self): + "Return the size of a long in bits" + return 32 + + def sizeof_pointer(self): + "Return the size of a void* in bits" + return 32 + + +class LifterModelCallMepl(Lifter_MEPl, LifterModelCallMepb): + """MeP high level IR manipulations - Little Endian""" + + def __init__(self, loc_db): + LifterModelCallMepb.__init__(self, loc_db) diff --git a/src/miasm/arch/mep/regs.py b/src/miasm/arch/mep/regs.py new file mode 100644 index 00000000..be195b61 --- /dev/null +++ b/src/miasm/arch/mep/regs.py @@ -0,0 +1,91 @@ +# Toshiba MeP-c4 - miasm registers definition +# Guillaume Valadon <guillaume@valadon.net> + +from builtins import range +from miasm.expression.expression import ExprId +from miasm.core.cpu import reg_info, gen_reg, gen_regs + +# Used by internal miasm exceptions +exception_flags = ExprId("exception_flags", 32) +exception_flags_init = ExprId("exception_flags_init", 32) + +is_repeat_end = ExprId("is_repeat_end", 32) +is_repeat_end_init = ExprId("is_repeat_end_init", 32) +last_addr = ExprId("last_addr", 32) +last_addr_init = ExprId("last_addr_init", 32) +take_jmp = ExprId("take_jmp", 32) +take_jmp_init = ExprId("take_jmp_init", 32) +in_erepeat = ExprId("in_erepeat", 32) +in_erepeat_init = ExprId("take_jmp_init", 32) + + +# General-purpose registers (R0 to R15) names +gpr_names = ["R%d" % r for r in range(13)] # register names +gpr_names += ["TP", "GP", "SP"] # according to the manual GP does not exist +gpr_exprs, gpr_inits, gpr_infos = gen_regs(gpr_names, globals()) # sz=32 bits (default) + +# Notes: +# - gpr_exprs: register ExprIds on 32 bits. The size is important for +# symbolic execution. +# - gpr_inits: register initial values. +# - gpr_infos: object that binds names & ExprIds + +# Define aliases to general-purpose registers +TP = gpr_exprs[13] # Tiny data area Pointer +GP = gpr_exprs[14] # Global Pointer +SP = gpr_exprs[15] # Stack Pointer + + +# Control/special registers name +csr_names = ["PC", "LP", "SAR", "S3", "RPB", "RPE", "RPC", "HI", "LO", + "S9", "S10", "S11", "MB0", "ME0", "MB1", "ME1", "PSW", + "ID", "TMP", "EPC", "EXC", "CFG", "S22", "NPC", "DBG", + "DEPC", "OPT", "RCFG", "CCFG", "S29", "S30", "S31", "S32"] +csr_exprs, csr_inits, csr_infos = gen_regs(csr_names, globals()) + +# Define aliases to control/special registers +PC = csr_exprs[0] # Program Counter. On MeP, it is the special register R0 +LP = csr_exprs[1] # Link Pointer. On MeP, it is the special register R1 +SAR = csr_exprs[2] # Shift Amount Register. On MeP, it is the special register R2 +RPB = csr_exprs[4] # Repeat Begin. On MeP, it is the special register R4 +RPE = csr_exprs[5] # Repeat End. On MeP, it is the special register R5 +RPC = csr_exprs[6] # Repeat Counter. On MeP, it is the special register R6 + + +# Coprocesssor general-purpose registers (C0 to C15) names +# Note: a processor extension allows up to 32 coprocessor general-purpose registers +copro_gpr_names = ["C%d" % r for r in range(32)] # register names +copro_gpr_exprs, copro_gpr_inits, copro_gpr_infos = gen_regs(copro_gpr_names, globals()) + + +# Set registers initial values +all_regs_ids = gpr_exprs + csr_exprs + copro_gpr_exprs + [ + exception_flags, take_jmp, last_addr, is_repeat_end, + in_erepeat +] + +all_regs_ids_init = gpr_inits + csr_inits + copro_gpr_inits + [ + exception_flags_init, take_jmp_init, last_addr_init, is_repeat_end_init, + in_erepeat_init +] + +all_regs_ids_no_alias = all_regs_ids[:] # GV: not understood yet ! +all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) + + +float_st0 = ExprId("float_st0", 64) +float_st1 = ExprId("float_st1", 64) +float_st2 = ExprId("float_st2", 64) +float_st3 = ExprId("float_st3", 64) +float_st4 = ExprId("float_st4", 64) +float_st5 = ExprId("float_st5", 64) +float_st6 = ExprId("float_st6", 64) +float_st7 = ExprId("float_st7", 64) + +regs_flt_expr = [float_st0, float_st1, float_st2, float_st3, + float_st4, float_st5, float_st6, float_st7] + + +regs_init = dict() # mandatory name +for i, r in enumerate(all_regs_ids): + regs_init[r] = all_regs_ids_init[i] diff --git a/src/miasm/arch/mep/sem.py b/src/miasm/arch/mep/sem.py new file mode 100644 index 00000000..0ac50c58 --- /dev/null +++ b/src/miasm/arch/mep/sem.py @@ -0,0 +1,1240 @@ +# Toshiba MeP-c4 - miasm instructions side effects +# Guillaume Valadon <guillaume@valadon.net> + +from miasm.core.sembuilder import SemBuilder +from miasm.ir.ir import Lifter +from miasm.arch.mep.arch import mn_mep +from miasm.arch.mep.regs import PC, SP, LP, SAR, TP, RPB, RPE, RPC, EPC, NPC, \ + take_jmp, in_erepeat +from miasm.arch.mep.regs import EXC, HI, LO, PSW, DEPC, DBG +from miasm.expression.expression import ExprId, ExprInt, ExprOp, TOK_EQUAL +from miasm.expression.expression import ExprAssign, ExprCond, ExprMem +from miasm.core.cpu import sign_ext +from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO + +from miasm.arch.mep.regs import exception_flags + + +def compute_s_inf(arg1, arg2): + """Signed comparison operator""" + return ((arg1 - arg2) ^ ((arg1 ^ arg2) & ((arg1 - arg2) ^ arg1))).msb() + +def compute_u_inf(x, y): + """Unsigned comparison operator""" + result = (((x - y) ^ ((x ^ y) & ((x - y) ^ x))) ^ x ^ y).msb() + return result + +def i8(value): + return ExprInt(value, 8) + +def i32(value): + return ExprInt(value, 32) + + +# SemBuilder context +ctx = {"PC": PC, "SP": SP, "LP": LP, "SAR": SAR, "TP": TP, + "RPB": RPB, "RPE": RPE, "RPC": RPC, "EPC": EPC, "NPC": NPC, + "EXC": EXC, "HI": HI, "LO": LO, "PSW": PSW, "DEPC": DEPC, "DBG": DBG, + "exception_flags": exception_flags, "compute_s_inf": compute_s_inf, + "compute_u_inf": compute_u_inf, "take_jmp": take_jmp, + "in_erepeat": in_erepeat, "EXCEPT_DIV_BY_ZERO": EXCEPT_DIV_BY_ZERO} +sbuild = SemBuilder(ctx) + + +# Functions used to get an instruction IR +manual_functions = dict() + + +@sbuild.parse +def mep_nop(): + """Dummy instruction""" + + +@sbuild.parse +def mep_nop_2_args(arg1, arg2): + """Dummy instruction with two arguments""" + + +### Load/Store instructions + +# Register indirect addressing mode + +def sb(ir, instr, reg_src, deref_dst): + """SB - Store Byte into memory""" + + # MemByte(Rm31..0) <- Rn7..0 + # MemByte((ZeroExt(disp7)+TP)31..0)) <- Rn7..0 + # MemByte((SignExt(disp16)+Rm)31..0) <- Rn7..0 + e = [] + e.append(ExprAssign(ExprMem(deref_dst.ptr, 8), reg_src[:8])) + return e, [] + +manual_functions["sb"] = sb + + +def sh(ir, instr, reg_src, deref_dst): + """SH - Store Halfword into memory""" + + # MemHword(Rm31..1||0) <- Rn15..0 + # MemHword((ZeroExt((disp7)6..1||0)+TP)31..1||0)) <- Rn15..0 + # MemHword((SignExt(disp16)+Rm)31..1||0) <- Rn15..0 + e = [] + e.append(ExprAssign(ExprMem(deref_dst.ptr & i32(0xFFFFFFFE), 16), reg_src[:16])) + return e, [] + +manual_functions["sh"] = sh + + +def sw(ir, instr, reg_src, deref_dst): + """SW - Store Word into memory""" + + # MemWord(Rm31..2||00) <- Rn31..0 + # MemWord((ZeroExt((disp7)6..2||00)+SP)31..2||00)) <- Rn31..0 + # MemWord((ZeroExt((disp7)6..2||00)+TP)31..2||00)) <- Rn31..0 + # MemWord((SignExt(disp16)+Rm)31..2||00) <- Rn31..0 + # MemWord(ZeroExt((abs24)23..2||00)) - Rn31..0 + e = [] + e.append(ExprAssign(ExprMem(deref_dst.ptr & i32(0xFFFFFFFC), 32), reg_src)) + return e, [] + +manual_functions["sw"] = sw + +# Without the sembuilder +#def sw(ir, instr, reg_src, deref_reg_or_imm, deref_reg=None): +# """SW - store Word into memory. +# +# Note: there are three variants to get the memory address: +# - from a register +# - relatively to SP +# - relatively to TP""" +# +# if isinstance(deref_reg_or_imm, ExprMem): +# # MemWord(Rm31..2||00) <- Rn31..0 +# dst = deref_reg_or_imm +# +# elif isinstance(deref_reg_or_imm, ExprInt) and deref_reg: +# # MemWord((ZeroExt((disp7)6..2||00)+SP)31..2||00)) <- Rn31..0 +# # MemWord((ZeroExt((disp7)6..2||00)+TP)31..2||00)) <- Rn31..0 +# +# imm = deref_reg_or_imm.zeroExtend(32) +# dst = ExprMem(ExprOp("+", imm, deref_reg.arg)) +# +# return [ExprAssign(dst, reg_src)], [] + + +def lb(ir, instr, reg_dst, deref_dst): + """LB - Load Byte from memory""" + + # Rn <- SignExt(MemByte(Rm31..0)) + # Rn <- SignExt(MemByte((ZeroExt(disp7)+TP)31..0)) + # Rn <- SignExt(MemByte((SignExt(disp16)+Rm)31..0) + e = [] + e.append(ExprAssign(reg_dst, ExprMem(deref_dst.ptr, 8).signExtend(32))) + return e, [] + +manual_functions["lb"] = lb + + +def lh(ir, instr, reg_dst, deref_dst): + """LH - Load Halfword from memory""" + + # Rn <- SignExt(MemHword(Rm31..1||0)) + # Rn <- SignExt(MemHword((ZeroExt((disp7)6..1||0)+TP)31..1||0) + # Rn <- SignExt(MemHword((SignExt(disp16)+Rm)31..1||0)) + e = [] + e.append(ExprAssign(reg_dst, ExprMem(deref_dst.ptr & i32(0xFFFFFFFE), 16).signExtend(32))) + return e, [] + +manual_functions["lh"] = lh + +def lw(ir, instr, reg_dst, deref_dst): + """LW - Load Word from memory""" + + # Rn <- MemWord(Rm31..2||00) + # Rn <- MemWord((ZeroExt((disp7)6..2||00)+TP)31..2||00) + # Rn <- MemWord((SignExt(disp16)+Rm)31..2||00) + # Rn <- MemWord(ZeroExt((abs24)23..2||00)) + e = [] + e.append(ExprAssign(reg_dst, ExprMem(deref_dst.ptr & i32(0xFFFFFFFC), 32))) + return e, [] + +manual_functions["lw"] = lw + + +def lbu(ir, instr, reg_dst, deref_dst): + """LBU - Load an unsigned Byte from memory""" + + # Rn <- ZeroExt(MemByte(Rm31..0)) + # Rn <- ZeroExt(MemByte((ZeroExt(disp7)+TP)31..0)) + # Rn <- ZeroExt(MemByte((SignExt(disp16)+Rm)31..0)) + e = [] + e.append(ExprAssign(reg_dst, ExprMem(deref_dst.ptr, 8).zeroExtend(32))) + return e, [] + +manual_functions["lbu"] = lbu + + +def lhu(ir, instr, reg_dst, deref_dst): + """LHU - Load an unsigned Halfword from memory""" + + # Rn <- ZeroExt(MemHword(Rm31..1||0)) + # Rn <- ZeroExt(MemHword((SignExt(disp16)+Rm)31..1||0)) + # Rn <- ZeroExt(MemHword((ZeroExt((disp7)6..1||0)+TP)31..1||0)) + e = [] + e.append(ExprAssign(reg_dst, ExprMem(deref_dst.ptr & i32(0xFFFFFFFE), 16).zeroExtend(32))) + return e, [] + +manual_functions["lhu"] = lhu + + + +### Byte/Halfword extension instructions + +@sbuild.parse +def extb(reg): + """EXTB - Sign extend a byte""" + + # Rn <- SignExt(Rn7..0) + reg = reg[:8].signExtend(32) + + +@sbuild.parse +def exth(reg): + """EXTH - Sign extend a word""" + + # Rn <- ZeroExt(Rn15..0) + reg = reg[:16].signExtend(32) + + +@sbuild.parse +def extub(reg): + """EXUTB - Zero extend a byte""" + + # Rn <- SignExt(Rn7..0) + reg = reg[:8].zeroExtend(32) + + +@sbuild.parse +def extuh(reg): + """EXTUH - Zero extend a word""" + + # Rn <- ZeroExt(Rn15..0) + reg = reg[:16].zeroExtend(32) + + +### Shift amount manipulation instructions + +#@sbuild.parse +#def ssarb(deref_reg): + + +### Move instructions + +@sbuild.parse +def mov(reg, value): + """MOV - Copy 'value' to a register. The three alternatives are handled.""" + + # Rn <- Rm + # Rn <- SignExt(imm8) + # Rn <- SignExt(imm16) + reg = value.signExtend(32) + + +@sbuild.parse +def movu(reg, value): + """MOV - Copy 'value' to a register. The two alternatives are handled.""" + + # Rn[0-7] <- ZeroExt(imm24) + # Rn <- ZeroExt(imm16) + reg = value.zeroExtend(32) + + +@sbuild.parse +def movh(reg, imm16): + """MOVH - Copy a shifted imm16 to a register.""" + + # Rn <- imm16 <<16 + reg = imm16.zeroExtend(32) << i32(16) + + +### Arithmetic instructions + +def add3(ir, instr, reg_dst, reg_src, reg_or_imm): + """ADD3 - Add two register and store the result to a register, or + add a register and an immediate and store the result to a register""" + + if isinstance(reg_or_imm, ExprId): + # Rl <- Rn + Rm + result = ExprOp("+", reg_src, reg_or_imm) + else: + # Rn <- Rm + SignExt(imm16) + value = int(reg_or_imm) + result = ExprOp("+", reg_src, ExprInt(value, 32)) + + return [ExprAssign(reg_dst, result)], [] + +manual_functions["add3"] = add3 + + +@sbuild.parse +def add(arg1, arg2): + """ADD - Add a register and an immediate.""" + + # Rn <- Rn + SignExt(imm6) + arg1 = arg1 + arg2.signExtend(32) + + +@sbuild.parse +def advck3(r0, rn, rm): + """ADVCK3 - Check addition overflow.""" + + # if(Overflow(Rn+Rm)) R0<-1 else R0<-0 (Signed) + r0 = i32(1) if compute_u_inf(i64(0xFFFFFFFF), rn.zeroExtend(64) + rm.zeroExtend(64)) else i32(0) + + +@sbuild.parse +def sub(reg1, reg2): + """SUB - Subtract one register to another.""" + + # Rn <- Rn - Rm + reg1 = reg1 - reg2 + + +def sbvck3(ir, instr, r0, rn, rm): + """SBVCK3 - Check subtraction overflow""" + + # if(Overflow(Rn-Rm)) R0<-1 else R0<-0 (Signed) + + # Subtract registers + reg_sub = ExprOp("+", rn, rm) + + # Get the register storing the highest value + max_rn_rm = ExprCond(ExprOp(">", rn, rm), rn, rm) + + # Check for an overflow + overflow_test = ExprOp(">", reg_sub, max_rn_rm) + + # Return the result + condition = ExprCond(overflow_test, ExprInt(1, 32), ExprInt(0, 32)) + return [ExprAssign(r0, condition)], [] + +manual_functions["sbvck3"] = sbvck3 + + +@sbuild.parse +def neg(reg1, reg2): + """NEG - Negate one register.""" + + # Rn <- - Rm + reg1 = - reg2 + + +@sbuild.parse +def slt3(r0, rn, rm_or_imm5): + """SLT3 - Set on less than (signed).""" + + # if (Rn<Rm) R0<-1 else R0<-0 (Signed) + # if (Rn<ZeroExt(imm5)) R0<-1 else R0<-0(Signed) + r0 = i32(1) if compute_s_inf(rn, rm_or_imm5.signExtend(32)) else i32(0) + +if False: + rm_ext = rm_or_imm5 + + # Mask sign bits + sign_mask = i32(0x80000000) + sign_rn = rn & sign_mask + sign_rm = rm_ext & sign_mask + + # Check if both numbers are positive or negative + are_both_neg = sign_rn & sign_rm + are_both_pos = ~(sign_rn & sign_rm) >> i32(31) + + # rn is positive and rm negative, return 1 + r0_mixed = i32(1) if sign_rn else i32(0) + + # rn & rm are both positives, test and return 1 or 0 + r0_pos = (i32(1) if "<"(rn, rm_ext) else i32(0)) if are_both_pos else r0_mixed + + # rn & rm are both negatives, test and return 0 or 1 + r0 = (i32(0) if "<"(rn, rm_ext) else i32(1)) if are_both_neg else r0_pos + + +@sbuild.parse +def sltu3(r0, rn, rm_or_imm5): + """SLTU3 - Set on less than (unsigned).""" + + # if (Rn<Rm) R0<-1 else R0<-0 (Unsigned) + # if (Rn<ZeroExt(imm5)) R0<-1 else R0<-0(Unsigned) + r0 = i32(1) if compute_u_inf(rn, rm_or_imm5) else i32(0) + + +@sbuild.parse +def sl1ad3(r0, rn, rm): + """SL1AD3 - Shift a register one bit left, then add another one.""" + + # R0 <- (Rn<<1) + Rm + r0 = (rn << i32(1)) + rm + + +@sbuild.parse +def sl2ad3(r0, rn, rm): + """SL2AD3 - Shift a register two bits left, then add another one.""" + + # R0 <- (Rn<<2) + Rm + r0 = (rn << i32(2)) + rm + + +### Logical instructions + +@sbuild.parse +def logical_or(rn, rm): + """OR - Logical OR between two registers.""" + + # Rn <- Rn or Rm + rn = rn | rm + +manual_functions["or"] = logical_or + + +@sbuild.parse +def logical_and(rn, rm): + """AND - Logical AND between two registers.""" + + # Rn <- Rn and Rm + rn = rn & rm + +manual_functions["and"] = logical_and + + +@sbuild.parse +def xor(rn, rm): + """XOR - Logical XOR between two registers.""" + + # Rn <- Rn xor Rm + rn = rn ^ rm + + +@sbuild.parse +def nor(rn, rm): + """NOR - Logical NOR between two registers.""" + + # Rn <- Rn nor Rm + rn = ~ (rn | rm) + + +@sbuild.parse +def or3(rn, rm, imm16): + """OR3 - Logical OR between a register and an immediate""" + + # Rn <- Rm or ZeroExt(imm16) + rn = rm | imm16 + + +@sbuild.parse +def and3(rn, rm, imm16): + """AND3 - Logical AND between a register and an immediate""" + + # Rn <- Rm and ZeroExt(imm16) + rn = rm & imm16 + + +@sbuild.parse +def xor3(rn, rm, imm16): + """XOR3 - Logical XOR between a register and an immediate""" + + # Rn <- Rm xor ZeroExt(imm16) + rn = rm ^ imm16 + + +### Shift instruction + +@sbuild.parse +def sra(rn, rm_or_imm5): + """SRA - Shift Right signed""" + + # Rn <- (Signed) Rn >> Rm4..0 + # Rn <- (Signed) Rn >> imm5 + + # Unsigned result + shift_u = rn >> rm_or_imm5 + + # Signed result + shift_mask = i32(32) - rm_or_imm5 + mask = (i32(0xFFFFFFFF) >> shift_mask) << shift_mask + shift_s = shift_u | mask + + rn = shift_s if rn.msb() else shift_u + + +@sbuild.parse +def srl(rn, rm_or_imm5): + """SRL - Shift Right unsigned.""" + + # Rn <- (Unsigned) Rn >> Rm4..0 + # Rn <- (Unsigned) Rn >> imm5 + rn = rn >> rm_or_imm5 + + +@sbuild.parse +def sll(rn, rm_or_imm5): + """SLL - Shift Left unsigned.""" + + # Rn <- (Unsigned) Rn >> Rm4..0 + # Rn <- (Unsigned) Rn << imm5 + rn = rn << rm_or_imm5 + + +@sbuild.parse +def sll3(r0, rn, imm5): + """SLL3 - Shift Left unsigned, with 3 arguments.""" + + # R0 <- (Unsigned) Rn << imm5 + r0 = rn << imm5 + + +@sbuild.parse +def fsft(rn, rm): + """FSFT - Funnel shift.""" + + # Rn <- ((Rn||Rm)<<SAR5..0)63..32 + # Note: lowest Rm bits are discarded + + sar = SAR[:5].zeroExtend(32) + tmp_rn = rn << sar # Shift Rn + tmp_rm = rm >> (i32(32) - sar) # Shift Rm in the reverse order + rn = tmp_rn | tmp_rm # Concatenate registers + + +## Branch/Jump instructions + +@sbuild.parse +def bra(disp12): + """BRA - Branch to an address.""" + + # PC <- PC + SignExt((disp12)11..1||0) + dst = disp12 + PC = dst + take_jmp = ExprInt(1, 32) + ir.IRDst = dst + + +@sbuild.parse +def beqz(reg_test, disp8): + """BEQZ - Branch if the register stores zero.""" + + # if(Rn==0) PC <- PC +SignExt((disp8)7..1||0) + dst = ExprLoc(ir.get_next_break_loc_key(instr), 32) if reg_test else disp8 + take_jmp = ExprInt(0, 32) if reg_test else ExprInt(1, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def bnez(reg_test, disp8): + """BNEZ - Branch if the register does not store zero.""" + + # if(Rn!=0) PC <- PC + SignExt((disp8)7..1||0) + dst = disp8 if reg_test else ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) if reg_test else ExprInt(0, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def beqi(reg_test, imm4, disp16): + """BEQI - Branch if the register stores imm4.""" + + # if(Rn==ZeroExt(imm4)) PC <- PC +SignExt((disp17)16..1||0) + dst = ExprLoc(ir.get_next_break_loc_key(instr), 32) if (reg_test - imm4) else disp16 + take_jmp = ExprInt(0, 32) if (reg_test - imm4) else ExprInt(1, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def bnei(reg_test, imm4, disp16): + """BNEI - Branch if the register does not store imm4.""" + + # if(Rn!=ZeroExt(imm4)) PC <- PC+SignExt((disp17)16..1||0) + dst = disp16 if (reg_test - imm4) else ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) if (reg_test - imm4) else ExprInt(0, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def blti(reg_test, imm4, disp16): + """BLTI - Branch if the register is lower than imm4.""" + + # if(Rn< ZeroExt(imm4)) PC <- PC +SignExt((disp17)16..1||0) - (Signed comparison) + dst = disp16 if compute_s_inf(reg_test, imm4) else ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) if compute_s_inf(reg_test, imm4) else ExprInt(0, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def bgei(reg_test, imm4, disp16): + """BGEI - Branch if the register is greater or equal to imm4.""" + + # if(Rn>=ZeroExt(imm4)) PC <- PC +SignExt((disp17)16..1||0) - (Signed comparison) + cond = i32(1) if ExprOp(TOK_EQUAL, reg_test, imm4) else compute_s_inf(imm4, reg_test).zeroExtend(32) + dst = disp16 if cond else ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) if cond else ExprInt(0, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def beq(rn, rm, disp16): + """BEQ - Branch if the two registers are equal.""" + + # if(Rn==Rm) PC <- PC +SignExt((disp17)16..1||0) + dst = ExprLoc(ir.get_next_break_loc_key(instr), 32) if (rn - rm) else disp16 + take_jmp = ExprInt(0, 32) if (rn - rm) else ExprInt(1, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def bne(rn, rm, disp16): + """BNE - Branch if the two registers are not equal.""" + + # if(Rn!=Rm) PC <- PC +SignExt((disp17)16..1||0) + dst = disp16 if (rn - rm) else ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) if (rn - rm) else ExprInt(0, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def bsr(disp): + """BSR - Branch to an address, and store the return address.""" + + # 16-bit variant: LP <- PC + 2; PC <- PC +SignExt((disp12)11..1||0) + # 32-bit variant: LP <- PC + 4; PC <- PC +SignExt((disp24)23..1||0) + + # Set LP + LP = ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) + + # Set PC according to the immediate size + dst = disp + PC = dst + ir.IRDst = dst + + +def jmp(ir, instr, reg_or_imm): + """JMP - Change PC to a register content or an immediate. + Note: the behavior in VLIW mode is not implemented""" + + take_jmp = ExprInt(1, 32) + + if isinstance(reg_or_imm, ExprId): + # PC <- Rm31..1||0 + new_PC = ExprAssign(PC, reg_or_imm) + else: + # PC <- PC31..28||0000||(target24)23..1||0 + new_PC = ExprAssign(PC, ExprOp("+", ExprOp("&", PC, ExprInt(0xF0000000, 32)), reg_or_imm)) + + return [new_PC, ExprAssign(ir.IRDst, new_PC)], [] + +manual_functions["jmp"] = jmp + + +@sbuild.parse +def jsr(reg): + """JSR - Jump to the register, and store the return address.""" + + # LP <- PC + 2; PC <- Rm31..1||0 + LP = ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) + PC = reg + ir.IRDst = reg + + +@sbuild.parse +def ret(): + """RET - Return from a function call. + Note: the behavior in VLIW mode is not implemented""" + + # PC <- LP31..1||0 + dst = LP + PC = dst + ir.IRDst = dst + + +# Repeat instructions + +@sbuild.parse +def repeat(rn, disp17): + """REPEAT - This instruction repeats an instruction block. It sets the RPB, + RPE and RPC control registers.""" + + # RPB <- pc+4 // Repeat Begin + RPB = PC + i32(4) + # RPE <- pc+SignExt((disp17)16..1||0)) // Repeat End + RPE = PC + i32(int(disp17) & 0xFFFFFFFE) + # RPC <- Rn + RPC = rn + in_erepeat = ExprInt(0, 32) + + +@sbuild.parse +def erepeat(disp17): + """EREPEAT - This instruction repeats an instruction block. It sets the RPB + and RPE control registers. To distinguish from the repeat instruction, + the least significant bit in the RPE register (ELR) is set to 1.""" + + # RPB <- pc+4 // Repeat Begin + RPB = PC + i32(4) + # RPE <- pc+SignExt((disp17)16..1||1)) (EREPEAT) + RPE = PC + i32(int(disp17) + 1) + # RPC <- undefined + in_erepeat = ExprInt(1, 32) + + +## Control Instructions + +@sbuild.parse +def stc(reg, control_reg): + """STC - Copy a general-purpose register into a control register.""" + + # ControlReg(imm5) <- Rn + control_reg = reg + + +@sbuild.parse +def ldc(reg, control_reg): + """LDC - Copy a control register into a general-purpose register.""" + + # Rn <- ControlReg(imm5) + reg = control_reg + + +@sbuild.parse +def di(): + """DI - Disable Interrupt""" + + # PSW.IEC<-0 + PSW = PSW & i32(0xFFFFFFFE) # PSW.IEC: bit 0 + + +@sbuild.parse +def ei(): + """EI - Enable Interrupt""" + + # PSW.IEC<-1 + PSW = PSW ^ i32(0b1) # PSW.IEC: bit 0 + + +@sbuild.parse +def reti(): + """RETI - Return from the exception/interrupt handler. + Note: the behavior in VLIW mode is not implemented""" + + #if (PSW.NMI==1) { + # PC <- NPC31..1 || 0; PSW.NMI<-0; + #} else { + # PC <- EPC31..1 || 0; + # PSW.UMC <- PSW.UMP; PSW.IEC <- PSW.IEP + #} + + # PSW.NMI == bit 9 + NMI_mask = i32(1 << 9) + + # PSW.UMP == bit 3 + # PSW.IEP == bit 1 + UMP_IEP_mask = i32((1 << 3) ^ (1 << 1)) + + # PSW.UMC == bit 2 + # PSW.IEC == bit 0 + UMC_IEC_mask = (PSW & UMP_IEP_mask) >> i32(1) + + # Get PSW.NMI + PSW_NMI = (PSW & NMI_mask) >> i32(9) + + # Set PC + dst = NPC & i32(0xFFFFFFFE) if PSW_NMI else EPC & i32(0xFFFFFFFE) + PC = dst + + # Set flags + PSW = PSW ^ NMI_mask if PSW_NMI else PSW ^ UMC_IEC_mask + + ir.IRDst = dst + + +@sbuild.parse +def swi(imm2): + """SWI - Software Interrupt""" + + # if(imm2==0) EXC.SIP0 <- 1 + # else if (imm2==1) EXC.SIP1 <- 1 + # else if (imm2==2) EXC.SIP2 <- 1 + # else if (imm2==3) EXC.SIP3 <- 1 + + # EXC.SIP0 == bit 4 + # EXC.SIP1 == bit 5 + # EXC.SIP2 == bit 6 + # EXC.SIP3 == bit 7 + + EXC = EXC ^ (i32(1) << (i32(4) + imm2)) + + +# Note: the following instructions can't be implemented +manual_functions["halt"] = mep_nop +manual_functions["sleep"] = mep_nop +manual_functions["break"] = mep_nop +manual_functions["syncm"] = mep_nop +manual_functions["stcb"] = mep_nop_2_args +manual_functions["ldcb"] = mep_nop_2_args + + +### Bit manipulation instruction option + +def bsetm(ir, instr, rm_deref, imm3): + """BSETM - Bit Set Memory""" + + # MemByte(Rm) <- MemByte(Rm) or (1<<imm3) + e = [] + e.append(ExprAssign(ExprMem(rm_deref.ptr, 8), ExprOp("|", ExprMem(rm_deref.ptr, 8), (i8(1) << imm3[:8])))) + return e, [] + +manual_functions["bsetm"] = bsetm + + +def bclrm(ir, instr, rm_deref, imm3): + """BCLRM - Bit Clear Memory""" + + # MemByte(Rm) <- MemByte(Rm) and ~(1<<imm3) + e = [] + shift = ExprOp("<<", i8(1), imm3[:8]) + e.append(ExprAssign(ExprMem(rm_deref.ptr, 8), ExprOp("&", ExprMem(rm_deref.ptr, 8), shift.__invert__()))) + return e, [] + +manual_functions["bclrm"] = bclrm + + +def bnotm(ir, instr, rm_deref, imm3): + """BNOTM - Bit Not Memory""" + + # MemByte(Rm) <- MemByte(Rm) xor (1<<imm3) + e = [] + e.append(ExprAssign(ExprMem(rm_deref.ptr, 8), ExprOp("^", ExprMem(rm_deref.ptr, 8), (i8(1) << imm3[:8])))) + return e, [] + +manual_functions["bnotm"] = bnotm + + +def btstm(ir, instr, r0, rm_deref, imm3): + """BTSTM - Bit Test Memory""" + + # R0 <- ZeroExt( MemByte(Rm) and (1<<imm3) ) + e = [] + e.append(ExprAssign(r0, ExprOp("&", ExprMem(rm_deref.ptr, 8), i8(1) << imm3[:8]).zeroExtend(32))) + return e, [] + +manual_functions["btstm"] = btstm + + +def tas(ir, instr, rn, rm_deref): + """TAS - Load And Set""" + + # temp <- Rm; Rn <- ZeroExt(MemByte(temp)); MemByte(temp) <- 1 + e = [] + temp = rm_deref + e.append(ExprAssign(rn, ExprMem(temp.ptr, 8).zeroExtend(32))) + e.append(ExprAssign(ExprMem(temp.ptr, 8), i8(1))) + return e, [] + +manual_functions["tas"] = tas + + +### Data cache option + +# Note: the following instruction can't be implemented +manual_functions["cache"] = mep_nop_2_args + + +### 32-bit multiply instruction option + +@sbuild.parse +def mul(rn, rm): + """MUL - Signed 32-bit multiplication""" + + # HI||LO <- Rn * Rm (Signed) + result = rn.signExtend(64) * rm.signExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + + +@sbuild.parse +def mulu(rn, rm): + """MUL - Unsigned 32-bit multiplication""" + + # HI||LO <- Rn * Rm (Unsigned) + result = rn.zeroExtend(64) * rm.zeroExtend(64) # expand registers size + HI = result[32:64] + LO = result[0:32] + + +@sbuild.parse +def mulr(rn, rm): + """MULR - Signed 32-bit multiplication & store LO in Rn""" + + # HI||LO <- Rn * Rm; Rn <- LO (Signed) + result = rn.signExtend(64) * rm.signExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + rn = result[:32] + + +@sbuild.parse +def mulru(rn, rm): + """MULRU - Unsigned 32-bit multiplication & store LO in Rn""" + + # HI||LO <- Rn * Rm; Rn <- LO (Unsigned) + result = rn.zeroExtend(64) * rm.zeroExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + rn = result[:32] + + +@sbuild.parse +def madd(rn, rm): + """MADD - Signed 32-bit multiplication, adding results to HI & LO registers""" + + # HI||LO <- HI||LO + Rn*Rm (Signed) + result = (HI << i32(32)).signExtend(64) + LO.signExtend(64) + rn.signExtend(64) * rm.signExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + + +@sbuild.parse +def maddu(rn, rm): + """MADDU - Unsigned 32-bit multiplication, adding results to HI & LO registers""" + + # HI||LO <- HI||LO + Rn*Rm (Unsigned) + result = (HI << i32(32)).zeroExtend(64) + LO.zeroExtend(64) + rn.zeroExtend(64) * rm.zeroExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + + +@sbuild.parse +def maddr(rn, rm): + """MADDR - Signed 32-bit multiplication, adding results to HI & LO registers & storing LO in Rn""" + + # HI||LO <- HI||LO + Rn*Rm; Rn <- LO (Signed) + result = (HI << i32(32)).signExtend(64) + LO.signExtend(64) + rn.signExtend(64) * rm.signExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + rn = result[:32] + + +@sbuild.parse +def maddru(rn, rm): + """MADDRU - Unsigned 32-bit multiplication, adding results to HI & LO registers & storing LO in Rn""" + + # HI||LO <- HI||LO + Rn*Rm; Rn <- LO (Unsigned) + result = (HI << i32(32)).zeroExtend(64) + LO.zeroExtend(64) + rn.zeroExtend(64) * rm.zeroExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + rn = result[:32] + + +### 32-bit divide instruction option + +@sbuild.parse +def div(rn, rm): + """DIV - Signed division""" + + # LO <- Rn / Rm, HI <- Rn % Rm (Signed) + + # Mask sign bits + sign_mask = i32(0x80000000) + sign_rn = rn & sign_mask + sign_rm = rm & sign_mask + + # Check if both numbers are positive or negative + are_both_neg = sign_rn & sign_rm + are_both_pos = ExprCond( + are_both_neg - sign_mask, + ExprInt(0, are_both_neg.size), + ExprInt(1, are_both_neg.size) + ) + + + # Invert both numbers + rn_inv = ~rn + i32(1) + rm_inv = ~rm + i32(1) + + # Used to delay the arithmetic computations + tmp_rm = rm if rm else i32(1) + tmp_rm_inv = rm_inv if rm_inv else i32(1) + + # Results if only rn, or rm is negative + LO_rn_neg = (~(rn_inv // tmp_rm) + i32(1)) if sign_rn else (~(rn // tmp_rm_inv) + i32(1)) + HI_rn_neg = (~(rn_inv % tmp_rm) + i32(1)) if sign_rn else (~(rn % tmp_rm_inv) + i32(1)) + + # Results if both numbers are positive + LO_pos = rn // tmp_rm if are_both_pos else LO_rn_neg + HI_pos = rn % tmp_rm if are_both_pos else HI_rn_neg + + # Results if both numbers are negative + LO_neg = rn_inv // tmp_rm_inv if are_both_neg else LO_pos + HI_neg = rn_inv % tmp_rm_inv if are_both_neg else HI_pos + + # Results if rm is equal to zero + LO = LO_neg if rm else LO + HI = HI_neg if rm else HI + + exception_flags = i32(0) if rm else i32(EXCEPT_DIV_BY_ZERO) + + +@sbuild.parse +def divu(rn, rm): + """DIVU - Unsigned division""" + + # LO <- Rn / Rm, HI <- Rn % Rm (Unsigned) + + tmp_rm = rm if rm else i32(1) # used to delay the arithmetic computations + LO = rn // tmp_rm if rm else LO + HI = rn % tmp_rm if rm else HI + + exception_flags = i32(0) if rm else i32(EXCEPT_DIV_BY_ZERO) + + +### Debug function option + +@sbuild.parse +def dret(): + """DRET - Debug Exception Return""" + + # PC <- DEPC; DBG.DM <- 0 + PC = DEPC + DBG = DBG & i32(0xFFFFBFFF) # DBG.DM: bit 15 + + +@sbuild.parse +def dbreak(): + """DBREAK - Debug break""" + + # The DBG.DBP bit becomes 1 + DBG = DBG ^ i32(0b10) # DBG.DBP: bit 2 + + +### Leading zero instruction option + +@sbuild.parse +def ldz(rn, rm): + """LDZ - Count Leading Zeroes + + Note: this implementation is readable, yet slow. Each bit are tested + individually, and the results are propagated to other bits. + + Here is the commented implementation for 4-bit integers: + rm = 0b0001 + + # Invert the value + reversed_rm = ~rm + -> reversed_rm = 0b1110 + + # Test bits individually + b3 = (reversed_rm & i32(2**3)) >> i32(3) if reversed_rm else i32(0) + -> b3 = (0b1110 & 0b1000 >> 3) = 1 + + b2 = (reversed_rm & i32(2**2)) >> i32(2) if b3 else i32(0) + -> b2 = (0b1110 & 0b0100 >> 2) = 1 + + b1 = (reversed_rm & i32(2**1)) >> i32(1) if b2 else i32(0) + -> b1 = (0b1110 & 0b0010 >> 1) = 1 + + b0 = (reversed_rm & i32(2**0)) >> i32(0) if b1 else i32(0) + -> b0 = (0b1110 & 0b0001 >> 0) = 0 + + # Sum all partial results + rn = b3 + b2 + b1 + b0 + -> rn = 1 + 1 + 1 + 0 = 3 + """ + + # Rn <- LeadingZeroDetect(Rm) + + # Invert the value + reversed_rm = ~rm + + # Test bits individually + b31 = (reversed_rm & i32(2**31)) >> i32(31) if reversed_rm else i32(0) + b30 = (reversed_rm & i32(2**30)) >> i32(30) if b31 else i32(0) + b29 = (reversed_rm & i32(2**29)) >> i32(29) if b30 else i32(0) + b28 = (reversed_rm & i32(2**28)) >> i32(28) if b29 else i32(0) + b27 = (reversed_rm & i32(2**27)) >> i32(27) if b28 else i32(0) + b26 = (reversed_rm & i32(2**26)) >> i32(26) if b27 else i32(0) + b25 = (reversed_rm & i32(2**25)) >> i32(25) if b26 else i32(0) + b24 = (reversed_rm & i32(2**24)) >> i32(24) if b25 else i32(0) + b23 = (reversed_rm & i32(2**23)) >> i32(23) if b24 else i32(0) + b22 = (reversed_rm & i32(2**22)) >> i32(22) if b23 else i32(0) + b21 = (reversed_rm & i32(2**21)) >> i32(21) if b22 else i32(0) + b20 = (reversed_rm & i32(2**20)) >> i32(20) if b21 else i32(0) + b19 = (reversed_rm & i32(2**19)) >> i32(19) if b20 else i32(0) + b18 = (reversed_rm & i32(2**18)) >> i32(18) if b19 else i32(0) + b17 = (reversed_rm & i32(2**17)) >> i32(17) if b18 else i32(0) + b16 = (reversed_rm & i32(2**16)) >> i32(16) if b17 else i32(0) + b15 = (reversed_rm & i32(2**15)) >> i32(15) if b16 else i32(0) + b14 = (reversed_rm & i32(2**14)) >> i32(14) if b15 else i32(0) + b13 = (reversed_rm & i32(2**13)) >> i32(13) if b14 else i32(0) + b12 = (reversed_rm & i32(2**12)) >> i32(12) if b13 else i32(0) + b11 = (reversed_rm & i32(2**11)) >> i32(11) if b12 else i32(0) + b10 = (reversed_rm & i32(2**10)) >> i32(10) if b11 else i32(0) + b09 = (reversed_rm & i32(2 ** 9)) >> i32(9) if b10 else i32(0) + b08 = (reversed_rm & i32(2 ** 8)) >> i32(8) if b09 else i32(0) + b07 = (reversed_rm & i32(2 ** 7)) >> i32(7) if b08 else i32(0) + b06 = (reversed_rm & i32(2 ** 6)) >> i32(6) if b07 else i32(0) + b05 = (reversed_rm & i32(2 ** 5)) >> i32(5) if b06 else i32(0) + b04 = (reversed_rm & i32(2 ** 4)) >> i32(4) if b05 else i32(0) + b03 = (reversed_rm & i32(2 ** 3)) >> i32(3) if b04 else i32(0) + b02 = (reversed_rm & i32(2 ** 2)) >> i32(2) if b03 else i32(0) + b01 = (reversed_rm & i32(2 ** 1)) >> i32(1) if b02 else i32(0) + b00 = (reversed_rm & i32(2 ** 0)) >> i32(0) if b01 else i32(0) + + # Sum all partial results + rn = b31 + b30 + b29 + b28 + b27 + b26 + b25 + b24 + b23 + b22 + b21 + b20 \ + + b19 + b18 + b17 + b16 + b15 + b14 + b13 + b12 + b11 + b10 + b09 + b08 \ + + b07 + b06 + b05 + b04 + b03 + b02 + b01 + b00 + + +### Coprocessor option + +# Note: these instructions are implemented when needed + +# SWCP - Store Word to memory from a coprocessor register +# MemWord(Rm31..2||00) <- CRn 31..0 +manual_functions["swcp"] = sw + + +# LWCP - Load Word from memory to a coprocessor register +# CRn <- MemWord(Rm31..2||00) +manual_functions["lwcp"] = lw + + +def smcp(ir, instr, reg_src, deref_dst): + """SMCP - Store Word to memory from a coprocessor register""" + + # MemDword(Rm31..3||000) <- CRn + e = [] + e.append(ExprAssign(ExprMem(deref_dst.ptr & i32(0xFFFFFFF8), 32), reg_src)) + return e, [] + +manual_functions["smcp"] = smcp + + +def lmcp(ir, instr, reg_dst, deref_src): + """LMCP - Load Word from memory to a coprocessor register""" + + # CRn <- MemDword(Rm31..3||000) + e = [] + e.append(ExprAssign(reg_dst, ExprMem(deref_src.ptr & i32(0xFFFFFFF8), 32))) + return e, [] + +manual_functions["lmcp"] = lmcp + + +def swcpi(ir, instr, reg_src, deref_dst): + """SWCPI - Store Word to memory, and increment the address""" + + # MemWord(Rm31..2||00) <- CRn 31..0; Rm<-Rm+4 + e = [] + e.append(ExprAssign(ExprMem(deref_dst.ptr & i32(0xFFFFFFFC), 32), reg_src)) + e.append(ExprAssign(deref_dst.ptr, deref_dst.ptr + i32(4))) + return e, [] + +manual_functions["swcpi"] = swcpi + + +def lwcpi(ir, instr, reg_dst, deref_src): + """LWCPI - Load Word from memory, and increment the address""" + + # CRn <- MemWord(Rm31..2||00); Rm<-Rm+4 + e = [] + e.append(ExprAssign(reg_dst, ExprMem(deref_src.ptr & i32(0xFFFFFFFC), 32))) + e.append(ExprAssign(deref_src.ptr, deref_src.ptr + i32(4))) + return e, [] + +manual_functions["lwcpi"] = lwcpi + +def smcpi(ir, instr, reg_src, deref_dst): + """SMCPI - Store Word to memory, and increment the address""" + + # MemDword(Rm31..3||000) <- CRn; Rm<-Rm+8 + e = [] + e.append(ExprAssign(ExprMem(deref_dst.ptr & i32(0xFFFFFFF8), 32), reg_src)) + e.append(ExprAssign(deref_dst.ptr, deref_dst.ptr + i32(8))) + return e, [] + +manual_functions["smcpi"] = smcpi + + +def lmcpi(ir, instr, reg_dst, deref_src): + """LMCPI - Load Word from memory, and increment the address""" + + # CRn <- MemDword(Rm31..3||000); Rm<-Rm+8 + e = [] + e.append(ExprAssign(reg_dst, ExprMem(deref_src.ptr & i32(0xFFFFFFFC), 32))) + e.append(ExprAssign(deref_src.ptr, deref_src.ptr + i32(8))) + return e, [] + +manual_functions["lmcpi"] = lmcpi + + +### IR MeP definitions + +def get_mnemo_expr(ir, instr, *args): + """Simplify getting the IR from a miasm instruction.""" + + if instr.name.lower() in sbuild.functions: + mnemo_func = sbuild.functions[instr.name.lower()] + else: + mnemo_func = manual_functions[instr.name.lower()] + + ir, extra_ir = mnemo_func(ir, instr, *args) + return ir, extra_ir + + +class Lifter_MEPb(Lifter): + """Toshiba MeP miasm IR - Big Endian + + It transforms an instructon into an IR. + """ + + addrsize = 32 + + def __init__(self, loc_db): + Lifter.__init__(self, mn_mep, "b", loc_db) + self.pc = mn_mep.getpc() + self.sp = mn_mep.getsp() + self.IRDst = ExprId("IRDst", 32) + + def get_ir(self, instr): + """Get the IR from a miasm instruction.""" + + instr_ir, extra_ir = get_mnemo_expr(self, instr, *instr.args) + + return instr_ir, extra_ir + + def get_next_break_loc_key(self, instr): + """Returns a new label that identifies where the instruction is going. + + Note: it eases linking IR blocks + """ + + l = self.loc_db.get_or_create_offset_location(instr.offset + instr.l) + return l + + +class Lifter_MEPl(Lifter_MEPb): + """Toshiba MeP miasm IR - Little Endian""" + + def __init__(self, loc_db): + Lifter.__init__(self, mn_mep, "l", loc_db) + self.pc = mn_mep.getpc() + self.sp = mn_mep.getsp() + self.IRDst = ExprId("IRDst", 32) diff --git a/src/miasm/arch/mips32/__init__.py b/src/miasm/arch/mips32/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/miasm/arch/mips32/__init__.py diff --git a/src/miasm/arch/mips32/arch.py b/src/miasm/arch/mips32/arch.py new file mode 100644 index 00000000..76ebe730 --- /dev/null +++ b/src/miasm/arch/mips32/arch.py @@ -0,0 +1,838 @@ +#-*- coding:utf-8 -*- + +import logging +from collections import defaultdict + +from pyparsing import Literal, Optional + +from miasm.expression.expression import ExprMem, ExprInt, ExprId, ExprOp, ExprLoc +from miasm.core.bin_stream import bin_stream +import miasm.arch.mips32.regs as regs +import miasm.core.cpu as cpu +from miasm.ir.ir import color_expr_html + +from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp + +log = logging.getLogger("mips32dis") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.DEBUG) + + +gpregs = cpu.reg_info(regs.regs32_str, regs.regs32_expr) + + +LPARENTHESIS = Literal("(") +RPARENTHESIS = Literal(")") + +def cb_deref(tokens): + if len(tokens) != 4: + raise NotImplementedError("TODO") + return AstMem(tokens[2] + tokens[0], 32) + +def cb_deref_nooff(tokens): + if len(tokens) != 3: + raise NotImplementedError("TODO") + return AstMem(tokens[1], 32) + +base_expr = cpu.base_expr + +deref_off = (Optional(base_expr) + LPARENTHESIS + gpregs.parser + RPARENTHESIS).setParseAction(cb_deref) +deref_nooff = (LPARENTHESIS + gpregs.parser + RPARENTHESIS).setParseAction(cb_deref_nooff) +deref = deref_off | deref_nooff + + +class additional_info(object): + def __init__(self): + self.except_on_instr = False + +br_0 = ['B', 'J', 'JR', 'BAL', 'JAL', 'JALR'] +br_1 = ['BGEZ', 'BLTZ', 'BGTZ', 'BGTZL', 'BLEZ', 'BLEZL', 'BC1T', 'BC1TL', 'BC1F', 'BC1FL'] +br_2 = ['BEQ', 'BEQL', 'BNE', 'BNEL'] + + +class instruction_mips32(cpu.instruction): + __slots__ = [] + + def __init__(self, *args, **kargs): + super(instruction_mips32, self).__init__(*args, **kargs) + self.delayslot = 1 + + + @staticmethod + def arg2str(expr, index=None, loc_db=None): + if expr.is_id() or expr.is_int(): + return str(expr) + elif expr.is_loc(): + if loc_db is not None: + return loc_db.pretty_str(expr.loc_key) + else: + return str(expr) + assert(isinstance(expr, ExprMem)) + arg = expr.ptr + if isinstance(arg, ExprId): + return "(%s)"%arg + assert(len(arg.args) == 2 and arg.op == '+') + return "%s(%s)"%(arg.args[1], arg.args[0]) + + @staticmethod + def arg2html(expr, index=None, loc_db=None): + if expr.is_id() or expr.is_int() or expr.is_loc(): + return color_expr_html(expr, loc_db) + assert(isinstance(expr, ExprMem)) + arg = expr.ptr + if isinstance(arg, ExprId): + return "(%s)"%color_expr_html(arg, loc_db) + assert(len(arg.args) == 2 and arg.op == '+') + return "%s(%s)"%( + color_expr_html(arg.args[1], loc_db), + color_expr_html(arg.args[0], loc_db) + ) + + def dstflow(self): + if self.name == 'BREAK': + return False + if self.name in br_0 + br_1 + br_2: + return True + return False + + def get_dst_num(self): + if self.name in br_0: + i = 0 + elif self.name in br_1: + i = 1 + elif self.name in br_2: + i = 2 + else: + raise NotImplementedError("TODO %s"%self) + return i + + def dstflow2label(self, loc_db): + if self.name in ["J", 'JAL']: + expr = self.args[0] + offset = int(expr) + addr = ((self.offset & (0xFFFFFFFF ^ ((1<< 28)-1))) + offset) & int(expr.mask) + loc_key = loc_db.get_or_create_offset_location(addr) + self.args[0] = ExprLoc(loc_key, expr.size) + return + + ndx = self.get_dst_num() + expr = self.args[ndx] + + if not isinstance(expr, ExprInt): + return + addr = (int(expr) + self.offset) & int(expr.mask) + loc_key = loc_db.get_or_create_offset_location(addr) + self.args[ndx] = ExprLoc(loc_key, expr.size) + + def breakflow(self): + if self.name == 'BREAK': + return False + if self.name in br_0 + br_1 + br_2: + return True + return False + + def is_subcall(self): + if self.name in ['JAL', 'JALR', 'BAL']: + return True + return False + + def getdstflow(self, loc_db): + if self.name in br_0: + return [self.args[0]] + elif self.name in br_1: + return [self.args[1]] + elif self.name in br_2: + return [self.args[2]] + elif self.name in ['JAL', 'JALR', 'JR', 'J']: + return [self.args[0]] + else: + raise NotImplementedError("fix mnemo %s"%self.name) + + def splitflow(self): + if self.name in ["B", 'JR', 'J']: + return False + if self.name in br_0: + return True + if self.name in br_1: + return True + if self.name in br_2: + return True + if self.name in ['JAL', 'JALR']: + return True + return False + + def get_symbol_size(self, symbol, loc_db): + return 32 + + def fixDstOffset(self): + ndx = self.get_dst_num() + e = self.args[ndx] + if self.offset is None: + raise ValueError('symbol not resolved %s' % self.l) + if not isinstance(e, ExprInt): + return + off = (int(e) - self.offset) & int(e.mask) + if int(off % 4): + raise ValueError('strange offset! %r' % off) + self.args[ndx] = ExprInt(off, 32) + + def get_args_expr(self): + args = [a for a in self.args] + return args + + +class mn_mips32(cpu.cls_mn): + delayslot = 1 + name = "mips32" + regs = regs + bintree = {} + num = 0 + all_mn = [] + all_mn_mode = defaultdict(list) + all_mn_name = defaultdict(list) + all_mn_inst = defaultdict(list) + pc = {'l':regs.PC, 'b':regs.PC} + sp = {'l':regs.SP, 'b':regs.SP} + instruction = instruction_mips32 + max_instruction_len = 4 + + @classmethod + def getpc(cls, attrib = None): + return regs.PC + + @classmethod + def getsp(cls, attrib = None): + return regs.SP + + def additional_info(self): + info = additional_info() + return info + + @classmethod + def getbits(cls, bitstream, attrib, start, n): + if not n: + return 0 + o = 0 + while n: + offset = start // 8 + n_offset = cls.endian_offset(attrib, offset) + c = cls.getbytes(bitstream, n_offset, 1) + if not c: + raise IOError + c = ord(c) + r = 8 - start % 8 + c &= (1 << r) - 1 + l = min(r, n) + c >>= (r - l) + o <<= l + o |= c + n -= l + start += l + return o + + @classmethod + def endian_offset(cls, attrib, offset): + if attrib == "l": + return (offset & ~3) + 3 - offset % 4 + elif attrib == "b": + return offset + else: + raise NotImplementedError('bad attrib') + + @classmethod + def check_mnemo(cls, fields): + l = sum([x.l for x in fields]) + assert l == 32, "len %r" % l + + @classmethod + def getmn(cls, name): + return name.upper() + + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + dct['mode'] = None + return [(subcls, name, bases, dct, fields)] + + def value(self, mode): + v = super(mn_mips32, self).value(mode) + if mode == 'l': + return [x[::-1] for x in v] + elif mode == 'b': + return [x for x in v] + else: + raise NotImplementedError('bad attrib') + + + +def mips32op(name, fields, args=None, alias=False): + dct = {"fields": fields} + dct["alias"] = alias + if args is not None: + dct['args'] = args + type(name, (mn_mips32,), dct) + #type(name, (mn_mips32b,), dct) + +class mips32_arg(cpu.m_arg): + def asm_ast_to_expr(self, arg, loc_db): + if isinstance(arg, AstId): + if isinstance(arg.name, ExprId): + return arg.name + if arg.name in gpregs.str: + return None + loc_key = loc_db.get_or_create_name_location(arg.name) + return ExprLoc(loc_key, 32) + if isinstance(arg, AstOp): + args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args] + if None in args: + return None + return ExprOp(arg.op, *args) + if isinstance(arg, AstInt): + return ExprInt(arg.value, 32) + if isinstance(arg, AstMem): + ptr = self.asm_ast_to_expr(arg.ptr, loc_db) + if ptr is None: + return None + return ExprMem(ptr, arg.size) + return None + + +class mips32_reg(cpu.reg_noarg, mips32_arg): + pass + +class mips32_gpreg(mips32_reg): + reg_info = gpregs + parser = reg_info.parser + +class mips32_fltpreg(mips32_reg): + reg_info = regs.fltregs + parser = reg_info.parser + + +class mips32_fccreg(mips32_reg): + reg_info = regs.fccregs + parser = reg_info.parser + +class mips32_imm(cpu.imm_noarg): + parser = base_expr + + +class mips32_s16imm_noarg(mips32_imm): + def decode(self, v): + v = v & self.lmask + v = cpu.sign_ext(v, 16, 32) + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if v & 0x80000000: + nv = v & ((1 << 16) - 1) + assert( v == cpu.sign_ext(nv, 16, 32)) + v = nv + self.value = v + return True + + +class mips32_s09imm_noarg(mips32_imm): + def decode(self, v): + v = v & self.lmask + v = cpu.sign_ext(v, 9, 32) + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if v & 0x80000000: + nv = v & ((1 << 9) - 1) + assert( v == cpu.sign_ext(nv, 9, 32)) + v = nv + self.value = v + return True + + +class mips32_soff_noarg(mips32_imm): + def decode(self, v): + v = v & self.lmask + v <<= 2 + v = cpu.sign_ext(v, 16+2, 32) + # Add pipeline offset + self.expr = ExprInt(v + 4, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + # Remove pipeline offset + v = (int(self.expr) - 4) & 0xFFFFFFFF + if v & 0x80000000: + nv = v & ((1 << 16+2) - 1) + assert( v == cpu.sign_ext(nv, 16+2, 32)) + v = nv + self.value = v>>2 + return True + + +class mips32_s16imm(mips32_s16imm_noarg, mips32_arg): + pass + +class mips32_s09imm(mips32_s09imm_noarg, mips32_arg): + pass + +class mips32_soff(mips32_soff_noarg, mips32_arg): + pass + + +class mips32_instr_index(mips32_imm, mips32_arg): + def decode(self, v): + v = v & self.lmask + self.expr = ExprInt(v<<2, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if v & 3: + return False + v>>=2 + if v > (1<<self.l): + return False + self.value = v + return True + + +class mips32_u16imm(mips32_imm, mips32_arg): + def decode(self, v): + v = v & self.lmask + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + assert(v < (1<<16)) + self.value = v + return True + +class mips32_dreg_imm(mips32_arg): + parser = deref + def decode(self, v): + imm = self.parent.imm.expr + r = gpregs.expr[v] + self.expr = ExprMem(r+imm, 32) + return True + + def encode(self): + e = self.expr + if not isinstance(e, ExprMem): + return False + ptr = e.ptr + if isinstance(ptr, ExprId): + self.parent.imm.expr = ExprInt(0, 32) + r = ptr + elif len(ptr.args) == 2 and ptr.op == "+": + self.parent.imm.expr = ptr.args[1] + r = ptr.args[0] + else: + return False + self.value = gpregs.expr.index(r) + return True + + @staticmethod + def arg2str(expr, index=None): + assert(isinstance(expr, ExprMem)) + ptr = expr.ptr + if isinstance(ptr, ExprId): + return "(%s)"%ptr + assert(len(ptr.args) == 2 and ptr.op == '+') + return "%s(%s)"%(ptr.args[1], ptr.args[0]) + +class mips32_esize(mips32_imm, mips32_arg): + def decode(self, v): + v = v & self.lmask + self.expr = ExprInt(v+1, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) -1 + assert(v < (1<<16)) + self.value = v + return True + +class mips32_eposh(mips32_imm, mips32_arg): + def decode(self, v): + self.expr = ExprInt(v-int(self.parent.epos.expr)+1, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + int(self.parent.epos.expr) -1 + self.value = v + return True + + + + +class mips32_cpr(mips32_arg): + parser = regs.regs_cpr0_info.parser + def decode(self, v): + index = int(self.parent.cpr0.expr) << 3 + index += v + self.expr = regs.regs_cpr0_expr[index] + return True + def encode(self): + e = self.expr + if not e in regs.regs_cpr0_expr: + return False + index = regs.regs_cpr0_expr.index(e) + self.value = index & 7 + index >>=2 + self.parent.cpr0.value = index + return True + +rs = cpu.bs(l=5, cls=(mips32_gpreg,)) +rt = cpu.bs(l=5, cls=(mips32_gpreg,)) +rd = cpu.bs(l=5, cls=(mips32_gpreg,)) +ft = cpu.bs(l=5, cls=(mips32_fltpreg,)) +fs = cpu.bs(l=5, cls=(mips32_fltpreg,)) +fd = cpu.bs(l=5, cls=(mips32_fltpreg,)) + +s16imm = cpu.bs(l=16, cls=(mips32_s16imm,)) +u16imm = cpu.bs(l=16, cls=(mips32_u16imm,)) +s09imm = cpu.bs(l=9, cls=(mips32_s09imm,)) +sa = cpu.bs(l=5, cls=(mips32_u16imm,)) +base = cpu.bs(l=5, cls=(mips32_dreg_imm,)) +soff = cpu.bs(l=16, cls=(mips32_soff,)) +oper = cpu.bs(l=5, cls=(mips32_u16imm,)) + +cpr0 = cpu.bs(l=5, cls=(mips32_imm,), fname="cpr0") +cpr = cpu.bs(l=3, cls=(mips32_cpr,)) + +stype = cpu.bs(l=5, cls=(mips32_u16imm,)) +hint_pref = cpu.bs(l=5, cls=(mips32_u16imm,)) + +s16imm_noarg = cpu.bs(l=16, cls=(mips32_s16imm_noarg,), fname="imm", + order=-1) +s09imm_noarg = cpu.bs(l=9, cls=(mips32_s09imm_noarg,), fname="imm", + order=-1) + +hint = cpu.bs(l=5, default_val="00000") +fcc = cpu.bs(l=3, cls=(mips32_fccreg,)) + +sel = cpu.bs(l=3, cls=(mips32_u16imm,)) + +code = cpu.bs(l=20, cls=(mips32_u16imm,)) + +esize = cpu.bs(l=5, cls=(mips32_esize,)) +epos = cpu.bs(l=5, cls=(mips32_u16imm,), fname="epos", + order=-1) + +eposh = cpu.bs(l=5, cls=(mips32_eposh,)) + +instr_index = cpu.bs(l=26, cls=(mips32_instr_index,)) +bs_fmt = cpu.bs_mod_name(l=5, fname='fmt', mn_mod={0x10: '.S', 0x11: '.D', + 0x14: '.W', 0x15: '.L', + 0x16: '.PS'}) +class bs_cond(cpu.bs_mod_name): + mn_mod = ['.F', '.UN', '.EQ', '.UEQ', + '.OLT', '.ULT', '.OLE', '.ULE', + '.SF', '.NGLE', '.SEQ', '.NGL', + '.LT', '.NGE', '.LE', '.NGT' + ] + + def modname(self, name, f_i): + raise NotImplementedError("Not implemented") + + +class bs_cond_name(cpu.bs_divert): + prio = 2 + mn_mod = [['.F', '.UN', '.EQ', '.UEQ', + '.OLT', '.ULT', '.OLE', '.ULE'], + ['.SF', '.NGLE', '.SEQ', '.NGL', + '.LT', '.NGE', '.LE', '.NGT'] + ] + + def divert(self, index, candidates): + out = [] + for candidate in candidates: + cls, name, bases, dct, fields = candidate + cond1 = [f for f in fields if f.fname == "cond1"] + assert(len(cond1) == 1) + cond1 = cond1.pop() + mm = self.mn_mod[cond1.value] + for value, new_name in enumerate(mm): + nfields = fields[:] + s = cpu.int2bin(value, self.args['l']) + args = dict(self.args) + args.update({'strbits': s}) + f = cpu.bs(**args) + nfields[index] = f + ndct = dict(dct) + ndct['name'] = name + new_name + out.append((cls, new_name, bases, ndct, nfields)) + return out + + + +class bs_cond_mod(cpu.bs_mod_name): + prio = 1 + +bs_cond = bs_cond_mod(l=4, + mn_mod = ['.F', '.UN', '.EQ', '.UEQ', + '.OLT', '.ULT', '.OLE', '.ULE', + '.SF', '.NGLE', '.SEQ', '.NGL', + '.LT', '.NGE', '.LE', '.NGT']) + + + +bs_arith = cpu.bs_name(l=6, name={'ADDU':0b100001, + 'SUBU':0b100011, + 'OR':0b100101, + 'AND':0b100100, + 'SLTU':0b101011, + 'XOR':0b100110, + 'SLT':0b101010, + 'SUBU':0b100011, + 'NOR':0b100111, + 'MOVN':0b001011, + 'MOVZ':0b001010, + }) + +bs_shift = cpu.bs_name(l=6, name={'SLL':0b000000, + 'SRL':0b000010, + 'SRA':0b000011, + }) + +bs_shift1 = cpu.bs_name(l=6, name={'SLLV':0b000100, + 'SRLV':0b000110, + 'SRAV':0b000111, + }) + + +bs_arithfmt = cpu.bs_name(l=6, name={'ADD':0b000000, + 'SUB':0b000001, + 'MUL':0b000010, + 'DIV':0b000011, + }) + +bs_s_l = cpu.bs_name(l=6, name = {"SW": 0b101011, + "SH": 0b101001, + "SB": 0b101000, + "LW": 0b100011, + "LH": 0b100001, + "LB": 0b100000, + "LHU": 0b100101, + "LBU": 0b100100, + "LWL": 0b100010, + "LWR": 0b100110, + + "SWL": 0b101010, + "SWR": 0b101110, + }) + + +bs_oax = cpu.bs_name(l=6, name = {"ORI": 0b001101, + "ANDI": 0b001100, + "XORI": 0b001110, + }) + +bs_bcc = cpu.bs_name(l=5, name = {"BGEZ": 0b00001, + "BGEZL": 0b00011, + "BGEZAL": 0b10001, + "BGEZALL": 0b10011, + "BLTZ": 0b00000, + "BLTZL": 0b00010, + "BLTZAL": 0b10000, + "BLTZALL": 0b10010, + }) + + +bs_code = cpu.bs(l=10) + + +mips32op("addi", [cpu.bs('001000'), rs, rt, s16imm], [rt, rs, s16imm]) +mips32op("addiu", [cpu.bs('001001'), rs, rt, s16imm], [rt, rs, s16imm]) +mips32op("nop", [cpu.bs('0'*32)], alias = True) +mips32op("lui", [cpu.bs('001111'), cpu.bs('00000'), rt, u16imm]) +mips32op("oax", [bs_oax, rs, rt, u16imm], [rt, rs, u16imm]) + +mips32op("arith", [cpu.bs('000000'), rs, rt, rd, cpu.bs('00000'), bs_arith], + [rd, rs, rt]) +mips32op("shift1", [cpu.bs('000000'), rs, rt, rd, cpu.bs('00000'), bs_shift1], + [rd, rt, rs]) + +mips32op("shift", [cpu.bs('000000'), cpu.bs('00000'), rt, rd, sa, bs_shift], + [rd, rt, sa]) + +mips32op("rotr", [cpu.bs('000000'), cpu.bs('00001'), rt, rd, sa, + cpu.bs('000010')], [rd, rt, sa]) + +mips32op("mul", [cpu.bs('011100'), rs, rt, rd, cpu.bs('00000'), + cpu.bs('000010')], [rd, rs, rt]) +mips32op("div", [cpu.bs('000000'), rs, rt, cpu.bs('0000000000'), + cpu.bs('011010')]) + +mips32op("s_l", [bs_s_l, base, rt, s16imm_noarg], [rt, base]) + +#mips32op("mfc0", [bs('010000'), bs('00000'), rt, rd, bs('00000000'), sel]) +mips32op("mfc0", [cpu.bs('010000'), cpu.bs('00000'), rt, cpr0, + cpu.bs('00000000'), cpr]) +mips32op("mfc1", [cpu.bs('010001'), cpu.bs('00000'), rt, fs, + cpu.bs('00000000000')]) + +mips32op("ldc1", [cpu.bs('110101'), base, ft, s16imm_noarg], [ft, base]) + +mips32op("mov", [cpu.bs('010001'), bs_fmt, cpu.bs('00000'), fs, fd, + cpu.bs('000110')], [fd, fs]) + +mips32op("add", [cpu.bs('010001'), bs_fmt, ft, fs, fd, bs_arithfmt], + [fd, fs, ft]) + +mips32op("divu", [cpu.bs('000000'), rs, rt, cpu.bs('0000000000'), + cpu.bs('011011')]) +mips32op("mult", [cpu.bs('000000'), rs, rt, cpu.bs('0000000000'), + cpu.bs('011000')]) +mips32op("multu", [cpu.bs('000000'), rs, rt, cpu.bs('0000000000'), + cpu.bs('011001')]) +mips32op("mflo", [cpu.bs('000000'), cpu.bs('0000000000'), rd, + cpu.bs('00000'), cpu.bs('010010')]) +mips32op("mfhi", [cpu.bs('000000'), cpu.bs('0000000000'), rd, + cpu.bs('00000'), cpu.bs('010000')]) + + +mips32op("b", [cpu.bs('000100'), cpu.bs('00000'), cpu.bs('00000'), soff], + alias = True) +mips32op("bne", [cpu.bs('000101'), rs, rt, soff]) +mips32op("bnel", [cpu.bs('010101'), rs, rt, soff]) + +mips32op("beq", [cpu.bs('000100'), rs, rt, soff]) +mips32op("beql", [cpu.bs('010100'), rs, rt, soff]) + +mips32op("blez", [cpu.bs('000110'), rs, cpu.bs('00000'), soff]) +mips32op("blezl", [cpu.bs('010110'), rs, cpu.bs('00000'), soff]) + +mips32op("bcc", [cpu.bs('000001'), rs, bs_bcc, soff]) + +mips32op("bgtz", [cpu.bs('000111'), rs, cpu.bs('00000'), soff]) +mips32op("bgtzl", [cpu.bs('010111'), rs, cpu.bs('00000'), soff]) +mips32op("bal", [cpu.bs('000001'), cpu.bs('00000'), cpu.bs('10001'), soff], + alias = True) + + +mips32op("slti", [cpu.bs('001010'), rs, rt, s16imm], [rt, rs, s16imm]) +mips32op("sltiu", [cpu.bs('001011'), rs, rt, s16imm], [rt, rs, s16imm]) + + +mips32op("j", [cpu.bs('000010'), instr_index]) +mips32op("jal", [cpu.bs('000011'), instr_index]) +mips32op("jalr", [cpu.bs('000000'), rs, cpu.bs('00000'), rd, hint, + cpu.bs('001001')]) +mips32op("jr", [cpu.bs('000000'), rs, cpu.bs('0000000000'), hint, + cpu.bs('001000')]) + +mips32op("lwc1", [cpu.bs('110001'), base, ft, s16imm_noarg], [ft, base]) + +#mips32op("mtc0", [bs('010000'), bs('00100'), rt, rd, bs('00000000'), sel]) +mips32op("mtc0", [cpu.bs('010000'), cpu.bs('00100'), rt, cpr0, + cpu.bs('00000000'), cpr]) +mips32op("mtc1", [cpu.bs('010001'), cpu.bs('00100'), rt, fs, + cpu.bs('00000000000')]) +# XXXX TODO CFC1 +mips32op("cfc1", [cpu.bs('010001'), cpu.bs('00010'), rt, fs, + cpu.bs('00000000000')]) +# XXXX TODO CTC1 +mips32op("ctc1", [cpu.bs('010001'), cpu.bs('00110'), rt, fs, + cpu.bs('00000000000')]) + +mips32op("break", [cpu.bs('000000'), code, cpu.bs('001101')]) +mips32op("syscall", [cpu.bs('000000'), code, cpu.bs('001100')]) + + +mips32op("c", [cpu.bs('010001'), bs_fmt, ft, fs, fcc, cpu.bs('0'), + cpu.bs('0'), cpu.bs('11'), bs_cond], [fcc, fs, ft]) + + +mips32op("bc1t", [cpu.bs('010001'), cpu.bs('01000'), fcc, cpu.bs('0'), + cpu.bs('1'), soff]) +mips32op("bc1tl", [cpu.bs('010001'), cpu.bs('01000'), fcc, cpu.bs('1'), + cpu.bs('1'), soff]) +mips32op("bc1f", [cpu.bs('010001'), cpu.bs('01000'), fcc, cpu.bs('0'), + cpu.bs('0'), soff]) +mips32op("bc1fl", [cpu.bs('010001'), cpu.bs('01000'), fcc, cpu.bs('1'), + cpu.bs('0'), soff]) + +mips32op("swc1", [cpu.bs('111001'), base, ft, s16imm_noarg], [ft, base]) + +mips32op("cvt.d", [cpu.bs('010001'), bs_fmt, cpu.bs('00000'), fs, fd, + cpu.bs('100001')], [fd, fs]) +mips32op("cvt.w", [cpu.bs('010001'), bs_fmt, cpu.bs('00000'), fs, fd, + cpu.bs('100100')], [fd, fs]) +mips32op("cvt.s", [cpu.bs('010001'), bs_fmt, cpu.bs('00000'), fs, fd, + cpu.bs('100000')], [fd, fs]) + +mips32op("ext", [cpu.bs('011111'), rs, rt, esize, epos, cpu.bs('000000')], + [rt, rs, epos, esize]) +mips32op("ins", [cpu.bs('011111'), rs, rt, eposh, epos, cpu.bs('000100')], + [rt, rs, epos, eposh]) + +mips32op("seb", [cpu.bs('011111'), cpu.bs('00000'), rt, rd, cpu.bs('10000'), + cpu.bs('100000')], [rd, rt]) +mips32op("seh", [cpu.bs('011111'), cpu.bs('00000'), rt, rd, cpu.bs('11000'), + cpu.bs('100000')], [rd, rt]) +mips32op("wsbh", [cpu.bs('011111'), cpu.bs('00000'), rt, rd, cpu.bs('00010'), + cpu.bs('100000')], [rd, rt]) + +mips32op("di", [cpu.bs('010000'), cpu.bs('01011'), rt, cpu.bs('01100'), + cpu.bs('00000'), cpu.bs('0'), cpu.bs('00'), cpu.bs('000')]) +mips32op("ei", [cpu.bs('010000'), cpu.bs('01011'), rt, cpu.bs('01100'), + cpu.bs('00000'), cpu.bs('1'), cpu.bs('00'), cpu.bs('000')]) + + +mips32op("tlbp", [cpu.bs('010000'), cpu.bs('1'), cpu.bs('0'*19), + cpu.bs('001000')]) +mips32op("tlbwi", [cpu.bs('010000'), cpu.bs('1'), cpu.bs('0'*19), + cpu.bs('000010')]) + + +mips32op("teq", [cpu.bs('000000'), rs, rt, bs_code, cpu.bs('110100')], + [rs, rt]) +mips32op("tne", [cpu.bs('000000'), rs, rt, bs_code, cpu.bs('110110')], + [rs, rt]) + +mips32op("clz", [cpu.bs('011100'), rs, rt, rd, cpu.bs('00000'), cpu.bs('100000')], + [rd, rs]) +mips32op("clz", [cpu.bs('000000'), rs, cpu.bs('00000'), rd, cpu.bs('00001010000')], + [rd, rs]) + +mips32op("ll", [cpu.bs('110000'), base, rt, s16imm_noarg], [rt, base]) +mips32op("ll", [cpu.bs('011111'), base, rt, s09imm_noarg, cpu.bs('0110110')], [rt, base]) + +mips32op("sc", [cpu.bs('111000'), base, rt, s16imm_noarg], [rt, base]) +mips32op("sc", [cpu.bs('011111'), base, rt, s09imm_noarg, cpu.bs('0'), cpu.bs('100110')], [rt, base]) + +mips32op("sync", [cpu.bs('000000000000000000000'), stype, cpu.bs('001111')], [stype]) + +mips32op("pref", [cpu.bs('110011'), base, hint_pref, s16imm_noarg], [hint_pref, base]) +mips32op("pref", [cpu.bs('011111'), base, hint_pref, s09imm_noarg, cpu.bs('0110101')], [hint_pref, base]) + +mips32op("tlbwr", [cpu.bs('01000010000000000000000000000110')], []) +mips32op("tlbr", [cpu.bs('01000010000000000000000000000001')], []) + +mips32op("cache", [cpu.bs('101111'), base, oper, s16imm_noarg], [oper, base]) +mips32op("cache", [cpu.bs('011111'), base, oper, s09imm_noarg, cpu.bs('0100101')], [oper, base]) + +mips32op("eret", [cpu.bs('01000010000000000000000000011000')], []) + +mips32op("mtlo", [cpu.bs('000000'), rs, cpu.bs('000000000000000'), cpu.bs('010011')], [rs]) +mips32op("mthi", [cpu.bs('000000'), rs, cpu.bs('000000000000000'), cpu.bs('010001')], [rs]) + diff --git a/src/miasm/arch/mips32/disasm.py b/src/miasm/arch/mips32/disasm.py new file mode 100644 index 00000000..b6c05cb7 --- /dev/null +++ b/src/miasm/arch/mips32/disasm.py @@ -0,0 +1,16 @@ +from miasm.core.asmblock import disasmEngine +from miasm.arch.mips32.arch import mn_mips32 + + + +class dis_mips32b(disasmEngine): + attrib = 'b' + def __init__(self, bs=None, **kwargs): + super(dis_mips32b, self).__init__(mn_mips32, self.attrib, bs, **kwargs) + + +class dis_mips32l(disasmEngine): + attrib = "l" + def __init__(self, bs=None, **kwargs): + super(dis_mips32l, self).__init__(mn_mips32, self.attrib, bs, **kwargs) + diff --git a/src/miasm/arch/mips32/jit.py b/src/miasm/arch/mips32/jit.py new file mode 100644 index 00000000..a4d8a193 --- /dev/null +++ b/src/miasm/arch/mips32/jit.py @@ -0,0 +1,160 @@ +from builtins import range +import logging + +from miasm.jitter.jitload import Jitter, named_arguments +from miasm.core.locationdb import LocationDB +from miasm.core.utils import pck32, upck32 +from miasm.arch.mips32.sem import Lifter_Mips32l, Lifter_Mips32b +from miasm.jitter.codegen import CGen +from miasm.ir.ir import AssignBlock, IRBlock +import miasm.expression.expression as m2_expr + +log = logging.getLogger('jit_mips32') +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) + + +class mipsCGen(CGen): + CODE_INIT = CGen.CODE_INIT + r""" + unsigned int branch_dst_pc; + unsigned int branch_dst_irdst; + unsigned int branch_dst_set=0; + """ + + CODE_RETURN_NO_EXCEPTION = r""" + %s: + if (branch_dst_set) { + %s = %s; + BlockDst->address = %s; + } else { + BlockDst->address = %s; + } + return JIT_RET_NO_EXCEPTION; + """ + + def __init__(self, lifter): + super(mipsCGen, self).__init__(lifter) + self.delay_slot_dst = m2_expr.ExprId("branch_dst_irdst", 32) + self.delay_slot_set = m2_expr.ExprId("branch_dst_set", 32) + + def block2assignblks(self, block): + irblocks_list = super(mipsCGen, self).block2assignblks(block) + for irblocks in irblocks_list: + for blk_idx, irblock in enumerate(irblocks): + has_breakflow = any(assignblock.instr.breakflow() for assignblock in irblock) + if not has_breakflow: + continue + + irs = [] + for assignblock in irblock: + if self.lifter.pc not in assignblock: + irs.append(AssignBlock(assignments, assignblock.instr)) + continue + assignments = dict(assignblock) + # Add internal branch destination + assignments[self.delay_slot_dst] = assignblock[ + self.lifter.pc] + assignments[self.delay_slot_set] = m2_expr.ExprInt(1, 32) + # Replace IRDst with next instruction + dst_loc_key = self.lifter.get_next_instr(assignblock.instr) + assignments[self.lifter.IRDst] = m2_expr.ExprLoc(dst_loc_key, 32) + irs.append(AssignBlock(assignments, assignblock.instr)) + irblocks[blk_idx] = IRBlock(irblock.loc_db, irblock.loc_key, irs) + + return irblocks_list + + def gen_finalize(self, block): + """ + Generate the C code for the final block instruction + """ + + loc_key = self.get_block_post_label(block) + offset = self.lifter.loc_db.get_location_offset(loc_key) + out = (self.CODE_RETURN_NO_EXCEPTION % (loc_key, + self.C_PC, + m2_expr.ExprId('branch_dst_irdst', 32), + m2_expr.ExprId('branch_dst_irdst', 32), + self.id_to_c(m2_expr.ExprInt(offset, 32))) + ).split('\n') + return out + + +class jitter_mips32l(Jitter): + + C_Gen = mipsCGen + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_Mips32l(loc_db), *args, **kwargs) + self.vm.set_little_endian() + + def push_uint32_t(self, value): + self.cpu.SP -= 4 + self.vm.set_mem(self.cpu.SP, pck32(value)) + + def pop_uint32_t(self): + value = self.vm.get_u32(self.cpu.SP) + self.cpu.SP += 4 + return value + + def get_stack_arg(self, index): + return self.vm.get_u32(self.cpu.SP + 4 * index) + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.PC = self.pc + + # calling conventions + + @named_arguments + def func_args_stdcall(self, n_args): + args = [self.get_arg_n_stdcall(i) for i in range(n_args)] + ret_ad = self.cpu.RA + return ret_ad, args + + def func_ret_stdcall(self, ret_addr, ret_value1=None, ret_value2=None): + self.pc = self.cpu.PC = ret_addr + if ret_value1 is not None: + self.cpu.V0 = ret_value1 + if ret_value2 is not None: + self.cpu.V1 = ret_value2 + return True + + def func_prepare_stdcall(self, ret_addr, *args): + for index in range(min(len(args), 4)): + setattr(self.cpu, 'A%d' % index, args[index]) + for index in range(4, len(args)): + self.vm.set_mem(self.cpu.SP + 4 * (index - 4), pck32(args[index])) + self.cpu.RA = ret_addr + + def get_arg_n_stdcall(self, index): + if index < 4: + arg = getattr(self.cpu, 'A%d' % index) + else: + arg = self.get_stack_arg(index-4) + return arg + + def syscall_args_systemv(self, n_args): + # Documentation: http://man7.org/linux/man-pages/man2/syscall.2.html + # mips/o32 a0 a1 a2 a3 stack + args = [self.get_arg_n_stdcall(i) for i in range(n_args)] + return args + + def syscall_ret_systemv(self, value1, value2, error): + # Documentation: http://man7.org/linux/man-pages/man2/syscall.2.html + self.cpu.V0 = value1 + self.cpu.V1 = value2 + self.cpu.A3 = error # 0 -> no error, -1 -> error + + func_args_systemv = func_args_stdcall + func_ret_systemv = func_ret_stdcall + func_prepare_systemv = func_prepare_stdcall + get_arg_n_systemv = get_arg_n_stdcall + + +class jitter_mips32b(jitter_mips32l): + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_Mips32b(loc_db), *args, **kwargs) + self.vm.set_big_endian() diff --git a/src/miasm/arch/mips32/lifter_model_call.py b/src/miasm/arch/mips32/lifter_model_call.py new file mode 100644 index 00000000..bd0e8506 --- /dev/null +++ b/src/miasm/arch/mips32/lifter_model_call.py @@ -0,0 +1,104 @@ +#-*- coding:utf-8 -*- + +from miasm.expression.expression import ExprAssign, ExprOp +from miasm.ir.ir import IRBlock, AssignBlock +from miasm.ir.analysis import LifterModelCall +from miasm.arch.mips32.sem import Lifter_Mips32l, Lifter_Mips32b + +class LifterModelCallMips32l(Lifter_Mips32l, LifterModelCall): + def __init__(self, loc_db): + Lifter_Mips32l.__init__(self, loc_db) + self.ret_reg = self.arch.regs.V0 + + def call_effects(self, ad, instr): + call_assignblk = AssignBlock( + [ + ExprAssign( + self.ret_reg, + ExprOp( + 'call_func_ret', + ad, + self.arch.regs.A0, + self.arch.regs.A1, + self.arch.regs.A2, + self.arch.regs.A3, + ) + ), + ], + instr + ) + + return [call_assignblk], [] + + + def add_asmblock_to_ircfg(self, block, ircfg, gen_pc_updt=False): + """ + Add a native block to the current IR + @block: native assembly block + @ircfg: IRCFG instance + @gen_pc_updt: insert PC update effects between instructions + """ + loc_key = block.loc_key + ir_blocks_all = [] + + assignments = [] + for index, instr in enumerate(block.lines): + if loc_key is None: + assignments = [] + loc_key = self.get_loc_key_for_instr(instr) + if instr.is_subcall(): + assert index == len(block.lines) - 2 + + # Add last instruction first (before call) + split = self.add_instr_to_current_state( + block.lines[-1], block, assignments, + ir_blocks_all, gen_pc_updt + ) + assert not split + # Add call effects after the delay splot + split = self.add_instr_to_current_state( + instr, block, assignments, + ir_blocks_all, gen_pc_updt + ) + assert split + break + split = self.add_instr_to_current_state( + instr, block, assignments, + ir_blocks_all, gen_pc_updt + ) + if split: + ir_blocks_all.append(IRBlock(self.loc_db, loc_key, assignments)) + loc_key = None + assignments = [] + if loc_key is not None: + ir_blocks_all.append(IRBlock(self.loc_db, loc_key, assignments)) + + new_ir_blocks_all = self.post_add_asmblock_to_ircfg(block, ircfg, ir_blocks_all) + for irblock in new_ir_blocks_all: + ircfg.add_irblock(irblock) + return new_ir_blocks_all + + def get_out_regs(self, _): + return set([self.ret_reg, self.sp]) + + def sizeof_char(self): + return 8 + + def sizeof_short(self): + return 16 + + def sizeof_int(self): + return 32 + + def sizeof_long(self): + return 32 + + def sizeof_pointer(self): + return 32 + + + +class LifterModelCallMips32b(Lifter_Mips32b, LifterModelCallMips32l): + def __init__(self, loc_db): + Lifter_Mips32b.__init__(self, loc_db) + self.ret_reg = self.arch.regs.V0 diff --git a/src/miasm/arch/mips32/regs.py b/src/miasm/arch/mips32/regs.py new file mode 100644 index 00000000..967b7458 --- /dev/null +++ b/src/miasm/arch/mips32/regs.py @@ -0,0 +1,101 @@ +#-*- coding:utf-8 -*- + +from builtins import range +from miasm.expression.expression import ExprId +from miasm.core.cpu import gen_reg, gen_regs + + +PC, _ = gen_reg('PC') +PC_FETCH, _ = gen_reg('PC_FETCH') + +R_LO, _ = gen_reg('R_LO') +R_HI, _ = gen_reg('R_HI') + +exception_flags = ExprId('exception_flags', 32) + +PC_init = ExprId("PC_init", 32) +PC_FETCH_init = ExprId("PC_FETCH_init", 32) + +regs32_str = ["ZERO", 'AT', 'V0', 'V1'] +\ + ['A%d'%i for i in range(4)] +\ + ['T%d'%i for i in range(8)] +\ + ['S%d'%i for i in range(8)] +\ + ['T%d'%i for i in range(8, 10)] +\ + ['K0', 'K1'] +\ + ['GP', 'SP', 'FP', 'RA'] + +regs32_expr = [ExprId(x, 32) for x in regs32_str] +ZERO = regs32_expr[0] + +regs_flt_str = ['F%d'%i for i in range(0x20)] + +regs_fcc_str = ['FCC%d'%i for i in range(8)] + +R_LO = ExprId('R_LO', 32) +R_HI = ExprId('R_HI', 32) + +R_LO_init = ExprId('R_LO_init', 32) +R_HI_init = ExprId('R_HI_init', 32) + + +cpr0_str = ["CPR0_%d"%x for x in range(0x100)] +cpr0_str[0] = "INDEX" +cpr0_str[8] = "RANDOM" +cpr0_str[16] = "ENTRYLO0" +cpr0_str[24] = "ENTRYLO1" +cpr0_str[32] = "CONTEXT" +cpr0_str[33] = "CONTEXTCONFIG" +cpr0_str[40] = "PAGEMASK" +cpr0_str[41] = "PAGEGRAIN" +cpr0_str[42] = "SEGCTL0" +cpr0_str[43] = "SEGCTL1" +cpr0_str[44] = "SEGCTL2" +cpr0_str[45] = "PWBASE" +cpr0_str[46] = "PWFIELD" +cpr0_str[47] = "PWSIZE" +cpr0_str[48] = "WIRED" +cpr0_str[54] = "PWCTL" +cpr0_str[64] = "BADVADDR" +cpr0_str[65] = "BADINSTR" +cpr0_str[66] = "BADINSTRP" +cpr0_str[72] = "COUNT" +cpr0_str[80] = "ENTRYHI" +cpr0_str[104] = "CAUSE" +cpr0_str[112] = "EPC" +cpr0_str[120] = "PRID" +cpr0_str[121] = "EBASE" +cpr0_str[128] = "CONFIG" +cpr0_str[129] = "CONFIG1" +cpr0_str[130] = "CONFIG2" +cpr0_str[131] = "CONFIG3" +cpr0_str[132] = "CONFIG4" +cpr0_str[133] = "CONFIG5" +cpr0_str[152] = "WATCHHI" +cpr0_str[250] = "KSCRATCH" +cpr0_str[251] = "KSCRATCH1" +cpr0_str[252] = "KSCRATCH2" +cpr0_str[253] = "KSCRATCH3" +cpr0_str[254] = "KSCRATCH4" +cpr0_str[255] = "KSCRATCH5" + +regs_cpr0_expr, regs_cpr0_init, regs_cpr0_info = gen_regs(cpr0_str, globals()) + +gpregs_expr, gpregs_init, gpregs = gen_regs(regs32_str, globals()) +regs_flt_expr, regs_flt_init, fltregs = gen_regs(regs_flt_str, globals(), sz=64) +regs_fcc_expr, regs_fcc_init, fccregs = gen_regs(regs_fcc_str, globals()) + + +all_regs_ids = [PC, PC_FETCH, R_LO, R_HI, exception_flags] + gpregs_expr + regs_flt_expr + \ + regs_fcc_expr + regs_cpr0_expr +all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) +all_regs_ids_init = [ExprId("%s_init" % reg.name, reg.size) for reg in all_regs_ids] +all_regs_ids_no_alias = all_regs_ids[:] + +attrib_to_regs = { + 'l': all_regs_ids_no_alias, + 'b': all_regs_ids_no_alias, +} + +regs_init = {} +for i, r in enumerate(all_regs_ids): + regs_init[r] = all_regs_ids_init[i] diff --git a/src/miasm/arch/mips32/sem.py b/src/miasm/arch/mips32/sem.py new file mode 100644 index 00000000..649adcaa --- /dev/null +++ b/src/miasm/arch/mips32/sem.py @@ -0,0 +1,667 @@ +import miasm.expression.expression as m2_expr +from miasm.ir.ir import Lifter, IRBlock, AssignBlock +from miasm.arch.mips32.arch import mn_mips32 +from miasm.arch.mips32.regs import R_LO, R_HI, PC, RA, ZERO, exception_flags +from miasm.core.sembuilder import SemBuilder +from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO, EXCEPT_SOFT_BP, EXCEPT_SYSCALL + + +# SemBuilder context +ctx = { + "R_LO": R_LO, + "R_HI": R_HI, + "PC": PC, + "RA": RA, + "m2_expr": m2_expr +} + +sbuild = SemBuilder(ctx) + + +@sbuild.parse +def addiu(arg1, arg2, arg3): + """Adds a register @arg3 and a sign-extended immediate value @arg2 and + stores the result in a register @arg1""" + arg1 = arg2 + arg3 + +@sbuild.parse +def lw(arg1, arg2): + "A word is loaded into a register @arg1 from the specified address @arg2." + arg1 = arg2 + +@sbuild.parse +def sw(arg1, arg2): + "The contents of @arg2 is stored at the specified address @arg1." + arg2 = arg1 + +@sbuild.parse +def jal(arg1): + "Jumps to the calculated address @arg1 and stores the return address in $RA" + PC = arg1 + ir.IRDst = arg1 + RA = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), RA.size) + +@sbuild.parse +def jalr(arg1, arg2): + """Jump to an address stored in a register @arg1, and store the return + address in another register @arg2""" + PC = arg1 + ir.IRDst = arg1 + arg2 = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), arg2.size) + +@sbuild.parse +def bal(arg1): + PC = arg1 + ir.IRDst = arg1 + RA = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), RA.size) + +@sbuild.parse +def l_b(arg1): + PC = arg1 + ir.IRDst = arg1 + +@sbuild.parse +def lbu(arg1, arg2): + """A byte is loaded (unsigned extended) into a register @arg1 from the + specified address @arg2.""" + arg1 = m2_expr.ExprMem(arg2.ptr, 8).zeroExtend(32) + +@sbuild.parse +def lh(arg1, arg2): + """A word is loaded into a register @arg1 from the + specified address @arg2.""" + arg1 = m2_expr.ExprMem(arg2.ptr, 16).signExtend(32) + +@sbuild.parse +def lhu(arg1, arg2): + """A word is loaded (unsigned extended) into a register @arg1 from the + specified address @arg2.""" + arg1 = m2_expr.ExprMem(arg2.ptr, 16).zeroExtend(32) + +@sbuild.parse +def lb(arg1, arg2): + "A byte is loaded into a register @arg1 from the specified address @arg2." + arg1 = m2_expr.ExprMem(arg2.ptr, 8).signExtend(32) + +@sbuild.parse +def ll(arg1, arg2): + "To load a word from memory for an atomic read-modify-write" + arg1 = arg2 + +@sbuild.parse +def beq(arg1, arg2, arg3): + "Branches on @arg3 if the quantities of two registers @arg1, @arg2 are eq" + dst = arg3 if m2_expr.ExprOp(m2_expr.TOK_EQUAL, arg1, arg2) else m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) + PC = dst + ir.IRDst = dst + +@sbuild.parse +def beql(arg1, arg2, arg3): + "Branches on @arg3 if the quantities of two registers @arg1, @arg2 are eq" + dst = arg3 if m2_expr.ExprOp(m2_expr.TOK_EQUAL, arg1, arg2) else m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) + PC = dst + ir.IRDst = dst + +@sbuild.parse +def bgez(arg1, arg2): + """Branches on @arg2 if the quantities of register @arg1 is greater than or + equal to zero""" + dst = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) if m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) else arg2 + PC = dst + ir.IRDst = dst + +@sbuild.parse +def bgezl(arg1, arg2): + """Branches on @arg2 if the quantities of register @arg1 is greater than or + equal to zero""" + dst = m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) if m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) else arg2 + PC = dst + ir.IRDst = dst + +@sbuild.parse +def bne(arg1, arg2, arg3): + """Branches on @arg3 if the quantities of two registers @arg1, @arg2 are NOT + equal""" + dst = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) if m2_expr.ExprOp(m2_expr.TOK_EQUAL, arg1, arg2) else arg3 + PC = dst + ir.IRDst = dst + +@sbuild.parse +def bnel(arg1, arg2, arg3): + """Branches on @arg3 if the quantities of two registers @arg1, @arg2 are NOT + equal""" + dst = m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) if m2_expr.ExprOp(m2_expr.TOK_EQUAL, arg1, arg2) else arg3 + PC = dst + ir.IRDst = dst + +@sbuild.parse +def lui(arg1, arg2): + """The immediate value @arg2 is shifted left 16 bits and stored in the + register @arg1. The lower 16 bits are zeroes.""" + arg1 = m2_expr.ExprCompose(i16(0), arg2[:16]) + +@sbuild.parse +def nop(): + """Do nothing""" + +@sbuild.parse +def sync(arg1): + """Synchronize Shared Memory""" + +@sbuild.parse +def pref(arg1, arg2): + """To move data between memory and cache""" + +@sbuild.parse +def j(arg1): + """Jump to an address @arg1""" + PC = arg1 + ir.IRDst = arg1 + +@sbuild.parse +def l_or(arg1, arg2, arg3): + """Bitwise logical ors two registers @arg2, @arg3 and stores the result in a + register @arg1""" + arg1 = arg2 | arg3 + +@sbuild.parse +def nor(arg1, arg2, arg3): + """Bitwise logical Nors two registers @arg2, @arg3 and stores the result in + a register @arg1""" + arg1 = (arg2 | arg3) ^ i32(-1) + +@sbuild.parse +def l_and(arg1, arg2, arg3): + """Bitwise logical ands two registers @arg2, @arg3 and stores the result in + a register @arg1""" + arg1 = arg2 & arg3 + +@sbuild.parse +def ext(arg1, arg2, arg3, arg4): + pos = int(arg3) + size = int(arg4) + arg1 = arg2[pos:pos + size].zeroExtend(32) + +@sbuild.parse +def mul(arg1, arg2, arg3): + """Multiplies @arg2 by $arg3 and stores the result in @arg1.""" + arg1 = 'imul'(arg2, arg3) + +@sbuild.parse +def sltu(arg1, arg2, arg3): + """If @arg2 is less than @arg3 (unsigned), @arg1 is set to one. It gets zero + otherwise.""" + arg1 = m2_expr.ExprCond( + m2_expr.ExprOp(m2_expr.TOK_INF_UNSIGNED, arg2, arg3), + m2_expr.ExprInt(1, arg1.size), + m2_expr.ExprInt(0, arg1.size) + ) + +@sbuild.parse +def slt(arg1, arg2, arg3): + """If @arg2 is less than @arg3 (signed), @arg1 is set to one. It gets zero + otherwise.""" + arg1 = m2_expr.ExprCond( + m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg2, arg3), + m2_expr.ExprInt(1, arg1.size), + m2_expr.ExprInt(0, arg1.size) + ) + + +@sbuild.parse +def l_sub(arg1, arg2, arg3): + arg1 = arg2 - arg3 + +def sb(ir, instr, arg1, arg2): + """The least significant byte of @arg1 is stored at the specified address + @arg2.""" + e = [] + e.append(m2_expr.ExprAssign(m2_expr.ExprMem(arg2.ptr, 8), arg1[:8])) + return e, [] + +def sh(ir, instr, arg1, arg2): + e = [] + e.append(m2_expr.ExprAssign(m2_expr.ExprMem(arg2.ptr, 16), arg1[:16])) + return e, [] + +@sbuild.parse +def movn(arg1, arg2, arg3): + if arg3: + arg1 = arg2 + +@sbuild.parse +def movz(arg1, arg2, arg3): + if not arg3: + arg1 = arg2 + +@sbuild.parse +def srl(arg1, arg2, arg3): + """Shifts arg1 register value @arg2 right by the shift amount @arg3 and + places the value in the destination register @arg1. + Zeroes are shifted in.""" + arg1 = arg2 >> arg3 + +@sbuild.parse +def sra(arg1, arg2, arg3): + """Shifts arg1 register value @arg2 right by the shift amount @arg3 and + places the value in the destination register @arg1. The sign bit is shifted + in.""" + arg1 = 'a>>'(arg2, arg3) + +@sbuild.parse +def srav(arg1, arg2, arg3): + arg1 = 'a>>'(arg2, arg3 & i32(0x1F)) + +@sbuild.parse +def sll(arg1, arg2, arg3): + arg1 = arg2 << arg3 + +@sbuild.parse +def srlv(arg1, arg2, arg3): + """Shifts a register value @arg2 right by the amount specified in @arg3 and + places the value in the destination register @arg1. + Zeroes are shifted in.""" + arg1 = arg2 >> (arg3 & i32(0x1F)) + +@sbuild.parse +def sllv(arg1, arg2, arg3): + """Shifts a register value @arg2 left by the amount specified in @arg3 and + places the value in the destination register @arg1. + Zeroes are shifted in.""" + arg1 = arg2 << (arg3 & i32(0x1F)) + +@sbuild.parse +def l_xor(arg1, arg2, arg3): + """Exclusive ors two registers @arg2, @arg3 and stores the result in a + register @arg3""" + arg1 = arg2 ^ arg3 + +@sbuild.parse +def seb(arg1, arg2): + arg1 = arg2[:8].signExtend(32) + +@sbuild.parse +def seh(arg1, arg2): + arg1 = arg2[:16].signExtend(32) + +@sbuild.parse +def bltz(arg1, arg2): + """Branches on @arg2 if the register @arg1 is less than zero""" + dst_o = arg2 if m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) else m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) + PC = dst_o + ir.IRDst = dst_o + +@sbuild.parse +def bltzl(arg1, arg2): + """Branches on @arg2 if the register @arg1 is less than zero""" + dst_o = arg2 if m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) else m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) + PC = dst_o + ir.IRDst = dst_o + +@sbuild.parse +def blez(arg1, arg2): + """Branches on @arg2 if the register @arg1 is less than or equal to zero""" + cond = m2_expr.ExprOp(m2_expr.TOK_INF_EQUAL_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) + dst_o = arg2 if cond else m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) + PC = dst_o + ir.IRDst = dst_o + +@sbuild.parse +def blezl(arg1, arg2): + """Branches on @arg2 if the register @arg1 is less than or equal to zero""" + cond = m2_expr.ExprOp(m2_expr.TOK_INF_EQUAL_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) + dst_o = arg2 if cond else m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) + PC = dst_o + ir.IRDst = dst_o + +@sbuild.parse +def bgtz(arg1, arg2): + """Branches on @arg2 if the register @arg1 is greater than zero""" + cond = m2_expr.ExprOp(m2_expr.TOK_INF_EQUAL_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) + dst_o = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) if cond else arg2 + PC = dst_o + ir.IRDst = dst_o + +@sbuild.parse +def bgtzl(arg1, arg2): + """Branches on @arg2 if the register @arg1 is greater than zero""" + cond = m2_expr.ExprOp(m2_expr.TOK_INF_EQUAL_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) + dst_o = m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) if cond else arg2 + PC = dst_o + ir.IRDst = dst_o + +@sbuild.parse +def wsbh(arg1, arg2): + arg1 = m2_expr.ExprCompose(arg2[8:16], arg2[0:8], arg2[24:32], arg2[16:24]) + +@sbuild.parse +def rotr(arg1, arg2, arg3): + arg1 = '>>>'(arg2, arg3) + +@sbuild.parse +def add_d(arg1, arg2, arg3): + # XXX TODO check + arg1 = 'fadd'(arg2, arg3) + +@sbuild.parse +def sub_d(arg1, arg2, arg3): + # XXX TODO check + arg1 = 'fsub'(arg2, arg3) + +@sbuild.parse +def div_d(arg1, arg2, arg3): + # XXX TODO check + arg1 = 'fdiv'(arg2, arg3) + +@sbuild.parse +def mul_d(arg1, arg2, arg3): + # XXX TODO check + arg1 = 'fmul'(arg2, arg3) + +@sbuild.parse +def mov_d(arg1, arg2): + # XXX TODO check + arg1 = arg2 + +@sbuild.parse +def mfc0(arg1, arg2): + arg1 = arg2 + +@sbuild.parse +def mfc1(arg1, arg2): + arg1 = arg2 + +@sbuild.parse +def mtc0(arg1, arg2): + arg2 = arg1 + +@sbuild.parse +def mtc1(arg1, arg2): + arg2 = arg1 + +@sbuild.parse +def tlbwi(): + "TODO XXX" + +@sbuild.parse +def tlbp(): + "TODO XXX" + +@sbuild.parse +def tlbwr(): + "TODO XXX" + +@sbuild.parse +def tlbr(): + "TODO XXX" + +def break_(ir, instr): + e = [] + e.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(EXCEPT_SOFT_BP, 32))) + return e, [] + +def syscall(ir, instr, code): + e = [] + e.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(EXCEPT_SYSCALL, 32))) + return e, [] + +def ins(ir, instr, a, b, c, d): + e = [] + pos = int(c) + l = int(d) + + my_slices = [] + if pos != 0: + my_slices.append(a[:pos]) + if l != 0: + my_slices.append(b[:l]) + if pos + l != 32: + my_slices.append(a[pos+l:]) + r = m2_expr.ExprCompose(*my_slices) + e.append(m2_expr.ExprAssign(a, r)) + return e, [] + + +@sbuild.parse +def lwc1(arg1, arg2): + arg1 = ('mem_%.2d_to_single' % arg2.size)(arg2) + +@sbuild.parse +def swc1(arg1, arg2): + arg2 = ('single_to_mem_%.2d' % arg1.size)(arg1) + +@sbuild.parse +def c_lt_d(arg1, arg2, arg3): + arg1 = 'fcomp_lt'(arg2, arg3) + +@sbuild.parse +def c_eq_d(arg1, arg2, arg3): + arg1 = 'fcomp_eq'(arg2, arg3) + +@sbuild.parse +def c_le_d(arg1, arg2, arg3): + arg1 = 'fcomp_le'(arg2, arg3) + +@sbuild.parse +def bc1t(arg1, arg2): + dst_o = arg2 if arg1 else m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) + PC = dst_o + ir.IRDst = dst_o + +@sbuild.parse +def bc1tl(arg1, arg2): + dst_o = arg2 if arg1 else m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) + PC = dst_o + ir.IRDst = dst_o + +@sbuild.parse +def bc1f(arg1, arg2): + dst_o = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) if arg1 else arg2 + PC = dst_o + ir.IRDst = dst_o + +@sbuild.parse +def bc1fl(arg1, arg2): + dst_o = m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) if arg1 else arg2 + PC = dst_o + ir.IRDst = dst_o + +@sbuild.parse +def cvt_d_w(arg1, arg2): + # TODO XXX + arg1 = 'flt_d_w'(arg2) + +@sbuild.parse +def mult(arg1, arg2): + """Multiplies (signed) @arg1 by @arg2 and stores the result in $R_HI:$R_LO""" + size = arg1.size + result = arg1.signExtend(size * 2) * arg2.signExtend(size * 2) + R_LO = result[:32] + R_HI = result[32:] + +@sbuild.parse +def multu(arg1, arg2): + """Multiplies (unsigned) @arg1 by @arg2 and stores the result in $R_HI:$R_LO""" + size = arg1.size + result = arg1.zeroExtend(size * 2) * arg2.zeroExtend(size * 2) + R_LO = result[:32] + R_HI = result[32:] + +@sbuild.parse +def div(arg1, arg2): + """Divide (signed) @arg1 by @arg2 and stores the remaining/result in $R_HI/$R_LO""" + R_LO = m2_expr.ExprOp('sdiv' ,arg1, arg2) + R_HI = m2_expr.ExprOp('smod', arg1, arg2) + +@sbuild.parse +def divu(arg1, arg2): + """Divide (unsigned) @arg1 by @arg2 and stores the remaining/result in $R_HI/$R_LO""" + R_LO = m2_expr.ExprOp('udiv', arg1, arg2) + R_HI = m2_expr.ExprOp('umod', arg1, arg2) + +@sbuild.parse +def mfhi(arg1): + "The contents of register $R_HI are moved to the specified register @arg1." + arg1 = R_HI + +@sbuild.parse +def mflo(arg1): + "The contents of register R_LO are moved to the specified register @arg1." + arg1 = R_LO + +@sbuild.parse +def di(arg1): + "NOP" + +@sbuild.parse +def ei(arg1): + "NOP" + +@sbuild.parse +def ehb(arg1): + "NOP" + +@sbuild.parse +def sc(arg1, arg2): + arg2 = arg1; + arg1 = m2_expr.ExprInt(0x1, 32) + +@sbuild.parse +def mthi(arg1): + R_HI = arg1 + +@sbuild.parse +def mtlo(arg1): + R_LOW = arg1 + +def clz(ir, instr, rs, rd): + e = [] + e.append(m2_expr.ExprAssign(rd, m2_expr.ExprOp('cntleadzeros', rs))) + return e, [] + +def teq(ir, instr, arg1, arg2): + e = [] + + loc_except, loc_except_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size) + + do_except = [] + do_except.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt( + EXCEPT_DIV_BY_ZERO, exception_flags.size))) + do_except.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + blk_except = IRBlock(ir.loc_db, loc_except, [AssignBlock(do_except, instr)]) + + cond = arg1 - arg2 + + + e = [] + e.append(m2_expr.ExprAssign(ir.IRDst, + m2_expr.ExprCond(cond, loc_next_expr, loc_except_expr))) + + return e, [blk_except] + +def tne(ir, instr, arg1, arg2): + e = [] + + loc_except, loc_except_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size) + + do_except = [] + do_except.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt( + EXCEPT_DIV_BY_ZERO, exception_flags.size))) + do_except.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + blk_except = IRBlock(ir.loc_db, loc_except, [AssignBlock(do_except, instr)]) + + cond = arg1 ^ arg2 + + + e = [] + e.append(m2_expr.ExprAssign(ir.IRDst, + m2_expr.ExprCond(cond, loc_next_expr, loc_except_expr))) + + return e, [blk_except] + + +mnemo_func = sbuild.functions +mnemo_func.update( + { + 'add.d': add_d, + 'addu': addiu, + 'addi': addiu, + 'and': l_and, + 'andi': l_and, + 'b': l_b, + 'c.eq.d': c_eq_d, + 'c.le.d': c_le_d, + 'c.lt.d': c_lt_d, + 'cvt.d.w': cvt_d_w, + 'div.d': div_d, + 'ins': ins, + 'jr': j, + 'mov.d': mov_d, + 'mul.d': mul_d, + 'or': l_or, + 'ori': l_or, + 'slti': slt, + 'sltiu': sltu, + 'sub.d': sub_d, + 'subu': l_sub, + 'xor': l_xor, + 'xori': l_xor, + 'clz': clz, + 'teq': teq, + 'tne': tne, + 'break': break_, + 'sb': sb, + 'sh': sh, + 'syscall': syscall, + } +) + +def get_mnemo_expr(ir, instr, *args): + instr, extra_ir = mnemo_func[instr.name.lower()](ir, instr, *args) + return instr, extra_ir + +class Lifter_Mips32l(Lifter): + + def __init__(self, loc_db): + Lifter.__init__(self, mn_mips32, 'l', loc_db) + self.pc = mn_mips32.getpc() + self.sp = mn_mips32.getsp() + self.IRDst = m2_expr.ExprId('IRDst', 32) + self.addrsize = 32 + + def get_ir(self, instr): + args = instr.args + instr_ir, extra_ir = get_mnemo_expr(self, instr, *args) + + fixed_regs = { + self.pc: m2_expr.ExprInt(instr.offset + 4, 32), + ZERO: m2_expr.ExprInt(0, 32) + } + + instr_ir = [m2_expr.ExprAssign(expr.dst, expr.src.replace_expr(fixed_regs)) + for expr in instr_ir] + + new_extra_ir = [irblock.modify_exprs(mod_src=lambda expr: expr.replace_expr(fixed_regs)) + for irblock in extra_ir] + return instr_ir, new_extra_ir + + def get_next_instr(self, instr): + return self.loc_db.get_or_create_offset_location(instr.offset + 4) + + def get_next_break_loc_key(self, instr): + return self.loc_db.get_or_create_offset_location(instr.offset + 8) + + def get_next_delay_loc_key(self, instr): + return self.loc_db.get_or_create_offset_location(instr.offset + 16) + +class Lifter_Mips32b(Lifter_Mips32l): + def __init__(self, loc_db): + self.addrsize = 32 + Lifter.__init__(self, mn_mips32, 'b', loc_db) + self.pc = mn_mips32.getpc() + self.sp = mn_mips32.getsp() + self.IRDst = m2_expr.ExprId('IRDst', 32) diff --git a/src/miasm/arch/msp430/__init__.py b/src/miasm/arch/msp430/__init__.py new file mode 100644 index 00000000..bbad893b --- /dev/null +++ b/src/miasm/arch/msp430/__init__.py @@ -0,0 +1 @@ +__all__ = ["arch", "disasm", "regs", "sem"] diff --git a/src/miasm/arch/msp430/arch.py b/src/miasm/arch/msp430/arch.py new file mode 100644 index 00000000..417511fa --- /dev/null +++ b/src/miasm/arch/msp430/arch.py @@ -0,0 +1,610 @@ +#-*- coding:utf-8 -*- + +from builtins import range + +import logging +from pyparsing import * +from miasm.expression.expression import * +from miasm.core.cpu import * +from collections import defaultdict +from miasm.core.bin_stream import bin_stream +import miasm.arch.msp430.regs as regs_module +from miasm.arch.msp430.regs import * +from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html + +log = logging.getLogger("msp430dis") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.DEBUG) + +conditional_branch = ['jnz', 'jz', 'jnc', 'jc', + 'jn', 'jge', 'jl'] +unconditional_branch = ['jmp'] + +def cb_deref_nooff(tokens): + assert len(tokens) == 1 + result = AstMem(tokens[0], 16) + return result + + +def cb_deref_pinc(tokens): + assert len(tokens) == 1 + + result = AstOp('autoinc', *tokens) + return result + + +def cb_deref_off(tokens): + assert len(tokens) == 2 + result = AstMem(tokens[1] + tokens[0], 16) + return result + + +def cb_expr(tokens): + assert(len(tokens) == 1) + result = tokens[0] + return result + + +ARO = Suppress("@") +LPARENT = Suppress("(") +RPARENT = Suppress(")") + +PINC = Suppress("+") + +deref_nooff = (ARO + base_expr).setParseAction(cb_deref_nooff) +deref_pinc = (ARO + base_expr + PINC).setParseAction(cb_deref_pinc) +deref_off = (base_expr + LPARENT + gpregs.parser + RPARENT).setParseAction(cb_deref_off) +sreg_p = (deref_pinc | deref_nooff | deref_off | base_expr).setParseAction(cb_expr) + + + +class msp430_arg(m_arg): + def asm_ast_to_expr(self, value, loc_db): + if isinstance(value, AstId): + name = value.name + if is_expr(name): + return name + assert isinstance(name, str) + if name in gpregs.str: + index = gpregs.str.index(name) + reg = gpregs.expr[index] + return reg + loc_key = loc_db.get_or_create_name_location(value.name) + return ExprLoc(loc_key, 16) + if isinstance(value, AstOp): + args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in value.args] + if None in args: + return None + return ExprOp(value.op, *args) + if isinstance(value, AstInt): + return ExprInt(value.value, 16) + if isinstance(value, AstMem): + ptr = self.asm_ast_to_expr(value.ptr, loc_db) + if ptr is None: + return None + return ExprMem(ptr, value.size) + return None + + +class additional_info(object): + + def __init__(self): + self.except_on_instr = False + + +class instruction_msp430(instruction): + __slots__ = [] + + def dstflow(self): + if self.name.startswith('j'): + return True + return self.name in ['call'] + + @staticmethod + def arg2str(expr, index=None, loc_db=None): + if isinstance(expr, ExprId): + o = str(expr) + elif isinstance(expr, ExprInt): + o = str(expr) + elif expr.is_loc(): + if loc_db is not None: + return loc_db.pretty_str(expr.loc_key) + else: + return str(expr) + elif isinstance(expr, ExprOp) and expr.op == "autoinc": + o = "@%s+" % str(expr.args[0]) + elif isinstance(expr, ExprMem): + if isinstance(expr.ptr, ExprId): + if index == 0: + o = "@%s" % expr.ptr + else: + o = "0x0(%s)" % expr.ptr + elif isinstance(expr.ptr, ExprInt): + o = "@%s" % expr.ptr + elif isinstance(expr.ptr, ExprOp): + o = "%s(%s)" % (expr.ptr.args[1], expr.ptr.args[0]) + else: + raise NotImplementedError('unknown instance expr = %s' % type(expr)) + return o + + @staticmethod + def arg2html(expr, index=None, loc_db=None): + if isinstance(expr, ExprId) or isinstance(expr, ExprInt) or expr.is_loc(): + return color_expr_html(expr, loc_db) + elif isinstance(expr, ExprOp) and expr.op == "autoinc": + o = "@%s+" % color_expr_html(expr.args[0], loc_db) + elif isinstance(expr, ExprMem): + if isinstance(expr.ptr, ExprId): + if index == 0: + o = "@%s" % color_expr_html(expr.ptr, loc_db) + else: + o = "0x0(%s)" % color_expr_html(expr.ptr, loc_db) + elif isinstance(expr.ptr, ExprInt): + o = "@%s" % color_expr_html(expr.ptr, loc_db) + elif isinstance(expr.ptr, ExprOp): + o = "%s(%s)" % ( + color_expr_html(expr.ptr.args[1], loc_db), + color_expr_html(expr.ptr.args[0], loc_db) + ) + else: + raise NotImplementedError('unknown instance expr = %s' % type(expr)) + return o + + + def dstflow2label(self, loc_db): + expr = self.args[0] + if not isinstance(expr, ExprInt): + return + if self.name == "call": + addr = int(expr) + else: + addr = (int(expr) + int(self.offset)) & int(expr.mask) + + loc_key = loc_db.get_or_create_offset_location(addr) + self.args[0] = ExprLoc(loc_key, expr.size) + + def breakflow(self): + if self.name in conditional_branch + unconditional_branch: + return True + if self.name.startswith('ret'): + return True + if self.name.startswith('int'): + return True + if self.name.startswith('mov') and self.args[1] == PC: + return True + return self.name in ['call'] + + def splitflow(self): + if self.name in conditional_branch: + return True + if self.name in unconditional_branch: + return False + return self.name in ['call'] + + def setdstflow(self, a): + return + + def is_subcall(self): + return self.name in ['call'] + + def getdstflow(self, loc_db): + return [self.args[0]] + + def get_symbol_size(self, symbol, loc_db): + return 16 + + def fixDstOffset(self): + e = self.args[0] + if self.offset is None: + raise ValueError('symbol not resolved %s' % l) + if not isinstance(e, ExprInt): + # raise ValueError('dst must be int or label') + log.warning('dynamic dst %r', e) + return + + # Call argument is an absolute offset + # Other offsets are relative to instruction offset + if self.name != "call": + self.args[0] = ExprInt(int(e) - self.offset, 16) + + def get_info(self, c): + pass + + def __str__(self): + o = super(instruction_msp430, self).__str__() + return o + + def get_args_expr(self): + args = [] + for a in self.args: + args.append(a) + return args + + +mode_msp430 = None + + +class mn_msp430(cls_mn): + name = "msp430" + regs = regs_module + all_mn = [] + bintree = {} + num = 0 + delayslot = 0 + pc = {None: PC} + sp = {None: SP} + all_mn_mode = defaultdict(list) + all_mn_name = defaultdict(list) + all_mn_inst = defaultdict(list) + instruction = instruction_msp430 + max_instruction_len = 8 + + @classmethod + def getpc(cls, attrib): + return PC + + @classmethod + def getsp(cls, attrib): + return SP + + @classmethod + def check_mnemo(cls, fields): + l = sum([x.l for x in fields]) + assert l % 16 == 00, "len %r" % l + + @classmethod + def getbits(cls, bs, attrib, start, n): + if not n: + return 0 + o = 0 + if n > bs.getlen() * 8: + raise ValueError('not enough bits %r %r' % (n, len(bs.bin) * 8)) + while n: + i = start // 8 + c = cls.getbytes(bs, i) + if not c: + raise IOError + c = ord(c) + r = 8 - start % 8 + c &= (1 << r) - 1 + l = min(r, n) + c >>= (r - l) + o <<= l + o |= c + n -= l + start += l + return o + + @classmethod + def getbytes(cls, bs, offset, l=1): + out = b"" + for _ in range(l): + n_offset = (offset & ~1) + 1 - offset % 2 + out += bs.getbytes(n_offset, 1) + offset += 1 + return out + + def decoded2bytes(self, result): + tmp = super(mn_msp430, self).decoded2bytes(result) + out = [] + for x in tmp: + o = b"" + while x: + o += x[:2][::-1] + x = x[2:] + out.append(o) + return out + + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + dct['mode'] = None + return [(subcls, name, bases, dct, fields)] + + def additional_info(self): + info = additional_info() + return info + + @classmethod + def getmn(cls, name): + return name.upper() + + def reset_class(self): + super(mn_msp430, self).reset_class() + + def getnextflow(self, loc_db): + raise NotImplementedError('not fully functional') + + +def addop(name, fields, args=None, alias=False): + dct = {"fields": fields} + dct["alias"] = alias + if args is not None: + dct['args'] = args + type(name, (mn_msp430,), dct) + + +class bw_mn(bs_mod_name): + prio = 5 + mn_mod = ['.w', '.b'] + + +class msp430_sreg_arg(reg_noarg, msp430_arg): + prio = default_prio + 1 + reg_info = gpregs + parser = sreg_p + + def decode(self, v): + size = 16 + if hasattr(self.parent, 'size'): + size = [16, 8][self.parent.size.value] + v = v & self.lmask + e = self.reg_info.expr[v] + if self.parent.a_s.value == 0b00: + if e == R3: + self.expr = ExprInt(0, size) + else: + self.expr = e + elif self.parent.a_s.value == 0b01: + if e == SR: + self.expr = ExprMem(ExprInt(self.parent.off_s.value, 16), size) + elif e == R3: + self.expr = ExprInt(1, size) + else: + self.expr = ExprMem( + e + ExprInt(self.parent.off_s.value, 16), size) + elif self.parent.a_s.value == 0b10: + if e == SR: + self.expr = ExprInt(4, size) + elif e == R3: + self.expr = ExprInt(2, size) + else: + self.expr = ExprMem(e, size) + elif self.parent.a_s.value == 0b11: + if e == SR: + self.expr = ExprInt(8, size) + elif e == R3: + if self.parent.size.value == 0: + self.expr = ExprInt(0xffff, size) + else: + self.expr = ExprInt(0xff, size) + elif e == PC: + self.expr = ExprInt(self.parent.off_s.value, size) + else: + self.expr = ExprOp('autoinc', e) + else: + raise NotImplementedError( + "unknown value self.parent.a_s.value = " + + "%d" % self.parent.a_s.value) + return True + + def encode(self): + e = self.expr + if e in self.reg_info.expr: + self.parent.a_s.value = 0 + self.value = self.reg_info.expr.index(e) + elif isinstance(e, ExprInt): + v = int(e) + if v == 0xffff and self.parent.size.value == 0: + self.parent.a_s.value = 0b11 + self.value = 3 + elif v == 0xff and self.parent.size.value == 1: + self.parent.a_s.value = 0b11 + self.value = 3 + elif v == 2: + self.parent.a_s.value = 0b10 + self.value = 3 + elif v == 1: + self.parent.a_s.value = 0b01 + self.value = 3 + elif v == 8: + self.parent.a_s.value = 0b11 + self.value = 2 + elif v == 4: + self.parent.a_s.value = 0b10 + self.value = 2 + elif v == 0: + self.parent.a_s.value = 0b00 + self.value = 3 + else: + self.parent.a_s.value = 0b11 + self.value = 0 + self.parent.off_s.value = v + elif isinstance(e, ExprMem): + if isinstance(e.ptr, ExprId): + self.parent.a_s.value = 0b10 + self.value = self.reg_info.expr.index(e.ptr) + elif isinstance(e.ptr, ExprInt): + self.parent.a_s.value = 0b01 + self.value = self.reg_info.expr.index(SR) + self.parent.off_s.value = int(e.ptr) + elif isinstance(e.ptr, ExprOp): + self.parent.a_s.value = 0b01 + self.value = self.reg_info.expr.index(e.ptr.args[0]) + self.parent.off_s.value = int(e.ptr.args[1]) + else: + raise NotImplementedError( + 'unknown instance e.ptr = %s' % type(e.ptr)) + elif isinstance(e, ExprOp) and e.op == "autoinc": + self.parent.a_s.value = 0b11 + self.value = self.reg_info.expr.index(e.args[0]) + else: + raise NotImplementedError('unknown instance e = %s' % type(e)) + return True + + +class msp430_dreg_arg(msp430_sreg_arg): + prio = default_prio + 1 + reg_info = gpregs + parser = sreg_p + + def decode(self, v): + if hasattr(self.parent, 'size'): + size = [16, 8][self.parent.size.value] + else: + size = 16 + + v = v & self.lmask + e = self.reg_info.expr[v] + if self.parent.a_d.value == 0: + self.expr = e + elif self.parent.a_d.value == 1: + if e == SR: + x = ExprInt(self.parent.off_d.value, 16) + else: + x = e + ExprInt(self.parent.off_d.value, 16) + self.expr = ExprMem(x, size) + else: + raise NotImplementedError( + "unknown value self.parent.a_d.value = " + + "%d" % self.parent.a_d.value) + return True + + def encode(self): + e = self.expr + if e in self.reg_info.expr: + self.parent.a_d.value = 0 + self.value = self.reg_info.expr.index(e) + elif isinstance(e, ExprMem): + if isinstance(e.ptr, ExprId): + r, i = e.ptr, ExprInt(0, 16) + elif isinstance(e.ptr, ExprOp): + r, i = e.ptr.args[0], e.ptr.args[1] + elif isinstance(e.ptr, ExprInt): + r, i = SR, e.ptr + else: + raise NotImplementedError( + 'unknown instance e.arg = %s' % type(e.ptr)) + self.parent.a_d.value = 1 + self.value = self.reg_info.expr.index(r) + self.parent.off_d.value = int(i) + else: + raise NotImplementedError('unknown instance e = %s' % type(e)) + return True + +class bs_cond_off_s(bs_cond): + + @classmethod + def flen(cls, mode, v): + if v['a_s'] == 0b00: + return None + elif v['a_s'] == 0b01: + if v['sreg'] in [3]: + return None + else: + return 16 + elif v['a_s'] == 0b10: + return None + elif v['a_s'] == 0b11: + """ + if v['sreg'] in [2, 3]: + return None + else: + return 16 + """ + if v['sreg'] in [0]: + return 16 + else: + return None + else: + raise NotImplementedError("unknown value v[a_s] = %d" % v['a_s']) + + def encode(self): + return super(bs_cond_off_s, self).encode() + + def decode(self, v): + if self.l == 0: + self.value = None + self.value = v + return True + + +class bs_cond_off_d(bs_cond_off_s): + + @classmethod + def flen(cls, mode, v): + if v['a_d'] == 0: + return None + elif v['a_d'] == 1: + return 16 + else: + raise NotImplementedError("unknown value v[a_d] = %d" % v['a_d']) + + +class msp430_offs(imm_noarg, msp430_arg): + parser = base_expr + + def int2expr(self, v): + if v & ~self.intmask != 0: + return None + return ExprInt(v, 16) + + def decodeval(self, v): + v <<= 1 + v += self.parent.l + return v + + def encodeval(self, v): + plen = self.parent.l + self.l + assert(plen % 8 == 0) + v -= plen // 8 + if v % 2 != 0: + return False + return v >> 1 + + def decode(self, v): + v = v & self.lmask + if (1 << (self.l - 1)) & v: + v |= ~0 ^ self.lmask + v = self.decodeval(v) + self.expr = ExprInt(v, 16) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if (1 << (self.l - 1)) & v: + v = -((0xffff ^ v) + 1) + v = self.encodeval(v) + self.value = (v & 0xffff) & self.lmask + return True + + +off_s = bs(l=16, order=-10, cls=(bs_cond_off_s,), fname = "off_s") +off_d = bs(l=16, order=-10, cls=(bs_cond_off_d,), fname = "off_d") + +a_s = bs(l=2, order=-4, fname='a_s') +a_d = bs(l=1, order=-6, fname='a_d') + +a_d2 = bs(l=2, order=-2, fname='a_d') + +sreg = bs(l=4, order=-3, cls=(msp430_sreg_arg,), fname='sreg') +dreg = bs(l=4, order=-5, cls=(msp430_dreg_arg,), fname='dreg') + +bw = bw_mn(l=1, order=-10, mn_mod=['.w', '.b'], fname='size') + +bs_f1 = bs_name( + l=4, name={ + 'mov': 4, 'add': 5, 'addc': 6, 'subc': 7, 'sub': 8, 'cmp': 9, + 'dadd': 10, 'bit': 11, 'bic': 12, 'bis': 13, 'xor': 14, 'and': 15}) +addop("f1", [bs_f1, sreg, a_d, bw, a_s, dreg, off_s, off_d]) + +bs_f2 = bs_name(l=3, name={'rrc': 0, 'rra': 2, + 'push': 4}) +addop("f2_1", [bs('000100'), bs_f2, bw, a_s, sreg, off_s]) + + +bs_f2_nobw = bs_name(l=3, name={'swpb': 1, 'sxt': 3, + 'call': 5}) +addop("f2_2", [bs('000100'), bs_f2_nobw, bs('0'), a_s, sreg, off_s]) + +# Offset must be decoded in last position to have final instruction len +offimm = bs(l=10, cls=(msp430_offs,), fname="offs", order=-1) + +bs_f2_jcc = bs_name(l=3, name={'jnz': 0, 'jz': 1, 'jnc': 2, 'jc': 3, 'jn': 4, + 'jge': 5, 'jl': 6, 'jmp': 7}) +addop("f2_3", [bs('001'), bs_f2_jcc, offimm]) + diff --git a/src/miasm/arch/msp430/ctype.py b/src/miasm/arch/msp430/ctype.py new file mode 100644 index 00000000..0e6562e8 --- /dev/null +++ b/src/miasm/arch/msp430/ctype.py @@ -0,0 +1,68 @@ +from miasm.core.objc import CLeafTypes, ObjCDecl, PADDING_TYPE_NAME +from miasm.core.ctypesmngr import CTypeId, CTypePtr + + +class CTypeMSP430_unk(CLeafTypes): + """Define C types sizes/alignment for msp430 architecture""" + + obj_pad = ObjCDecl(PADDING_TYPE_NAME, 1, 1) # __padding__ is size 1/align 1 + + obj_char = ObjCDecl("char", 1, 1) + obj_short = ObjCDecl("short", 2, 2) + obj_int = ObjCDecl("int", 2, 2) + obj_long = ObjCDecl("long", 2, 2) + + obj_uchar = ObjCDecl("uchar", 1, 1) + obj_ushort = ObjCDecl("ushort", 2, 2) + obj_uint = ObjCDecl("uint", 2, 2) + obj_ulong = ObjCDecl("ulong", 2, 2) + + obj_void = ObjCDecl("void", 1, 1) + + obj_enum = ObjCDecl("enum", 2, 2) + + obj_float = ObjCDecl("float", 4, 4) + obj_double = ObjCDecl("double", 8, 8) + obj_ldouble = ObjCDecl("ldouble", 16, 16) + + def __init__(self): + self.types = { + CTypeId(PADDING_TYPE_NAME): self.obj_pad, + + CTypeId('char'): self.obj_char, + CTypeId('short'): self.obj_short, + CTypeId('int'): self.obj_int, + CTypeId('void'): self.obj_void, + CTypeId('long',): self.obj_long, + CTypeId('float'): self.obj_float, + CTypeId('double'): self.obj_double, + + CTypeId('signed', 'char'): self.obj_char, + CTypeId('unsigned', 'char'): self.obj_uchar, + + CTypeId('short', 'int'): self.obj_short, + CTypeId('signed', 'short'): self.obj_short, + CTypeId('signed', 'short', 'int'): self.obj_short, + CTypeId('unsigned', 'short'): self.obj_ushort, + CTypeId('unsigned', 'short', 'int'): self.obj_ushort, + + CTypeId('unsigned', ): self.obj_uint, + CTypeId('unsigned', 'int'): self.obj_uint, + CTypeId('signed', 'int'): self.obj_int, + + CTypeId('long', 'int'): self.obj_long, + CTypeId('long', 'long'): self.obj_long, + CTypeId('long', 'long', 'int'): self.obj_long, + CTypeId('signed', 'long', 'long'): self.obj_long, + CTypeId('unsigned', 'long', 'long'): self.obj_ulong, + CTypeId('signed', 'long', 'long', 'int'): self.obj_long, + CTypeId('unsigned', 'long', 'long', 'int'): self.obj_ulong, + + CTypeId('signed', 'long'): self.obj_long, + CTypeId('unsigned', 'long'): self.obj_ulong, + CTypeId('signed', 'long', 'int'): self.obj_long, + CTypeId('unsigned', 'long', 'int'): self.obj_ulong, + + CTypeId('long', 'double'): self.obj_ldouble, + CTypePtr(CTypeId('void')): self.obj_uint, + } diff --git a/src/miasm/arch/msp430/disasm.py b/src/miasm/arch/msp430/disasm.py new file mode 100644 index 00000000..eff77d2d --- /dev/null +++ b/src/miasm/arch/msp430/disasm.py @@ -0,0 +1,8 @@ +from miasm.core.asmblock import disasmEngine +from miasm.arch.msp430.arch import mn_msp430 + + +class dis_msp430(disasmEngine): + + def __init__(self, bs=None, **kwargs): + super(dis_msp430, self).__init__(mn_msp430, None, bs, **kwargs) diff --git a/src/miasm/arch/msp430/jit.py b/src/miasm/arch/msp430/jit.py new file mode 100644 index 00000000..ad767588 --- /dev/null +++ b/src/miasm/arch/msp430/jit.py @@ -0,0 +1,41 @@ +from miasm.jitter.jitload import Jitter +from miasm.core.locationdb import LocationDB +from miasm.core.utils import pck16, upck16 +from miasm.arch.msp430.sem import Lifter_MSP430 + +import logging + +log = logging.getLogger('jit_msp430') +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) + +class jitter_msp430(Jitter): + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_MSP430(loc_db), *args, **kwargs) + self.vm.set_little_endian() + + def push_uint16_t(self, value): + regs = self.cpu.get_gpreg() + regs['SP'] -= 2 + self.cpu.set_gpreg(regs) + self.vm.set_mem(regs['SP'], pck16(value)) + + def pop_uint16_t(self): + regs = self.cpu.get_gpreg() + value = self.vm.get_u16(regs['SP']) + regs['SP'] += 2 + self.cpu.set_gpreg(regs) + return value + + def get_stack_arg(self, index): + regs = self.cpu.get_gpreg() + value = self.vm.get_u16(regs['SP'] + 2 * index) + return value + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.PC = self.pc + diff --git a/src/miasm/arch/msp430/lifter_model_call.py b/src/miasm/arch/msp430/lifter_model_call.py new file mode 100644 index 00000000..05f649e5 --- /dev/null +++ b/src/miasm/arch/msp430/lifter_model_call.py @@ -0,0 +1,31 @@ +#-*- coding:utf-8 -*- + +from miasm.ir.analysis import LifterModelCall +from miasm.arch.msp430.sem import Lifter_MSP430 +from miasm.ir.ir import AssignBlock +from miasm.expression.expression import * + +class LifterModelCallMsp430Base(Lifter_MSP430, LifterModelCall): + + def __init__(self, loc_db): + Lifter_MSP430.__init__(self, loc_db) + self.ret_reg = self.arch.regs.R15 + + def call_effects(self, addr, instr): + call_assignblk = AssignBlock( + [ + ExprAssign(self.ret_reg, ExprOp('call_func_ret', addr, self.sp, self.arch.regs.R15)), + ExprAssign(self.sp, ExprOp('call_func_stack', addr, self.sp)) + ], + instr + ) + return [call_assignblk], [] + +class LifterModelCallMsp430(LifterModelCallMsp430Base): + + def __init__(self, loc_db): + LifterModelCallMsp430Base.__init__(self, loc_db) + + def get_out_regs(self, _): + return set([self.ret_reg, self.sp]) + diff --git a/src/miasm/arch/msp430/regs.py b/src/miasm/arch/msp430/regs.py new file mode 100644 index 00000000..2bcaa055 --- /dev/null +++ b/src/miasm/arch/msp430/regs.py @@ -0,0 +1,116 @@ +from builtins import range +from miasm.expression.expression import * +from miasm.core.cpu import reg_info + + +# GP + +regs16_str = ["PC", "SP", "SR"] + ["R%d" % i for i in range(3, 16)] +regs16_expr = [ExprId(x, 16) for x in regs16_str] + +exception_flags = ExprId('exception_flags', 32) + +gpregs = reg_info(regs16_str, regs16_expr) + +PC = regs16_expr[0] +SP = regs16_expr[1] +SR = regs16_expr[2] +R3 = regs16_expr[3] +R4 = regs16_expr[4] +R5 = regs16_expr[5] +R6 = regs16_expr[6] +R7 = regs16_expr[7] +R8 = regs16_expr[8] +R9 = regs16_expr[9] +R10 = regs16_expr[10] +R11 = regs16_expr[11] +R12 = regs16_expr[12] +R13 = regs16_expr[13] +R14 = regs16_expr[14] +R15 = regs16_expr[15] + +PC_init = ExprId("PC_init", 16) +SP_init = ExprId("SP_init", 16) +SR_init = ExprId("SR_init", 16) +R3_init = ExprId("R3_init", 16) +R4_init = ExprId("R4_init", 16) +R5_init = ExprId("R5_init", 16) +R6_init = ExprId("R6_init", 16) +R7_init = ExprId("R7_init", 16) +R8_init = ExprId("R8_init", 16) +R9_init = ExprId("R9_init", 16) +R10_init = ExprId("R10_init", 16) +R11_init = ExprId("R11_init", 16) +R12_init = ExprId("R12_init", 16) +R13_init = ExprId("R13_init", 16) +R14_init = ExprId("R14_init", 16) +R15_init = ExprId("R15_init", 16) + + +reg_zf = 'zf' +reg_nf = 'nf' +reg_of = 'of' +reg_cf = 'cf' +reg_cpuoff = 'cpuoff' +reg_gie = 'gie' +reg_osc = 'osc' +reg_scg0 = 'scg0' +reg_scg1 = 'scg1' +reg_res = 'res' + +zf = ExprId(reg_zf, size=1) +nf = ExprId(reg_nf, size=1) +of = ExprId(reg_of, size=1) +cf = ExprId(reg_cf, size=1) + +cpuoff = ExprId(reg_cpuoff, size=1) +gie = ExprId(reg_gie, size=1) +osc = ExprId(reg_osc, size=1) +scg0 = ExprId(reg_scg0, size=1) +scg1 = ExprId(reg_scg1, size=1) +res = ExprId(reg_res, size=7) + + +zf_init = ExprId("zf_init", size=1) +nf_init = ExprId("nf_init", size=1) +of_init = ExprId("of_init", size=1) +cf_init = ExprId("cf_init", size=1) + + +cpuoff_init = ExprId("cpuoff_init", size=1) +gie_init = ExprId("gie_init", size=1) +osc_init = ExprId("osc_init", size=1) +scg0_init = ExprId("scg0_init", size=1) +scg1_init = ExprId("scg1_init", size=1) +res_init = ExprId("res_init", size=7) + + +all_regs_ids = [ + PC, SP, SR, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, + zf, nf, of, cf, + cpuoff, gie, osc, scg0, scg1, res, +] + +all_regs_ids_no_alias = all_regs_ids + +attrib_to_regs = { + 'l': all_regs_ids_no_alias, + 'b': all_regs_ids_no_alias, +} + +all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) + +all_regs_ids_init = [PC_init, SP_init, SR_init, R3_init, + R4_init, R5_init, R6_init, R7_init, + R8_init, R9_init, R10_init, R11_init, + R12_init, R13_init, R14_init, R15_init, + zf_init, nf_init, of_init, cf_init, + cpuoff_init, gie_init, osc_init, + scg0_init, scg1_init, res_init, + ] + +regs_init = {} +for i, r in enumerate(all_regs_ids): + regs_init[r] = all_regs_ids_init[i] + +regs_flt_expr = [] diff --git a/src/miasm/arch/msp430/sem.py b/src/miasm/arch/msp430/sem.py new file mode 100644 index 00000000..d4d3221b --- /dev/null +++ b/src/miasm/arch/msp430/sem.py @@ -0,0 +1,509 @@ +#-*- coding:utf-8 -*- + +from miasm.expression.expression import * +from miasm.arch.msp430.regs import * +from miasm.arch.msp430.arch import mn_msp430 +from miasm.ir.ir import Lifter + + +# Utils +def hex2bcd(val): + "Return val as BCD" + try: + return int("%x" % val, 10) + except ValueError: + raise NotImplementedError("Not defined behaviour") + + +def bcd2hex(val): + "Return the hex value of a BCD" + try: + return int("0x%d" % val, 16) + except ValueError: + raise NotImplementedError("Not defined behaviour") + + +def reset_sr_res(): + return [ExprAssign(res, ExprInt(0, 7))] + + +def update_flag_cf_inv_zf(a): + return [ExprAssign(cf, ExprCond(a, ExprInt(1, 1), ExprInt(0, 1)))] + + +def update_flag_zf_eq(a, b): + return [ExprAssign(zf, ExprOp("FLAG_EQ_CMP", a, b))] + + +def update_flag_zf(a): + return [ExprAssign(zf, ExprOp("FLAG_EQ", a))] + + +def update_flag_nf(arg): + return [ + ExprAssign( + nf, + ExprOp("FLAG_SIGN_SUB", arg, ExprInt(0, arg.size)) + ) + ] + + +def update_flag_add_cf(op1, op2, res): + "Compute cf in @res = @op1 + @op2" + return [ExprAssign(cf, ExprOp("FLAG_ADD_CF", op1, op2))] + + +def update_flag_add_of(op1, op2, res): + "Compute of in @res = @op1 + @op2" + return [ExprAssign(of, ExprOp("FLAG_ADD_OF", op1, op2))] + + +# checked: ok for sbb add because b & c before +cf +def update_flag_sub_cf(op1, op2, res): + "Compote CF in @op1 - @op2" + return [ExprAssign(cf, ExprOp("FLAG_SUB_CF", op1, op2) ^ ExprInt(1, 1))] + + +def update_flag_sub_of(op1, op2, res): + "Compote OF in @res = @op1 - @op2" + return [ExprAssign(of, ExprOp("FLAG_SUB_OF", op1, op2))] + + +def update_flag_arith_sub_zn(arg1, arg2): + """ + Compute znp flags for (arg1 - arg2) + """ + e = [] + e += update_flag_zf_eq(arg1, arg2) + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, arg2))] + return e + + +def update_flag_arith_add_zn(arg1, arg2): + """ + Compute zf and nf flags for (arg1 + arg2) + """ + e = [] + e += update_flag_zf_eq(arg1, -arg2) + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, -arg2))] + return e + + + +def mng_autoinc(a, b, size): + e = [] + if not (isinstance(a, ExprOp) and a.op == "autoinc"): + return e, a, b + + a_r = a.args[0] + e.append(ExprAssign(a_r, a_r + ExprInt(size // 8, a_r.size))) + a = ExprMem(a_r, size) + if isinstance(b, ExprMem) and a_r in b.arg: + b = ExprMem(b.arg + ExprInt(size // 8, 16), b.size) + return e, a, b + +# Mnemonics + + +def mov_b(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 8) + if isinstance(b, ExprMem): + b = ExprMem(b.arg, 8) + a = a[:8] + else: + a = a[:8].zeroExtend(16) + e.append(ExprAssign(b, a)) + return e, [] + + +def mov_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + e.append(ExprAssign(b, a)) + if b == ir.pc: + e.append(ExprAssign(ir.IRDst, a)) + return e, [] + + +def and_b(ir, instr, a, b): + e, arg1, arg2 = mng_autoinc(a, b, 8) + arg1, arg2 = arg1[:8], arg2[:8] + res = arg1 & arg2 + e.append(ExprAssign(b, res.zeroExtend(16))) + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))] + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", res, ExprInt(0, res.size)))] + e += reset_sr_res() + e += update_flag_cf_inv_zf(res) + e += [ExprAssign(of, ExprInt(0, 1))] + + return e, [] + + +def and_w(ir, instr, a, b): + e, arg1, arg2 = mng_autoinc(a, b, 16) + res = arg1 & arg2 + e.append(ExprAssign(arg2, res)) + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))] + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", res, ExprInt(0, res.size)))] + e += reset_sr_res() + e += update_flag_cf_inv_zf(res) + e += [ExprAssign(of, ExprInt(0, 1))] + + return e, [] + + +def bic_b(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 8) + c = (a[:8] ^ ExprInt(0xff, 8)) & b[:8] + c = c.zeroExtend(b.size) + e.append(ExprAssign(b, c)) + return e, [] + + +def bic_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + if b == SR: + # Special case + if a.is_int(1): + # cf + e.append(ExprAssign(cf, ExprInt(0, 1))) + return e, [] + c = (a ^ ExprInt(0xffff, 16)) & b + e.append(ExprAssign(b, c)) + return e, [] + + +def bis_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + c = a | b + e.append(ExprAssign(b, c)) + return e, [] + + +def bit_w(ir, instr, a, b): + e, arg1, arg2 = mng_autoinc(a, b, 16) + res = arg1 & arg2 + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))] + e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", res, ExprInt(0, res.size)))] + e += reset_sr_res() + e += update_flag_cf_inv_zf(res) + e += [ExprAssign(of, ExprInt(0, 1))] + + return e, [] + + +def sub_w(ir, instr, a, b): + e, arg1, arg2 = mng_autoinc(a, b, 16) + res = arg2 - arg1 + + e.append(ExprAssign(b, res)) + + e += update_flag_arith_sub_zn(arg2, arg1) + e += update_flag_sub_cf(arg2, arg1, res) + e += update_flag_sub_of(arg2, arg1, res) + e += reset_sr_res() + + # micrcorruption + # e += update_flag_sub_of(a, b, c) + # e += update_flag_sub_of(b, a, c) + return e, [] + + +def add_b(ir, instr, a, b): + e, arg1, arg2 = mng_autoinc(a, b, 8) + if isinstance(arg2, ExprMem): + arg2 = ExprMem(arg2.arg, 8) + else: + arg2 = arg2[:8] + arg1 = arg1[:8] + res = arg2 + arg1 + e.append(ExprAssign(b, res)) + + e += update_flag_arith_add_zn(arg2, arg1) + e += update_flag_add_cf(arg2, arg1, res) + e += update_flag_add_of(arg2, arg1, res) + e += reset_sr_res() + + return e, [] + + +def add_w(ir, instr, a, b): + e, arg1, arg2 = mng_autoinc(a, b, 16) + res = arg2 + arg1 + e.append(ExprAssign(b, res)) + + e += update_flag_arith_add_zn(arg2, arg1) + e += update_flag_add_cf(arg2, arg1, res) + e += update_flag_add_of(arg2, arg1, res) + e += reset_sr_res() + + return e, [] + + +def dadd_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + # TODO: microcorruption no carryflag + c = ExprOp("bcdadd", b, a) # +zeroExtend(cf, 16)) + + e.append(ExprAssign(b, c)) + + # micrcorruption + e += update_flag_zf(a) + # e += update_flag_nf(a) + e += reset_sr_res() + + e.append(ExprAssign(cf, ExprOp("bcdadd_cf", b, a))) # +zeroExtend(cf, 16)))) + + # of : undefined + return e, [] + + +def xor_w(ir, instr, a, b): + e, arg1, arg2 = mng_autoinc(a, b, 16) + res = arg2 ^ arg1 + e.append(ExprAssign(b, res)) + + e += [ExprAssign(zf, ExprOp('FLAG_EQ_CMP', arg2, arg1))] + e += update_flag_nf(res) + e += reset_sr_res() + e += update_flag_cf_inv_zf(res) + e.append(ExprAssign(of, arg2.msb() & arg1.msb())) + + return e, [] + + +def push_w(ir, instr, a): + e = [] + e.append(ExprAssign(ExprMem(SP - ExprInt(2, 16), 16), a)) + e.append(ExprAssign(SP, SP - ExprInt(2, 16))) + return e, [] + + +def call(ir, instr, a): + e, a, dummy = mng_autoinc(a, None, 16) + + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 16) + + e.append(ExprAssign(ExprMem(SP - ExprInt(2, 16), 16), loc_next_expr)) + e.append(ExprAssign(SP, SP - ExprInt(2, 16))) + e.append(ExprAssign(PC, a)) + e.append(ExprAssign(ir.IRDst, a)) + return e, [] + + +def swpb(ir, instr, a): + e = [] + x, y = a[:8], a[8:16] + e.append(ExprAssign(a, ExprCompose(y, x))) + return e, [] + + +def cmp_w(ir, instr, a, b): + e, arg1, arg2 = mng_autoinc(a, b, 16) + res = arg2 - arg1 + + e += update_flag_arith_sub_zn(arg2, arg1) + e += update_flag_sub_cf(arg2, arg1, res) + e += update_flag_sub_of(arg2, arg1, res) + e += reset_sr_res() + + return e, [] + + +def cmp_b(ir, instr, a, b): + e, arg1, arg2 = mng_autoinc(a, b, 8) + arg1, arg2 = arg1[:8], arg2[:8] + res = arg2 - arg1 + + e += update_flag_arith_sub_zn(arg2, arg1) + e += update_flag_sub_cf(arg2, arg1, res) + e += update_flag_sub_of(arg2, arg1, res) + e += reset_sr_res() + + return e, [] + + +def jz(ir, instr, a): + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 16) + e = [] + e.append(ExprAssign(PC, ExprCond(ExprOp("CC_EQ", zf), a, loc_next_expr))) + e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_EQ", zf), a, loc_next_expr))) + return e, [] + + +def jnz(ir, instr, a): + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 16) + e = [] + e.append(ExprAssign(PC, ExprCond(ExprOp("CC_EQ", zf), loc_next_expr, a))) + e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_EQ", zf), loc_next_expr, a))) + return e, [] + + +def jl(ir, instr, a): + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 16) + e = [] + e.append(ExprAssign(PC, ExprCond(ExprOp("CC_S<", nf, of), a, loc_next_expr))) + e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_S<", nf, of), a, loc_next_expr))) + return e, [] + + +def jc(ir, instr, a): + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 16) + e = [] + e.append(ExprAssign(PC, ExprCond(ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), a, loc_next_expr))) + e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), a, loc_next_expr))) + return e, [] + + +def jnc(ir, instr, a): + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 16) + e = [] + e.append(ExprAssign(PC, ExprCond(ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), loc_next_expr, a))) + e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), loc_next_expr, a))) + return e, [] + + +def jge(ir, instr, a): + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = ExprLoc(loc_next, 16) + e = [] + e.append(ExprAssign(PC, ExprCond(ExprOp("CC_S>=", nf, of), a, loc_next_expr))) + e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_S>=", nf, of), a, loc_next_expr))) + return e, [] + + +def jmp(ir, instr, a): + e = [] + e.append(ExprAssign(PC, a)) + e.append(ExprAssign(ir.IRDst, a)) + return e, [] + + +def rrc_w(ir, instr, a): + e = [] + c = ExprCompose(a[1:16], cf) + e.append(ExprAssign(a, c)) + e.append(ExprAssign(cf, a[:1])) + + # micrcorruption + e += update_flag_zf(a) + # e += update_flag_nf(a) + e += reset_sr_res() + + e.append(ExprAssign(of, ExprInt(0, 1))) + return e, [] + + +def rra_w(ir, instr, a): + e = [] + c = ExprCompose(a[1:16], a[15:16]) + e.append(ExprAssign(a, c)) + # TODO: error in disasm microcorruption? + # e.append(ExprAssign(cf, a[:1])) + + # micrcorruption + e += update_flag_zf(a) + # e += update_flag_nf(a) + e += reset_sr_res() + + e.append(ExprAssign(of, ExprInt(0, 1))) + return e, [] + + +def sxt(ir, instr, a): + e = [] + c = a[:8].signExtend(16) + e.append(ExprAssign(a, c)) + + e += update_flag_zf(a) + e += update_flag_nf(a) + e += reset_sr_res() + e += update_flag_cf_inv_zf(c) + e.append(ExprAssign(of, ExprInt(0, 1))) + + return e, [] + +mnemo_func = { + "mov.b": mov_b, + "mov.w": mov_w, + "and.b": and_b, + "and.w": and_w, + "bic.b": bic_b, + "bic.w": bic_w, + "bis.w": bis_w, + "bit.w": bit_w, + "sub.w": sub_w, + "add.b": add_b, + "add.w": add_w, + "push.w": push_w, + "dadd.w": dadd_w, + "xor.w": xor_w, + "call": call, + "swpb": swpb, + "cmp.w": cmp_w, + "cmp.b": cmp_b, + "jz": jz, + "jnz": jnz, + "jl": jl, + "jc": jc, + "jnc": jnc, + "jmp": jmp, + "jge": jge, + "rrc.w": rrc_w, + "rra.w": rra_w, + "sxt": sxt, +} + + +composed_sr = ExprCompose(cf, zf, nf, gie, cpuoff, osc, scg0, scg1, of, res) + + +def ComposeExprAssign(dst, src): + e = [] + for start, arg in dst.iter_args(): + e.append(ExprAssign(arg, src[start:start+arg.size])) + return e + + +class Lifter_MSP430(Lifter): + + def __init__(self, loc_db): + Lifter.__init__(self, mn_msp430, None, loc_db) + self.pc = PC + self.sp = SP + self.IRDst = ExprId('IRDst', 16) + self.addrsize = 16 + + def mod_pc(self, instr, instr_ir, extra_ir): + pass + + def get_ir(self, instr): + args = instr.args + instr_ir, extra_ir = mnemo_func[instr.name](self, instr, *args) + self.mod_sr(instr, instr_ir, extra_ir) + + return instr_ir, extra_ir + + def mod_sr(self, instr, instr_ir, extra_ir): + for i, x in enumerate(instr_ir): + x = ExprAssign(x.dst, x.src.replace_expr({SR: composed_sr})) + instr_ir[i] = x + if x.dst != SR: + continue + xx = ComposeExprAssign(composed_sr, x.src) + instr_ir[i:i+1] = xx + for i, x in enumerate(instr_ir): + x = ExprAssign(x.dst, x.src.replace_expr( + {self.pc: ExprInt(instr.offset + instr.l, 16)})) + instr_ir[i] = x + + if extra_ir: + raise NotImplementedError('not fully functional') diff --git a/src/miasm/arch/ppc/__init__.py b/src/miasm/arch/ppc/__init__.py new file mode 100644 index 00000000..bbad893b --- /dev/null +++ b/src/miasm/arch/ppc/__init__.py @@ -0,0 +1 @@ +__all__ = ["arch", "disasm", "regs", "sem"] diff --git a/src/miasm/arch/ppc/arch.py b/src/miasm/arch/ppc/arch.py new file mode 100644 index 00000000..a1bde2a6 --- /dev/null +++ b/src/miasm/arch/ppc/arch.py @@ -0,0 +1,826 @@ +from builtins import range + +import logging +from pyparsing import * +from miasm.expression.expression import * +from miasm.core.cpu import * +from collections import defaultdict +from miasm.core.bin_stream import bin_stream +import miasm.arch.ppc.regs as regs_module +from miasm.arch.ppc.regs import * +from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html + +log = logging.getLogger("ppcdis") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.DEBUG) + +LPARENTHESIS = Suppress(Literal("(")) +RPARENTHESIS = Suppress(Literal(")")) + +def cb_deref_imm_reg(tokens): + if len(tokens) == 1: + return AstMem(tokens[0], 32) + elif len(tokens) == 2: + return AstMem(tokens[1] + tokens[0], 32) + else: + raise NotImplementedError('len(tokens) > 2') + + +deref_reg_disp = (Optional(base_expr) + LPARENTHESIS + gpregs.parser + RPARENTHESIS).setParseAction(cb_deref_imm_reg) +deref_reg = (LPARENTHESIS + gpregs.parser + RPARENTHESIS).setParseAction(cb_deref_imm_reg) + +deref = deref_reg | deref_reg_disp + + +class ppc_arg(m_arg): + def asm_ast_to_expr(self, arg, loc_db): + if isinstance(arg, AstId): + if isinstance(arg.name, ExprId): + return arg.name + if arg.name in gpregs.str: + return None + loc_key = loc_db.get_or_create_name_location(arg.name) + return ExprLoc(loc_key, 32) + if isinstance(arg, AstOp): + args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args] + if None in args: + return None + return ExprOp(arg.op, *args) + if isinstance(arg, AstInt): + return ExprInt(arg.value, 32) + if isinstance(arg, AstMem): + ptr = self.asm_ast_to_expr(arg.ptr, loc_db) + if ptr is None: + return None + return ExprMem(ptr, arg.size) + return None + + +class additional_info(object): + + def __init__(self): + self.except_on_instr = False + self.bo_bi_are_defined = False + self.bi = 0 + self.bo = 0 + + +class instruction_ppc(instruction): + + def __init__(self, *args, **kargs): + super(instruction_ppc, self).__init__(*args, **kargs) + + @staticmethod + def arg2str(e, pos = None, loc_db=None): + if isinstance(e, ExprId) or isinstance(e, ExprInt): + return str(e) + elif isinstance(e, ExprMem): + addr = e.ptr + if isinstance(addr, ExprInt) or isinstance(addr, ExprId): + out = '(%s)'%addr + elif isinstance(addr, ExprOp): + if len(addr.args) == 1: + out = '(%s)'%addr + elif len(addr.args) == 2: + out = '%s(%s)'%(addr.args[1], addr.args[0]) + else: + raise NotImplementedError('More than two args to ExprOp of address') + else: + raise NotImplementedError('Invalid memory expression') + return out + + return str(e) + + + @staticmethod + def arg2html(e, pos = None, loc_db=None): + if isinstance(e, ExprId) or isinstance(e, ExprInt) or isinstance(e, ExprLoc): + return color_expr_html(e, loc_db) + elif isinstance(e, ExprMem): + addr = e.ptr + if isinstance(addr, ExprInt) or isinstance(addr, ExprId): + out = '(%s)'%color_expr_html(addr, loc_db) + elif isinstance(addr, ExprOp): + if len(addr.args) == 1: + out = '(%s)'%color_expr_html(addr, loc_db) + elif len(addr.args) == 2: + out = '%s(%s)'%(color_expr_html(addr.args[1], loc_db), color_expr_html(addr.args[0], loc_db)) + else: + raise NotImplementedError('More than two args to ExprOp of address') + else: + raise NotImplementedError('Invalid memory expression') + return out + + return color_expr_html(e, loc_db) + + @staticmethod + def is_conditional_jump(s): + return (s[0] == 'B' and + s[1:3] in { 'DN', 'DZ', 'LT', 'GT', 'EQ', 'SO', + 'GE', 'LE', 'NE', 'NS' }) + + def dstflow(self): + name = self.name + if name[-1] == '+' or name[-1] == '-': + name = name[:-1] + return (name[0] == 'B' and + name[-2:] != 'LR' and + name[-3:] != 'LRL' and + name[-3:] != 'CTR' and + name[-4:] != 'CTRL') + + def dstflow2label(self, loc_db): + name = self.name + if name[-1] == '+' or name[-1] == '-': + name = name[:-1] + + if name[-1] == 'L': + name = name[:-1] + elif name[-2:] == 'LA': + name = name[:-2] + 'A' + + if name[-2:] != 'LR' and name[-3:] != 'CTR': + if len(self.args) == 2: + address_index = 1 + else: + address_index = 0 + e = self.args[address_index] + if not isinstance(e, ExprInt): + return + if name[-1] != 'A': + ad = (int(e) + self.offset) & 0xFFFFFFFF + else: + ad = int(e) + loc_key = loc_db.get_or_create_offset_location(ad) + s = ExprLoc(loc_key, e.size) + self.args[address_index] = s + + def breakflow(self): + return self.name[0] == 'B' + + def is_subcall(self): + name = self.name + if name[-1] == '+' or name[-1] == '-': + name = name[0:-1] + return name[0] == 'B' and (name[-1] == 'L' or name[-2:-1] == 'LA') + + def getdstflow(self, loc_db): + if 'LR' in self.name: + return [ LR ] + elif 'CTR' in self.name: + return [ CTR ] + elif len(self.args) == 2: + address_index = 1 + else: + address_index = 0 + return [ self.args[address_index] ] + + def splitflow(self): + ret = False + if self.is_conditional_jump(self.name): + if self.additional_info.bo & 0b10100 != 0b10100: + ret = True + ret = ret or self.is_subcall() + return ret + + def get_symbol_size(self, symbol, loc_db): + return 32 + + def fixDstOffset(self): + e = self.args[0] + if not isinstance(e, ExprInt): + log.debug('Dynamic destination offset %r' % e) + return + if self.name[-1] != 'A': + if self.offset is None: + raise ValueError('symbol not resolved %s' % self.l) + off = (int(e) + 0x100000000 - (self.offset + self.l)) & 0xFFFFFFFF + if int(off % 4): + raise ValueError('Offset %r must be a multiple of four' % off) + else: + off = int(e) + self.args[0] = ExprInt(off, 32) + + def get_args_expr(self): + args = [a for a in self.args] + return args + + def get_asm_offset(self, x): + return ExprInt_from(x, self.offset) + + +class mn_ppc(cls_mn): + delayslot = 0 + name = "ppc32" + regs = regs_module + bintree = {} + num = 0 + all_mn = [] + all_mn_mode = defaultdict(list) + all_mn_name = defaultdict(list) + all_mn_inst = defaultdict(list) + instruction = instruction_ppc + max_instruction_len = 4 + + @classmethod + def getpc(cls, attrib = None): + return PC + + @classmethod + def getsp(cls, attrib = None): + return R1 + + def additional_info(self): + info = additional_info() + info.bo_bi_are_defined = False + if hasattr(self, "bo"): + info.bo_bi_are_defined = True + info.bi = int(self.bi.strbits, 2) + info.bo = int(self.bo.strbits, 2) + return info + + @classmethod + def getbits(cls, bs, attrib, start, n): + if not n: + return 0 + o = 0 + if n > bs.getlen() * 8: + raise ValueError('not enough bits %r %r' % (n, len(bs.bin) * 8)) + while n: + offset = start // 8 + n_offset = cls.endian_offset(attrib, offset) + c = cls.getbytes(bs, n_offset, 1) + if not c: + raise IOError + c = ord(c) + r = 8 - start % 8 + c &= (1 << r) - 1 + l = min(r, n) + c >>= (r - l) + o <<= l + o |= c + n -= l + start += l + return o + + @classmethod + def endian_offset(cls, attrib, offset): + if attrib == "b": + return offset + else: + raise NotImplementedError("bad attrib") + + @classmethod + def check_mnemo(cls, fields): + l = sum([x.l for x in fields]) + assert l == 32, "len %r" % l + + @classmethod + def getmn(cls, name): + return name.upper() + + @classmethod + def mod_fields(cls, fields): + l = sum([x.l for x in fields]) + return fields + + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + dct['mode'] = None + return [(subcls, name, bases, dct, fields)] + + def post_dis(self): + return self + + def value(self, mode): + v = super(mn_ppc, self).value(mode) + if mode == 'b': + return [x for x in v] + else: + raise NotImplementedError("bad attrib") + + def get_symbol_size(self, symbol, loc_db, mode): + return 32 + + +class ppc_reg(reg_noarg, ppc_arg): + pass + + +class ppc_gpreg_noarg(reg_noarg): + reg_info = gpregs + parser = reg_info.parser + +class ppc_gpreg_or_0_noarg(reg_noarg): + reg_info = gpregs + parser = reg_info.parser + + def decode(self, v): + ret = super(ppc_gpreg_or_0_noarg, self).decode(v) + if ret == False: + return False + reg = self.expr + if reg == R0: + self.expr = ExprInt(0, 32) + return ret + +class ppc_gpreg(ppc_reg): + reg_info = gpregs + parser = reg_info.parser + +class ppc_gpreg_or_0(ppc_reg): + reg_info = gpregs + parser = reg_info.parser + + def decode(self, v): + ret = super(ppc_gpreg_or_0, self).decode(v) + if ret == False: + return False + reg = self.expr + if reg == R0: + self.expr = ExprInt(0, 32) + return ret + +class ppc_crfreg_noarg(reg_noarg): + reg_info = crfregs + parser = reg_info.parser + +class ppc_crfreg(ppc_reg): + reg_info = crfregs + parser = reg_info.parser + +class ppc_imm(imm_noarg, ppc_arg): + parser = base_expr + +class ppc_s14imm_branch(ppc_imm): + + def decode(self, v): + v = sign_ext(v << 2, 16, 32) + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if v & 0x3: + return False + v = v >> 2 + if sign_ext(v & self.lmask, 14, 32) != v: + return False + self.value = v & self.lmask + return True + +class ppc_s24imm_branch(ppc_imm): + + def decode(self, v): + v = sign_ext(v << 2, 26, 32) + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if v & 0x3: + return False + v = v >> 2 + if sign_ext(v & self.lmask, 24, 32) != v: + return False + self.value = v & self.lmask + return True + +class ppc_s16imm(ppc_imm): + + def decode(self, v): + v = sign_ext(v, 16, 32) + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if sign_ext(v & self.lmask, 16, 32) != v: + return False + self.value = v & self.lmask + return True + +class ppc_u16imm(ppc_imm): + + def decode(self, v): + if v & self.lmask != v: + return False + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if v & self.lmask != v: + return False + self.value = v & self.lmask + return True + +def ppc_swap_10(v): + return ((v & 0b11111) << 5) | ((v & 0b1111100000) >> 5) + +class ppc_spr(ppc_imm): + + def decode(self, v): + self.expr = ExprInt(ppc_swap_10(v), 32) + return True + + def encode(self, e): + if not isinstance(e, ExprInt): + return False + self.value = ppc_swap_10(int(e)) + return True + +class ppc_tbr(ppc_imm): + + def decode(self, v): + self.expr = ExprInt(ppc_swap_10(v), 32) + return True + + def encode(self, e): + if not isinstance(e, ExprInt): + return False + self.value = ppc_swap_10(int(e)) + return True + +class ppc_u08imm(ppc_u16imm): + pass + +class ppc_u05imm(ppc_u16imm): + pass + +class ppc_u04imm(ppc_u16imm): + pass + +class ppc_u02imm_noarg(imm_noarg): + pass + +class ppc_float(ppc_reg): + reg_info = floatregs + parser = reg_info.parser + +class ppc_vex(ppc_reg): + reg_info = vexregs + parser = reg_info.parser + +def ppc_bo_bi_to_mnemo(bo, bi, prefer_taken=True, default_taken=True): + bo2mnemo = { 0: 'DNZF', 2: 'DZF', 4: 'F', 8: 'DNZT', + 10: 'DZT', 12: 'T', 16: 'DNZ', 18: 'DZ', + 20: '' } + bi2cond = { 0b00: 'LT', 0b01: 'GT', 0b10: 'EQ', 0b11: 'SO' } + bi2ncond = { 0b00: 'GE', 0b01: 'LE', 0b10: 'NE', 0b11: 'NS' } + n = bo & 0b11110 + if not n in bo2mnemo: + raise NotImplementedError("Unknown BO field") + mnem = 'B' + bo2mnemo[n] + if mnem[-1] == 'T': + mnem = mnem[:-1] + bi2cond[bi & 0b11] + if mnem[-1] == 'F': + mnem = mnem[:-1] + bi2ncond[bi & 0b11] + + if prefer_taken != default_taken: + if prefer_taken: + mnem += '+' + else: + mnem += '-' + + return mnem + +def ppc_all_bo_bi(): + for bo in [0, 2, 4, 8, 10, 12, 16, 18, 20]: + for bi in range(4): + yield bo, bi + +class ppc_divert_conditional_branch(bs_divert): + prio=3 + def divert(self, i, candidates): + out = [] + for cls, _, bases, dct, fields in candidates: + bi_i = getfieldindexby_name(fields, 'bi')[1] + bo_i = getfieldindexby_name(fields, 'bo')[1] + + for bo, bi in ppc_all_bo_bi(): + nfields = fields[:] + nfields[bi_i] = bs(int2bin(bi, 2), fname="bi") + nfields[bo_i] = bs(int2bin(bo, 5), fname="bo") + ndct = dict(dct) + ndct['name'] = ppc_bo_bi_to_mnemo(bo, bi) + out.append((cls, ndct['name'], bases, ndct, nfields)) + + nfields = fields[:] + nfields[bi_i] = bs(int2bin(bi, 2), fname="bi") + nfields[bo_i] = bs(int2bin(bo+1, 5), fname="bo") + ndct = dict(dct) + ndct['name'] = ppc_bo_bi_to_mnemo(bo, bi) + out.append((cls, ndct['name'], bases, ndct, nfields)) + + return out + +class ppc_deref32(ppc_arg): + parser = deref + + def decode(self, v): + v = sign_ext(v, 16, 32) + e = self.parent.ra.expr + ExprInt(v, 32) + self.expr = ExprMem(e, size=32) + return True + + def encode(self): + e = self.expr + if not isinstance(e, ExprMem): + return False + addr = e.ptr + if isinstance(addr, ExprId) or isinstance(addr, ExprInt): + addr = addr + ExprInt(0, 32) + elif not isinstance(addr, ExprOp): + return False + if addr.op != '+': + return False + if len(addr.args) != 2: + return False + reg, disp = addr.args[0], addr.args[1] + v = int(disp) + if sign_ext(v & 0xFFFF, 16, 32) != v: + return False + v &= 0xFFFF + self.value = v + self.parent.ra.expr = reg + return True + + +def ppcop(name, fields, args=None, alias=False): + dct = {"fields": fields} + dct["alias"] = alias + if args is not None: + dct['args'] = args + type(name, (mn_ppc,), dct) + +rd = bs(l=5, cls=(ppc_gpreg,)) +ra = bs(l=5, cls=(ppc_gpreg,)) +ra_or_0 = bs(l=5, cls=(ppc_gpreg_or_0,)) +rb = bs(l=5, cls=(ppc_gpreg,)) +rs = bs(l=5, cls=(ppc_gpreg,)) +crfd = bs(l=3, cls=(ppc_crfreg,)) +crfs = bs(l=3, cls=(ppc_crfreg,)) +sh = bs(l=5, cls=(ppc_u05imm,)) +mb = bs(l=5, cls=(ppc_u05imm,)) +me = bs(l=5, cls=(ppc_u05imm,)) +nb = bs(l=5, cls=(ppc_u05imm,)) +crm = bs(l=8, cls=(ppc_u08imm,)) +sr = bs(l=4, cls=(ppc_u04imm,)) +spr = bs(l=10, cls=(ppc_spr,)) +tbr = bs(l=10, cls=(ppc_tbr,)) +u05imm = bs(l=5, cls=(ppc_u05imm,)) + +s24imm_branch = bs(l=24, cls=(ppc_s24imm_branch,), fname="imm") +s14imm_branch = bs(l=14, cls=(ppc_s14imm_branch,), fname="imm") +s16imm = bs(l=16, cls=(ppc_s16imm,), fname="imm") +u16imm = bs(l=16, cls=(ppc_u16imm,), fname="imm") +u08imm = bs(l=5, cls=(ppc_u08imm,), fname="imm") +u02imm_noarg = bs(l=2, cls=(ppc_u02imm_noarg,), fname="imm") + +ra_noarg = bs(l=5, cls=(ppc_gpreg_noarg,), fname="ra") +ra_or_0_noarg = bs(l=5, cls=(ppc_gpreg_or_0_noarg,), fname="ra") +dregimm = bs(l=16, cls=(ppc_deref32,)) + +rc_mod = bs_mod_name(l=1, mn_mod=['', '.'], fname='rc') + +frd = bs(l=5, cls=(ppc_float,)) +frb = bs(l=5, cls=(ppc_float,)) +frs = bs(l=5, cls=(ppc_float,)) +fm = bs(l=8, cls=(ppc_u08imm,)) + +va = bs(l=5, cls=(ppc_vex,)) +vb = bs(l=5, cls=(ppc_vex,)) +vd = bs(l=5, cls=(ppc_vex,)) +rb_noarg = bs(l=5, cls=(ppc_gpreg_noarg,), fname="rb") + +arith1_name = {"MULLI": 0b000111, "SUBFIC": 0b001000, "ADDIC": 0b001100, + "ADDIC.": 0b001101 } + +logic2_name = {"ORI": 0b011000, "XORI": 0b011010, "ANDI.": 0b011100 } +slogic2_name = {"ORIS": 0b011001, "XORIS": 0b011011, "ANDIS.": 0b011101 } + +arith3_name = {"SUBFC": 0b0000001000, "ADDC": 0b0000001010, + "MULHWU": 0b0000001011, "SUBF": 0b0000101000, + "MULHW": 0b0001001011, "SUBFE": 0b0010001000, + "ADDE": 0b0010001010, "MULLW": 0b0011101011, + "ADD": 0b0100001010, "DIVWU": 0b0111001011, + "DIVW": 0b0111101011, "SUBFCO": 0b1000001000, + "ADDCO": 0b1000001010, "SUBFO": 0b1000101000, + "SUBFEO": 0b1010001000, "ADDEO": 0b1010001010, + "MULLWO": 0b1011101011, "ADDO": 0b1100001010, + "DIVWUO": 0b1111001011, "DIVWO": 0b1111101011 } + +xor_name = { "EQV": 0b0100011100, "XOR": 0b0100111100 } + +arith4_name = {"NEG": 0b0001101000, "SUBFZE": 0b0011001000, + "ADDZE": 0b0011001010, "SUBFME": 0b0011101000, + "ADDME": 0b0011101010, "NEGO": 0b1001101000, + "SUBFZEO": 0b1011001000, "ADDZEO": 0b1011001010, + "SUBFMEO": 0b1011101000, "ADDMEO": 0b1011101010 } + +arith5_name = {"CNTLZW": 0b00000, "EXTSH": 0b11100, "EXTSB": 0b11101 } + +crlogic_name = {"CRAND": 0b1000, "CRANDC": 0b0100, "CREQV": 0b1001, + "CRNAND": 0b0111, "CRNOR": 0b0001, "CROR": 0b1110, + "CRORC": 0b1101, "CRXOR": 0b0110 } + +rotins_name = {"RLWIMI": 0b010100, "RLWINM": 0b010101 } + +bs_arith1_name = bs_name(l=6, name=arith1_name) + +load1_name = {"LWARX": 0b0000010100, "LWZX": 0b0000010111, + "LBZX": 0b0001010111, "LHZX": 0b0100010111, + "ECIWX": 0b0100110110, "LHAX": 0b0101010111, + "LSWX": 0b1000010101, "LWBRX": 0b1000010110, + "LHBRX": 0b1100010110 } + +load1_name_u = {"LWZUX": 0b0000110111, "LBZUX": 0b0001110111, + "LHZUX": 0b0100110111, "LHAUX": 0b0101110111 } + +load2_name = {"LWZ": 0b0000, "LBZ": 0b0010, "LHZ": 0b1000, "LHA": 0b1010, + "LMW": 0b1110 } + +load2_name_u = {"LWZU": 0b0001, "LBZU": 0b0011, "LHZU": 0b1001, "LHAU": 0b1011} + +store1_name = { "STWCX.": 0b00100101101, "STWX": 0b00100101110, + "STBX": 0b00110101110, "STHX": 0b01100101110, + "ECOWX": 0b01101101100, "STSWX": 0b10100101010, + "STWBRX": 0b10100101100, "STHBRX": 0b11100101100 } +store1_name_u = { "STWUX": 0b00101101110, "STBUX": 0b00111101110, + "STHUX": 0b01101101110 } + +store2_name = { "STW": 0b0100, "STB": 0b0110, "STH": 0b1100, "STMW": 0b1111 } +store2_name_u = { "STWU": 0b0101, "STBU": 0b0111, "STHU": 0b1101 } + +logic1_name = {"SLW": 0b0000011000, "AND": 0b0000011100, + "ANDC": 0b0000111100, "NOR": 0b0001111100, + "ORC": 0b0110011100, "OR": 0b0110111100, + "NAND": 0b0111011100, "SRW": 0b1000011000, + "SRAW": 0b1100011000 } + +dcb_name = {"DCBST": 0b00001, "DCBF": 0b00010, + "DCBTST": 0b00111, "DCBT": 0b01000, + "DCBI": 0b01110, "DCBA": 0b10111, + "ICBI": 0b11110, "DCBZ": 0b11111 } + + +load1_name_float = {"LFS": 0b110000, "LFD": 0b110010 } +load1_name_float_u = {"LFSU": 0b110001, "LFDU": 0b110011 } +store1_name_float = {"STFS": 0b110100, "STFD": 0b110110 } +store1_name_float_u = {"STFSU": 0b110101, "STFDU": 0b110111 } + +load1_name_vex = {"LVEBX": 0b0000000111, "LVEHX": 0b0000100111, + "LVEWX": 0b0001000111, "LVSL": 0b0000000110, + "LVSR": 0b0000100110, "LVX": 0b0001100111, + "LVXL": 0b0101100111 } + +class bs_mod_name_prio4(bs_mod_name): + prio = 4 + +class bs_mod_name_prio5(bs_mod_name): + prio = 5 + +class bs_mod_name_prio6(bs_mod_name): + prio = 6 + +branch_to_reg = bs_mod_name_prio4(l=1, mn_mod=['LR', 'CTR'], fname='btoreg') +branch_lk = bs_mod_name_prio5(l=1, mn_mod=['', 'L'], fname='lk') +branch_aa = bs_mod_name_prio6(l=1, mn_mod=['', 'A'], fname='aa') + +ppcop("arith1", [bs_arith1_name, rd, ra, s16imm]) +ppcop("ADDIS", [bs('001111'), rd, ra_or_0, u16imm]) +ppcop("ADDI", [bs('001110'), rd, ra_or_0, s16imm]) + +ppcop("logic2", [bs_name(l=6, name=logic2_name), rs, ra, u16imm], + [ra, rs, u16imm]) +ppcop("slogic2", [bs_name(l=6, name=slogic2_name), rs, ra, u16imm], + [ra, rs, u16imm]) + +ppcop("store1", [bs('011111'), rs, ra_or_0, rb, + bs_name(l=11, name=store1_name)]) +ppcop("store1u", [bs('011111'), rs, ra, rb, + bs_name(l=11, name=store1_name_u)]) + +ppcop("store2", [bs('10'), bs_name(l=4, name=store2_name), rs, + ra_noarg, dregimm]) +ppcop("store2u", [bs('10'), bs_name(l=4, name=store2_name_u), rs, + ra_or_0_noarg, dregimm]) + +ppcop("arith3", [bs('011111'), rd, ra, rb, bs_name(l=10, name=arith3_name), + rc_mod]) + +ppcop("xor", [bs('011111'), rs, ra, rb, bs_name(l=10, name=xor_name), + rc_mod], [ra, rs, rb]) + +ppcop("arith4", [bs('011111'), rd, ra, bs('00000'), + bs_name(l=10, name=arith4_name), rc_mod]) + +ppcop("arith5", [bs('011111'), rs, ra, bs('00000'), + bs_name(l=5, name=arith5_name), + bs('11010'), rc_mod], [ra, rs]) + +ppcop("load1", [bs('011111'), rd, ra_or_0, rb, + bs_name(l=10, name=load1_name), bs('0')]) +ppcop("load1u", [bs('011111'), rd, ra, rb, + bs_name(l=10, name=load1_name_u), bs('0')]) +ppcop("load2", [bs('10'), bs_name(l=4, name=load2_name), + rd, ra_or_0_noarg, dregimm]) +ppcop("load2u", [bs('10'), bs_name(l=4, name=load2_name_u), + rd, ra_noarg, dregimm]) + +ppcop("logic1", [bs('011111'), rs, ra, rb, bs_name(l=10, name=logic1_name), + rc_mod], + [ra, rs, rb]) + +ppcop("TWI", [bs('000011'), u05imm, ra, s16imm]) +ppcop("TW", [bs('011111'), u05imm, ra, rb, bs('00000001000')]) + +ppcop("CMPW", [bs('011111'), crfd, bs('00'), ra, rb, bs('00000000000')]) +ppcop("CMPLW", [bs('011111'), crfd, bs('00'), ra, rb, bs('00001000000')]) +ppcop("CMPLWI", [bs('001010'), crfd, bs('00'), ra, u16imm]) +ppcop("CMPWI", [bs('001011'), crfd, bs('00'), ra, s16imm]) + +ppcop("BC", [bs('010000'), bs(l=5, cls=(ppc_u05imm,), fname='bo'), + crfs, + ppc_divert_conditional_branch(l=2, fname='bi'), + s14imm_branch, branch_aa, branch_lk]) +ppcop("SC", [bs('01000100000000000000000000000010')]) +ppcop("B", [bs('010010'), s24imm_branch, branch_aa, branch_lk]) +ppcop("MCRF", [bs('010011'), crfd, bs('00'), crfs, bs('000000000000000000')]) + +ppcop("BCXXX", [bs('010011'), bs(l=5, cls=(ppc_u05imm,), fname='bo'), + crfs, + ppc_divert_conditional_branch(l=2, fname='bi'), + bs('00000'), branch_to_reg, + bs('000010000'), branch_lk]) + +ppcop("crlogic", [bs('010011'), + bs(l=5, cls=(ppc_u05imm,), fname='crbd'), + bs(l=5, cls=(ppc_u05imm,), fname='crba'), + bs(l=5, cls=(ppc_u05imm,), fname='crbb'), + bs('0'), + bs_name(l=4, name=crlogic_name), + bs('000010')]) + +ppcop("rotins", [bs_name(l=6, name=rotins_name), + rs, ra, sh, mb, me, rc_mod], + [ ra, rs, sh, mb, me ]) +ppcop("RLWNM", [bs('010111'), rs, ra, rb, mb, me, rc_mod], + [ ra, rs, rb, mb, me ]) +ppcop("MFXXX", [bs('011111'), rd, bs('0000000000'), + bs('000'), + bs_name(l=1, name={'MFCR':0, 'MFMSR':1}), + bs('0100110')]) + +ppcop("dcb", [bs('01111100000'), ra, rb, bs_name(l=5, name=dcb_name), + bs('101100')]) + +ppcop("MTCRF", [bs('011111'), rs, bs('0'), crm, bs('000100100000')], [crm, rs]) +ppcop("MTMSR", [bs('011111'), rs, bs('0000000000'), bs('00100100100')]) +ppcop("MTSR", [bs('011111'), rs, bs('0'), sr, bs('0000000110100100')], [sr, rs]) +ppcop("MTSRIN", [bs('011111'), rs, bs('00000'), rb, bs('00111100100')]) + +ppcop("TLBIE", [bs('011111'), bs('0000000000'), rb, bs('01001100100')]) +ppcop("MFSPR", [bs('011111'), rd, spr, bs('01010100110')]) +ppcop("TLBIA", [bs('01111100000000000000001011100100')]) +ppcop("MFTB", [bs('011111'), rd, tbr, bs('01011100110')]) +ppcop("RFI", [bs('01001100000000000000000001100100')]) +ppcop("ISYNC", [bs('01001100000000000000000100101100')]) +ppcop("MTSPR", [bs('011111'), rs, spr, bs('01110100110')], [spr, rs]) +ppcop("MCRXR", [bs('011111'), crfd, bs('000000000000'), + bs('10000000000')]) +ppcop("TLBSYNC", [bs('01111100000000000000010001101100')]) +ppcop("MFSR", [bs('011111'), rd, bs('0'), sr, bs('00000'), bs('10010100110')]) +ppcop("LSWI", [bs('011111'), rd, ra, nb, bs('10010101010')]) +ppcop("STSWI", [bs('011111'), rs, ra, nb, bs('10110101010')]) +ppcop("SYNC", [bs('011111'), bs('000000000000000'), bs('10010101100')]) +ppcop("MFSRIN", [bs('011111'), rd, bs('00000'), rb, bs('10100100110')]) + +ppcop("SRAWI", [bs('011111'), rs, ra, sh, bs('1100111000'), rc_mod], + [ra, rs, sh]) + +ppcop("EIEIO", [bs('011111'), bs('000000000000000'), bs('11010101100')]) + +ppcop("load1f", [bs_name(l=6, name=load1_name_float), frd, ra_noarg, dregimm]) +ppcop("load1fu", [bs_name(l=6, name=load1_name_float_u), frd, ra_noarg, dregimm]) +ppcop("store1f", [bs_name(l=6, name=store1_name_float), frd, ra_noarg, dregimm]) +ppcop("store1fu", [bs_name(l=6, name=store1_name_float_u), frd, ra_noarg, dregimm]) +ppcop("MTFSF", [bs('111111'), bs('0'), fm, bs('0'), frb, bs('10110001110')]) +ppcop("MTFSF.", [bs('111111'), bs('0'), fm, bs('0'), frb, bs('10110001111')]) +ppcop("MFFS", [bs('111111'), frd, bs('00000000001001000111'), bs('0')]) +ppcop("MFFS.", [bs('111111'), frd, bs('00000000001001000111'), bs('1')]) + +ppcop("load1vex", [bs('011111'), vd, ra, rb, bs_name(l=10, name=load1_name_vex), bs('0')]) +ppcop("mtvscr", [bs('0001000000000000'), vb, bs('11001000100')]) diff --git a/src/miasm/arch/ppc/disasm.py b/src/miasm/arch/ppc/disasm.py new file mode 100644 index 00000000..b91d96bf --- /dev/null +++ b/src/miasm/arch/ppc/disasm.py @@ -0,0 +1,7 @@ +from miasm.arch.ppc.arch import mn_ppc +from miasm.core.asmblock import disasmEngine + +class dis_ppc32b(disasmEngine): + def __init__(self, bs=None, **kwargs): + super(dis_ppc32b, self).__init__(mn_ppc, None, bs, **kwargs) + self.attrib = 'b' diff --git a/src/miasm/arch/ppc/jit.py b/src/miasm/arch/ppc/jit.py new file mode 100644 index 00000000..dcaff82c --- /dev/null +++ b/src/miasm/arch/ppc/jit.py @@ -0,0 +1,70 @@ +from builtins import range +from miasm.jitter.jitload import Jitter, named_arguments +from miasm.arch.ppc.sem import Lifter_PPC32b +import struct + +import logging + +log = logging.getLogger('jit_ppc') +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) + +class jitter_ppc32b(Jitter): + max_reg_arg = 8 + + def __init__(self, loc_db, *args, **kwargs): + super(jitter_ppc32b, self).__init__(Lifter_PPC32b(loc_db), + *args, **kwargs) + self.vm.set_big_endian() + + def push_uint32_t(self, v): + self.cpu.R1 -= 4 + self.vm.set_mem(self.cpu.R1, struct.pack(">I", v)) + + def pop_uint32_t(self): + x = struct.unpack(">I", self.vm.get_mem(self.cpu.R1, 4))[0] + self.cpu.R1 += 4 + return x + + def get_stack_arg(self, n): + x = struct.unpack(">I", self.vm.get_mem(self.cpu.R1 + 8 + 4 * n, 4))[0] + return x + + @named_arguments + def func_args_systemv(self, n_args): + args = [self.get_arg_n_systemv(i) for i in range(n_args)] + ret_ad = self.cpu.LR + return ret_ad, args + + def func_ret_systemv(self, ret_addr, ret_value1=None, ret_value2=None): + self.pc = self.cpu.PC = ret_addr + if ret_value1 is not None: + self.cpu.R3 = ret_value1 + if ret_value2 is not None: + self.cpu.R4 = ret_value2 + return True + + def func_prepare_systemv(self, ret_addr, *args): + for index in range(min(len(args), self.max_reg_arg)): + setattr(self.cpu, 'R%d' % (index + 3), args[index]) + for index in range(len(args) - 1, self.max_reg_arg - 1, -1): + self.push_uint32_t(args[index]) + + # reserve room for LR save word and backchain + self.cpu.R1 -= 8 + + self.cpu.LR = ret_addr + + def get_arg_n_systemv(self, index): + if index < self.max_reg_arg: + arg = getattr(self.cpu, 'R%d' % (index + 3)) + else: + arg = self.get_stack_arg(index - self.max_reg_arg) + return arg + + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.PC = self.pc diff --git a/src/miasm/arch/ppc/lifter_model_call.py b/src/miasm/arch/ppc/lifter_model_call.py new file mode 100644 index 00000000..06691190 --- /dev/null +++ b/src/miasm/arch/ppc/lifter_model_call.py @@ -0,0 +1,87 @@ +from miasm.expression.expression import ExprAssign, ExprOp +from miasm.ir.ir import AssignBlock +from miasm.ir.analysis import LifterModelCall +from miasm.arch.ppc.sem import Lifter_PPC32b + + +class LifterModelCallPpc32b(Lifter_PPC32b, LifterModelCall): + + def __init__(self, loc_db, *args): + super(LifterModelCallPpc32b, self).__init__(loc_db, *args) + self.ret_reg = self.arch.regs.R3 + + # for test XXX TODO + def set_dead_regs(self, irblock): + pass + + def get_out_regs(self, _): + return set([self.ret_reg, self.sp]) + + def add_unused_regs(self): + leaves = [self.blocks[label] for label in self.g.leafs()] + for irblock in leaves: + self.set_dead_regs(irblock) + + def call_effects(self, ad, instr): + call_assignblks = AssignBlock( + [ + ExprAssign( + self.ret_reg, + ExprOp( + 'call_func_ret', + ad, + self.sp, + self.arch.regs.R3, + self.arch.regs.R4, + self.arch.regs.R5, + ) + ), + ExprAssign(self.sp, ExprOp('call_func_stack', ad, self.sp)), + ], + instr + ) + return [call_assignblks], [] + + def add_instr_to_current_state(self, instr, block, assignments, ir_blocks_all, gen_pc_updt): + """ + Add the IR effects of an instruction to the current state. + + @instr: native instruction + @block: native block source + @assignments: list of current AssignBlocks + @ir_blocks_all: list of additional effects + @gen_pc_updt: insert PC update effects between instructions + """ + if instr.is_subcall(): + call_assignblks, extra_irblocks = self.call_effects( + instr.getdstflow(None)[0], + instr + ) + assignments += call_assignblks + ir_blocks_all += extra_irblocks + return True + + if gen_pc_updt is not False: + self.gen_pc_update(assignments, instr) + + assignblk, ir_blocks_extra = self.instr2ir(instr) + assignments.append(assignblk) + ir_blocks_all += ir_blocks_extra + if ir_blocks_extra: + return True + return False + + def sizeof_char(self): + return 8 + + def sizeof_short(self): + return 16 + + def sizeof_int(self): + return 32 + + def sizeof_long(self): + return 32 + + def sizeof_pointer(self): + return 32 diff --git a/src/miasm/arch/ppc/regs.py b/src/miasm/arch/ppc/regs.py new file mode 100644 index 00000000..00781d6a --- /dev/null +++ b/src/miasm/arch/ppc/regs.py @@ -0,0 +1,77 @@ + +from builtins import range +from miasm.expression.expression import * +from miasm.core.cpu import gen_reg, gen_regs + +exception_flags = ExprId('exception_flags', 32) +spr_access = ExprId('spr_access', 32) + +reserve = ExprId('reserve', 1) +reserve_address = ExprId('reserve_address', 32) + +SPR_ACCESS_IS_WRITE = 0x80000000 +SPR_ACCESS_SPR_MASK = 0x000003FF +SPR_ACCESS_SPR_OFF = 0 +SPR_ACCESS_GPR_MASK = 0x0001F000 +SPR_ACCESS_GPR_OFF = 12 + +gpregs_str = ["R%d" % i for i in range(32)] +gpregs_expr, gpregs_init, gpregs = gen_regs(gpregs_str, globals(), 32) + +crfregs_str = ["CR%d" % i for i in range(8)] +crfregs_expr, crfregs_init, crfregs = gen_regs(crfregs_str, globals(), 4) + +crfbitregs_str = ["CR%d_%s" % (i, flag) for i in range(8) + for flag in ['LT', 'GT', 'EQ', 'SO'] ] +crfbitregs_expr, crfbitregs_init, crfbitregs = gen_regs(crfbitregs_str, + globals(), 1) + +xerbitregs_str = ["XER_%s" % field for field in ['SO', 'OV', 'CA'] ] +xerbitregs_expr, xerbitregs_init, xerbitregs = gen_regs(xerbitregs_str, + globals(), 1) + +xerbcreg_str = ["XER_BC"] +xerbcreg_expr, xerbcreg_init, xerbcreg = gen_regs(xerbcreg_str, + globals(), 7) + + +otherregs_str = ["PC", "CTR", "LR", "FPSCR", "VRSAVE", "VSCR" ] +otherregs_expr, otherregs_init, otherregs = gen_regs(otherregs_str, + globals(), 32) + +superregs_str = (["SPRG%d" % i for i in range(4)] + + ["SRR%d" % i for i in range(2)] + + ["DAR", "DSISR", "MSR", "PIR", "PVR", + "DEC", "TBL", "TBU"]) +superregs_expr, superregs_init, superregs = gen_regs(superregs_str, + globals(), 32) + +mmuregs_str = (["SR%d" % i for i in range(16)] + + ["IBAT%dU" % i for i in range(4)] + + ["IBAT%dL" % i for i in range(4)] + + ["DBAT%dU" % i for i in range(4)] + + ["DBAT%dL" % i for i in range(4)] + + ["SDR1"]) +mmuregs_expr, mmuregs_init, mmuregs = gen_regs(mmuregs_str, + globals(), 32) + +floatregs_str = (["FPR%d" % i for i in range(32)]) +floatregs_expr, floatregs_init, floatregs = gen_regs(floatregs_str, + globals(), 64) + +vexregs_str = (["VR%d" % i for i in range(32)]) +vexregs_expr, vexregs_init, vexregs = gen_regs(vexregs_str, + globals(), 128) + +regs_flt_expr = [] + +all_regs_ids = (gpregs_expr + crfbitregs_expr + xerbitregs_expr + + xerbcreg_expr + otherregs_expr + superregs_expr + mmuregs_expr + floatregs_expr + vexregs_expr + + [ exception_flags, spr_access, reserve, reserve_address ]) +all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) +all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids] +all_regs_ids_no_alias = all_regs_ids[:] + +regs_init = {} +for i, r in enumerate(all_regs_ids): + regs_init[r] = all_regs_ids_init[i] diff --git a/src/miasm/arch/ppc/sem.py b/src/miasm/arch/ppc/sem.py new file mode 100644 index 00000000..7fbf61e6 --- /dev/null +++ b/src/miasm/arch/ppc/sem.py @@ -0,0 +1,981 @@ +from __future__ import print_function +from builtins import range + +import miasm.expression.expression as expr +from miasm.ir.ir import AssignBlock, Lifter, IRBlock +from miasm.arch.ppc.arch import mn_ppc +from miasm.arch.ppc.regs import * +from miasm.core.sembuilder import SemBuilder +from miasm.jitter.csts import * + +spr_dict = { + 8: LR, 9: CTR, 18: DSISR, 19: DAR, + 22: DEC, 25: SDR1, 26: SRR0, 27: SRR1, + 272: SPRG0, 273: SPRG0, 274: SPRG1, 275: SPRG2, 276: SPRG3, + 284: TBL, 285: TBU, 287: PVR, + 528: IBAT0U, 529: IBAT0L, 530: IBAT1U, 531: IBAT1L, 532: IBAT2U, 533: IBAT2L, 534: IBAT3U, 535: IBAT3L, + 536: DBAT0U, 537: DBAT0L, 538: DBAT1U, 539: DBAT1L, 540: DBAT2U, 541: DBAT2L, 542: DBAT3U, 543: DBAT3L, + 1023: PIR +} + +sr_dict = { + 0: SR0, 1: SR1, 2: SR2, 3: SR3, + 4: SR4, 5: SR5, 6: SR6, 7: SR7, + 8: SR8, 9: SR9, 10: SR10, 11: SR11, + 12: SR12, 13: SR13, 14: SR14, 15: SR15 +} + +float_dict = { + 0: FPR0, 1: FPR1, 2: FPR2, 3: FPR3, 4: FPR4, 5: FPR5, 6: FPR6, 7: FPR7, 8: FPR8, + 9: FPR9, 10: FPR10, 11: FPR11, 12: FPR12, 13: FPR13, 14: FPR14, 15: FPR15, 16: FPR16, + 17: FPR17, 18: FPR18, 19: FPR19, 20: FPR20, 21: FPR21, 22: FPR22, 23: FPR23, 24: FPR24, + 25: FPR25, 26: FPR26, 27: FPR27, 28: FPR28, 29: FPR29, 30: FPR30, 31: FPR31 +} + +vex_dict = { + 0: VR0, 1: VR1, 2: VR2, 3: VR3, 4: VR4, 5: VR5, 6: VR6, 7: VR7, 8: VR8, + 9: VR9, 10: VR10, 11: VR11, 12: VR12, 13: VR13, 14: VR14, 15: VR15, 16: VR16, + 17: VR17, 18: VR18, 19: VR19, 20: VR20, 21: VR21, 22: VR22, 23: VR23, 24: VR24, + 25: VR25, 26: VR26, 27: VR27, 28: VR28, 29: VR29, 30: VR30, 31: VR31, +} + +crf_dict = dict((ExprId("CR%d" % i, 4), + dict( (bit, ExprId("CR%d_%s" % (i, bit), 1)) + for bit in ['LT', 'GT', 'EQ', 'SO' ] )) + for i in range(8) ) + +ctx = { + 'crf_dict': crf_dict, + 'spr_dict': spr_dict, + 'sr_dict': sr_dict, + 'float_dict': float_dict, + 'vex_dict': vex_dict, + 'expr': expr, +} + +ctx.update(all_regs_ids_byname) +sbuild = SemBuilder(ctx) + +def mn_compute_flags(rvalue, overflow_expr=None): + ret = [] + ret.append(ExprAssign(CR0_LT, rvalue.msb())) + ret.append(ExprAssign(CR0_GT, (ExprCond(rvalue, ExprInt(1, 1), + ExprInt(0, 1)) & ~rvalue.msb()))) + ret.append(ExprAssign(CR0_EQ, ExprCond(rvalue, ExprInt(0, 1), + ExprInt(1, 1)))) + if overflow_expr != None: + ret.append(ExprAssign(CR0_SO, XER_SO | overflow_expr)) + else: + ret.append(ExprAssign(CR0_SO, XER_SO)) + + return ret + +def mn_do_add(ir, instr, arg1, arg2, arg3): + assert instr.name[0:3] == 'ADD' + + flags_update = [] + + has_dot = False + has_c = False + has_e = False + has_o = False + + for l in instr.name[3:]: + if l == '.': + has_dot = True + elif l == 'C': + has_c = True + elif l == 'E': + has_e = True + elif l == 'O': + has_o = True + elif l == 'I' or l == 'M' or l == 'S' or l == 'Z': + pass # Taken care of earlier + else: + assert False + + rvalue = arg2 + arg3 + + if has_e: + rvalue = rvalue + XER_CA.zeroExtend(32) + + over_expr = None + if has_o: + msb1 = arg2.msb() + msb2 = arg3.msb() + msba = rvalue.msb() + over_expr = ~(msb1 ^ msb2) & (msb1 ^ msba) + flags_update.append(ExprAssign(XER_OV, over_expr)) + flags_update.append(ExprAssign(XER_SO, XER_SO | over_expr)) + + if has_dot: + flags_update += mn_compute_flags(rvalue, over_expr) + + if has_c or has_e: + carry_expr = (((arg2 ^ arg3) ^ rvalue) ^ + ((arg2 ^ rvalue) & (~(arg2 ^ arg3)))).msb() + flags_update.append(ExprAssign(XER_CA, carry_expr)) + + return ([ ExprAssign(arg1, rvalue) ] + flags_update), [] + +def mn_do_and(ir, instr, ra, rs, arg2): + if len(instr.name) > 3 and instr.name[3] == 'C': + oarg = ~arg2 + else: + oarg = arg2 + + rvalue = rs & oarg + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def mn_do_cntlzw(ir, instr, ra, rs): + ret = [ ExprAssign(ra, ExprOp('cntleadzeros', rs)) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def crbit_to_reg(bit): + bit = int(bit) + crid = bit // 4 + bitname = [ 'LT', 'GT', 'EQ', 'SO' ][bit % 4] + return all_regs_ids_byname["CR%d_%s" % (crid, bitname)] + +def mn_do_cr(ir, instr, crd, cra, crb): + a = crbit_to_reg(cra) + b = crbit_to_reg(crb) + d = crbit_to_reg(crd) + + op = instr.name[2:] + + if op == 'AND': + r = a & b + elif op == 'ANDC': + r = a & ~b + elif op == 'EQV': + r = ~(a ^ b) + elif op == 'NAND': + r = ~(a & b) + elif op == 'NOR': + r = ~(a | b) + elif op == 'OR': + r = a | b + elif op == 'ORC': + r = a | ~b + elif op == 'XOR': + r = a ^ b + else: + raise RuntimeError("Unknown operation on CR") + return [ ExprAssign(d, r) ], [] + +def mn_do_div(ir, instr, rd, ra, rb): + assert instr.name[0:4] == 'DIVW' + + flags_update = [] + + has_dot = False + has_c = False + has_o = False + has_u = False + + for l in instr.name[3:]: + if l == '.': + has_dot = True + elif l == 'C': + has_c = True + elif l == 'O': + has_o = True + elif l == 'U': + has_u = True + elif l == 'W': + pass + else: + assert False + + if has_u: + op = 'udiv' + else: + op = 'sdiv' + + rvalue = ExprOp(op, ra, rb) + + over_expr = None + if has_o: + over_expr = ExprCond(rb, ExprInt(0, 1), ExprInt(1, 1)) + if not has_u: + over_expr = over_expr | (ExprCond(ra ^ 0x80000000, ExprInt(0, 1), + ExprInt(1, 1)) & + ExprCond(rb ^ 0xFFFFFFFF, ExprInt(0, 1), + ExprInt(1, 1))) + flags_update.append(ExprAssign(XER_OV, over_expr)) + flags_update.append(ExprAssign(XER_SO, XER_SO | over_expr)) + + if has_dot: + flags_update += mn_compute_flags(rvalue, over_expr) + + return ([ ExprAssign(rd, rvalue) ] + flags_update), [] + + +def mn_do_eqv(ir, instr, ra, rs, rb): + rvalue = ~(rs ^ rb) + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def mn_do_exts(ir, instr, ra, rs): + if instr.name[4] == 'B': + size = 8 + elif instr.name[4] == 'H': + size = 16 + else: + assert False + + rvalue = rs[0:size].signExtend(32) + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def byte_swap(expr): + nbytes = expr.size // 8 + lbytes = [ expr[i*8:i*8+8] for i in range(nbytes - 1, -1, -1) ] + return ExprCompose(*lbytes) + +def mn_do_load(ir, instr, arg1, arg2, arg3=None): + assert instr.name[0] == 'L' + + ret = [] + + if instr.name[1] == 'M': + return mn_do_lmw(ir, instr, arg1, arg2) + elif instr.name[1] == 'S': + raise RuntimeError("LSWI, and LSWX need implementing") + elif instr.name[1] == 'F': + print("Warning, instruction %s implemented as NOP" % instr) + return [], [] + elif instr.name[1] == 'V': + print("Warning, instruction %s implemented as NOP" % instr) + return [], [] + + size = {'B': 8, 'H': 16, 'W': 32}[instr.name[1]] + + has_a = False + has_b = False + has_u = False + is_lwarx = False + + for l in instr.name[2:]: + if l == 'A': + has_a = True + elif l == 'B': + has_b = True + elif l == 'U': + has_u = True + elif l == 'X' or l == 'Z': + pass # Taken care of earlier + elif l == 'R' and not has_b: + is_lwarx = True + else: + assert False + + if arg3 is None: + assert isinstance(arg2, ExprMem) + + address = arg2.ptr + else: + address = arg2 + arg3 + + src = ExprMem(address, size) + + if has_b: + src = byte_swap(src) + + if has_a: + src = src.signExtend(32) + else: + src = src.zeroExtend(32) + + ret.append(ExprAssign(arg1, src)) + if has_u: + if arg3 is None: + ret.append(ExprAssign(arg2.ptr.args[0], address)) + else: + ret.append(ExprAssign(arg2, address)) + + if is_lwarx: + ret.append(ExprAssign(reserve, ExprInt(1, 1))) + ret.append(ExprAssign(reserve_address, address)) # XXX should be the PA + + return ret, [] + +def mn_do_lmw(ir, instr, rd, src): + ret = [] + address = src.ptr + ri = int(rd.name[1:],10) + i = 0 + while ri <= 31: + ret.append(ExprAssign(all_regs_ids_byname["R%d" % ri], + ExprMem(address + ExprInt(i, 32), 32))) + ri += 1 + i += 4 + + return ret, [] + +def mn_do_lswi(ir, instr, rd, ra, nb): + if nb == 0: + nb = 32 + i = 32 + raise RuntimeError("%r not implemented" % instr) + +def mn_do_lswx(ir, instr, rd, ra, nb): + raise RuntimeError("%r not implemented" % instr) + +def mn_do_mcrf(ir, instr, crfd, crfs): + ret = [] + + for bit in [ 'LT', 'GT', 'EQ', 'SO' ]: + d = all_regs_ids_byname["%s_%s" % (crfd, bit)] + s = all_regs_ids_byname["%s_%s" % (crfs, bit)] + ret.append(ExprAssign(d, s)) + + return ret, [] + +def mn_do_mcrxr(ir, instr, crfd): + ret = [] + + for (bit, val) in [ ('LT', XER_SO), ('GT', XER_OV), ('EQ', XER_CA), + ('SO', ExprInt(0, 1)) ]: + ret.append(ExprAssign(all_regs_ids_byname["%s_%s" % (crfd, bit)], val)) + + return ret, [] + +def mn_do_mfcr(ir, instr, rd): + return ([ ExprAssign(rd, ExprCompose(*[ all_regs_ids_byname["CR%d_%s" % (i, b)] + for i in range(7, -1, -1) + for b in ['SO', 'EQ', 'GT', 'LT']]))], + []) + +@sbuild.parse +def mn_mfmsr(rd): + rd = MSR + +def mn_mfspr(ir, instr, arg1, arg2): + sprid = int(arg2) + gprid = int(arg1.name[1:]) + if sprid in spr_dict: + return [ ExprAssign(arg1, spr_dict[sprid]) ], [] + elif sprid == 1: # XER + return [ ExprAssign(arg1, ExprCompose(XER_BC, ExprInt(0, 22), + XER_CA, XER_OV, XER_SO)) ], [] + else: + return [ ExprAssign(spr_access, + ExprInt(((sprid << SPR_ACCESS_SPR_OFF) | + (gprid << SPR_ACCESS_GPR_OFF)), 32)), + ExprAssign(exception_flags, ExprInt(EXCEPT_SPR_ACCESS, 32)) ], [] + +def mn_mtcrf(ir, instr, crm, rs): + ret = [] + + for i in range(8): + if int(crm) & (1 << (7 - i)): + j = (28 - 4 * i) + 3 + for b in ['LT', 'GT', 'EQ', 'SO']: + ret.append(ExprAssign(all_regs_ids_byname["CR%d_%s" % (i, b)], + rs[j:j+1])) + j -= 1 + + return ret, [] + +def mn_mtmsr(ir, instr, rs): + print("%08x: MSR assigned" % instr.offset) + return [ ExprAssign(MSR, rs) ], [] + +def mn_mtspr(ir, instr, arg1, arg2): + sprid = int(arg1) + gprid = int(arg2.name[1:]) + if sprid in spr_dict: + return [ ExprAssign(spr_dict[sprid], arg2) ], [] + elif sprid == 1: # XER + return [ ExprAssign(XER_SO, arg2[31:32]), + ExprAssign(XER_OV, arg2[30:31]), + ExprAssign(XER_CA, arg2[29:30]), + ExprAssign(XER_BC, arg2[0:7]) ], [] + else: + return [ ExprAssign(spr_access, + ExprInt(((sprid << SPR_ACCESS_SPR_OFF) | + (gprid << SPR_ACCESS_GPR_OFF) | + SPR_ACCESS_IS_WRITE), 32)), + ExprAssign(exception_flags, ExprInt(EXCEPT_SPR_ACCESS, 32)) ], [] + +def mn_mtsr(ir, instr, sr, rs): + srid = sr.arg + return [ ExprAssign(sr_dict[srid], rs) ], [] + +# TODO +#def mn_mtsrin(ir, instr, rs, rb): +# return [ ExprAssign(sr_dict[rb[0:3]], rs) ], [] + +def mn_mfsr(ir, instr, rd, sr): + srid = sr.arg + return [ ExprAssign(rd, sr_dict[srid]) ], [] + +# TODO +#def mn_mfsrin(ir, instr, rd, rb): +# return [ ExprAssign(rd, sr_dict[rb[0:3]]) ], [] + +def mn_do_mul(ir, instr, rd, ra, arg2): + variant = instr.name[3:] + if variant[-1] == '.': + variant = variant[:-2] + + if variant == 'HW': + v1 = ra.signExtend(64) + v2 = arg2.signExtend(64) + shift = 32 + elif variant == 'HWU': + v1 = ra.zeroExtend(64) + v2 = arg2.zeroExtend(64) + shift = 32 + else: + v1 = ra + v2 = arg2 + shift = 0 + + rvalue = ExprOp('*', v1, v2) + if shift != 0: + rvalue = rvalue[shift : shift + 32] + + ret = [ ExprAssign(rd, rvalue) ] + + over_expr = None + if variant[-1] == 'O': + over_expr = ExprCond((rvalue.signExtend(64) ^ + ExprOp('*', v1.signExtend(64), + v2.signExtend(64))), + ExprInt(1, 1), ExprInt(0, 1)) + ret.append(ExprAssign(XER_OV, over_expr)) + ret.append(ExprAssign(XER_SO, XER_SO | over_expr)) + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue, over_expr) + + return ret, [] + +def mn_do_nand(ir, instr, ra, rs, rb): + rvalue = ~(rs & rb) + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def mn_do_neg(ir, instr, rd, ra): + rvalue = -ra + ret = [ ExprAssign(rd, rvalue) ] + has_o = False + + over_expr = None + if instr.name[-1] == 'O' or instr.name[-2] == 'O': + has_o = True + over_expr = ExprCond(ra ^ ExprInt(0x80000000, 32), + ExprInt(0, 1), ExprInt(1, 1)) + ret.append(ExprAssign(XER_OV, over_expr)) + ret.append(ExprAssign(XER_SO, XER_SO | over_expr)) + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue, over_expr) + + return ret, [] + +def mn_do_nor(ir, instr, ra, rs, rb): + + rvalue = ~(rs | rb) + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def mn_do_or(ir, instr, ra, rs, arg2): + if len(instr.name) > 2 and instr.name[2] == 'C': + oarg = ~arg2 + else: + oarg = arg2 + + rvalue = rs | oarg + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def mn_do_rfi(ir, instr): + dest = ExprCompose(ExprInt(0, 2), SRR0[2:32]) + ret = [ ExprAssign(MSR, (MSR & + ~ExprInt(0b1111111101110011, 32) | + ExprCompose(SRR1[0:2], ExprInt(0, 2), + SRR1[4:7], ExprInt(0, 1), + SRR1[8:16], ExprInt(0, 16)))), + ExprAssign(PC, dest), + ExprAssign(ir.IRDst, dest) ] + return ret, [] + +def mn_do_rotate(ir, instr, ra, rs, shift, mb, me): + r = ExprOp('<<<', rs, shift) + if mb <= me: + m = ExprInt(((1 << (32 - mb)) - 1) & ~((1 << (32 - me - 1)) - 1), 32) + else: + m = ExprInt(((1 << (32 - mb)) - 1) | ~((1 << (32 - me - 1)) - 1), 32) + rvalue = r & m + if instr.name[0:6] == 'RLWIMI': + rvalue = rvalue | (ra & ~m) + + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def mn_do_slw(ir, instr, ra, rs, rb): + + rvalue = ExprCond(rb[5:6], ExprInt(0, 32), + ExprOp('<<', rs, rb & ExprInt(0b11111, 32))) + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def mn_do_sraw(ir, instr, ra, rs, rb): + rvalue = ExprCond(rb[5:6], ExprInt(0xFFFFFFFF, 32), + ExprOp('a>>', rs, rb & ExprInt(0b11111, 32))) + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + mask = ExprCond(rb[5:6], ExprInt(0xFFFFFFFF, 32), + (ExprInt(0xFFFFFFFF, 32) >> + (ExprInt(32, 32) - (rb & ExprInt(0b11111, 32))))) + ret.append(ExprAssign(XER_CA, rs.msb() & + ExprCond(rs & mask, ExprInt(1, 1), ExprInt(0, 1)))) + + return ret, [] + +def mn_do_srawi(ir, instr, ra, rs, imm): + rvalue = ExprOp('a>>', rs, imm) + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + mask = ExprInt(0xFFFFFFFF >> (32 - int(imm)), 32) + + ret.append(ExprAssign(XER_CA, rs.msb() & + ExprCond(rs & mask, ExprInt(1, 1), ExprInt(0, 1)))) + + return ret, [] + +def mn_do_srw(ir, instr, ra, rs, rb): + rvalue = rs >> (rb & ExprInt(0b11111, 32)) + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def mn_do_stmw(ir, instr, rs, dest): + ret = [] + address = dest.ptr + ri = int(rs.name[1:],10) + i = 0 + while ri <= 31: + ret.append(ExprAssign(ExprMem(address + ExprInt(i,32), 32), + all_regs_ids_byname["R%d" % ri])) + ri += 1 + i += 4 + + return ret, [] + +def mn_do_store(ir, instr, arg1, arg2, arg3=None): + assert instr.name[0:2] == 'ST' + + ret = [] + additional_ir = [] + + if instr.name[2] == 'S': + raise RuntimeError("STSWI, and STSWX need implementing") + elif instr.name[2] == 'F': + print("Warning, instruction %s implemented as NOP" % instr) + return [], [] + + size = {'B': 8, 'H': 16, 'W': 32}[instr.name[2]] + + has_b = False + has_u = False + is_stwcx = False + + for l in instr.name[3:]: + if l == 'B' or l == 'R': + has_b = True + elif l == 'U': + has_u = True + elif l == 'X' or l == 'Z': + pass # Taken care of earlier + elif l == 'C' or l == '.': + is_stwcx = True + else: + assert False + + if arg3 is None: + assert isinstance(arg2, ExprMem) + + address = arg2.ptr + else: + address = arg2 + arg3 + + dest = ExprMem(address, size) + + src = arg1[0:size] + if has_b: + src = byte_swap(src) + + ret.append(ExprAssign(dest, src)) + if has_u: + if arg3 is None: + ret.append(ExprAssign(arg2.ptr.args[0], address)) + else: + ret.append(ExprAssign(arg2, address)) + + if is_stwcx: + loc_do = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) + loc_dont = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) + loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + flags = [ ExprAssign(CR0_LT, ExprInt(0,1)), + ExprAssign(CR0_GT, ExprInt(0,1)), + ExprAssign(CR0_SO, XER_SO)] + ret += flags + ret.append(ExprAssign(CR0_EQ, ExprInt(1,1))) + ret.append(ExprAssign(ir.IRDst, loc_next)) + dont = flags + [ ExprAssign(CR0_EQ, ExprInt(0,1)), + ExprAssign(ir.IRDst, loc_next) ] + additional_ir = [ IRBlock(ir.loc_db, loc_do.loc_key, [ AssignBlock(ret) ]), + IRBlock(ir.loc_db, loc_dont.loc_key, [ AssignBlock(dont) ]) ] + ret = [ ExprAssign(reserve, ExprInt(0, 1)), + ExprAssign(ir.IRDst, ExprCond(reserve, loc_do, loc_dont)) ] + + return ret, additional_ir + +def mn_do_sub(ir, instr, arg1, arg2, arg3): + assert instr.name[0:4] == 'SUBF' + + flags_update = [] + + has_dot = False + has_c = False + has_e = False + has_o = False + + for l in instr.name[4:]: + if l == '.': + has_dot = True + elif l == 'C': + has_c = True + elif l == 'E': + has_e = True + elif l == 'O': + has_o = True + elif l == 'I' or l == 'M' or l == 'S' or l == 'Z': + pass # Taken care of earlier + else: + assert False + + if has_e: + arg3 = arg3 + XER_CA.zeroExtend(32) + arg2 = arg2 + ExprInt(1, 32) + + rvalue = arg3 - arg2 + + over_expr = None + if has_o: + msb1 = arg2.msb() + msb2 = arg3.msb() + msba = rvalue.msb() + over_expr = (msb1 ^ msb2) & (msb1 ^ msba) + flags_update.append(ExprAssign(XER_OV, over_expr)) + flags_update.append(ExprAssign(XER_SO, XER_SO | over_expr)) + + if has_dot: + flags_update += mn_compute_flags(rvalue, over_expr) + + if has_c or has_e: + carry_expr = ((((arg3 ^ arg2) ^ rvalue) ^ + ((arg3 ^ rvalue) & (arg3 ^ arg2))).msb()) + flags_update.append(ExprAssign(XER_CA, ~carry_expr)) + + return ([ ExprAssign(arg1, rvalue) ] + flags_update), [] + +def mn_do_xor(ir, instr, ra, rs, rb): + rvalue = rs ^ rb + ret = [ ExprAssign(ra, rvalue) ] + + if instr.name[-1] == '.': + ret += mn_compute_flags(rvalue) + + return ret, [] + +def mn_b(ir, instr, arg1, arg2 = None): + if arg2 is not None: + arg1 = arg2 + return [ ExprAssign(PC, arg1), ExprAssign(ir.IRDst, arg1) ], [] + +def mn_bl(ir, instr, arg1, arg2 = None): + if arg2 is not None: + arg1 = arg2 + dst = ir.get_next_instr(instr) + return [ ExprAssign(LR, ExprLoc(dst, 32)), + ExprAssign(PC, arg1), + ExprAssign(ir.IRDst, arg1) ], [] + +def mn_get_condition(instr): + bit = instr.additional_info.bi & 0b11 + cr = instr.args[0].name + return all_regs_ids_byname[cr + '_' + ['LT', 'GT', 'EQ', 'SO'][bit]] + +def mn_do_cond_branch(ir, instr, dest): + bo = instr.additional_info.bo + bi = instr.additional_info.bi + ret = [] + + if bo & 0b00100: + ctr_cond = True + else: + ret.append(ExprAssign(CTR, CTR - ExprInt(1, 32))) + ctr_cond = ExprCond(CTR ^ ExprInt(1, 32), ExprInt(1, 1), ExprInt(0, 1)) + if bo & 0b00010: + ctr_cond = ~ctr_cond + + if (bo & 0b10000): + cond_cond = True + else: + cond_cond = mn_get_condition(instr) + if not (bo & 0b01000): + cond_cond = ~cond_cond + + if ctr_cond != True or cond_cond != True: + if ctr_cond != True: + condition = ctr_cond + if cond_cond != True: + condition = condition & cond_cond + else: + condition = cond_cond + dst = ir.get_next_instr(instr) + dest_expr = ExprCond(condition, dest, + ExprLoc(dst, 32)) + else: + dest_expr = dest + + if instr.name[-1] == 'L' or instr.name[-2:-1] == 'LA': + dst = ir.get_next_instr(instr) + ret.append(ExprAssign(LR, ExprLoc(dst, 32))) + + ret.append(ExprAssign(PC, dest_expr)) + ret.append(ExprAssign(ir.IRDst, dest_expr)) + + return ret, [] + +def mn_do_nop_warn(ir, instr, *args): + print("Warning, instruction %s implemented as NOP" % instr) + return [], [] + +@sbuild.parse +def mn_cmp_signed(arg1, arg2, arg3): + crf_dict[arg1]['LT'] = expr.ExprOp(expr.TOK_INF_SIGNED, arg2, arg3) + crf_dict[arg1]['GT'] = expr.ExprOp(expr.TOK_INF_SIGNED, arg3, arg2) + crf_dict[arg1]['EQ'] = expr.ExprOp(expr.TOK_EQUAL, arg2, arg3) + crf_dict[arg1]['SO'] = XER_SO + +@sbuild.parse +def mn_cmp_unsigned(arg1, arg2, arg3): + crf_dict[arg1]['LT'] = expr.ExprOp(expr.TOK_INF_UNSIGNED, arg2, arg3) + crf_dict[arg1]['GT'] = expr.ExprOp(expr.TOK_INF_UNSIGNED, arg3, arg2) + crf_dict[arg1]['EQ'] = expr.ExprOp(expr.TOK_EQUAL, arg2, arg3) + crf_dict[arg1]['SO'] = XER_SO + +def mn_nop(ir, instr, *args): + return [], [] + +@sbuild.parse +def mn_or(arg1, arg2, arg3): + arg1 = arg2 | arg3 + +@sbuild.parse +def mn_assign(arg1, arg2): + arg2 = arg1 + +def mn_stb(ir, instr, arg1, arg2): + dest = ExprMem(arg2.arg, 8) + return [ExprAssign(dest, ExprSlice(arg1, 0, 8))], [] + +@sbuild.parse +def mn_stwu(arg1, arg2): + arg2 = arg1 + arg1 = arg2.arg + +sem_dir = { + 'B': mn_b, + 'BA': mn_b, + 'BL': mn_bl, + 'BLA': mn_bl, + 'CMPLW': mn_cmp_unsigned, + 'CMPLWI': mn_cmp_unsigned, + 'CMPW': mn_cmp_signed, + 'CMPWI': mn_cmp_signed, + 'CNTLZW': mn_do_cntlzw, + 'CNTLZW.': mn_do_cntlzw, + 'ECIWX': mn_do_nop_warn, + 'ECOWX': mn_do_nop_warn, + 'EIEIO': mn_do_nop_warn, + 'EQV': mn_do_eqv, + 'EQV.': mn_do_eqv, + 'ICBI': mn_do_nop_warn, + 'ISYNC': mn_do_nop_warn, + 'MCRF': mn_do_mcrf, + 'MCRXR': mn_do_mcrxr, + 'MFCR': mn_do_mfcr, + 'MFFS': mn_do_nop_warn, + 'MFFS.': mn_do_nop_warn, + 'MFMSR': mn_mfmsr, + 'MFSPR': mn_mfspr, + 'MFSR': mn_mfsr, + 'MFSRIN': mn_do_nop_warn, + 'MTFSF': mn_do_nop_warn, + 'MTFSF.': mn_do_nop_warn, + 'MFTB': mn_mfspr, + 'MTCRF': mn_mtcrf, + 'MTMSR': mn_mtmsr, + 'MTSPR': mn_mtspr, + 'MTSR': mn_mtsr, + 'MTSRIN': mn_do_nop_warn, + 'MTVSCR': mn_do_nop_warn, + 'NAND': mn_do_nand, + 'NAND.': mn_do_nand, + 'NOR': mn_do_nor, + 'NOR.': mn_do_nor, + 'RFI': mn_do_rfi, + 'SC': mn_do_nop_warn, + 'SLW': mn_do_slw, + 'SLW.': mn_do_slw, + 'SRAW': mn_do_sraw, + 'SRAW.': mn_do_sraw, + 'SRAWI': mn_do_srawi, + 'SRAWI.': mn_do_srawi, + 'SRW': mn_do_srw, + 'SRW.': mn_do_srw, + 'SYNC': mn_do_nop_warn, + 'TLBIA': mn_do_nop_warn, + 'TLBIE': mn_do_nop_warn, + 'TLBSYNC': mn_do_nop_warn, + 'TW': mn_do_nop_warn, + 'TWI': mn_do_nop_warn, +} + + +class Lifter_PPC32b(Lifter): + + def __init__(self, loc_db): + super(Lifter_PPC32b, self).__init__(mn_ppc, 'b', loc_db) + self.pc = mn_ppc.getpc() + self.sp = mn_ppc.getsp() + self.IRDst = expr.ExprId('IRDst', 32) + self.addrsize = 32 + + def get_ir(self, instr): + args = instr.args[:] + if instr.name[0:5] in [ 'ADDIS', 'ORIS', 'XORIS', 'ANDIS' ]: + args[2] = ExprInt(int(args[2]) << 16, 32) + if instr.name[0:3] == 'ADD': + if instr.name[0:4] == 'ADDZ': + last_arg = ExprInt(0, 32) + elif instr.name[0:4] == 'ADDM': + last_arg = ExprInt(0xFFFFFFFF, 32) + else: + last_arg = args[2] + instr_ir, extra_ir = mn_do_add(self, instr, args[0], args[1], + last_arg) + elif instr.name[0:3] == 'AND': + instr_ir, extra_ir = mn_do_and(self, instr, *args) + elif instr.additional_info.bo_bi_are_defined: + name = instr.name + if name[-1] == '+' or name[-1] == '-': + name = name[0:-1] + if name[-3:] == 'CTR' or name[-4:] == 'CTRL': + arg1 = ExprCompose(ExprInt(0, 2), CTR[2:32]) + elif name[-2:] == 'LR' or name[-3:] == 'LRL': + arg1 = ExprCompose(ExprInt(0, 2), LR[2:32]) + else: + arg1 = args[1] + instr_ir, extra_ir = mn_do_cond_branch(self, instr, arg1) + elif instr.name[0:2] == 'CR': + instr_ir, extra_ir = mn_do_cr(self, instr, *args) + elif instr.name[0:3] == 'DCB': + instr_ir, extra_ir = mn_do_nop_warn(self, instr, *args) + elif instr.name[0:3] == 'DIV': + instr_ir, extra_ir = mn_do_div(self, instr, *args) + elif instr.name[0:4] == 'EXTS': + instr_ir, extra_ir = mn_do_exts(self, instr, *args) + elif instr.name[0] == 'L': + instr_ir, extra_ir = mn_do_load(self, instr, *args) + elif instr.name[0:3] == 'MUL': + instr_ir, extra_ir = mn_do_mul(self, instr, *args) + elif instr.name[0:3] == 'NEG': + instr_ir, extra_ir = mn_do_neg(self, instr, *args) + elif instr.name[0:2] == 'OR': + instr_ir, extra_ir = mn_do_or(self, instr, *args) + elif instr.name[0:2] == 'RL': + instr_ir, extra_ir = mn_do_rotate(self, instr, args[0], args[1], + args[2], int(args[3]), + int(args[4])) + elif instr.name == 'STMW': + instr_ir, extra_ir = mn_do_stmw(self, instr, *args) + elif instr.name[0:2] == 'ST': + instr_ir, extra_ir = mn_do_store(self, instr, *args) + elif instr.name[0:4] == 'SUBF': + if instr.name[0:5] == 'SUBFZ': + last_arg = ExprInt(0, 32) + elif instr.name[0:5] == 'SUBFM': + last_arg = ExprInt(0xFFFFFFFF, 32) + else: + last_arg = args[2] + instr_ir, extra_ir = mn_do_sub(self, instr, args[0], args[1], + last_arg) + elif instr.name[0:3] == 'XOR': + instr_ir, extra_ir = mn_do_xor(self, instr, *args) + else: + instr_ir, extra_ir = sem_dir[instr.name](self, instr, *args) + + return instr_ir, extra_ir + + def get_next_instr(self, instr): + l = self.loc_db.get_or_create_offset_location(instr.offset + 4) + return l + + def get_next_break_loc_key(self, instr): + l = self.loc_db.get_or_create_offset_location(instr.offset + 4) + return l diff --git a/src/miasm/arch/sh4/__init__.py b/src/miasm/arch/sh4/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/miasm/arch/sh4/__init__.py diff --git a/src/miasm/arch/sh4/arch.py b/src/miasm/arch/sh4/arch.py new file mode 100644 index 00000000..76489aee --- /dev/null +++ b/src/miasm/arch/sh4/arch.py @@ -0,0 +1,998 @@ +#-*- coding:utf-8 -*- + +from __future__ import print_function +from builtins import range + +from pyparsing import * +from miasm.core.cpu import * +from miasm.expression.expression import * +from collections import defaultdict +import miasm.arch.sh4.regs as regs_module +from miasm.arch.sh4.regs import * + + +from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp + +jra = ExprId('jra', 32) +jrb = ExprId('jrb', 32) +jrc = ExprId('jrc', 32) + + +# parser helper ########### +PLUS = Suppress("+") +MULT = Suppress("*") +MINUS = Suppress("-") +AND = Suppress("&") +LBRACK = Suppress("[") +RBRACK = Suppress("]") +DEREF = Suppress("@") +COMMA = Suppress(",") +LPARENT = Suppress("(") +RPARENT = Suppress(")") + + +def cb_deref_pcimm(tokens): + return tokens[0] + tokens[1] + + +def cb_pcandimmimm(tokens): + return (tokens[0] & tokens[1]) + tokens[2] + + + +ref_pc = (LPARENT + reg_info_pc.parser + COMMA + base_expr + RPARENT).setParseAction(cb_deref_pcimm) +ref_pcandimm = (LPARENT + reg_info_pc.parser + AND + base_expr + COMMA + base_expr + RPARENT).setParseAction(cb_pcandimmimm) +pcdisp = (reg_info_pc.parser + AND + base_expr + PLUS + base_expr).setParseAction(cb_pcandimmimm) + +PTR = Suppress('PTR') + + +def cb_deref_mem(tokens): + assert len(tokens) == 1 + result = AstMem(tokens[0], 32) + return result + + +def cb_predec(tokens): + assert len(tokens) == 1 + result = AstMem(AstOp('predec', tokens[0]), 32) + return result + + +def cb_postinc(tokens): + assert len(tokens) == 1 + result = AstMem(AstOp('postinc', tokens[0]), 32) + return result + + +def cb_regdisp(tokens): + assert len(tokens) == 2 + result = AstMem(tokens[0] + tokens[1], 32) + return result + + +def cb_regreg(tokens): + assert len(tokens) == 2 + result = AstMem(tokens[0] + tokens[1], 32) + return result + + +deref_pc = (DEREF + ref_pc).setParseAction(cb_deref_mem) +deref_pcimm = (DEREF + ref_pcandimm).setParseAction(cb_deref_mem) + +dgpregs_base = (DEREF + gpregs.parser).setParseAction(cb_deref_mem) +dgpregs_predec = (DEREF + MINUS + gpregs.parser).setParseAction(cb_predec) +dgpregs_postinc = (DEREF + gpregs.parser + PLUS).setParseAction(cb_postinc) + +dgpregs = dgpregs_base | dgpregs_predec | dgpregs_postinc + +d_gpreg_gpreg = (DEREF + LPARENT + gpregs.parser + COMMA + gpregs.parser + RPARENT).setParseAction(cb_regdisp) +dgpregs_p = dgpregs_predec | dgpregs_postinc + + +dgpregs_ir = (DEREF + LPARENT + gpregs.parser + COMMA + base_expr + RPARENT).setParseAction(cb_regdisp) +dgpregs_ir |= d_gpreg_gpreg + +dgbr_imm = (DEREF + LPARENT + reg_info_gbr.parser + COMMA + base_expr + RPARENT).setParseAction(cb_regdisp) + +dgbr_reg = (DEREF + LPARENT + reg_info_gbr.parser + COMMA + gpregs.parser + RPARENT).setParseAction(cb_regreg) + + +class sh4_arg(m_arg): + def asm_ast_to_expr(self, arg, loc_db): + if isinstance(arg, AstId): + if isinstance(arg.name, ExprId): + return arg.name + if arg.name in gpregs.str: + return None + loc_key = loc_db.get_or_create_name_location(arg.name) + return ExprLoc(loc_key, 32) + if isinstance(arg, AstOp): + args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args] + if None in args: + return None + return ExprOp(arg.op, *args) + if isinstance(arg, AstInt): + return ExprInt(arg.value, 32) + if isinstance(arg, AstMem): + ptr = self.asm_ast_to_expr(arg.ptr, loc_db) + if ptr is None: + return None + return ExprMem(ptr, arg.size) + return None + + +_, bs_pr = gen_reg_bs('PR', reg_info_pr, (m_reg, sh4_arg,)) +_, bs_r0 = gen_reg_bs('R0', reg_info_r0, (m_reg, sh4_arg,)) +_, bs_sr = gen_reg_bs('SR', reg_info_sr, (m_reg, sh4_arg,)) +_, bs_gbr = gen_reg_bs('GBR', reg_info_gbr, (m_reg, sh4_arg,)) +_, bs_vbr = gen_reg_bs('VBR', reg_info_vbr, (m_reg, sh4_arg,)) +_, bs_ssr = gen_reg_bs('SSR', reg_info_ssr, (m_reg, sh4_arg,)) +_, bs_spc = gen_reg_bs('SPC', reg_info_spc, (m_reg, sh4_arg,)) +_, bs_sgr = gen_reg_bs('SGR', reg_info_sgr, (m_reg, sh4_arg,)) +_, bs_dbr = gen_reg_bs('dbr', reg_info_dbr, (m_reg, sh4_arg,)) +_, bs_mach = gen_reg_bs('mach', reg_info_mach, (m_reg, sh4_arg,)) +_, bs_macl = gen_reg_bs('macl', reg_info_macl, (m_reg, sh4_arg,)) +_, bs_fpul = gen_reg_bs('fpul', reg_info_fpul, (m_reg, sh4_arg,)) +_, bs_fr0 = gen_reg_bs('fr0', reg_info_fr0, (m_reg, sh4_arg,)) + +class sh4_reg(reg_noarg, sh4_arg): + pass + + +class sh4_gpreg(sh4_reg): + reg_info = gpregs + parser = reg_info.parser + + +class sh4_dr(sh4_reg): + reg_info = dregs + parser = reg_info.parser + + +class sh4_bgpreg(sh4_reg): + reg_info = bgpregs + parser = reg_info.parser + + +class sh4_gpreg_noarg(reg_noarg, ): + reg_info = gpregs + parser = reg_info.parser + + +class sh4_freg(sh4_reg): + reg_info = fregs + parser = reg_info.parser + + +class sh4_dgpreg(sh4_arg): + parser = dgpregs_base + + def fromstring(self, text, loc_db, parser_result=None): + start, stop = super(sh4_dgpreg, self).fromstring(text, loc_db, parser_result) + if start is None or self.expr == [None]: + return start, stop + self.expr = ExprMem(self.expr.ptr, self.sz) + return start, stop + + def decode(self, v): + r = gpregs.expr[v] + self.expr = ExprMem(r, self.sz) + return True + + def encode(self): + e = self.expr + if not isinstance(e, ExprMem): + return False + if not isinstance(e.ptr, ExprId): + return False + v = gpregs.expr.index(e.ptr) + self.value = v + return True + + +class sh4_dgpregpinc(sh4_arg): + parser = dgpregs_p + + def fromstring(self, text, loc_db, parser_result=None): + start, stop = super(sh4_dgpregpinc, self).fromstring(text, loc_db, parser_result) + if self.expr == [None]: + return None, None + if not isinstance(self.expr.ptr, ExprOp): + return None, None + if self.expr.ptr.op != self.op: + return None, None + return start, stop + + def decode(self, v): + r = gpregs.expr[v] + e = ExprOp(self.op, r) + self.expr = ExprMem(e, self.sz) + return True + + def encode(self): + e = self.expr + if not isinstance(e, ExprMem): + return False + e = e.ptr + res = match_expr(e, ExprOp(self.op, jra), [jra]) + if not res: + return False + r = res[jra] + if not r in gpregs.expr: + return False + v = gpregs.expr.index(r) + self.value = v + return True + + +class sh4_dgpregpdec(sh4_arg): + parser = dgpregs_postinc + op = "preinc" + + +class sh4_dgpreg_imm(sh4_dgpreg): + parser = dgpregs_ir + + def decode(self, v): + p = self.parent + r = gpregs.expr[v] + s = self.sz + d = ExprInt((p.disp.value * s) // 8, 32) + e = ExprMem(r + d, s) + self.expr = e + return True + + def encode(self): + e = self.expr + p = self.parent + s = self.sz + if not isinstance(e, ExprMem): + return False + if isinstance(e.ptr, ExprId): + v = gpregs.expr.index(e.ptr) + p.disp.value = 0 + elif isinstance(e.ptr, ExprOp): + res = match_expr(e, ExprMem(jra + jrb, self.sz), [jra, jrb]) + if not res: + return False + if not isinstance(res[jra], ExprId): + return False + if not isinstance(res[jrb], ExprInt): + return False + d = int(res[jrb]) + p.disp.value = d // (s // 8) + if not res[jra] in gpregs.expr: + return False + v = gpregs.expr.index(res[jra]) + else: + return False + self.value = v + return True + + +class sh4_imm(imm_noarg, sh4_arg): + parser = base_expr + pass + + +class sh4_simm(sh4_imm): + parser = base_expr + + def decode(self, v): + v = sign_ext(v, self.l, 32) + v = self.decodeval(v) + self.expr = ExprInt(v, 32) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + if (1 << (self.l - 1)) & v: + v = -((0xffffffff ^ v) + 1) + v = self.encodeval(v) + self.value = (v & 0xffffffff) & self.lmask + return True + + +class sh4_dpc16imm(sh4_dgpreg): + parser = deref_pc + + def decode(self, v): + self.expr = ExprMem(PC + ExprInt(v * 2 + 4, 32), 16) + return True + + def calcdisp(self, v): + v = (int(v) - 4) // 2 + if not 0 < v <= 0xff: + return None + return v + + def encode(self): + res = match_expr(self.expr, ExprMem(PC + jra, 16), [jra]) + if not res: + return False + if not isinstance(res[jra], ExprInt): + return False + v = self.calcdisp(res[jra]) + if v is None: + return False + self.value = v + return True + + +class sh4_dgbrimm8(sh4_dgpreg): + parser = dgbr_imm + + def decode(self, v): + s = self.sz + self.expr = ExprMem(GBR + ExprInt((v * s) // 8, 32), s) + return True + + def encode(self): + e = self.expr + s = self.sz + if e == ExprMem(GBR, 32): + self.value = 0 + return True + res = match_expr(self.expr, ExprMem(GBR + jra, s), [jra]) + if not res: + return False + if not isinstance(res[jra], ExprInt): + return False + self.value = int(res[jra]) // (s // 8) + return True + + +class sh4_dpc32imm(sh4_dpc16imm): + parser = deref_pcimm + + def decode(self, v): + self.expr = ExprMem( + (PC & ExprInt(0xfffffffc, 32)) + ExprInt(v * 4 + 4, 32), 32) + return True + + def calcdisp(self, v): + v = (int(v) - 4) // 4 + if not 0 < v <= 0xff: + return None + return v + + def encode(self): + res = match_expr( + self.expr, ExprMem((PC & ExprInt(0xFFFFFFFC, 32)) + jra, 32), [jra]) + if not res: + return False + if not isinstance(res[jra], ExprInt): + return False + v = self.calcdisp(res[jra]) + if v is None: + return False + self.value = v + return True + + +class sh4_pc32imm(sh4_arg): + parser = pcdisp + + def decode(self, v): + self.expr = (PC & ExprInt(0xfffffffc, 32)) + ExprInt(v * 4 + 4, 32) + return True + + def encode(self): + res = match_expr(self.expr, (PC & ExprInt(0xfffffffc, 32)) + jra, [jra]) + if not res: + return False + if not isinstance(res[jra], ExprInt): + return False + v = (int(res[jra]) - 4) // 4 + if v is None: + return False + self.value = v + return True + +class additional_info(object): + + def __init__(self): + self.except_on_instr = False + + +class instruction_sh4(instruction): + __slots__ = [] + + def __init__(self, *args, **kargs): + super(instruction_sh4, self).__init__(*args, **kargs) + + def dstflow(self): + return self.name.startswith('J') + + @staticmethod + def arg2str(expr, index=None, loc_db=None): + if isinstance(expr, ExprId) or isinstance(expr, ExprInt): + return str(expr) + elif expr.is_loc(): + if loc_db is not None: + return loc_db.pretty_str(expr.loc_key) + else: + return str(expr) + assert(isinstance(expr, ExprMem)) + ptr = expr.ptr + + if isinstance(ptr, ExprOp): + if ptr.op == "predec": + s = '-%s' % ptr.args[0] + elif ptr.op == "postinc": + s = '%s+' % ptr.args[0] + else: + s = ','.join( + str(x).replace('(', '').replace(')', '') + for x in ptr.args + ) + s = "(%s)"%s + s = "@%s" % s + elif isinstance(ptr, ExprId): + s = "@%s" % ptr + else: + raise NotImplementedError('zarb arg2str') + return s + + + """ + def dstflow2label(self, loc_db): + e = self.args[0] + if not isinstance(e, ExprInt): + return + if self.name == 'BLX': + ad = e.arg+8+self.offset + else: + ad = e.arg+8+self.offset + l = loc_db.get_or_create_offset_location(ad) + s = ExprId(l, e.size) + self.args[0] = s + """ + + def breakflow(self): + if self.name.startswith('J'): + return True + return False + + def is_subcall(self): + return self.name == 'JSR' + + def getdstflow(self, loc_db): + return [self.args[0]] + + def splitflow(self): + return self.name == 'JSR' + + def get_symbol_size(self, symbol, loc_db): + return 32 + + def fixDstOffset(self): + e = self.args[0] + if self.offset is None: + raise ValueError('symbol not resolved %s' % l) + if not isinstance(e, ExprInt): + log.debug('dyn dst %r', e) + return + off = e.arg - (self.offset + 4 + self.l) + print(hex(off)) + if int(off % 4): + raise ValueError('strange offset! %r' % off) + self.args[0] = ExprInt(off, 32) + print('final', self.args[0]) + + def get_args_expr(self): + args = [a for a in self.args] + return args + + +class mn_sh4(cls_mn): + bintree = {} + regs = regs_module + num = 0 + all_mn = [] + all_mn_mode = defaultdict(list) + all_mn_name = defaultdict(list) + all_mn_inst = defaultdict(list) + pc = PC + # delayslot: + # http://resource.renesas.com/lib/eng/e_learnig/sh4/13/index.html + delayslot = 0 # unit is instruction instruction + instruction = instruction_sh4 + + def additional_info(self): + info = additional_info() + return info + + @classmethod + def getbits(cls, bs, attrib, start, n): + if not n: + return 0 + o = 0 + if n > bs.getlen() * 8: + raise ValueError('not enough bits %r %r' % (n, len(bs.bin) * 8)) + while n: + i = start // 8 + c = cls.getbytes(bs, i) + if not c: + raise IOError + c = ord(c) + r = 8 - start % 8 + c &= (1 << r) - 1 + l = min(r, n) + c >>= (r - l) + o <<= l + o |= c + n -= l + start += l + return o + + @classmethod + def getbytes(cls, bs, offset, l=1): + out = b"" + for _ in range(l): + n_offset = (offset & ~1) + 1 - offset % 2 + out += bs.getbytes(n_offset, 1) + offset += 1 + return out + + @classmethod + def check_mnemo(cls, fields): + l = sum([x.l for x in fields]) + assert l == 16, "len %r" % l + + @classmethod + def getmn(cls, name): + return name.upper().replace('_', '.') + + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + dct['mode'] = None + return [(subcls, name, bases, dct, fields)] + + def value(self, mode): + v = super(mn_sh4, self).value(mode) + return [x[::-1] for x in v] + + +class bs_dr0gbr(sh4_dgpreg): + parser = dgbr_reg + + def decode(self, v): + self.expr = ExprMem(GBR + R0, 8) + return True + + def encode(self): + return self.expr == ExprMem(GBR + R0, 8) + + +class bs_dr0gp(sh4_dgpreg): + parser = d_gpreg_gpreg + + def decode(self, v): + self.expr = ExprMem(gpregs.expr[v] + R0, self.sz) + return True + + def encode(self): + res = match_expr(self.expr, ExprMem(R0 + jra, self.sz), [jra]) + if not res: + return False + r = res[jra] + if not r in gpregs.expr: + return False + self.value = gpregs.expr.index(r) + return True + + +class bs_dgpreg(sh4_dgpreg): + parser = dgpregs_base + + +rn = bs(l=4, cls=(sh4_gpreg,), fname="rn") +rm = bs(l=4, cls=(sh4_gpreg,), fname="rm") + + +d08_rn = bs(l=4, cls=(sh4_dgpreg,), fname="rn", sz = 8) +d16_rn = bs(l=4, cls=(sh4_dgpreg,), fname="rn", sz = 16) +d32_rn = bs(l=4, cls=(sh4_dgpreg,), fname="rn", sz = 32) +d08_rm = bs(l=4, cls=(sh4_dgpreg,), fname="rm", sz = 8) +d16_rm = bs(l=4, cls=(sh4_dgpreg,), fname="rm", sz = 16) +d32_rm = bs(l=4, cls=(sh4_dgpreg,), fname="rm", sz = 32) + + +brm = bs(l=3, cls=(sh4_bgpreg,), fname="brm") +brn = bs(l=3, cls=(sh4_bgpreg,), fname="brn") + +d08rnimm = bs(l=4, fname="rn", cls=(sh4_dgpreg_imm,), sz = 8) +d16rnimm = bs(l=4, fname="rn", cls=(sh4_dgpreg_imm,), sz = 16) +d32rnimm = bs(l=4, fname="rn", cls=(sh4_dgpreg_imm,), sz = 32) + +d08rmimm = bs(l=4, fname="rm", cls=(sh4_dgpreg_imm,), sz = 8) +d16rmimm = bs(l=4, fname="rm", cls=(sh4_dgpreg_imm,), sz = 16) +d32rmimm = bs(l=4, fname="rm", cls=(sh4_dgpreg_imm,), sz = 32) + +btype = bs(l=4, fname="btype", order=-1) + +s08imm = bs(l=8, cls=(sh4_simm,), fname="imm") +s12imm = bs(l=12, cls=(sh4_simm,), fname="imm") +dpc16imm = bs(l=8, cls=(sh4_dpc16imm,), fname="pcimm", sz=16) +dpc32imm = bs(l=8, cls=(sh4_dpc32imm,), fname="pcimm", sz=32) +dimm4 = bs(l=4, fname='disp', order=-1) +d08gbrimm8 = bs(l=8, cls=(sh4_dgbrimm8,), fname='disp', sz=8) +d16gbrimm8 = bs(l=8, cls=(sh4_dgbrimm8,), fname='disp', sz=16) +d32gbrimm8 = bs(l=8, cls=(sh4_dgbrimm8,), fname='disp', sz=32) + +pc32imm = bs(l=8, cls=(sh4_pc32imm,), fname="pcimm") + +d08rnpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=8, fname="rn") +d08rmpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=8, fname="rm") + +d16rnpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=16, fname="rn") +d16rmpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=16, fname="rm") + +d32rnpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=32, fname="rn") +d32rmpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=32, fname="rm") + +d08rnpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=8, fname="rn") +d08rmpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=8, fname="rm") + +d16rnpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=16, fname="rn") +d16rmpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=16, fname="rm") + +d32rnpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=32, fname="rn") +d32rmpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=32, fname="rm") + + +u08imm = bs(l=8, cls=(sh4_imm,), fname="imm") +dr0gbr = bs(l=0, cls=(bs_dr0gbr,), sz=8) + +d08gpreg = bs(l=4, cls=(bs_dgpreg,), sz=8) +d32gpreg = bs(l=4, cls=(bs_dgpreg,), sz=32) + +frn = bs(l=4, cls=(sh4_freg,), fname="frn") +frm = bs(l=4, cls=(sh4_freg,), fname="frm") + +bd08r0gp = bs(l=4, cls=(bs_dr0gp,), sz=8) +bd16r0gp = bs(l=4, cls=(bs_dr0gp,), sz=16) +bd32r0gp = bs(l=4, cls=(bs_dr0gp,), sz=32) + +drn = bs(l=3, cls=(sh4_dr,), fname="drn") +drm = bs(l=3, cls=(sh4_dr,), fname="drm") + + +def addop(name, fields, args=None, alias=False): + dct = {"fields": fields} + dct["alias"] = alias + if args is not None: + dct['args'] = args + type(name, (mn_sh4,), dct) + +addop("mov", [bs('1110'), rn, s08imm], [s08imm, rn]) +addop("mov_w", [bs('1001'), rn, dpc16imm], [dpc16imm, rn]) +addop("mov_l", [bs('1101'), rn, dpc32imm], [dpc32imm, rn]) +addop("mov", [bs('0110', fname="opc"), rn, rm, bs('0011')], [rm, rn]) +addop("mov_b", [bs('0010', fname="opc"), d08_rn, rm, bs('0000')], [rm, d08_rn]) +addop("mov_w", [bs('0010', fname="opc"), d16_rn, rm, bs('0001')], [rm, d16_rn]) +addop("mov_l", [bs('0010', fname="opc"), d32_rn, rm, bs('0010')], [rm, d32_rn]) +addop("mov_b", [bs('0110', fname="opc"), rn, d08_rm, bs('0000')], [d08_rm, rn]) +addop("mov_w", [bs('0110', fname="opc"), rn, d16_rm, bs('0001')], [d16_rm, rn]) +addop("mov_l", [bs('0110', fname="opc"), rn, d32_rm, bs('0010')], [d32_rm, rn]) +addop("mov_b", + [bs('0010', fname="opc"), d08rnpdec, rm, bs('0100')], [rm, d08rnpdec]) +addop("mov_w", + [bs('0010', fname="opc"), d16rnpdec, rm, bs('0101')], [rm, d16rnpdec]) +addop("mov_l", + [bs('0010', fname="opc"), d32rnpdec, rm, bs('0110')], [rm, d32rnpdec]) +addop("mov_b", + [bs('0110', fname="opc"), rn, d08rmpinc, bs('0100')], [rm, d08rnpinc]) +addop("mov_w", + [bs('0110', fname="opc"), rn, d16rmpinc, bs('0101')], [d16rmpinc, rn]) +addop("mov_l", + [bs('0110', fname="opc"), rn, d32rmpinc, bs('0110')], [d32rmpinc, rn]) +addop("mov_b", [bs('10000000', fname='opc'), bs_r0, d08rnimm, dimm4]) +addop("mov_w", [bs('10000001', fname='opc'), bs_r0, d16rnimm, dimm4]) +addop("mov_l", [bs('0001', fname='opc'), d32rnimm, rm, dimm4], [rm, d32rnimm]) +addop("mov_b", [bs('10000100', fname='opc'), d08rmimm, dimm4, bs_r0]) +addop("mov_w", [bs('10000101', fname='opc'), d16rmimm, dimm4, bs_r0]) +addop("mov_l", [bs('0101', fname='opc'), rn, d32rmimm, dimm4], [d32rmimm, rn]) +addop("mov_b", + [bs('0000', fname='opc'), bd08r0gp, rm, bs('0100')], [rm, bd08r0gp]) +addop("mov_w", + [bs('0000', fname='opc'), bd16r0gp, rm, bs('0101')], [rm, bd16r0gp]) +addop("mov_l", + [bs('0000', fname='opc'), bd32r0gp, rm, bs('0110')], [rm, bd32r0gp]) +addop("mov_b", + [bs('0000', fname='opc'), rn, bd08r0gp, bs('1100')], [bd08r0gp, rn]) +addop("mov_w", + [bs('0000', fname='opc'), rn, bd16r0gp, bs('1101')], [bd16r0gp, rn]) +addop("mov_l", + [bs('0000', fname='opc'), rn, bd32r0gp, bs('1110')], [bd32r0gp, rn]) + +addop("mov_b", [bs('11000000'), bs_r0, d08gbrimm8]) +addop("mov_w", [bs('11000001'), bs_r0, d16gbrimm8]) +addop("mov_l", [bs('11000010'), bs_r0, d32gbrimm8]) + +addop("mov_b", [bs('11000100'), d08gbrimm8, bs_r0]) +addop("mov_w", [bs('11000101'), d16gbrimm8, bs_r0]) +addop("mov_l", [bs('11000110'), d32gbrimm8, bs_r0]) + +addop("mov", [bs('11000111'), pc32imm, bs_r0]) + +addop("swapb", [bs('0110'), rn, rm, bs('1000')], [rm, rn]) +addop("swapw", [bs('0110'), rn, rm, bs('1001')], [rm, rn]) +addop("xtrct", [bs('0010'), rn, rm, bs('1101')], [rm, rn]) + + +addop("add", [bs('0011'), rn, rm, bs('1100')], [rm, rn]) +addop("add", [bs('0111'), rn, s08imm], [s08imm, rn]) +addop("addc", [bs('0011'), rn, rm, bs('1110')], [rm, rn]) +addop("addv", [bs('0011'), rn, rm, bs('1111')], [rm, rn]) + + +addop("cmpeq", [bs('10001000'), s08imm, bs_r0]) + + +addop("cmpeq", [bs('0011'), rn, rm, bs('0000')], [rm, rn]) +addop("cmphs", [bs('0011'), rn, rm, bs('0010')], [rm, rn]) +addop("cmpge", [bs('0011'), rn, rm, bs('0011')], [rm, rn]) +addop("cmphi", [bs('0011'), rn, rm, bs('0110')], [rm, rn]) +addop("cmpgt", [bs('0011'), rn, rm, bs('0111')], [rm, rn]) + + +addop("cmppz", [bs('0100'), rn, bs('00010001')]) +addop("cmppl", [bs('0100'), rn, bs('00010101')]) +addop("cmpstr", [bs('0010'), rn, rm, bs('1100')], [rm, rn]) + + +addop("div1", [bs('0011'), rn, rm, bs('0100')], [rm, rn]) + +addop("div0s", [bs('0010'), rn, rm, bs('0111')], [rm, rn]) +addop("div0u", [bs('0000000000011001')]) + +addop("dmuls", [bs('0011'), rn, rm, bs('1101')], [rm, rn]) +addop("dmulu", [bs('0011'), rn, rm, bs('0101')], [rm, rn]) + +addop("dt", [bs('0100'), rn, bs('00010000')]) + + +addop("extsb", [bs('0110'), rn, rm, bs('1110')], [rm, rn]) +addop("extsw", [bs('0110'), rn, rm, bs('1111')], [rm, rn]) +addop("extub", [bs('0110'), rn, rm, bs('1100')], [rm, rn]) +addop("extuw", [bs('0110'), rn, rm, bs('1101')], [rm, rn]) + +addop("mac_l", [bs('0000', fname='opc'), d32rnpinc, + d32rmpinc, bs('1111')], [d32rmpinc, d32rnpinc]) +addop("mac_w", [bs('0100', fname='opc'), d16rnpinc, + d16rmpinc, bs('1111')], [d16rmpinc, d16rnpinc]) + +addop("mull", [bs('0000'), rn, rm, bs('0111')], [rm, rn]) +addop("mulsw", [bs('0010'), rn, rm, bs('1111')], [rm, rn]) +addop("muluw", [bs('0010'), rn, rm, bs('1110')], [rm, rn]) + +addop("neg", [bs('0110'), rn, rm, bs('1011')], [rm, rn]) +addop("negc", [bs('0110'), rn, rm, bs('1010')], [rm, rn]) + +addop("sub", [bs('0011'), rn, rm, bs('1000')], [rm, rn]) +addop("subc", [bs('0011'), rn, rm, bs('1010')], [rm, rn]) +addop("subv", [bs('0011'), rn, rm, bs('1011')], [rm, rn]) + +addop("and", [bs('0010'), rn, rm, bs('1001')], [rm, rn]) +addop("and", [bs('11001001'), u08imm, bs_r0]) +addop("and_b", [bs('11001101'), u08imm, dr0gbr]) + +addop("not", [bs('0110'), rn, rm, bs('0111')], [rm, rn]) + +addop("or", [bs('0010'), rn, rm, bs('1011')], [rm, rn]) + +addop("or", [bs('11001011'), u08imm, bs_r0]) +addop("or_b", [bs('11001111'), u08imm, dr0gbr]) + +addop("tas_b", [bs('0100'), d08gpreg, bs('00011011')]) +addop("tst", [bs('0010'), rn, rm, bs('1000')], [rm, rn]) +addop("tst", [bs('11001000'), u08imm, bs_r0]) +addop("tst_b", [bs('11001100'), u08imm, dr0gbr]) + + +addop("xor", [bs('0010'), rn, rm, bs('1010')], [rm, rn]) +addop("xor", [bs('11001010'), u08imm, bs_r0]) +addop("xor_b", [bs('11001110'), u08imm, dr0gbr]) + +addop("rotl", [bs('0100'), rn, bs('00000100')]) +addop("rotr", [bs('0100'), rn, bs('00000101')]) +addop("rotcl", [bs('0100'), rn, bs('00100100')]) +addop("rotcr", [bs('0100'), rn, bs('00100101')]) + +addop("shad", [bs('0100'), rn, rm, bs('1100')], [rm, rn]) +addop("shal", [bs('0100'), rn, bs('00100000')]) +addop("shar", [bs('0100'), rn, bs('00100001')]) +addop("shld", [bs('0100'), rn, rm, bs('1101')], [rm, rn]) + +addop("shll", [bs('0100'), rn, bs('00000000')]) +addop("shlr", [bs('0100'), rn, bs('00000001')]) +addop("shll2", [bs('0100'), rn, bs('00001000')]) +addop("shlr2", [bs('0100'), rn, bs('00001001')]) +addop("shll8", [bs('0100'), rn, bs('00011000')]) +addop("shlr8", [bs('0100'), rn, bs('00011001')]) +addop("shll16", [bs('0100'), rn, bs('00101000')]) +addop("shlr16", [bs('0100'), rn, bs('00101001')]) + + +addop("bf", [bs('10001011'), s08imm]) +""" + def splitflow(self): + return True + def breakflow(self): + return True + def dstflow(self): + return True + def dstflow2label(self, loc_db): + e = self.args[0].expr + ad = e.arg*2+4+self.offset + l = loc_db.get_or_create_offset_location(ad) + s = ExprId(l, e.size) + self.args[0].expr = s +""" + +addop("bfs", [bs('10001111'), s08imm]) +""" + delayslot = 1 +""" +addop("bt", [bs('10001001'), s08imm]) + +addop("bts", [bs('10001101'), s08imm]) + +addop("bra", [bs('1010'), s12imm]) +""" + delayslot = 1 + def breakflow(self): + return True + def dstflow(self): + return True + def dstflow2label(self, loc_db): + e = self.args[0].expr + ad = e.arg*2+4+self.offset + l = loc_db.get_or_create_offset_location(ad) + s = ExprId(l, e.size) + self.args[0].expr = s +""" + +addop("braf", [bs('0000'), rn, bs('00100011')]) +""" + delayslot = 1 + def breakflow(self): + return True + def dstflow(self): + return True +""" +addop("bsr", [bs('1011'), s12imm]) + +addop("bsrf", [bs('0000'), rn, bs('00000011')]) +""" + delayslot = 1 + def breakflow(self): + return True + def is_subcall(self): + return True + def splitflow(self): + return True +""" + +addop("jmp_l", [bs('0100'), d32gpreg, bs('00101011')]) +""" + delayslot = 1 + def breakflow(self): + return True +""" + +addop("jsr_l", [bs('0100'), d32gpreg, bs('00001011')]) +""" + delayslot = 1 + def breakflow(self): + return True + def is_subcall(self): + return True + def splitflow(self): + return True +""" + +addop("rts", [bs('0000000000001011')]) +""" + delayslot = 1 + def breakflow(self): + return True +""" +addop("clrmac", [bs('0000000000101000')]) +addop("clrs", [bs('0000000001001000')]) +addop("clrt", [bs('0000000000001000')]) + + +addop("ldc", [bs('0100'), rm, bs_sr, bs('00001110')]) +addop("ldc", [bs('0100'), rm, bs_gbr, bs('00011110')]) +addop("ldc", [bs('0100'), rm, bs_vbr, bs('00101110')]) +addop("ldc", [bs('0100'), rm, bs_ssr, bs('00111110')]) +addop("ldc", [bs('0100'), rm, bs_spc, bs('01001110')]) +addop("ldc", [bs('0100'), rm, bs_dbr, bs('11111010')]) +addop("ldc", [bs('0100'), rm, bs('1'), brn, bs('1110')], [rm, brn]) +addop("ldc_l", [bs('0100'), d32rmpinc, bs_sr, bs('00000111')]) +addop("ldc_l", [bs('0100'), d32rmpinc, bs_gbr, bs('00010111')]) +addop("ldc_l", [bs('0100'), d32rmpinc, bs_vbr, bs('00100111')]) +addop("ldc_l", [bs('0100'), d32rmpinc, bs_ssr, bs('00110111')]) +addop("ldc_l", [bs('0100'), d32rmpinc, bs_spc, bs('01000111')]) +addop("ldc_l", [bs('0100'), d32rmpinc, bs_dbr, bs('11110110')]) +addop("ldc_l", [bs('0100'), d32rmpinc, bs('1'), brn, bs('0111')]) +addop("lds", [bs('0100'), rm, bs_mach, bs('00001010')]) +addop("lds", [bs('0100'), rm, bs_macl, bs('00011010')]) +addop("lds", [bs('0100'), rm, bs_pr, bs('00101010')]) +addop("lds_l", [bs('0100'), d32rmpinc, bs_mach, bs('00000110')]) +addop("lds_l", [bs('0100'), d32rmpinc, bs_macl, bs('00010110')]) +addop("lds_l", [bs('0100'), d32rmpinc, bs_pr, bs('00100110')]) +addop("ldtlb", [bs('0000000000111000')]) + +addop("movca_l", [bs('0000'), bs_r0, d32gpreg, bs('11000011')]) +addop("nop", [bs('0000000000001001')]) +addop("ocbi_l", [bs('0000'), d32gpreg, bs('10010011')]) +addop("ocbp_l", [bs('0000'), d32gpreg, bs('10100011')]) +addop("ocbwb_l", [bs('0000'), d32gpreg, bs('10110011')]) +addop("pref_l", [bs('0000'), d32gpreg, bs('10000011')]) + + +addop("rte", [bs('0000000000101011')]) +addop("sets", [bs('0000000001011000')]) +addop("sett", [bs('0000000000011000')]) +addop("sleep", [bs('0000000000011011')]) +addop("stc", [bs('0000'), bs_sr, rn, bs('00000010')]) +addop("stc", [bs('0000'), bs_gbr, rn, bs('00010010')]) +addop("stc", [bs('0000'), bs_vbr, rn, bs('00100010')]) +addop("stc", [bs('0000'), bs_ssr, rn, bs('00110010')]) +addop("stc", [bs('0000'), bs_spc, rn, bs('01000010')]) +addop("stc", [bs('0000'), bs_sgr, rn, bs('00111010')]) +addop("stc", [bs('0000'), bs_dbr, rn, bs('11111010')]) +addop("stc", [bs('0000'), rn, bs('1'), brm, bs('0010')], [brm, rn]) + +addop("stc_l", [bs('0100'), bs_sr, d32rmpdec, bs('00000011')]) +addop("stc_l", [bs('0100'), bs_gbr, d32rmpdec, bs('00010011')]) +addop("stc_l", [bs('0100'), bs_vbr, d32rmpdec, bs('00100011')]) +addop("stc_l", [bs('0100'), bs_ssr, d32rmpdec, bs('00110011')]) +addop("stc_l", [bs('0100'), bs_spc, d32rmpdec, bs('01000011')]) +addop("stc_l", [bs('0100'), bs_sgr, d32rmpdec, bs('00110010')]) +addop("stc_l", [bs('0100'), bs_dbr, d32rmpdec, bs('11110010')]) +addop("stc_l", + [bs('0100'), d32rnpdec, bs('1'), brm, bs('0011')], [brm, d32rnpdec]) + +# float +addop("sts", [bs('0000'), bs_mach, rm, bs('00001010')]) +addop("sts", [bs('0000'), bs_macl, rm, bs('00011010')]) +addop("sts", [bs('0000'), bs_pr, rm, bs('00101010')]) +addop("sts_l", [bs('0100'), bs_mach, d32rmpdec, bs('00000010')]) +addop("sts_l", [bs('0100'), bs_macl, d32rmpdec, bs('00010010')]) +addop("sts_l", + [bs('0100'), d32rnpdec, bs_pr, bs('00100010')], [bs_pr, d32rnpdec]) +addop("trapa", [bs('11000011'), u08imm]) + +addop("fldi0", [bs('1111'), frn, bs('10001101')]) +addop("fldi1", [bs('1111'), frn, bs('10011101')]) +addop("fmov", [bs('1111'), frn, frm, bs('1100')], [frm, frn]) +addop("fmov_s", [bs('1111'), frn, d32gpreg, bs('1000')], [d32gpreg, frn]) +addop("fmov_s", [bs('1111'), frn, bd32r0gp, bs('0110')], [bd32r0gp, frn]) +addop("fmov_s", [bs('1111'), frn, d32rmpinc, bs('1001')], [d32rmpinc, frn]) +addop("fmov_s", [bs('1111'), d32gpreg, frm, bs('1010')], [frm, d32gpreg]) +addop("fmov_s", [bs('1111'), d32rnpdec, frm, bs('1011')], [frm, d32rnpdec]) +addop("fmov_s", [bs('1111'), bd32r0gp, frm, bs('0111')], [frm, bd32r0gp]) + +addop("flds", [bs('1111'), frm, bs_fpul, bs('00011101')]) +addop("fsts", [bs('1111'), bs_fpul, frm, bs('00001101')]) +addop("fabs", [bs('1111'), frn, bs('01011101')]) +addop("fadd", [bs('1111'), frn, frm, bs('0000')], [frm, frn]) +addop("fcmpeq", [bs('1111'), frn, frm, bs('0100')], [frm, frn]) +addop("fcmpgt", [bs('1111'), frn, frm, bs('0101')], [frm, frn]) +addop("fdiv", [bs('1111'), frn, frm, bs('0011')], [frm, frn]) + +addop("float", [bs('1111'), bs_fpul, frn, bs('00101101')]) +addop("fmac", [bs('1111'), bs_fr0, frn, frm, bs('1110')], [bs_fr0, frm, frn]) +addop("fmul", [bs('1111'), frn, frm, bs('0010')], [frm, frn]) +addop("fneg", [bs('1111'), frn, bs('01001101')]) +addop("fsqrt", [bs('1111'), frn, bs('01101101')]) +addop("fsub", [bs('1111'), frn, frm, bs('0001')], [frm, frn]) +addop("ftrc", [bs('1111'), frm, bs_fpul, bs('00111101')]) diff --git a/src/miasm/arch/sh4/regs.py b/src/miasm/arch/sh4/regs.py new file mode 100644 index 00000000..8a7e1881 --- /dev/null +++ b/src/miasm/arch/sh4/regs.py @@ -0,0 +1,84 @@ +from builtins import range +from miasm.expression.expression import * +from miasm.core.cpu import reg_info, gen_reg + +# GP +gpregs_str = ['R%d' % r for r in range(0x10)] +gpregs_expr = [ExprId(x, 32) for x in gpregs_str] +gpregs = reg_info(gpregs_str, gpregs_expr) + +bgpregs_str = ['R%d_BANK' % r for r in range(0x8)] +bgpregs_expr = [ExprId(x, 32) for x in bgpregs_str] +bgpregs = reg_info(bgpregs_str, bgpregs_expr) + +fregs_str = ['FR%d' % r for r in range(0x10)] +fregs_expr = [ExprId(x, 32) for x in fregs_str] +fregs = reg_info(fregs_str, fregs_expr) + +dregs_str = ['DR%d' % r for r in range(0x8)] +dregs_expr = [ExprId(x, 32) for x in dregs_str] +dregs = reg_info(dregs_str, dregs_expr) + + +PC, reg_info_pc = gen_reg('PC') +PR, reg_info_pr = gen_reg('PR') +R0, reg_info_r0 = gen_reg('R0') +GBR, reg_info_gbr = gen_reg('GBR') +SR, reg_info_sr = gen_reg('SR') +VBR, reg_info_vbr = gen_reg('VBR') +SSR, reg_info_ssr = gen_reg('SSR') +SPC, reg_info_spc = gen_reg('SPC') +SGR, reg_info_sgr = gen_reg('SGR') +DBR, reg_info_dbr = gen_reg('DBR') +MACH, reg_info_mach = gen_reg('MACH') +MACL, reg_info_macl = gen_reg('MACL') +FPUL, reg_info_fpul = gen_reg('FPUL') +FR0, reg_info_fr0 = gen_reg('FR0') + +R0 = gpregs_expr[0] +R1 = gpregs_expr[1] +R2 = gpregs_expr[2] +R3 = gpregs_expr[3] +R4 = gpregs_expr[4] +R5 = gpregs_expr[5] +R6 = gpregs_expr[6] +R7 = gpregs_expr[7] +R8 = gpregs_expr[8] +R9 = gpregs_expr[9] +R10 = gpregs_expr[10] +R11 = gpregs_expr[11] +R12 = gpregs_expr[12] +R13 = gpregs_expr[13] +R14 = gpregs_expr[14] +R15 = gpregs_expr[15] + + +reg_zf = 'zf' +reg_nf = 'nf' +reg_of = 'of' +reg_cf = 'cf' + +zf = ExprId(reg_zf, size=1) +nf = ExprId(reg_nf, size=1) +of = ExprId(reg_of, size=1) +cf = ExprId(reg_cf, size=1) + + +all_regs_ids = [ + R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, + zf, nf, of, cf, + + PC, PR, R0, GBR, SR, VBR, SSR, SPC, + SGR, DBR, MACH, MACL, FPUL, FR0] + +all_regs_ids_no_alias = all_regs_ids + +all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) + +all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids] + +regs_init = {} +for i, r in enumerate(all_regs_ids): + regs_init[r] = all_regs_ids_init[i] + +regs_flt_expr = [] diff --git a/src/miasm/arch/x86/__init__.py b/src/miasm/arch/x86/__init__.py new file mode 100644 index 00000000..bbad893b --- /dev/null +++ b/src/miasm/arch/x86/__init__.py @@ -0,0 +1 @@ +__all__ = ["arch", "disasm", "regs", "sem"] diff --git a/src/miasm/arch/x86/arch.py b/src/miasm/arch/x86/arch.py new file mode 100644 index 00000000..5464a779 --- /dev/null +++ b/src/miasm/arch/x86/arch.py @@ -0,0 +1,4878 @@ +#-*- coding:utf-8 -*- + +from __future__ import print_function +from builtins import range +import re + +from future.utils import viewitems + +from miasm.core import utils +from miasm.expression.expression import * +from pyparsing import * +from miasm.core.cpu import * +from collections import defaultdict +import miasm.arch.x86.regs as regs_module +from miasm.arch.x86.regs import * +from miasm.core.asm_ast import AstNode, AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html +from miasm.core.utils import BRACKET_O, BRACKET_C + + +log = logging.getLogger("x86_arch") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.WARN) + +conditional_branch = ["JO", "JNO", "JB", "JAE", + "JZ", "JNZ", "JBE", "JA", + "JS", "JNS", "JPE", "JNP", + #"L", "NL", "NG", "G"] + "JL", "JGE", "JLE", "JG", + "JCXZ", "JECXZ", "JRCXZ"] + +unconditional_branch = ['JMP', 'JMPF'] + +f_isad = "AD" +f_s08 = "S08" +f_u08 = "U08" +f_s16 = "S16" +f_u16 = "U16" +f_s32 = "S32" +f_u32 = "U32" +f_s64 = "S64" +f_u64 = "U64" +f_imm = 'IMM' + +f_imm2size = {f_s08: 8, f_s16: 16, f_s32: 32, f_s64: 64, + f_u08: 8, f_u16: 16, f_u32: 32, f_u64: 64} + + +size2gpregs = {8: gpregs08, 16: gpregs16, + 32: gpregs32, 64: gpregs64} + + +replace_regs64 = { + AL: RAX[:8], CL: RCX[:8], DL: RDX[:8], BL: RBX[:8], + AH: RAX[8:16], CH: RCX[8:16], DH: RDX[8:16], BH: RBX[8:16], + SPL: RSP[0:8], BPL: RBP[0:8], SIL: RSI[0:8], DIL: RDI[0:8], + R8B: R8[0:8], R9B: R9[0:8], R10B: R10[0:8], R11B: R11[0:8], + R12B: R12[0:8], R13B: R13[0:8], R14B: R14[0:8], R15B: R15[0:8], + + AX: RAX[:16], CX: RCX[:16], DX: RDX[:16], BX: RBX[:16], + SP: RSP[:16], BP: RBP[:16], SI: RSI[:16], DI: RDI[:16], + R8W: R8[:16], R9W: R9[:16], R10W: R10[:16], R11W: R11[:16], + R12W: R12[:16], R13W: R13[:16], R14W: R14[:16], R15W: R15[:16], + + EAX: RAX[:32], ECX: RCX[:32], EDX: RDX[:32], EBX: RBX[:32], + ESP: RSP[:32], EBP: RBP[:32], ESI: RSI[:32], EDI: RDI[:32], + R8D: R8[:32], R9D: R9[:32], R10D: R10[:32], R11D: R11[:32], + R12D: R12[:32], R13D: R13[:32], R14D: R14[:32], R15D: R15[:32], + + IP: RIP[:16], EIP: RIP[:32], + + ExprId("ST", 64): float_st0, + ExprId("ST(0)", 64): float_st0, + ExprId("ST(1)", 64): float_st1, + ExprId("ST(2)", 64): float_st2, + ExprId("ST(3)", 64): float_st3, + ExprId("ST(4)", 64): float_st4, + ExprId("ST(5)", 64): float_st5, + ExprId("ST(6)", 64): float_st6, + ExprId("ST(7)", 64): float_st7, + +} + +replace_regs32 = { + AL: EAX[:8], CL: ECX[:8], DL: EDX[:8], BL: EBX[:8], + AH: EAX[8:16], CH: ECX[8:16], DH: EDX[8:16], BH: EBX[8:16], + + AX: EAX[:16], CX: ECX[:16], DX: EDX[:16], BX: EBX[:16], + SP: ESP[:16], BP: EBP[:16], SI: ESI[:16], DI: EDI[:16], + + IP: EIP[:16], + + + ExprId("ST", 64): float_st0, + ExprId("ST(0)", 64): float_st0, + ExprId("ST(1)", 64): float_st1, + ExprId("ST(2)", 64): float_st2, + ExprId("ST(3)", 64): float_st3, + ExprId("ST(4)", 64): float_st4, + ExprId("ST(5)", 64): float_st5, + ExprId("ST(6)", 64): float_st6, + ExprId("ST(7)", 64): float_st7, + +} + +replace_regs16 = { + AL: AX[:8], CL: CX[:8], DL: DX[:8], BL: BX[:8], + AH: AX[8:16], CH: CX[8:16], DH: DX[8:16], BH: BX[8:16], + + AX: AX[:16], CX: CX[:16], DX: DX[:16], BX: BX[:16], + SP: SP[:16], BP: BP[:16], SI: SI[:16], DI: DI[:16], + + + ExprId("ST", 64): float_st0, + ExprId("ST(0)", 64): float_st0, + ExprId("ST(1)", 64): float_st1, + ExprId("ST(2)", 64): float_st2, + ExprId("ST(3)", 64): float_st3, + ExprId("ST(4)", 64): float_st4, + ExprId("ST(5)", 64): float_st5, + ExprId("ST(6)", 64): float_st6, + ExprId("ST(7)", 64): float_st7, + +} + +replace_regs = {16: replace_regs16, + 32: replace_regs32, + 64: replace_regs64} + + +segm2enc = {CS: 1, SS: 2, DS: 3, ES: 4, FS: 5, GS: 6} +enc2segm = dict((value, key) for key, value in viewitems(segm2enc)) + +segm_info = reg_info_dct(enc2segm) + + + +enc2crx = { + 0: cr0, + 1: cr1, + 2: cr2, + 3: cr3, + 4: cr4, + 5: cr5, + 6: cr6, + 7: cr7, +} + +crx_info = reg_info_dct(enc2crx) + + +enc2drx = { + 0: dr0, + 1: dr1, + 2: dr2, + 3: dr3, + 4: dr4, + 5: dr5, + 6: dr6, + 7: dr7, +} + +drx_info = reg_info_dct(enc2drx) + + + +# parser helper ########### +PLUS = Suppress("+") +MULT = Suppress("*") + +COLON = Suppress(":") + + +LBRACK = Suppress("[") +RBRACK = Suppress("]") + + +gpreg = ( + gpregs08.parser | + gpregs08_64.parser | + gpregs16.parser | + gpregs32.parser | + gpregs64.parser | + gpregs_xmm.parser | + gpregs_mm.parser | + gpregs_bnd.parser +) + + +def is_op_segm(expr): + """Returns True if is ExprOp and op == 'segm'""" + return expr.is_op('segm') + +def is_mem_segm(expr): + """Returns True if is ExprMem and ptr is_op_segm""" + return expr.is_mem() and is_op_segm(expr.ptr) + + +def cb_deref_segmoff(tokens): + assert len(tokens) == 2 + return AstOp('segm', tokens[0], tokens[1]) + + +def cb_deref_base_expr(tokens): + tokens = tokens[0] + assert isinstance(tokens, AstNode) + addr = tokens + return addr + + +deref_mem_ad = (LBRACK + base_expr + RBRACK).setParseAction(cb_deref_base_expr) + +deref_ptr = (base_expr + COLON + base_expr).setParseAction(cb_deref_segmoff) + + +PTR = Suppress('PTR') + +FAR = Suppress('FAR') + + +BYTE = Literal('BYTE') +WORD = Literal('WORD') +DWORD = Literal('DWORD') +QWORD = Literal('QWORD') +TBYTE = Literal('TBYTE') +XMMWORD = Literal('XMMWORD') + +MEMPREFIX2SIZE = {'BYTE': 8, 'WORD': 16, 'DWORD': 32, + 'QWORD': 64, 'TBYTE': 80, 'XMMWORD': 128} + +SIZE2MEMPREFIX = dict((value, key) for key, value in viewitems(MEMPREFIX2SIZE)) + +def cb_deref_mem(tokens): + if len(tokens) == 2: + s, ptr = tokens + assert isinstance(ptr, AstNode) + return AstMem(ptr, MEMPREFIX2SIZE[s]) + elif len(tokens) == 3: + s, segm, ptr = tokens + return AstMem(AstOp('segm', segm, ptr), MEMPREFIX2SIZE[s]) + raise ValueError('len(tokens) > 3') + +mem_size = (BYTE | DWORD | QWORD | WORD | TBYTE | XMMWORD) +deref_mem = (mem_size + PTR + Optional((base_expr + COLON))+ deref_mem_ad).setParseAction(cb_deref_mem) + + +rmarg = ( + gpregs08.parser | + gpregs08_64.parser | + gpregs16.parser | + gpregs32.parser | + gpregs64.parser | + gpregs_mm.parser | + gpregs_xmm.parser | + gpregs_bnd.parser +) + +rmarg |= deref_mem + + +mem_far = FAR + deref_mem + + +cl_or_imm = r08_ecx.parser +cl_or_imm |= base_expr + + + +class x86_arg(m_arg): + def asm_ast_to_expr(self, value, loc_db, size_hint=None, fixed_size=None): + if size_hint is None: + size_hint = self.parent.mode + if fixed_size is None: + fixed_size = set() + if isinstance(value, AstId): + if value.name in all_regs_ids_byname: + reg = all_regs_ids_byname[value.name] + fixed_size.add(reg.size) + return reg + if isinstance(value.name, ExprId): + fixed_size.add(value.name.size) + return value.name + if value.name in MEMPREFIX2SIZE: + return None + if value.name in ["FAR"]: + return None + + loc_key = loc_db.get_or_create_name_location(value.name) + return ExprLoc(loc_key, size_hint) + if isinstance(value, AstOp): + # First pass to retrieve fixed_size + if value.op == "segm": + segm = self.asm_ast_to_expr(value.args[0], loc_db) + ptr = self.asm_ast_to_expr(value.args[1], loc_db, None, fixed_size) + return ExprOp('segm', segm, ptr) + args = [self.asm_ast_to_expr(arg, loc_db, None, fixed_size) for arg in value.args] + if len(fixed_size) == 0: + # No fixed size + pass + elif len(fixed_size) == 1: + # One fixed size, regen all + size = list(fixed_size)[0] + args = [self.asm_ast_to_expr(arg, loc_db, size, fixed_size) for arg in value.args] + else: + raise ValueError("Size conflict") + if None in args: + return None + return ExprOp(value.op, *args) + if isinstance(value, AstInt): + if 1 << size_hint < value.value: + size_hint *= 2 + return ExprInt(value.value, size_hint) + if isinstance(value, AstMem): + fixed_size.add(value.size) + ptr = self.asm_ast_to_expr(value.ptr, loc_db, None, set()) + if ptr is None: + return None + return ExprMem(ptr, value.size) + return None + +class r_al(reg_noarg, x86_arg): + reg_info = r08_eax + parser = reg_info.parser + + +class r_ax(reg_noarg, x86_arg): + reg_info = r16_eax + parser = reg_info.parser + + +class r_dx(reg_noarg, x86_arg): + reg_info = r16_edx + parser = reg_info.parser + + +class r_eax(reg_noarg, x86_arg): + reg_info = r32_eax + parser = reg_info.parser + + +class r_rax(reg_noarg, x86_arg): + reg_info = r64_eax + parser = reg_info.parser + + +class r_cl(reg_noarg, x86_arg): + reg_info = r08_ecx + parser = reg_info.parser + + +invmode = {16: 32, 32: 16} + + +def opmode_prefix(mode): + size, opmode, admode = mode + if size in [16, 32]: + if opmode: + return invmode[size] + else: + return size + elif size == 64: + if opmode: + return 16 + else: + return 32 + raise NotImplementedError('not fully functional') + + +def admode_prefix(mode): + size, opmode, admode = mode + if size in [16, 32]: + if admode: + return invmode[size] + else: + return size + elif size == 64: + return 64 + raise NotImplementedError('not fully functional') + + +def v_opmode_info(size, opmode, rex_w, stk): + if size in [16, 32]: + if opmode: + return invmode[size] + else: + return size + elif size == 64: + # Rex has the maximum priority + # Then opmode + # Then stacker + if rex_w == 1: + return 64 + elif opmode == 1: + return 16 + elif stk: + return 64 + else: + return 32 + + +def v_opmode(p): + stk = hasattr(p, 'stk') + return v_opmode_info(p.mode, p.opmode, p.rex_w.value, stk) + + +def v_admode_info(size, admode): + if size in [16, 32]: + if admode: + return invmode[size] + else: + return size + elif size == 64: + if admode == 1: + return 32 + return 64 + + +def v_admode(p): + return v_admode_info(p.mode, p.admode) + + +def offsize(p): + if p.opmode: + return 16 + else: + return p.mode + + +def get_prefix(s): + g = re.search(r'(\S+)(\s+)', s) + if not g: + return None, s + prefix, b = g.groups() + return prefix, s[len(prefix) + len(b):] + + +repeat_mn = ["INS", "OUTS", + "MOVSB", "MOVSW", "MOVSD", "MOVSQ", + "SCASB", "SCASW", "SCASD", "SCASQ", + "LODSB", "LODSW", "LODSD", "LODSQ", + "STOSB", "STOSW", "STOSD", "STOSQ", + "CMPSB", "CMPSW", "CMPSD", "CMPSQ", + ] + + +class group(object): + + def __init__(self): + self.value = None + + +class additional_info(object): + + def __init__(self): + self.except_on_instr = False + self.g1 = group() + self.g2 = group() + self.vopmode = None + self.stk = False + self.v_opmode = None + self.v_admode = None + self.prefixed = b'' + + +class instruction_x86(instruction): + __slots__ = [] + + def __init__(self, *args, **kargs): + super(instruction_x86, self).__init__(*args, **kargs) + + def v_opmode(self): + return self.additional_info.v_opmode + + def v_admode(self): + return self.additional_info.v_admode + + def dstflow(self): + if self.name in conditional_branch + unconditional_branch: + return True + if self.name.startswith('LOOP'): + return True + return self.name in ['CALL'] + + def dstflow2label(self, loc_db): + if self.additional_info.g1.value & 14 and self.name in repeat_mn: + return + expr = self.args[0] + if not expr.is_int(): + return + addr = (int(expr) + int(self.offset)) & int(expr.mask) + loc_key = loc_db.get_or_create_offset_location(addr) + self.args[0] = ExprLoc(loc_key, expr.size) + + def breakflow(self): + if self.name in conditional_branch + unconditional_branch: + return True + if self.name.startswith('LOOP'): + return True + if self.name.startswith('RET'): + return True + if self.name.startswith('INT'): + return True + if self.name.startswith('SYS'): + return True + return self.name in ['CALL', 'HLT', 'IRET', 'IRETD', 'IRETQ', 'ICEBP', 'UD2'] + + def splitflow(self): + if self.name in conditional_branch: + return True + if self.name in unconditional_branch: + return False + if self.name.startswith('LOOP'): + return True + if self.name.startswith('INT'): + return True + if self.name.startswith('SYS'): + return True + return self.name in ['CALL'] + + def setdstflow(self, a): + return + + def is_subcall(self): + return self.name in ['CALL'] + + def getdstflow(self, loc_db): + if self.additional_info.g1.value & 14 and self.name in repeat_mn: + addr = int(self.offset) + loc_key = loc_db.get_or_create_offset_location(addr) + return [ExprLoc(loc_key, self.v_opmode())] + return [self.args[0]] + + def get_symbol_size(self, symbol, loc_db): + return self.mode + + def fixDstOffset(self): + expr = self.args[0] + if self.offset is None: + raise ValueError('symbol not resolved %s' % l) + if not isinstance(expr, ExprInt): + log.warning('dynamic dst %r', expr) + return + self.args[0] = ExprInt(int(expr) - self.offset, self.mode) + + def get_info(self, c): + self.additional_info.g1.value = c.g1.value + self.additional_info.g2.value = c.g2.value + self.additional_info.stk = hasattr(c, 'stk') + self.additional_info.v_opmode = c.v_opmode() + self.additional_info.v_admode = c.v_admode() + self.additional_info.prefix = c.prefix + self.additional_info.prefixed = getattr(c, "prefixed", b"") + + def __str__(self): + return self.to_string() + + def to_string(self, loc_db=None): + o = super(instruction_x86, self).to_string(loc_db) + if self.additional_info.g1.value & 1: + o = "LOCK %s" % o + if self.additional_info.g1.value & 2: + if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF2": + o = "REPNE %s" % o + if self.additional_info.g1.value & 8: + if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3": + o = "REP %s" % o + elif self.additional_info.g1.value & 4: + if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3": + o = "REPE %s" % o + return o + + def to_html(self, loc_db=None): + o = super(instruction_x86, self).to_html(loc_db) + if self.additional_info.g1.value & 1: + text = utils.set_html_text_color("LOCK", utils.COLOR_MNEMO) + o = "%s %s" % (text, o) + if self.additional_info.g1.value & 2: + if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF2": + text = utils.set_html_text_color("REPNE", utils.COLOR_MNEMO) + o = "%s %s" % (text, o) + if self.additional_info.g1.value & 8: + if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3": + text = utils.set_html_text_color("REP", utils.COLOR_MNEMO) + o = "%s %s" % (text, o) + elif self.additional_info.g1.value & 4: + if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3": + text = utils.set_html_text_color("REPE", utils.COLOR_MNEMO) + o = "%s %s" % (text, o) + return o + + + def get_args_expr(self): + args = [] + for a in self.args: + a = a.replace_expr(replace_regs[self.mode]) + args.append(a) + return args + + @staticmethod + def arg2str(expr, index=None, loc_db=None): + if expr.is_id() or expr.is_int(): + o = str(expr) + elif expr.is_loc(): + if loc_db is not None: + o = loc_db.pretty_str(expr.loc_key) + else: + o = str(expr) + elif ((isinstance(expr, ExprOp) and expr.op == 'far' and + isinstance(expr.args[0], ExprMem)) or + isinstance(expr, ExprMem)): + if isinstance(expr, ExprOp): + prefix, expr = "FAR ", expr.args[0] + else: + prefix = "" + sz = SIZE2MEMPREFIX[expr.size] + segm = "" + if is_mem_segm(expr): + segm = "%s:" % expr.ptr.args[0] + expr = expr.ptr.args[1] + else: + expr = expr.ptr + if isinstance(expr, ExprOp): + s = str(expr).replace('(', '').replace(')', '') + else: + s = str(expr) + o = prefix + sz + ' PTR ' + str(segm) + '[%s]' % s + elif isinstance(expr, ExprOp) and expr.op == 'segm': + o = "%s:%s" % (expr.args[0], expr.args[1]) + else: + raise ValueError('check this %r' % expr) + return "%s" % o + + + @staticmethod + def arg2html(expr, index=None, loc_db=None): + if expr.is_id() or expr.is_int() or expr.is_loc(): + o = color_expr_html(expr, loc_db) + elif ((isinstance(expr, ExprOp) and expr.op == 'far' and + isinstance(expr.args[0], ExprMem)) or + isinstance(expr, ExprMem)): + if isinstance(expr, ExprOp): + prefix, expr = "FAR ", expr.args[0] + else: + prefix = "" + sz = SIZE2MEMPREFIX[expr.size] + sz = '<font color="%s">%s</font>' % (utils.COLOR_MEM, sz) + segm = "" + if is_mem_segm(expr): + segm = "%s:" % expr.ptr.args[0] + expr = expr.ptr.args[1] + else: + expr = expr.ptr + if isinstance(expr, ExprOp): + s = color_expr_html(expr, loc_db)#.replace('(', '').replace(')', '') + else: + s = color_expr_html(expr, loc_db) + o = prefix + sz + ' PTR ' + str(segm) + BRACKET_O + str(s) + BRACKET_C + elif isinstance(expr, ExprOp) and expr.op == 'segm': + o = "%s:%s" % ( + color_expr_html(expr.args[0], loc_db), + color_expr_html(expr.args[1], loc_db) + ) + else: + raise ValueError('check this %r' % expr) + return "%s" % o + + + +class mn_x86(cls_mn): + name = "x86" + prefix_op_size = False + prefix_ad_size = False + regs = regs_module + all_mn = [] + all_mn_mode = defaultdict(list) + all_mn_name = defaultdict(list) + all_mn_inst = defaultdict(list) + bintree = {} + num = 0 + delayslot = 0 + pc = {16: IP, 32: EIP, 64: RIP} + sp = {16: SP, 32: ESP, 64: RSP} + instruction = instruction_x86 + max_instruction_len = 15 + + @classmethod + def getpc(cls, attrib): + return cls.pc[attrib] + + @classmethod + def getsp(cls, attrib): + return cls.sp[attrib] + + def v_opmode(self): + if hasattr(self, 'stk'): + stk = 1 + else: + stk = 0 + return v_opmode_info(self.mode, self.opmode, self.rex_w.value, stk) + + def v_admode(self): + size, opmode, admode = self.mode, self.opmode, self.admode + if size in [16, 32]: + if admode: + return invmode[size] + else: + return size + elif size == 64: + if admode == 1: + return 32 + return 64 + + def additional_info(self): + info = additional_info() + info.g1.value = self.g1.value + info.g2.value = self.g2.value + info.stk = hasattr(self, 'stk') + info.v_opmode = self.v_opmode() + info.prefixed = b"" + if hasattr(self, 'prefixed'): + info.prefixed = self.prefixed.default + return info + + @classmethod + def check_mnemo(cls, fields): + pass + + @classmethod + def getmn(cls, name): + return name.upper() + + @classmethod + def mod_fields(cls, fields): + prefix = [d_g1, d_g2, d_rex_p, d_rex_w, d_rex_r, d_rex_x, d_rex_b, d_vex, d_vex_l, d_vex_p, d_vex_v, d_vex_m] + return prefix + fields + + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + dct['mode'] = None + return [(subcls, name, bases, dct, fields)] + + @classmethod + def fromstring(cls, text, loc_db, mode): + pref = 0 + prefix, new_s = get_prefix(text) + if prefix == "LOCK": + pref |= 1 + text = new_s + elif prefix == "REPNE" or prefix == "REPNZ": + pref |= 2 + text = new_s + elif prefix == "REPE" or prefix == "REPZ": + pref |= 4 + text = new_s + elif prefix == "REP": + pref |= 8 + text = new_s + c = super(mn_x86, cls).fromstring(text, loc_db, mode) + c.additional_info.g1.value = pref + return c + + @classmethod + def pre_dis(cls, v, mode, offset): + offset_o = offset + pre_dis_info = {'opmode': 0, + 'admode': 0, + 'g1': 0, + 'g2': 0, + 'rex_p': 0, + 'rex_w': 0, + 'rex_r': 0, + 'rex_x': 0, + 'rex_b': 0, + 'vex_l': 0, + 'vex_p': 0, + 'vex_v': 0, + 'vex_m': 0, + 'vex' : 0, + 'prefix': b"", + 'prefixed': b"", + } + while True: + c = v.getbytes(offset) + if c == b'\x66': + pre_dis_info['opmode'] = 1 + elif c == b'\x67': + pre_dis_info['admode'] = 1 + elif c == b'\xf0': + pre_dis_info['g1'] = 1 + elif c == b'\xf2': + pre_dis_info['g1'] = 2 + elif c == b'\xf3': + pre_dis_info['g1'] = 12 + + elif c == b'\x2e': + pre_dis_info['g2'] = 1 + elif c == b'\x36': + pre_dis_info['g2'] = 2 + elif c == b'\x3e': + pre_dis_info['g2'] = 3 + elif c == b'\x26': + pre_dis_info['g2'] = 4 + elif c == b'\x64': + pre_dis_info['g2'] = 5 + elif c == b'\x65': + pre_dis_info['g2'] = 6 + + else: + break + pre_dis_info['prefix'] += c + offset += 1 + vex3_prefix = b'\xc4' + vex2_prefix = b'\xc5' + rex_prefixes = b'@ABCDEFGHIJKLMNO' + if mode == 64 and c in rex_prefixes: + while c in rex_prefixes: + # multiple REX prefixes case - use last REX prefix + x = ord(c) + offset += 1 + c = v.getbytes(offset) + pre_dis_info['rex_p'] = 1 + pre_dis_info['rex_w'] = (x >> 3) & 1 + pre_dis_info['rex_r'] = (x >> 2) & 1 + pre_dis_info['rex_x'] = (x >> 1) & 1 + pre_dis_info['rex_b'] = (x >> 0) & 1 + elif mode == 64 and c == vex3_prefix: + offset += 1 + c = ord(v.getbytes(offset)) + pre_dis_info['vex'] = 1 + pre_dis_info['rex_r'] = ((c >> 7) ^ 1) & 1 + pre_dis_info['rex_x'] = ((c >> 6) ^ 1) & 1 + pre_dis_info['rex_b'] = ((c >> 5) ^ 1) & 1 + pre_dis_info['vex_m'] = (c & int('0b11111', 2)) + + offset += 1 + c = ord(v.getbytes(offset)) + pre_dis_info['rex_w'] = (c >> 7) & 1 + pre_dis_info['vex_v'] = ((c >> 3) ^ 15) & 15 + pre_dis_info['vex_l'] = (c >> 2) & 1 + pre_dis_info['vex_p'] = c & int('0b11', 2) + offset += 1 + + if pre_dis_info['vex_p'] == 1: + pre_dis_info['opmode'] = 1 + elif pre_dis_info['vex_p'] == 3: + pre_dis_info['g1'] = 2 + elif pre_dis_info['vex_p'] == 2: + pre_dis_info['g1'] = 12 + + elif mode == 64 and c == vex2_prefix and v.getlen() > 2: + offset += 1 + c = ord(v.getbytes(offset)) + pre_dis_info['vex'] = 1 + pre_dis_info['rex_r'] = ((c >> 7) ^ 1) & 1 + pre_dis_info['rex_x'] = 0 + pre_dis_info['rex_b'] = 0 + pre_dis_info['rex_w'] = 0 + pre_dis_info['vex_l'] = (c >> 2) & 1 + pre_dis_info['vex_p'] = c & int('0b11', 2) + offset += 1 + + if pre_dis_info['vex_p'] == 1: + pre_dis_info['opmode'] = 1 + elif pre_dis_info['vex_p'] == 3: + pre_dis_info['g1'] = 2 + elif pre_dis_info['vex_p'] == 2: + pre_dis_info['g1'] = 12 + + elif pre_dis_info.get('g1', None) == 12 and c in [b'\xa6', b'\xa7', b'\xae', b'\xaf']: + pre_dis_info['g1'] = 4 + return pre_dis_info, v, mode, offset, offset - offset_o + + @classmethod + def get_cls_instance(cls, cc, mode, infos=None): + for opmode in [0, 1]: + for admode in [0, 1]: + c = cc() + c.init_class() + + c.reset_class() + c.add_pre_dis_info() + c.dup_info(infos) + c.mode = mode + c.opmode = opmode + c.admode = admode + + if not hasattr(c, 'stk') and hasattr(c, "fopmode") and c.fopmode.mode == 64: + c.rex_w.value = 1 + yield c + + def post_dis(self): + if self.g2.value: + for a in self.args: + if not isinstance(a.expr, ExprMem): + continue + m = a.expr + a.expr = ExprMem( + ExprOp('segm', enc2segm[self.g2.value], m.ptr), m.size) + return self + + def dup_info(self, infos): + if infos is not None: + self.g1.value = infos.g1.value + self.g2.value = infos.g2.value + + def reset_class(self): + super(mn_x86, self).reset_class() + if hasattr(self, "opmode"): + del(self.opmode) + if hasattr(self, "admode"): + del(self.admode) + + def add_pre_dis_info(self, pre_dis_info=None): + if pre_dis_info is None: + return True + if hasattr(self, "prefixed") and self.prefixed.default == b"\x66": + pre_dis_info['opmode'] = 0 + self.opmode = pre_dis_info['opmode'] + self.admode = pre_dis_info['admode'] + + if hasattr(self, 'no_xmm_pref') and\ + pre_dis_info['prefix'] and\ + pre_dis_info['prefix'][-1] in b'\x66\xf2\xf3': + return False + if (hasattr(self, "prefixed") and + not pre_dis_info['prefix'].endswith(self.prefixed.default)): + return False + if (self.rex_w.value is not None and + self.rex_w.value != pre_dis_info['rex_w']): + return False + else: + self.rex_w.value = pre_dis_info['rex_w'] + self.rex_r.value = pre_dis_info['rex_r'] + self.rex_b.value = pre_dis_info['rex_b'] + self.rex_x.value = pre_dis_info['rex_x'] + self.rex_p.value = pre_dis_info['rex_p'] + + self.vex.value = pre_dis_info['vex'] + self.vex_l.value = pre_dis_info['vex_l'] + self.vex_p.value = pre_dis_info['vex_p'] + self.vex_v.value = pre_dis_info['vex_v'] + self.vex_m.value = pre_dis_info['vex_m'] + + if hasattr(self, 'no_rex') and\ + (self.rex_r.value or self.rex_b.value or + self.rex_x.value or self.rex_p.value): + return False + + if self.vex.value == 0 and (hasattr(self, 'pref_0f') + or hasattr(self, 'pref_0f38') + or hasattr(self, 'pref_0f3a')): + return False + + if hasattr(self, 'no_rep') and b'\xf3' in pre_dis_info['prefix']: + return False + + if self.vex_m.value == 1 and not hasattr(self, 'pref_0f'): + return False + if self.vex_m.value == 2 and not hasattr(self, 'pref_0f38'): + return False + if self.vex_m.value == 3 and not hasattr(self, 'pref_0f3a'): + return False + + self.g1.value = pre_dis_info['g1'] + self.g2.value = pre_dis_info['g2'] + self.prefix = pre_dis_info['prefix'] + return True + + def post_asm(self, v): + return v + + + def gen_prefix(self): + v = b"" + rex = 0x40 + if self.g1.value is None: + self.g1.value = 0 + if self.g2.value is None: + self.g2.value = 0 + + if self.rex_w.value: + rex |= 0x8 + if self.rex_r.value: + rex |= 0x4 + if self.rex_x.value: + rex |= 0x2 + if self.rex_b.value: + rex |= 0x1 + if (rex != 0x40 and not self.vex.value) or self.rex_p.value == 1: + v = utils.int_to_byte(rex) + v + if hasattr(self, 'no_rex'): + return None + + vex_byte1 = 0xc4 + vex_byte2 = 0x00 + vex_byte3 = 0x00 + + m_prefix = [field.fname for field in self.fields_order if 'pref_0f' in field.fname] + if m_prefix: + if m_prefix[0] == 'pref_0f': + vex_byte2 |= 0x01 + elif m_prefix[0] == 'pref_0f38': + vex_byte2 |= 0x02 + elif m_prefix[0] == 'pref_0f3a': + vex_byte2 |= 0x03 + + # TODO: L and p + if m_prefix and m_prefix[0] == 'pref_0f' and not self.rex_w.value and not self.rex_b.value and ((hasattr(self, 'mod') and self.mod.value == 3) or not self.rex_x.value): # VEX2 + print("test") + vex_version = 2 + vex_byte1 = 0x00 + vex_byte2 = 0xc5 + + if not hasattr(self, 'reg') or not self.rex_r.value: + vex_byte3 |= 0x80 + + else: + vex_version = 3 + if not hasattr(self, 'reg') or not self.rex_r.value: + vex_byte2 |= 0x80 + if (hasattr(self, 'mod') and self.mod.value == 3) or not self.rex_x.value: + vex_byte2 |= 0x40 + if not self.rex_b.value: + vex_byte2 |= 0x20 + + if self.rex_w.value: + vex_byte3 |= 0x80 + + if self.vex.value == 1: + vex_byte3 |= ((15 - self.vex_v.value) << 3) + vex = (vex_byte1 << 16) | (vex_byte2 << 8) | vex_byte3 + v = vex.to_bytes(vex_version, 'big') + v + + if hasattr(self, 'prefixed'): + v = self.prefixed.default + v + + if self.g1.value & 1: + v = b"\xf0" + v + if self.g1.value & 2: + if hasattr(self, 'no_xmm_pref'): + return None + v = b"\xf2" + v + if self.g1.value & 12: + if hasattr(self, 'no_xmm_pref'): + return None + v = b"\xf3" + v + if self.g2.value: + v = { + 1: b'\x2e', + 2: b'\x36', + 3: b'\x3e', + 4: b'\x26', + 5: b'\x64', + 6: b'\x65' + }[self.g2.value] + v + # mode prefix + if hasattr(self, "admode") and self.admode: + v = b"\x67" + v + + if hasattr(self, "opmode") and self.opmode: + if hasattr(self, 'no_xmm_pref'): + return None + v = b"\x66" + v + return v + + def encodefields(self, decoded): + v = super(mn_x86, self).encodefields(decoded) + prefix = self.gen_prefix() + if prefix is None: + return None + return prefix + v + + def getnextflow(self, loc_db): + raise NotImplementedError('not fully functional') + + def ir_pre_instruction(self): + return [ExprAssign(mRIP[self.mode], + ExprInt(self.offset + self.l, mRIP[self.mode].size))] + + @classmethod + def filter_asm_candidates(cls, instr, candidates): + + cand_same_mode = [] + cand_diff_mode = [] + out = [] + for c, v in candidates: + if (hasattr(c, 'no_xmm_pref') and + (c.g1.value & 2 or c.g1.value & 4 or c.g1.value & 8 or c.opmode)): + continue + if hasattr(c, "fopmode") and v_opmode(c) != c.fopmode.mode: + continue + if hasattr(c, "fadmode") and v_admode(c) != c.fadmode.mode: + continue + # relative dstflow must not have opmode set + # (assign IP instead of EIP for instance) + if (instr.dstflow() and + instr.name not in ["JCXZ", "JECXZ", "JRCXZ"] and + len(instr.args) == 1 and + isinstance(instr.args[0], ExprInt) and c.opmode): + continue + + out.append((c, v)) + candidates = out + for c, v in candidates: + if v_opmode(c) == instr.mode: + cand_same_mode += v + for c, v in candidates: + if v_opmode(c) != instr.mode: + cand_diff_mode += v + cand_same_mode.sort(key=len) + cand_diff_mode.sort(key=len) + return cand_same_mode + cand_diff_mode + + +class bs_modname_size(bs_divert): + prio = 1 + + def divert(self, i, candidates): + out = [] + for candidate in candidates: + cls, name, bases, dct, fields = candidate + fopmode = opmode_prefix( + (dct['mode'], dct['opmode'], dct['admode'])) + mode = dct['mode'] + size, opmode, admode = dct['mode'], dct['opmode'], dct['admode'] + # no mode64 exinstance in name means no 64bit version of mnemo + if mode == 64: + if mode in self.args['name']: + nfields = fields[:] + f, i = getfieldindexby_name(nfields, 'rex_w') + f = bs("1", l=0, cls=(bs_fbit,), fname="rex_w") + osize = v_opmode_info(size, opmode, 1, 0) + nfields[i] = f + nfields = nfields[:-1] + ndct = dict(dct) + if osize in self.args['name']: + ndct['name'] = self.args['name'][osize] + out.append((cls, ndct['name'], bases, ndct, nfields)) + + nfields = fields[:] + nfields = nfields[:-1] + f, i = getfieldindexby_name(nfields, 'rex_w') + f = bs("0", l=0, cls=(bs_fbit,), fname="rex_w") + osize = v_opmode_info(size, opmode, 0, 0) + nfields[i] = f + ndct = dict(dct) + if osize in self.args['name']: + ndct['name'] = self.args['name'][osize] + out.append((cls, ndct['name'], bases, ndct, nfields)) + else: + l = opmode_prefix((dct['mode'], dct['opmode'], dct['admode'])) + osize = v_opmode_info(size, opmode, None, 0) + nfields = fields[:-1] + ndct = dict(dct) + if osize in self.args['name']: + ndct['name'] = self.args['name'][osize] + out.append((cls, ndct['name'], bases, ndct, nfields)) + return out + + +class bs_modname_jecx(bs_divert): + prio = 1 + + def divert(self, i, candidates): + out = [] + for candidate in candidates: + cls, name, bases, dct, fields = candidate + fopmode = opmode_prefix( + (dct['mode'], dct['opmode'], dct['admode'])) + mode = dct['mode'] + size, opmode, admode = dct['mode'], dct['opmode'], dct['admode'] + + nfields = fields[:] + nfields = nfields[:-1] + args = dict(self.args) + ndct = dict(dct) + if mode == 64: + if admode: + ndct['name'] = "JECXZ" + else: + ndct['name'] = "JRCXZ" + elif mode == 32: + if admode: + ndct['name'] = "JCXZ" + else: + ndct['name'] = "JECXZ" + elif mode == 16: + if admode: + ndct['name'] = "JECXZ" + else: + ndct['name'] = "JCXZ" + else: + raise ValueError('unhandled mode') + out.append((cls, ndct['name'], bases, ndct, nfields)) + return out + + +class bs_modname_mode(bs_divert): + prio = 1 + + def divert(self, i, candidates): + out = [] + for candidate in candidates: + cls, name, bases, dct, fields = candidate + fopmode = opmode_prefix( + (dct['mode'], dct['opmode'], dct['admode'])) + size, opmode, admode = dct['mode'], dct['opmode'], dct['admode'] + + mode = dct['mode'] + l = opmode_prefix((dct['mode'], dct['opmode'], dct['admode'])) + osize = v_opmode_info(size, opmode, None, 0) + nfields = fields[:-1] + args = dict(self.args) + ndct = dict(dct) + if mode == 64 or osize == 32: + ndct['name'] = self.args['name'][mode] + else: + ndct['name'] = self.args['name'][16] + out.append((cls, ndct['name'], bases, ndct, nfields)) + return out + + +class x86_imm(imm_noarg): + parser = base_expr + + def decodeval(self, v): + return swap_uint(self.l, v) + + def encodeval(self, v): + return swap_uint(self.l, v) + + +class x86_imm_fix_08(imm_noarg): + parser = base_expr + intsize = 8 + intmask = (1 << intsize) - 1 + + def decodeval(self, v): + return self.ival + + def encode(self): + v = self.expr2int(self.expr) + if v != self.ival: + return False + self.value = 0 + return True + + +class x86_08(x86_imm): + intsize = 8 + intmask = (1 << intsize) - 1 + + +class x86_16(x86_imm): + intsize = 16 + intmask = (1 << intsize) - 1 + + +class x86_32(x86_imm): + intsize = 32 + intmask = (1 << intsize) - 1 + + +class x86_64(x86_imm): + intsize = 64 + intmask = (1 << intsize) - 1 + + +class x86_08_ne(x86_imm): + intsize = 8 + intmask = (1 << intsize) - 1 + + def encode(self): + return True + + def decode(self, v): + v = swap_uint(self.l, v) + p = self.parent + admode = p.v_admode() + value = sign_ext(v, self.intsize, admode) + self.expr = ExprInt(value, admode) + return True + + +class x86_16_ne(x86_08_ne): + intsize = 16 + intmask = (1 << intsize) - 1 + + +class x86_32_ne(x86_08_ne): + intsize = 32 + intmask = (1 << intsize) - 1 + + +class x86_64_ne(x86_08_ne): + intsize = 64 + intmask = (1 << intsize) - 1 + + +class x86_s08to16(x86_imm): + in_size = 8 + out_size = 16 + + def myexpr(self, x): + return ExprInt(x, 16) + + def int2expr(self, v): + return self.myexpr(v) + + def expr2int(self, e): + if not isinstance(e, ExprInt): + return None + v = int(e) + if v & ~((1 << self.l) - 1) != 0: + return None + return v + + def decode(self, v): + v = v & self.lmask + v = self.decodeval(v) + if self.parent.v_opmode() == 64: + self.expr = ExprInt(sign_ext(v, self.in_size, 64), 64) + else: + if (1 << (self.l - 1)) & v: + v = sign_ext(v, self.l, self.out_size) + self.expr = self.myexpr(v) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr) + opmode = self.parent.v_opmode() + + out_size = self.out_size + if opmode != self.out_size: + if opmode == 32 and self.out_size == 64: + out_size = opmode + if v == sign_ext( + int(v & ((1 << self.in_size) - 1)), self.in_size, out_size): + pass + else: + # test with rex_w + self.parent.rex_w.value = 1 + opmode = self.parent.v_opmode() + out_size = opmode + if (v != sign_ext( + int(v & ((1 << self.in_size) - 1)), + self.in_size, out_size)): + return False + if v != sign_ext( + int(v & ((1 << self.in_size) - 1)), self.in_size, out_size): + return False + v = self.encodeval(v) + self.value = (v & 0xffffffff) & self.lmask + return True + + def decodeval(self, v): + return swap_uint(self.l, v) + + def encodeval(self, v): + return swap_sint(self.l, v) + + +class x86_s08to32(x86_s08to16): + in_size = 8 + out_size = 32 + + def myexpr(self, x): + return ExprInt(x, 32) + + def decode(self, v): + v = v & self.lmask + v = self.decodeval(v) + if self.parent.rex_w.value == 1: + v = ExprInt(sign_ext(v, self.in_size, 64), 64) + else: + v = ExprInt(sign_ext(v, self.in_size, 32), 32) + + self.expr = v + return True + + +class x86_s08to64(x86_s08to32): + in_size = 8 + out_size = 64 + + def myexpr(self, x): + return ExprInt(x, 64) + + +class x86_s32to64(x86_s08to32): + in_size = 32 + out_size = 64 + + def myexpr(self, x): + return ExprInt(x, 64) + + +class bs_eax(x86_arg): + reg_info = r_eax_all + rindex = 0 + parser = reg_info.parser + + def decode(self, v): + p = self.parent + expr = None + if hasattr(p, 'w8') and p.w8.value == 0: + expr = regs08_expr[self.rindex] + else: + expr = size2gpregs[p.v_opmode()].expr[self.rindex] + self.expr = expr + return True + + def encode(self): + self.value = 0 + p = self.parent + expr = self.expr + osize = p.v_opmode() + if hasattr(p, 'w8'): + if p.w8.value is None: + # XXX TODO: priority in w8 erase? + if expr.size == 8: + p.w8.value = 0 + else: + p.w8.value = 1 + if hasattr(p, 'w8') and p.w8.value == 0: + return expr == regs08_expr[self.rindex] + elif p.mode in [16, 32]: + return expr == size2gpregs[osize].expr[self.rindex] + elif p.mode == 64: + if expr == size2gpregs[64].expr[self.rindex]: + p.rex_w.value = 1 + return True + elif expr == size2gpregs[osize].expr[self.rindex]: + return True + return False + return False + +class bs_seg(x86_arg): + reg_info = r_eax_all + rindex = 0 + parser = reg_info.parser + + def decode(self, v): + self.expr = self.reg_info.expr[0] + return True + + def encode(self): + self.value = 0 + return self.expr == self.reg_info.expr[0] + + +class bs_edx(bs_eax): + reg_info = r_edx_all + rindex = 2 + parser = reg_info.parser + + +class bs_st(bs_eax): + reg_info = r_st_all + rindex = 0 + parser = reg_info.parser + + +class bs_cs(bs_seg): + reg_info = r_cs_all + rindex = 0 + parser = reg_info.parser + + +class bs_ds(bs_seg): + reg_info = r_ds_all + rindex = 0 + parser = reg_info.parser + + +class bs_es(bs_seg): + reg_info = r_es_all + rindex = 0 + parser = reg_info.parser + + +class bs_ss(bs_seg): + reg_info = r_ss_all + rindex = 0 + parser = reg_info.parser + + +class bs_fs(bs_seg): + reg_info = r_fs_all + rindex = 0 + parser = reg_info.parser + + +class bs_gs(bs_seg): + reg_info = r_gs_all + rindex = 0 + parser = reg_info.parser + + +class x86_reg_st(reg_noarg, x86_arg): + reg_info = r_st_all + parser = reg_info.parser + + +class bs_sib_scale(bs_divert): + bsname = "sib_scale" + + def divert(self, i, candidates): + out = [] + done = False + for cls, name, bases, dct, fields in candidates: + if (not (admode_prefix( + (dct['mode'], dct['opmode'], dct['admode'])) != 16 and + 'rm' in dct and dct['rm'] == 0b100 and + 'mod' in dct and dct['mod'] != 0b11)): + ndct = dict(dct) + nfields = fields[:] + nfields[i] = None + ndct[self.args['fname']] = None + out.append((cls, ndct['name'], bases, ndct, nfields)) + continue + + nfields = fields[:] + args = dict(self.args) + ndct = dict(dct) + f = bs(**args) + nfields[i] = f + ndct[self.args['fname']] = None + out.append((cls, ndct['name'], bases, ndct, nfields)) + return out + + +class bs_sib_index(bs_sib_scale): + pass + + +class bs_sib_base(bs_sib_scale): + pass + + +class bs_disp(bs_divert): + + def divert(self, i, candidates): + out = [] + done = False + for cls, name, bases, dct, fields in candidates: + ndct = dict(dct) + nfields = fields[:] + if (admode_prefix( + (dct['mode'], dct['opmode'], dct['admode'])) == 16): + if 'mod' in dct and dct['mod'] == 0b00 and \ + 'rm' in dct and dct['rm'] == 0b110: + nfields[i] = bs( + l=16, cls=(x86_16_ne,), fname=self.args['fname']) + ndct[self.args['fname']] = True + out.append((cls, ndct['name'], bases, ndct, nfields)) + continue + elif 'mod' in dct and dct['mod'] == 0b01: + nfields[i] = bs( + l=8, cls=(x86_08_ne,), fname=self.args['fname']) + ndct[self.args['fname']] = True + out.append((cls, ndct['name'], bases, ndct, nfields)) + continue + elif 'mod' in dct and dct['mod'] == 0b10: + nfields[i] = bs( + l=16, cls=(x86_16_ne,), fname=self.args['fname']) + ndct[self.args['fname']] = True + out.append((cls, ndct['name'], bases, ndct, nfields)) + continue + else: + if 'mod' in dct and dct['mod'] == 0b00 and \ + 'rm' in dct and dct['rm'] == 0b101: + nfields[i] = bs( + l=32, cls=(x86_32_ne,), fname=self.args['fname']) + ndct[self.args['fname']] = True + out.append((cls, ndct['name'], bases, ndct, nfields)) + continue + elif 'mod' in dct and dct['mod'] == 0b01: + nfields[i] = bs( + l=8, cls=(x86_08_ne,), fname=self.args['fname']) + ndct[self.args['fname']] = True + out.append((cls, ndct['name'], bases, ndct, nfields)) + continue + elif 'mod' in dct and dct['mod'] == 0b10: + nfields[i] = bs( + l=32, cls=(x86_32_ne,), fname=self.args['fname']) + ndct[self.args['fname']] = True + out.append((cls, ndct['name'], bases, ndct, nfields)) + continue + + nfields[i] = None + ndct[self.args['fname']] = None + out.append((cls, ndct['name'], bases, ndct, nfields)) + return out + + +def getmodrm(c): + return (c >> 6) & 3, (c >> 3) & 7, c & 7 + + +def setmodrm(mod, re, rm): + return ((mod & 3) << 6) | ((re & 7) << 3) | (rm & 7) + + +def sib(c): + return modrm(c) + +db_afs_64 = [] +sib_64_s08_ebp = [] + + +def gen_modrm_form(): + global db_afs_64, sib_64_s08_ebp + ebp = 5 + + sib_s08_ebp = [{f_isad: True} for i in range(0x100)] + sib_u32_ebp = [{f_isad: True} for i in range(0x100)] + sib_u32 = [{f_isad: True} for i in range(0x100)] + + sib_u64 = [] + for rex_x in range(2): + o = [] + for rex_b in range(2): + x = [{f_isad: True} for i in range(0x100)] + o.append(x) + sib_u64.append(o) + + sib_u64_ebp = [] + for rex_x in range(2): + o = [] + for rex_b in range(2): + x = [{f_isad: True} for i in range(0x100)] + o.append(x) + sib_u64_ebp.append(o) + + sib_64_s08_ebp = [] + for rex_x in range(2): + o = [] + for rex_b in range(2): + x = [{f_isad: True} for i in range(0x100)] + o.append(x) + sib_64_s08_ebp.append(o) + + for sib_rez in [sib_s08_ebp, + sib_u32_ebp, + sib_u32, + sib_64_s08_ebp, + sib_u64_ebp, + sib_u64, + ]: + for index in range(0x100): + ss, i, b = getmodrm(index) + + if b == 0b101: + if sib_rez == sib_s08_ebp: + sib_rez[index][f_imm] = f_s08 + sib_rez[index][ebp] = 1 + elif sib_rez == sib_u32_ebp: + sib_rez[index][f_imm] = f_u32 + sib_rez[index][ebp] = 1 + elif sib_rez == sib_u32: + sib_rez[index][f_imm] = f_u32 + elif sib_rez == sib_u64_ebp: + for rex_b in range(2): + for rex_x in range(2): + sib_rez[rex_x][rex_b][index][f_imm] = f_u32 + sib_rez[rex_x][rex_b][index][ebp + 8 * rex_b] = 1 + elif sib_rez == sib_u64: + for rex_b in range(2): + for rex_x in range(2): + sib_rez[rex_x][rex_b][index][f_imm] = f_u32 + elif sib_rez == sib_64_s08_ebp: + for rex_b in range(2): + for rex_x in range(2): + sib_rez[rex_x][rex_b][index][f_imm] = f_s08 + sib_rez[rex_x][rex_b][index][ebp + 8 * rex_b] = 1 + + else: + if sib_rez == sib_s08_ebp: + sib_rez[index][b] = 1 + sib_rez[index][f_imm] = f_s08 + elif sib_rez == sib_u32_ebp: + sib_rez[index][b] = 1 + sib_rez[index][f_imm] = f_u32 + elif sib_rez == sib_u32: + sib_rez[index][b] = 1 + elif sib_rez == sib_u64_ebp: + for rex_b in range(2): + for rex_x in range(2): + sib_rez[rex_x][rex_b][index][b + 8 * rex_b] = 1 + sib_rez[rex_x][rex_b][index][f_imm] = f_u32 + elif sib_rez == sib_u64: + for rex_b in range(2): + for rex_x in range(2): + sib_rez[rex_x][rex_b][index][b + 8 * rex_b] = 1 + elif sib_rez == sib_64_s08_ebp: + for rex_b in range(2): + for rex_x in range(2): + sib_rez[rex_x][rex_b][index][f_imm] = f_s08 + sib_rez[rex_x][rex_b][index][b + 8 * rex_b] = 1 + + if i == 0b100 and sib_rez in [sib_s08_ebp, sib_u32_ebp, sib_u32]: + continue + + if sib_rez in [sib_s08_ebp, sib_u32_ebp, sib_u32]: + tmp = i + if not tmp in sib_rez[index]: + sib_rez[index][tmp] = 0 # 1 << ss + sib_rez[index][tmp] += 1 << ss + else: + for rex_b in range(2): + for rex_x in range(2): + tmp = i + 8 * rex_x + if i == 0b100 and rex_x == 0: + continue + if not tmp in sib_rez[rex_x][rex_b][index]: + sib_rez[rex_x][rex_b][index][tmp] = 0 # 1 << ss + sib_rez[rex_x][rex_b][index][tmp] += 1 << ss + + # 32bit + db_afs_32 = [None for i in range(0x100)] + for i in range(0x100): + index = i + mod, re, rm = getmodrm(i) + + if mod == 0b00: + if rm == 0b100: + db_afs_32[index] = sib_u32 + elif rm == 0b101: + db_afs_32[index] = {f_isad: True, f_imm: f_u32} + else: + db_afs_32[index] = {f_isad: True, rm: 1} + elif mod == 0b01: + if rm == 0b100: + db_afs_32[index] = sib_s08_ebp + continue + tmp = {f_isad: True, rm: 1, f_imm: f_s08} + db_afs_32[index] = tmp + + elif mod == 0b10: + if rm == 0b100: + db_afs_32[index] = sib_u32_ebp + else: + db_afs_32[index] = {f_isad: True, rm: 1, f_imm: f_u32} + elif mod == 0b11: + db_afs_32[index] = {f_isad: False, rm: 1} + + # 64bit + db_afs_64 = [None for i in range(0x400)] + for i in range(0x400): + index = i + rex_x = (index >> 9) & 1 + rex_b = (index >> 8) & 1 + mod, re, rm = getmodrm(i & 0xff) + + if mod == 0b00: + if rm == 0b100: + db_afs_64[i] = sib_u64[rex_x][rex_b] + elif rm == 0b101: + db_afs_64[i] = {f_isad: True, f_imm: f_u32, 16: 1} + else: + db_afs_64[i] = {f_isad: True, rm + 8 * rex_b: 1} + elif mod == 0b01: + if rm == 0b100: + db_afs_64[i] = sib_64_s08_ebp[rex_x][rex_b] + continue + tmp = {f_isad: True, rm + 8 * rex_b: 1, f_imm: f_s08} + db_afs_64[i] = tmp + + elif mod == 0b10: + if rm == 0b100: + db_afs_64[i] = sib_u64_ebp[rex_x][rex_b] + else: + db_afs_64[i] = {f_isad: True, rm + 8 * rex_b: 1, f_imm: f_u32} + elif mod == 0b11: + db_afs_64[i] = {f_isad: False, rm + 8 * rex_b: 1} + + # 16bit + db_afs_16 = [None for i in range(0x100)] + _si = 6 + _di = 7 + _bx = 3 + _bp = 5 + for i in range(0x100): + index = i + mod, re, rm = getmodrm(i) + + if mod == 0b00: + if rm == 0b100: + db_afs_16[index] = {f_isad: True, _si: 1} + elif rm == 0b101: + db_afs_16[index] = {f_isad: True, _di: 1} + elif rm == 0b110: + db_afs_16[index] = { + f_isad: True, f_imm: f_u16} # {f_isad:True,_bp:1} + elif rm == 0b111: + db_afs_16[index] = {f_isad: True, _bx: 1} + else: + db_afs_16[index] = {f_isad: True, + [_si, _di][rm % 2]: 1, + [_bx, _bp][(rm >> 1) % 2]: 1} + elif mod in [0b01, 0b10]: + if mod == 0b01: + my_imm = f_s08 + else: + my_imm = f_u16 + + if rm == 0b100: + db_afs_16[index] = {f_isad: True, _si: 1, f_imm: my_imm} + elif rm == 0b101: + db_afs_16[index] = {f_isad: True, _di: 1, f_imm: my_imm} + elif rm == 0b110: + db_afs_16[index] = {f_isad: True, _bp: 1, f_imm: my_imm} + elif rm == 0b111: + db_afs_16[index] = {f_isad: True, _bx: 1, f_imm: my_imm} + else: + db_afs_16[index] = {f_isad: True, + [_si, _di][rm % 2]: 1, + [_bx, _bp][(rm >> 1) % 2]: 1, + f_imm: my_imm} + + elif mod == 0b11: + db_afs_16[index] = {f_isad: False, rm: 1} + + byte2modrm = {} + byte2modrm[16] = db_afs_16 + byte2modrm[32] = db_afs_32 + byte2modrm[64] = db_afs_64 + + modrm2byte = {16: defaultdict(list), + 32: defaultdict(list), + 64: defaultdict(list), + } + for size, db_afs in viewitems(byte2modrm): + for i, modrm in enumerate(db_afs): + if not isinstance(modrm, list): + # We only need sort for determinism + modrm = tuple(sorted(viewitems(modrm), key=str)) + modrm2byte[size][modrm].append(i) + continue + for j, modrm_f in enumerate(modrm): + # We only need sort for determinism + modrm_f = tuple(sorted(viewitems(modrm_f), key=str)) + modrm2byte[size][modrm_f].append((i, j)) + + return byte2modrm, modrm2byte + +byte2modrm, modrm2byte = gen_modrm_form() + + +# ret is modr; ret is displacement +def exprfindmod(e, o=None): + if o is None: + o = {} + if isinstance(e, ExprInt): + return e + if isinstance(e, ExprId): + i = size2gpregs[e.size].expr.index(e) + o[i] = 1 + return None + elif isinstance(e, ExprOp): + out = None + if e.op == '+': + for a in e.args: + r = exprfindmod(a, o) + if out and r: + raise ValueError('multiple displacement!') + out = r + return out + elif e.op == "*": + mul = int(e.args[1]) + a = e.args[0] + i = size2gpregs[a.size].expr.index(a) + o[i] = mul + else: + raise ValueError('bad op') + return None + +def test_addr_size(ptr, size): + if isinstance(ptr, ExprInt): + return int(ptr) < (1 << size) + else: + return ptr.size == size + +SIZE2XMMREG = {64:gpregs_mm, + 128:gpregs_xmm} +SIZE2BNDREG = {64:gpregs_mm, + 128:gpregs_bnd} + +def parse_mem(expr, parent, w8, sx=0, xmm=0, mm=0, bnd=0): + dct_expr = {} + opmode = parent.v_opmode() + if is_mem_segm(expr) and expr.ptr.args[0].is_int(): + return None, None, False + + if is_mem_segm(expr): + segm = expr.ptr.args[0] + ptr = expr.ptr.args[1] + else: + segm = None + ptr = expr.ptr + + dct_expr[f_isad] = True + ad_size = ptr.size + admode = parent.v_admode() + if not test_addr_size(ptr, admode): + return None, None, False + + if (w8 == 1 and expr.size != opmode and not sx and + not (hasattr(parent, 'sd') or hasattr(parent, 'wd'))): + return None, None, False + + if hasattr(parent, 'wd'): + if expr.size == 16: + parent.wd.value = 1 + elif expr.size == 32: + pass + else: + return None, None, False + + if (not isinstance(ptr, ExprInt) and + parent.mode == 64 and + ptr.size == 32 and + parent.admode != 1): + return None, None, False + dct_expr = {f_isad: True} + disp = exprfindmod(ptr, dct_expr) + out = [] + if disp is None: + # add 0 disp + disp = ExprInt(0, 32) + if disp is not None: + for signed, encoding, cast_size in [(True, f_s08, 8), + (True, f_s16, 16), + (True, f_s32, 32), + (False, f_u08, 8), + (False, f_u16, 16), + (False, f_u32, 32)]: + value = ExprInt(int(disp), cast_size) + if admode < value.size: + if signed: + if int(disp) != sign_ext(int(value), admode, disp.size): + continue + else: + if int(disp) != int(value): + continue + else: + if int(disp) != sign_ext(int(value), value.size, admode): + continue + x1 = dict(dct_expr) + x1[f_imm] = (encoding, value) + out.append(x1) + else: + out = [dct_expr] + return out, segm, True + +def expr2modrm(expr, parent, w8, sx=0, xmm=0, mm=0, bnd=0): + dct_expr = {f_isad : False} + + if mm or xmm or bnd: + if mm and expr.size != 64: + return None, None, False + elif xmm and expr.size != 128: + return None, None, False + elif bnd and expr.size != 128: + return None, None, False + + if isinstance(expr, ExprId): + if bnd: + size2reg = SIZE2BNDREG + else: + size2reg = SIZE2XMMREG + selreg = size2reg[expr.size] + if not expr in selreg.expr: + return None, None, False + i = selreg.expr.index(expr) + dct_expr[i] = 1 + return [dct_expr], None, True + else: + return parse_mem(expr, parent, w8, sx, xmm, mm) + + elif expr.size == 64 and expr not in gpregs_mm.expr: + if hasattr(parent, 'sd'): + parent.sd.value = 1 + elif hasattr(parent, 'wd'): + pass + elif hasattr(parent, 'stk'): + pass + else: + parent.rex_w.value = 1 + opmode = parent.v_opmode() + if sx == 1: + opmode = 16 + if sx == 2: + opmode = 32 + if expr.size == 8 and w8 != 0: + return None, None, False + + if w8 == 0 and expr.size != 8: + return None, None, False + + if not isinstance(expr, ExprMem): + dct_expr[f_isad] = False + if xmm: + if expr in gpregs_xmm.expr: + i = gpregs_xmm.expr.index(expr) + dct_expr[i] = 1 + return [dct_expr], None, True + else: + return None, None, False + if bnd: + if expr in gpregs_bnd.expr: + i = gpregs_bnd.expr.index(expr) + dct_expr[i] = 1 + return [dct_expr], None, True + else: + return None, None, False + if mm: + if expr in gpregs_mm.expr: + i = gpregs_mm.expr.index(expr) + dct_expr[i] = 1 + return [dct_expr], None, True + else: + return None, None, False + if w8 == 0: + if parent.mode == 64 and expr in gpregs08_64.expr: + r = gpregs08_64 + parent.rex_p.value = 1 + else: + parent.rex_p.value = 0 + parent.rex_x.value = 0 + r = size2gpregs[8] + if not expr in r.expr: + return None, None, False + i = r.expr.index(expr) + dct_expr[i] = 1 + return [dct_expr], None, True + if opmode != expr.size: + return None, None, False + if not expr in size2gpregs[opmode].expr: + return None, None, False + i = size2gpregs[opmode].expr.index(expr) + if i > 7: + if parent.mode != 64: + return None, None, False + dct_expr[i] = 1 + return [dct_expr], None, True + return parse_mem(expr, parent, w8, sx, xmm, mm, bnd) + +def modrm2expr(modrm, parent, w8, sx=0, xmm=0, mm=0, bnd=0): + o = [] + if not modrm[f_isad]: + modrm_k = [key for key, value in viewitems(modrm) if value == 1] + if len(modrm_k) != 1: + raise ValueError('strange reg encoding %r' % modrm) + modrm_k = modrm_k[0] + if w8 == 0: + opmode = 8 + elif sx == 1: + opmode = 16 + elif sx == 2: + opmode = 32 + else: + opmode = parent.v_opmode() + if xmm: + expr = gpregs_xmm.expr[modrm_k] + elif mm: + expr = gpregs_mm.expr[modrm_k] + elif bnd: + expr = gpregs_bnd.expr[modrm_k] + elif opmode == 8 and (parent.v_opmode() == 64 or parent.rex_p.value == 1): + expr = gpregs08_64.expr[modrm_k] + else: + expr = size2gpregs[opmode].expr[modrm_k] + return expr + admode = parent.v_admode() + opmode = parent.v_opmode() + for modrm_k, scale in viewitems(modrm): + if isinstance(modrm_k, int): + expr = size2gpregs[admode].expr[modrm_k] + if scale != 1: + expr = ExprInt(scale, admode) * expr + o.append(expr) + if f_imm in modrm: + if parent.disp.value is None: + return None + o.append(ExprInt(int(parent.disp.expr), admode)) + if len(o) == 1: + expr = o[0] + else: + expr = ExprOp('+', *o) + if w8 == 0: + opmode = 8 + elif sx == 1: + opmode = 16 + elif sx == 2: + opmode = 32 + if xmm: + opmode = 128 + elif mm: + opmode = 64 + elif bnd: + opmode = 128 + + expr = ExprMem(expr, size=opmode) + return expr + + +class x86_rm_arg(x86_arg): + parser = rmarg + + def fromstring(self, text, loc_db, parser_result=None): + start, stop = super(x86_rm_arg, self).fromstring(text, loc_db, parser_result) + p = self.parent + if start is None: + return None, None + return start, stop + + def get_modrm(self): + p = self.parent + admode = p.v_admode() + + if not admode in [16, 32, 64]: + raise ValueError('strange admode %r', admode) + v = setmodrm(p.mod.value, 0, p.rm.value) + v |= p.rex_b.value << 8 + v |= p.rex_x.value << 9 + if p.mode == 64: + # XXXx to check + admode = 64 + + xx = byte2modrm[admode][v] + if isinstance(xx, list): + if not p.sib_scale: + return False + v = setmodrm(p.sib_scale.value, + p.sib_index.value, + p.sib_base.value) + xx = xx[v] + return xx + + def decode(self, v): + p = self.parent + xx = self.get_modrm() + self.expr = modrm2expr(xx, p, 1) + return self.expr is not None + + def gen_cand(self, v_cand, admode): + if not admode in modrm2byte: + # XXX TODO: 64bit + return + if not v_cand: + return + + p = self.parent + o_rex_x = p.rex_x.value + o_rex_b = p.rex_b.value + # add candidate without 0 imm + new_v_cand = [] + moddd = False + for v in v_cand: + new_v_cand.append(v) + if f_imm in v and int(v[f_imm][1]) == 0: + v = dict(v) + del(v[f_imm]) + new_v_cand.append(v) + moddd = True + + v_cand = new_v_cand + + out_c = [] + for v in v_cand: + disp = None + # patch value in modrm + if f_imm in v: + size, disp = v[f_imm] + disp = int(disp) + + v[f_imm] = size + vo = v + # We only need sort for determinism + v = tuple(sorted(viewitems(v), key=str)) + admode = 64 if p.mode == 64 else admode + if not v in modrm2byte[admode]: + continue + xx = modrm2byte[admode][v] + + # default case + for x in xx: + if type(x) == tuple: + modrm, sib = x + else: + modrm = x + sib = None + + # 16 bit cannot have sib + if sib is not None and admode == 16: + continue + rex = modrm >> 8 # 0# XXX HACK REM temporary REX modrm>>8 + if rex and admode != 64: + continue + + p.rex_x.value = (rex >> 1) & 1 + p.rex_b.value = rex & 1 + + if o_rex_x is not None and p.rex_x.value != o_rex_x: + continue + if o_rex_b is not None and p.rex_b.value != o_rex_b: + continue + + mod, re, rm = getmodrm(modrm) + # check re on parent + if hasattr(p, 'reg') and re != p.reg.value: + continue + + if sib is not None: + s_scale, s_index, s_base = getmodrm(sib) + else: + s_scale, s_index, s_base = None, None, None + + p.mod.value = mod + p.rm.value = rm + p.sib_scale.value = s_scale + p.sib_index.value = s_index + p.sib_base.value = s_base + p.disp.value = disp + if disp is not None: + p.disp.l = f_imm2size[vo[f_imm]] + + yield True + + return + + def encode(self): + if isinstance(self.expr, ExprInt): + return + p = self.parent + admode = p.v_admode() + mode = self.expr.size + v_cand, segm, ok = expr2modrm(self.expr, p, 1) + if segm: + p.g2.value = segm2enc[segm] + for x in self.gen_cand(v_cand, admode): + yield x + +class x86_rm_mem(x86_rm_arg): + def fromstring(self, text, loc_db, parser_result=None): + self.expr = None + start, stop = super(x86_rm_mem, self).fromstring(text, loc_db, parser_result) + if not isinstance(self.expr, ExprMem): + return None, None + return start, stop + + +class x86_rm_mem_far(x86_rm_arg): + parser = mem_far + def fromstring(self, text, loc_db, parser_result=None): + self.expr = None + start, stop = super(x86_rm_mem_far, self).fromstring(text, loc_db, parser_result) + if not isinstance(self.expr, ExprMem): + return None, None + self.expr = ExprOp('far', self.expr) + return start, stop + + def decode(self, v): + ret = super(x86_rm_mem_far, self).decode(v) + if not ret: + return ret + if isinstance(self.expr, m2_expr.ExprMem): + self.expr = ExprOp('far', self.expr) + return True + + def encode(self): + if not (isinstance(self.expr, m2_expr.ExprOp) and + self.expr.op == 'far'): + return + + expr = self.expr.args[0] + if isinstance(expr, ExprInt): + return + p = self.parent + admode = p.v_admode() + mode = expr.size + v_cand, segm, ok = expr2modrm(expr, p, 1) + if segm: + p.g2.value = segm2enc[segm] + for x in self.gen_cand(v_cand, admode): + yield x + +class x86_rm_w8(x86_rm_arg): + + def decode(self, v): + p = self.parent + xx = self.get_modrm() + self.expr = modrm2expr(xx, p, p.w8.value) + return self.expr is not None + + def encode(self): + if isinstance(self.expr, ExprInt): + return + p = self.parent + if p.w8.value is None: + if self.expr.size == 8: + p.w8.value = 0 + else: + p.w8.value = 1 + + v_cand, segm, ok = expr2modrm(self.expr, p, p.w8.value) + if segm: + p.g2.value = segm2enc[segm] + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + + +class x86_rm_sx(x86_rm_arg): + + def decode(self, v): + p = self.parent + xx = self.get_modrm() + self.expr = modrm2expr(xx, p, p.w8.value, 1) + return self.expr is not None + + def encode(self): + if isinstance(self.expr, ExprInt): + return + p = self.parent + if p.w8.value is None: + if self.expr.size == 8: + p.w8.value = 0 + else: + p.w8.value = 1 + v_cand, segm, ok = expr2modrm(self.expr, p, p.w8.value, 1) + if segm: + p.g2.value = segm2enc[segm] + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + + +class x86_rm_sxd(x86_rm_arg): + + def decode(self, v): + p = self.parent + xx = self.get_modrm() + self.expr = modrm2expr(xx, p, 1, 2) + return self.expr is not None + + def encode(self): + if isinstance(self.expr, ExprInt): + return + p = self.parent + v_cand, segm, ok = expr2modrm(self.expr, p, 1, 2) + if segm: + p.g2.value = segm2enc[segm] + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + + +class x86_rm_sd(x86_rm_arg): + out_size = 64 + def get_s_value(self): + return self.parent.sd.value + def set_s_value(self, value): + self.parent.sd.value = value + + def decode(self, v): + p = self.parent + xx = self.get_modrm() + expr = modrm2expr(xx, p, 1) + if not isinstance(expr, ExprMem): + return False + if self.get_s_value() == 0: + expr = ExprMem(expr.ptr, 32) + else: + expr = ExprMem(expr.ptr, self.out_size) + self.expr = expr + return self.expr is not None + + def encode(self): + if isinstance(self.expr, ExprInt): + return + p = self.parent + if not self.expr.size in [32, 64]: + return + self.set_s_value(0) + v_cand, segm, ok = expr2modrm(self.expr, p, 1) + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + + +class x86_rm_wd(x86_rm_sd): + out_size = 16 + def get_s_value(self): + return self.parent.wd.value + def set_s_value(self, value): + self.parent.wd.value = value + + def encode(self): + if isinstance(self.expr, ExprInt): + return + p = self.parent + p.wd.value = 0 + v_cand, segm, ok = expr2modrm(self.expr, p, 1) + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + + +class x86_rm_08(x86_rm_arg): + msize = 8 + + def decode(self, v): + p = self.parent + xx = self.get_modrm() + expr = modrm2expr(xx, p, 0) + if not isinstance(expr, ExprMem): + self.expr = expr + return True + self.expr = ExprMem(expr.ptr, self.msize) + return self.expr is not None + + def encode(self): + if isinstance(self.expr, ExprInt): + return + p = self.parent + v_cand, segm, ok = expr2modrm(self.expr, p, 0, 0, 0, 0) + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + +class x86_rm_reg_m08(x86_rm_arg): + msize = 8 + + def decode(self, v): + ret = x86_rm_arg.decode(self, v) + if not ret: + return ret + if not isinstance(self.expr, ExprMem): + return True + self.expr = ExprMem(self.expr.ptr, self.msize) + return self.expr is not None + + def encode(self): + if isinstance(self.expr, ExprInt): + return + p = self.parent + if isinstance(self.expr, ExprMem): + expr = ExprMem(self.expr.ptr, 32) + else: + expr = self.expr + v_cand, segm, ok = expr2modrm(expr, p, 1, 0, 0, 0) + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + +class x86_rm_reg_m16(x86_rm_reg_m08): + msize = 16 + +class x86_rm_m64(x86_rm_arg): + msize = 64 + + def decode(self, v): + p = self.parent + xx = self.get_modrm() + expr = modrm2expr(xx, p, 1) + if not isinstance(expr, ExprMem): + return False + self.expr = ExprMem(expr.ptr, self.msize) + return self.expr is not None + + def encode(self): + if isinstance(self.expr, ExprInt): + return + p = self.parent + v_cand, segm, ok = expr2modrm(self.expr, p, 0, 0, 0, 1) + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + + +class x86_rm_m80(x86_rm_m64): + msize = 80 + + def encode(self): + if isinstance(self.expr, ExprInt): + return + if not isinstance(self.expr, ExprMem) or self.expr.size != self.msize: + return + p = self.parent + mode = p.mode + if mode == 64: + mode = 32 + self.expr = ExprMem(self.expr.ptr, mode) + v_cand, segm, ok = expr2modrm(self.expr, p, 1) + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + + +class x86_rm_m08(x86_rm_arg): + msize = 8 + + def decode(self, v): + p = self.parent + xx = self.get_modrm() + self.expr = modrm2expr(xx, p, 0) + return self.expr is not None + + def encode(self): + if self.expr.size != 8: + return + p = self.parent + mode = p.mode + v_cand, segm, ok = expr2modrm(self.expr, p, 0) + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + + +class x86_rm_m16(x86_rm_m80): + msize = 16 + + +class x86_rm_mm(x86_rm_m80): + msize = 64 + is_mm = True + is_xmm = False + is_bnd = False + + def decode(self, v): + p = self.parent + xx = self.get_modrm() + expr = modrm2expr(xx, p, 0, 0, self.is_xmm, self.is_mm, self.is_bnd) + if isinstance(expr, ExprMem): + if self.msize is None: + return False + if expr.size != self.msize: + expr = ExprMem(expr.ptr, self.msize) + self.expr = expr + return True + + + def encode(self): + expr = self.expr + if isinstance(expr, ExprInt): + return + if isinstance(expr, ExprMem) and expr.size != self.msize: + return + p = self.parent + mode = p.mode + if mode == 64: + mode = 32 + if isinstance(expr, ExprMem): + if self.is_xmm: + expr = ExprMem(expr.ptr, 128) + elif self.is_mm: + expr = ExprMem(expr.ptr, 64) + + v_cand, segm, ok = expr2modrm(expr, p, 0, 0, self.is_xmm, self.is_mm, + self.is_bnd) + for x in self.gen_cand(v_cand, p.v_admode()): + yield x + + +class x86_rm_mm_m64(x86_rm_mm): + msize = 64 + is_mm = True + is_xmm = False + +class x86_rm_xmm(x86_rm_mm): + msize = 128 + is_mm = False + is_xmm = True + + +class x86_rm_xmm_m32(x86_rm_mm): + msize = 32 + is_mm = False + is_xmm = True + +class x86_rm_xmm_m64(x86_rm_mm): + msize = 64 + is_mm = False + is_xmm = True + +class x86_rm_xmm_m128(x86_rm_mm): + msize = 128 + is_mm = False + is_xmm = True + + +class x86_rm_xmm_reg(x86_rm_mm): + msize = None + is_mm = False + is_xmm = True + +class x86_rm_mm_reg(x86_rm_mm): + msize = None + is_mm = True + is_xmm = False + + +class x86_rm_bnd(x86_rm_mm): + msize = 128 + is_mm = False + is_xmm = False + is_bnd = True + + +class x86_rm_bnd_reg(x86_rm_mm): + msize = None + is_mm = False + is_xmm = False + is_bnd = True + + +class x86_rm_bnd_m64(x86_rm_mm): + msize = 64 + is_mm = False + is_xmm = False + is_bnd = True + + +class x86_rm_bnd_m128(x86_rm_mm): + msize = 128 + is_mm = False + is_xmm = False + is_bnd = True + + +class x86_rm_reg_noarg(object): + prio = default_prio + 1 + + parser = gpreg + + def fromstring(self, text, loc_db, parser_result=None): + if not hasattr(self.parent, 'sx') and hasattr(self.parent, "w8"): + self.parent.w8.value = 1 + if parser_result: + result, start, stop = parser_result[self.parser] + if result == [None]: + return None, None + self.expr = result + if self.expr.size == 8: + if hasattr(self.parent, 'sx') or not hasattr(self.parent, 'w8'): + return None, None + self.parent.w8.value = 0 + return start, stop + try: + result, start, stop = next(self.parser.scanString(text)) + except StopIteration: + return None, None + expr = self.asm_ast_to_expr(result[0], loc_db) + if expr is None: + return None, None + + self.expr = expr + if self.expr.size == 0: + if hasattr(self.parent, 'sx') or not hasattr(self.parent, 'w8'): + return None, None + self.parent.w8.value = 0 + + return start, stop + + def getrexsize(self): + return self.parent.rex_r.value + + def setrexsize(self, v): + self.parent.rex_r.value = v + + def decode(self, v): + v = v & self.lmask + p = self.parent + opmode = p.v_opmode() + if not hasattr(p, 'sx') and (hasattr(p, 'w8') and p.w8.value == 0): + opmode = 8 + r = size2gpregs[opmode] + if p.mode == 64 and self.getrexsize(): + v |= 0x8 + if p.v_opmode() == 64 or p.rex_p.value == 1: + if not hasattr(p, 'sx') and (hasattr(p, 'w8') and p.w8.value == 0): + r = gpregs08_64 + elif p.rex_r.value == 1: + v |= 8 + self.expr = r.expr[v] + return True + + def encode(self): + if not isinstance(self.expr, ExprId): + return False + if self.expr in gpregs64.expr and not hasattr(self.parent, 'stk'): + self.parent.rex_w.value = 1 + opmode = self.parent.v_opmode() + if not hasattr(self.parent, 'sx') and hasattr(self.parent, 'w8'): + self.parent.w8.value = 1 + if self.expr.size == 8: + if hasattr(self.parent, 'sx') or not hasattr(self.parent, 'w8'): + return False + self.parent.w8.value = 0 + opmode = 8 + r = size2gpregs[opmode] + if self.expr in r.expr: + i = r.expr.index(self.expr) + elif (opmode == 8 and self.parent.mode == 64 and + self.expr in gpregs08_64.expr): + i = gpregs08_64.expr.index(self.expr) + self.parent.rex_p.value = 1 + else: + log.debug("cannot encode reg %r", self.expr) + return False + if self.parent.v_opmode() == 64: + if i > 7: + self.setrexsize(1) + i -= 8 + elif self.parent.mode == 64 and i > 7: + i -= 8 + self.setrexsize(1) + self.value = i + return True + + +class x86_rm_reg_mm(x86_rm_reg_noarg, x86_arg): + selreg = gpregs_mm + def decode(self, v): + if self.parent.mode == 64 and self.getrexsize(): + v |= 0x8 + self.expr = self.selreg.expr[v] + return True + + def encode(self): + if not isinstance(self.expr, ExprId): + return False + if self.expr not in self.selreg.expr: + return False + i = self.selreg.expr.index(self.expr) + if self.parent.mode == 64 and i > 7: + i -= 8 + self.setrexsize(1) + self.value = i + return True + +class x86_rm_reg_xmm(x86_rm_reg_mm): + selreg = gpregs_xmm + +class x86_rm_reg_bnd(x86_rm_reg_mm): + selreg = gpregs_bnd + +class x86_rm_reg(x86_rm_reg_noarg, x86_arg): + pass + + +class x86_reg(x86_rm_reg): + + def getrexsize(self): + return self.parent.rex_b.value + + def setrexsize(self, v): + self.parent.rex_b.value = v + +class x86_vex_reg(x86_rm_reg): + # self.lmask = 15 + + def decode(self, v): + p = self.parent + + self.expr = size2gpregs[v_opmode(p)].expr[p.vex_v.value] + + return self.expr is not None + + def encode(self): + opmode = self.parent.mode + size = self.expr.size + + if opmode == 64 and size == 64: + self.parent.rex_w.value = 1 + else: + self.parent.rex_w.value = 0 + + r = size2gpregs[size] + if self.expr in r.expr: + i = r.expr.index(self.expr) + + self.parent.vex_v.value = i + self.parent.vex.value = 1 + return True + + +class x86_reg_modrm(x86_rm_reg): + + def getrexsize(self): + return self.parent.rex_r.value + + def setrexsize(self, v): + self.parent.rex_r.value = v + + + +class x86_reg_noarg(x86_rm_reg_noarg): + + def getrexsize(self): + return self.parent.rex_b.value + + def setrexsize(self, v): + self.parent.rex_b.value = v + + +class x86_rm_segm(reg_noarg, x86_arg): + prio = default_prio + 1 + reg_info = segmreg + parser = reg_info.parser + + +class x86_rm_cr(reg_noarg, x86_arg): + prio = default_prio + 1 + reg_info = crregs + parser = reg_info.parser + + +class x86_rm_dr(reg_noarg, x86_arg): + prio = default_prio + 1 + reg_info = drregs + parser = reg_info.parser + + +class x86_rm_flt(reg_noarg, x86_arg): + prio = default_prio + 1 + reg_info = fltregs + parser = reg_info.parser + + +class bs_fbit(bsi): + + def decode(self, v): + # value already decoded in pre_dis_info + return True + + +class bs_cl1(bsi, x86_arg): + parser = cl_or_imm + + def decode(self, v): + if v == 1: + self.expr = regs08_expr[1] + else: + self.expr = ExprInt(1, 8) + return True + + def encode(self): + if self.expr == regs08_expr[1]: + self.value = 1 + elif isinstance(self.expr, ExprInt) and int(self.expr) == 1: + self.value = 0 + else: + return False + return True + + +def sib_cond(cls, mode, v): + if admode_prefix((mode, v["opmode"], v["admode"])) == 16: + return None + if v['mod'] == 0b11: + return None + elif v['rm'] == 0b100: + return cls.ll + else: + return None + return v['rm'] == 0b100 + + +class bs_cond_scale(bs_cond): + # cond must return field len + ll = 2 + + @classmethod + def flen(cls, mode, v): + return sib_cond(cls, mode, v) + + def encode(self): + if self.value is None: + self.value = 0 + self.l = 0 + return True + return super(bs_cond_scale, self).encode() + + def decode(self, v): + self.value = v + return True + + +class bs_cond_index(bs_cond_scale): + ll = 3 + + @classmethod + def flen(cls, mode, v): + return sib_cond(cls, mode, v) + + +class bs_cond_disp(bs_cond): + # cond must return field len + + @classmethod + def flen(cls, mode, v): + if admode_prefix((mode, v['opmode'], v['admode'])) == 16: + if v['mod'] == 0b00: + if v['rm'] == 0b110: + return 16 + else: + return None + elif v['mod'] == 0b01: + return 8 + elif v['mod'] == 0b10: + return 16 + return None + # 32, 64 + if 'sib_base' in v and v['sib_base'] == 0b101: + if v['mod'] == 0b00: + return 32 + elif v['mod'] == 0b01: + return 8 + elif v['mod'] == 0b10: + return 32 + else: + return None + + if v['mod'] == 0b00: + if v['rm'] == 0b101: + return 32 + else: + return None + elif v['mod'] == 0b01: + return 8 + elif v['mod'] == 0b10: + return 32 + else: + return None + + def encode(self): + if self.value is None: + self.value = 0 + self.l = 0 + return True + self.value = swap_uint(self.l, self.value) + return True + + def decode(self, v): + admode = self.parent.v_admode() + v = swap_uint(self.l, v) + self.value = v + v = sign_ext(v, self.l, admode) + v = ExprInt(v, admode) + self.expr = v + return True + + +class bs_cond_imm(bs_cond_scale, x86_arg): + parser = base_expr + max_size = 32 + + def fromstring(self, text, loc_db, parser_result=None): + if parser_result: + expr, start, stop = parser_result[self.parser] + else: + try: + expr, start, stop = next(self.parser.scanString(text)) + except StopIteration: + expr = None + self.expr = expr + + if len(self.parent.args) > 1: + l = self.parent.args[0].expr.size + else: + l = self.parent.v_opmode() + if isinstance(self.expr, ExprInt): + v = int(self.expr) + mask = ((1 << l) - 1) + self.expr = ExprInt(v & mask, l) + + if self.expr is None: + log.debug('cannot fromstring int %r', text) + return None, None + return start, stop + + @classmethod + def flen(cls, mode, v): + if 'w8' not in v or v['w8'] == 1: + if 'se' in v and v['se'] == 1: + return 8 + else: + osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0) + osize = min(osize, cls.max_size) + return osize + return 8 + + def getmaxlen(self): + return 32 + + def encode(self): + if not isinstance(self.expr, ExprInt): + return + arg0_expr = self.parent.args[0].expr + self.parent.rex_w.value = 0 + # special case for push + if len(self.parent.args) == 1: + v = int(self.expr) + l = self.parent.v_opmode() + l = min(l, self.max_size) + + self.l = l + mask = ((1 << self.l) - 1) + if v != sign_ext(v & mask, self.l, l): + return + self.value = swap_uint(self.l, v & ((1 << self.l) - 1)) + yield True + return + + # assume 2 args; use first arg to guess op size + if arg0_expr.size == 64: + self.parent.rex_w.value = 1 + + l = self.parent.v_opmode() + v = int(self.expr) + if arg0_expr.size == 8: + if not hasattr(self.parent, 'w8'): + return + self.parent.w8.value = 0 + l = 8 + if hasattr(self.parent, 'se'): + self.parent.se.value = 0 + elif hasattr(self.parent, 'se'): + if hasattr(self.parent, 'w8'): + self.parent.w8.value = 1 + # try to generate signed extended version + if v == sign_ext(v & 0xFF, 8, arg0_expr.size): + self.parent.se.value = 1 + self.l = 8 + self.value = v & 0xFF + yield True + self.parent.se.value = 0 + else: + if hasattr(self.parent, 'w8'): + self.parent.w8.value = 1 + if l == 64: + self.l = self.getmaxlen() + else: + self.l = l + + mask = ((1 << self.l) - 1) + if v != sign_ext(v & mask, self.l, l): + return + self.value = swap_uint(self.l, v & ((1 << self.l) - 1)) + yield True + + def decode(self, v): + opmode = self.parent.v_opmode() + v = swap_uint(self.l, v) + self.value = v + l_out = opmode + if hasattr(self.parent, 'w8') and self.parent.w8.value == 0: + l_out = 8 + v = sign_ext(v, self.l, l_out) + self.expr = ExprInt(v, l_out) + return True + + +class bs_cond_imm64(bs_cond_imm): + max_size = 64 + + def getmaxlen(self): + return 64 + + @classmethod + def flen(cls, mode, v): + if 'w8' not in v or v['w8'] == 1: + if 'se' in v and v['se'] == 1: + return 8 + else: + osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0) + return osize + else: + return 8 + + +class bs_rel_off(bs_cond_imm): + parser = base_expr + + def fromstring(self, text, loc_db, parser_result=None): + if parser_result: + expr, start, stop = parser_result[self.parser] + else: + try: + expr, start, stop = next(self.parser.scanString(text)) + except StopIteration: + expr = None + self.expr = expr + l = self.parent.mode + if isinstance(self.expr, ExprInt): + v = int(self.expr) + mask = ((1 << l) - 1) + self.expr = ExprInt(v & mask, l) + return start, stop + + @classmethod + def flen(cls, mode, v): + osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0) + if osize == 16: + return 16 + else: + return 32 + + def encode(self): + if not isinstance(self.expr, ExprInt): + return + arg0_expr = self.parent.args[0].expr + if self.l == 0: + l = self.parent.v_opmode() + self.l = l + l = offsize(self.parent) + prefix = self.parent.gen_prefix() + parent_len = len(prefix) * 8 + self.parent.l + self.l + assert(parent_len % 8 == 0) + + v = int(self.expr) - parent_len // 8 + if prefix is None: + return + mask = ((1 << self.l) - 1) + if self.l > l: + return + if v != sign_ext(v & mask, self.l, l): + return + self.value = swap_uint(self.l, v & ((1 << self.l) - 1)) + yield True + + def decode(self, v): + v = swap_uint(self.l, v) + size = offsize(self.parent) + v = sign_ext(v, self.l, size) + v += self.parent.l + self.expr = ExprInt(v, size) + return True + +class bs_s08(bs_rel_off): + parser = base_expr + + @classmethod + def flen(cls, mode, v): + return 8 + + def encode(self): + if not isinstance(self.expr, ExprInt): + return + arg0_expr = self.parent.args[0].expr + if self.l != 0: + l = self.l + else: + l = self.parent.v_opmode() + self.l = l + l = offsize(self.parent) + v = int(self.expr) + mask = ((1 << self.l) - 1) + if self.l > l: + return + if v != sign_ext(v & mask, self.l, l): + return + self.value = swap_uint(self.l, v & ((1 << self.l) - 1)) + yield True + + def decode(self, v): + v = swap_uint(self.l, v) + size = offsize(self.parent) + v = sign_ext(v, self.l, size) + self.expr = ExprInt(v, size) + return True + + +class bs_rel_off08(bs_rel_off): + + @classmethod + def flen(cls, mode, v): + return 8 + + +class bs_moff(bsi): + + @classmethod + def flen(cls, mode, v): + osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0) + if osize == 16: + return 16 + else: + return 32 + + def encode(self): + if not hasattr(self.parent, "mseg"): + return + m = self.parent.mseg.expr + if not (isinstance(m, ExprOp) and m.op == 'segm'): + return + if not isinstance(m.args[1], ExprInt): + return + l = self.parent.v_opmode() + if l == 16: + self.l = 16 + else: + self.l = 32 + v = int(m.args[1]) + mask = ((1 << self.l) - 1) + if v != sign_ext(v & mask, self.l, l): + return + self.value = swap_uint(self.l, v & ((1 << self.l) - 1)) + yield True + + def decode(self, v): + opmode = self.parent.v_opmode() + if opmode == 64: + return False + v = swap_uint(self.l, v) + self.value = v + v = sign_ext(v, self.l, opmode) + self.expr = ExprInt(v, opmode) + return True + + +class bs_movoff(x86_arg): + parser = deref_mem + + def fromstring(self, text, loc_db, parser_result=None): + if parser_result: + e, start, stop = parser_result[self.parser] + if e is None: + return None, None + if not isinstance(e, ExprMem): + return None, None + self.expr = e + if self.expr is None: + return None, None + return start, stop + try: + v, start, stop = next(self.parser.scanString(text)) + except StopIteration: + return None, None + if not isinstance(e, ExprMem): + return None, None + self.expr = v[0] + if self.expr is None: + log.debug('cannot fromstring int %r', text) + return None, None + return start, stop + + @classmethod + def flen(cls, mode, v): + if mode == 64: + if v['admode']: + return 32 + else: + return 64 + asize = v_admode_info(mode, v['admode']) + return asize + + def encode(self): + p = self.parent + if not isinstance(self.expr, ExprMem) or not isinstance(self.expr.ptr, ExprInt): + return + self.l = p.v_admode() + v = int(self.expr.ptr) + mask = ((1 << self.l) - 1) + if v != mask & v: + return + self.value = swap_uint(self.l, v & ((1 << self.l) - 1)) + yield True + + def decode(self, v): + if self.parent.mode == 64: + if self.parent.admode == 1: + l = 32 + else: + l = 64 + else: + l = self.parent.v_admode() + v = swap_uint(self.l, v) + self.value = v + v = sign_ext(v, self.l, l) + v = ExprInt(v, l) + size = self.parent.v_opmode() + if self.parent.w8.value == 0: + size = 8 + self.expr = ExprMem(v, size) + return True + + +class bs_msegoff(x86_arg): + parser = deref_ptr + + def fromstring(self, text, loc_db, parser_result=None): + if parser_result: + e, start, stop = parser_result[self.parser] + if e is None: + return None, None + self.expr = e + if self.expr is None: + return None, None + return start, stop + try: + v, start, stop = next(self.parser.scanString(text)) + except StopIteration: + return None, None + self.expr = v[0] + if self.expr is None: + log.debug('cannot fromstring int %r', text) + return None, None + return start, stop + + def encode(self): + if not (isinstance(self.expr, ExprOp) and self.expr.op == 'segm'): + return + if not isinstance(self.expr.args[0], ExprInt): + return + if not isinstance(self.expr.args[1], ExprInt): + return + l = self.parent.v_opmode() + v = int(self.expr.args[0]) + mask = ((1 << self.l) - 1) + if v != sign_ext(v & mask, self.l, l): + return + self.value = swap_uint(self.l, v & ((1 << self.l) - 1)) + yield True + + def decode(self, v): + opmode = self.parent.v_opmode() + v = swap_uint(self.l, v) + self.value = v + v = ExprInt(v, 16) + self.expr = ExprOp('segm', v, self.parent.off.expr) + return True + + +d_rex_p = bs(l=0, cls=(bs_fbit,), fname="rex_p") +d_rex_w = bs(l=0, cls=(bs_fbit,), fname="rex_w") +d_rex_r = bs(l=0, cls=(bs_fbit,), fname="rex_r") +d_rex_x = bs(l=0, cls=(bs_fbit,), fname="rex_x") +d_rex_b = bs(l=0, cls=(bs_fbit,), fname="rex_b") + +d_vex = bs(l=0, cls=(bs_fbit,), fname="vex") +d_vex_l = bs(l=0, cls=(bs_fbit,), fname="vex_l") +d_vex_p = bs(l=0, cls=(bs_fbit,), fname="vex_p") +d_vex_v = bs(l=0, cls=(bs_fbit,), fname="vex_v") +d_vex_m = bs(l=0, cls=(bs_fbit,), fname="vex_m") + +pref_0f = bs(l=0, fname="pref_0f") +pref_0f38 = bs(l=0, fname="pref_0f38") +pref_0f3a = bs(l=0, fname="pref_0f3a") + +d_g1 = bs(l=0, cls=(bs_fbit,), fname="g1") +d_g2 = bs(l=0, cls=(bs_fbit,), fname="g2") + + +d_cl1 = bs(l=1, cls=(bs_cl1,), fname="cl1") + + +w8 = bs(l=1, fname="w8") +se = bs(l=1, fname="se") + +sx = bs(l=0, fname="sx") +sxd = bs(l=0, fname="sx") + + +xmmreg = bs(l=0, fname="xmmreg") +mmreg = bs(l=0, fname="mmreg") + +pref_f2 = bs(l=0, fname="prefixed", default=b"\xf2") +pref_f3 = bs(l=0, fname="prefixed", default=b"\xf3") +pref_66 = bs(l=0, fname="prefixed", default=b"\x66") +no_xmm_pref = bs(l=0, fname="no_xmm_pref") + +no_rex = bs(l=0, fname="no_rex") +no_rep = bs(l=0, fname="no_rep") + +sib_scale = bs(l=2, cls=(bs_cond_scale,), fname = "sib_scale") +sib_index = bs(l=3, cls=(bs_cond_index,), fname = "sib_index") +sib_base = bs(l=3, cls=(bs_cond_index,), fname = "sib_base") + +disp = bs(l=0, cls=(bs_cond_disp,), fname = "disp") + +s08 = bs(l=8, cls=(bs_s08, )) + +u08 = bs(l=8, cls=(x86_08, x86_arg)) +u07 = bs(l=7, cls=(x86_08, x86_arg)) +u16 = bs(l=16, cls=(x86_16, x86_arg)) +u32 = bs(l=32, cls=(x86_32, x86_arg)) +s3264 = bs(l=32, cls=(x86_s32to64, x86_arg)) + +u08_3 = bs(l=0, cls=(x86_imm_fix_08, x86_arg), ival = 3) + +d0 = bs("000", fname='reg') +d1 = bs("001", fname='reg') +d2 = bs("010", fname='reg') +d3 = bs("011", fname='reg') +d4 = bs("100", fname='reg') +d5 = bs("101", fname='reg') +d6 = bs("110", fname='reg') +d7 = bs("111", fname='reg') + +sd = bs(l=1, fname="sd") +wd = bs(l=1, fname="wd") + +stk = bs(l=0, fname="stk") + + +class field_size(object): + prio = default_prio + + def __init__(self, d=None): + if d is None: + d = {} + self.d = d + + def get(self, opm, adm=None): + return self.d[opm] + +class bs_mem(object): + def encode(self): + return self.value != 0b11 + + def decode(self, v): + self.value = v + return v != 0b11 + +class bs_reg(object): + def encode(self): + return self.value == 0b11 + + def decode(self, v): + self.value = v + return v == 0b11 + +d_imm64 = bs(l=0, fname="imm64") + +d_eax = bs(l=0, cls=(bs_eax, ), fname='eax') +d_edx = bs(l=0, cls=(bs_edx, ), fname='edx') +d_st = bs(l=0, cls=(x86_reg_st, ), fname='st') +d_imm = bs(l=0, cls=(bs_cond_imm,), fname="imm") +d_imm64 = bs(l=0, cls=(bs_cond_imm64,), fname="imm") +d_ax = bs(l=0, cls=(r_ax, ), fname='ax') +d_dx = bs(l=0, cls=(r_dx, ), fname='dx') +d_cl = bs(l=0, cls=(r_cl, ), fname='cl') + +d_cs = bs(l=0, cls=(bs_cs, ), fname='cs') +d_ds = bs(l=0, cls=(bs_ds, ), fname='ds') +d_es = bs(l=0, cls=(bs_es, ), fname='es') +d_ss = bs(l=0, cls=(bs_ss, ), fname='ss') +d_fs = bs(l=0, cls=(bs_fs, ), fname='fs') +d_gs = bs(l=0, cls=(bs_gs, ), fname='gs') + +# Offset must be decoded in last position to have final instruction len +rel_off = bs(l=0, cls=(bs_rel_off,), fname="off", order=-1) +# Offset must be decoded in last position to have final instruction len +rel_off08 = bs(l=8, cls=(bs_rel_off08,), fname="off", order=-1) +moff = bs(l=0, cls=(bs_moff,), fname="off") +msegoff = bs(l=16, cls=(bs_msegoff,), fname="mseg") +movoff = bs(l=0, cls=(bs_movoff,), fname="off") +mod = bs(l=2, fname="mod") +mod_mem = bs(l=2, cls=(bs_mem,), fname="mod") +mod_reg = bs(l=2, cls=(bs_reg,), fname="mod") + +rmreg = bs(l=3, cls=(x86_rm_reg, ), order =1, fname = "reg") +reg = bs(l=3, cls=(x86_reg, ), order =1, fname = "reg") + +reg_modrm = bs(l=3, cls=(x86_reg_modrm, ), order =1, fname = "reg") + +vex_reg = bs(l=0, cls=(x86_vex_reg, ), order =1, fname = "vex_reg") + +regnoarg = bs(l=3, default_val="000", order=1, fname="reg") +segm = bs(l=3, cls=(x86_rm_segm, ), order =1, fname = "reg") +crreg = bs(l=3, cls=(x86_rm_cr, ), order =1, fname = "reg") +drreg = bs(l=3, cls=(x86_rm_dr, ), order =1, fname = "reg") + + +mm_reg = bs(l=3, cls=(x86_rm_reg_mm, ), order =1, fname = "reg") +xmm_reg = bs(l=3, cls=(x86_rm_reg_xmm, ), order =1, fname = "reg") +bnd_reg = bs(l=3, cls=(x86_rm_reg_bnd, ), order =1, fname = "reg") + + +fltreg = bs(l=3, cls=(x86_rm_flt, ), order =1, fname = "reg") + +rm = bs(l=3, fname="rm") + +rm_arg = bs(l=0, cls=(x86_rm_arg,), fname='rmarg') +rm_arg_w8 = bs(l=0, cls=(x86_rm_w8,), fname='rmarg') +rm_arg_sx = bs(l=0, cls=(x86_rm_sx,), fname='rmarg') +rm_arg_sxd = bs(l=0, cls=(x86_rm_sxd,), fname='rmarg') +rm_arg_sd = bs(l=0, cls=(x86_rm_sd,), fname='rmarg') +rm_arg_wd = bs(l=0, cls=(x86_rm_wd,), fname='rmarg') +rm_arg_08 = bs(l=0, cls=(x86_rm_08,), fname='rmarg') +rm_arg_reg_m08 = bs(l=0, cls=(x86_rm_reg_m08,), fname='rmarg') +rm_arg_reg_m16 = bs(l=0, cls=(x86_rm_reg_m16,), fname='rmarg') +rm_arg_m08 = bs(l=0, cls=(x86_rm_m08,), fname='rmarg') +rm_arg_m64 = bs(l=0, cls=(x86_rm_m64,), fname='rmarg') +rm_arg_m80 = bs(l=0, cls=(x86_rm_m80,), fname='rmarg') +rm_arg_m16 = bs(l=0, cls=(x86_rm_m16,), fname='rmarg') + +rm_mem = bs(l=0, cls=(x86_rm_mem,), fname='rmarg') +rm_mem_far = bs(l=0, cls=(x86_rm_mem_far,), fname='rmarg') + +rm_arg_mm = bs(l=0, cls=(x86_rm_mm,), fname='rmarg') +rm_arg_mm_m64 = bs(l=0, cls=(x86_rm_mm_m64,), fname='rmarg') +rm_arg_mm_reg = bs(l=0, cls=(x86_rm_mm_reg,), fname='rmarg') + +rm_arg_xmm = bs(l=0, cls=(x86_rm_xmm,), fname='rmarg') +rm_arg_xmm_m32 = bs(l=0, cls=(x86_rm_xmm_m32,), fname='rmarg') +rm_arg_xmm_m64 = bs(l=0, cls=(x86_rm_xmm_m64,), fname='rmarg') +rm_arg_xmm_m128 = bs(l=0, cls=(x86_rm_xmm_m128,), fname='rmarg') +rm_arg_xmm_reg = bs(l=0, cls=(x86_rm_xmm_reg,), fname='rmarg') + +rm_arg_bnd = bs(l=0, cls=(x86_rm_bnd,), fname='rmarg') +rm_arg_bnd_m64 = bs(l=0, cls=(x86_rm_bnd_m64,), fname='rmarg') +rm_arg_bnd_m128 = bs(l=0, cls=(x86_rm_bnd_m128,), fname='rmarg') +rm_arg_bnd_reg = bs(l=0, cls=(x86_rm_bnd_reg,), fname='rmarg') + + +swapargs = bs_swapargs(l=1, fname="swap", mn_mod=list(range(1 << 1))) + + +class bs_op_mode(bsi): + + def decode(self, v): + opmode = self.parent.v_opmode() + return opmode == self.mode + + +class bs_ad_mode(bsi): + + def decode(self, v): + admode = self.parent.v_admode() + return admode == self.mode + + +class bs_op_mode_no64(bsi): + + def encode(self): + if self.parent.mode == 64: + return False + return super(bs_op_mode_no64, self).encode() + + def decode(self, v): + if self.parent.mode == 64: + return False + opmode = self.parent.v_opmode() + return opmode == self.mode + + +class bs_op_mode64(bsi): + def encode(self): + if self.parent.mode != 64: + return False + return super(bs_op_mode64, self).encode() + + def decode(self, v): + if self.parent.mode != 64: + return False + return True + +class bs_op_modeno64(bsi): + def encode(self): + if self.parent.mode == 64: + return False + return super(bs_op_modeno64, self).encode() + + def decode(self, v): + if self.parent.mode == 64: + return False + return True + + + +bs_opmode16 = bs(l=0, cls=(bs_op_mode,), mode = 16, fname="fopmode") +bs_opmode32 = bs(l=0, cls=(bs_op_mode,), mode = 32, fname="fopmode") +bs_opmode64 = bs(l=0, cls=(bs_op_mode,), mode = 64, fname="fopmode") + + +bs_admode16 = bs(l=0, cls=(bs_ad_mode,), mode = 16, fname="fadmode") +bs_admode32 = bs(l=0, cls=(bs_ad_mode,), mode = 32, fname="fadmode") +bs_admode64 = bs(l=0, cls=(bs_ad_mode,), mode = 64, fname="fadmode") + +bs_opmode16_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 16, fname="fopmode") +bs_opmode32_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 32, fname="fopmode") + +bs_mode64 = bs(l=0, cls=(bs_op_mode64,)) +bs_modeno64 = bs(l=0, cls=(bs_op_modeno64,)) + + +cond_list = ["O", "NO", "B", "AE", + "Z", "NZ", "BE", "A", + "S", "NS", "PE", "NP", + #"L", "NL", "NG", "G"] + "L", "GE", "LE", "G"] +cond = bs_mod_name(l=4, fname='cond', mn_mod=cond_list) + + +def rmmod(r, rm_arg_x=rm_arg, modrm=mod): + return [modrm, r, rm, sib_scale, sib_index, sib_base, disp, rm_arg_x] + +# +# mode | reg | rm # +# + +# +# scale | index | base # +# + +# +# Prefix | REX prefix | Opcode | mod/rm | sib | displacement | immediate # +# + + +def addop(name, fields, args=None, alias=False): + dct = {"fields": fields} + dct["alias"] = alias + if args is not None: + dct['args'] = args + type(name, (mn_x86,), dct) +""" +class ia32_aaa(mn_x86): + fields = [bs8(0x37)] +""" +addop("aaa", [bs8(0x37)]) +addop("aas", [bs8(0x3F)]) +addop("aad", [bs8(0xd5), u08]) +addop("aam", [bs8(0xd4), u08]) + +addop("adc", [bs("0001010"), w8, d_eax, d_imm]) +addop("adc", [bs("100000"), se, w8] + rmmod(d2, rm_arg_w8) + [d_imm]) +addop("adc", [bs("000100"), swapargs, w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) + +addop("add", [bs("0000010"), w8, d_eax, d_imm]) +addop("add", [bs("100000"), se, w8] + rmmod(d0, rm_arg_w8) + [d_imm]) +addop("add", [bs("000000"), swapargs, w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) + +addop("and", [bs("0010010"), w8, d_eax, d_imm]) +addop("and", [bs("100000"), se, w8] + rmmod(d4, rm_arg_w8) + [d_imm]) +addop("and", [bs("001000"), swapargs, w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) + +addop("bndmov", [bs8(0x0f), bs8(0x1a), pref_66, bs_modeno64] + + rmmod(bnd_reg, rm_arg_bnd_m64), [bnd_reg, rm_arg_bnd_m64]) +addop("bndmov", [bs8(0x0f), bs8(0x1a), pref_66, bs_mode64] + + rmmod(bnd_reg, rm_arg_bnd_m128), [bnd_reg, rm_arg_bnd_m128]) +addop("bndmov", [bs8(0x0f), bs8(0x1b), pref_66, bs_modeno64] + + rmmod(bnd_reg, rm_arg_bnd_m64), [rm_arg_bnd_m64, bnd_reg]) +addop("bndmov", [bs8(0x0f), bs8(0x1b), pref_66, bs_mode64] + + rmmod(bnd_reg, rm_arg_bnd_m128), [rm_arg_bnd_m128, bnd_reg]) + + + +addop("bsf", [bs8(0x0f), bs8(0xbc), no_rep] + rmmod(rmreg)) +addop("bsr", [bs8(0x0f), bs8(0xbd), mod, + rmreg, rm, sib_scale, sib_index, sib_base, disp, rm_arg]) + +addop("bswap", [bs8(0x0f), bs('11001'), reg]) + +addop("bt", [bs8(0x0f), bs8(0xa3)] + rmmod(rmreg), [rm_arg, rmreg]) +addop("bt", [bs8(0x0f), bs8(0xba)] + rmmod(d4) + [u08]) +addop("btc", [bs8(0x0f), bs8(0xbb)] + rmmod(rmreg), [rm_arg, rmreg]) +addop("btc", [bs8(0x0f), bs8(0xba)] + rmmod(d7) + [u08]) + + +addop("btr", [bs8(0x0f), bs8(0xb3)] + rmmod(rmreg), [rm_arg, rmreg]) +addop("btr", [bs8(0x0f), bs8(0xba)] + rmmod(d6) + [u08]) +addop("bts", [bs8(0x0f), bs8(0xab)] + rmmod(rmreg), [rm_arg, rmreg]) +addop("bts", [bs8(0x0f), bs8(0xba)] + rmmod(d5) + [u08]) + +addop("call", [bs8(0xe8), rel_off]) +addop("call", [bs8(0xff), stk] + rmmod(d2)) +addop("call", [bs8(0xff), stk] + rmmod(d3, rm_arg_x=rm_mem_far, modrm=mod_mem)) +addop("call", [bs8(0x9a), bs_modeno64, moff, msegoff]) + + +addop("cbw", [bs8(0x98), bs_opmode16]) +addop("cwde", [bs8(0x98), bs_opmode32]) +addop("cdqe", [bs8(0x98), bs_opmode64]) + +addop("clc", [bs8(0xf8)]) +addop("cld", [bs8(0xfc)]) +addop("cli", [bs8(0xfa)]) +addop("clts", [bs8(0x0f), bs8(0x06)]) +addop("cmc", [bs8(0xf5)]) + +addop("cmov", [bs8(0x0f), bs('0100'), cond] + rmmod(rmreg)) + +addop("cmp", [bs("0011110"), w8, d_eax, d_imm]) +addop("cmp", [bs("100000"), se, w8] + rmmod(d7, rm_arg_w8) + [d_imm]) +addop("cmp", [bs("001110"), swapargs, w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) + + +addop("cmpsb", [bs8(0xa6)]) +addop("cmpsw", [bs8(0xa7), bs_opmode16]) +addop("cmpsd", [bs8(0xa7), bs_opmode32]) +addop("cmpsq", [bs8(0xa7), bs_opmode64]) + +addop("cmpxchg", [bs8(0x0f), bs('1011000'), w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) +addop("cmpxchg8b", [bs8(0x0f), bs8(0xc7), bs_opmode16] + rmmod(d1, rm_arg_m64)) +addop("cmpxchg8b", [bs8(0x0f), bs8(0xc7), bs_opmode32] + rmmod(d1, rm_arg_m64)) +addop("cmpxchg16b", [bs8(0x0f), bs8(0xc7), bs_opmode64] + rmmod(d1, rm_arg_xmm_m128)) + +# XXX TODO CMPXCHG8/16 + +addop("comiss", [bs8(0x0f), bs8(0x2f), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm_m32), [xmm_reg, rm_arg_xmm_m32]) +addop("comisd", [bs8(0x0f), bs8(0x2f), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m64), [xmm_reg, rm_arg_xmm_m64]) + +addop("cpuid", [bs8(0x0f), bs8(0xa2)]) + +addop("cwd", [bs8(0x99), bs_opmode16]) +addop("cdq", [bs8(0x99), bs_opmode32]) +addop("cqo", [bs8(0x99), bs_opmode64]) + + +addop("daa", [bs8(0x27)]) +addop("das", [bs8(0x2f)]) +addop("dec", [bs('1111111'), w8] + rmmod(d1, rm_arg_w8)) +addop("dec", [bs('01001'), reg, bs_modeno64]) +addop("div", [bs('1111011'), w8] + rmmod(d6, rm_arg_w8)) +addop("enter", [bs8(0xc8), u16, u08]) + +# float ##### +addop("fwait", [bs8(0x9b)]) + +addop("f2xm1", [bs8(0xd9), bs8(0xf0)]) +addop("fabs", [bs8(0xd9), bs8(0xe1)]) + +addop("fadd", [bs("11011"), sd, bs("00")] + rmmod(d0, rm_arg_sd)) +addop("fadd", [bs("11011"), swapargs, bs("00"), + bs("11000"), d_st, fltreg], [d_st, fltreg]) +addop("faddp", [bs8(0xde), bs("11000"), fltreg, d_st]) +addop("fiadd", [bs("11011"), wd, bs("10")] + rmmod(d0, rm_arg_wd)) + +addop("fbld", [bs8(0xdf)] + rmmod(d4, rm_arg_m80)) +addop("fbldp", [bs8(0xdf)] + rmmod(d6, rm_arg_m80)) +addop("fchs", [bs8(0xd9), bs8(0xe0)]) +# addop("fclex", [bs8(0x9b), bs8(0xdb), bs8(0xe2)]) +addop("fnclex", [bs8(0xdb), bs8(0xe2)]) + +addop("fcmovb", [bs8(0xda), bs("11000"), d_st, fltreg]) +addop("fcmove", [bs8(0xda), bs("11001"), d_st, fltreg]) +addop("fcmovbe", [bs8(0xda), bs("11010"), d_st, fltreg]) +addop("fcmovu", [bs8(0xda), bs("11011"), d_st, fltreg]) +addop("fcmovnb", [bs8(0xdb), bs("11000"), d_st, fltreg]) +addop("fcmovne", [bs8(0xdb), bs("11001"), d_st, fltreg]) +addop("fcmovnbe", [bs8(0xdb), bs("11010"), d_st, fltreg]) +addop("fcmovnu", [bs8(0xdb), bs("11011"), d_st, fltreg]) + +addop("fcom", [bs("11011"), sd, bs("00")] + rmmod(d2, rm_arg_sd)) +addop("fcom", [bs("11011"), swapargs, bs("00"), + bs("11010"), d_st, fltreg], [d_st, fltreg]) +addop("fcomp", [bs("11011"), sd, bs("00")] + rmmod(d3, rm_arg_sd)) +addop("fcomp", + [bs("11011"), swapargs, bs("00"), bs("11011"), + d_st, fltreg], [d_st, fltreg]) +addop("fcompp", [bs8(0xde), bs8(0xd9)]) + +addop("fcomi", [bs8(0xdb), bs("11110"), d_st, fltreg]) +addop("fcomip", [bs8(0xdf), bs("11110"), d_st, fltreg]) +addop("fucomi", [bs8(0xdb), bs("11101"), d_st, fltreg]) +addop("fucomip", [bs8(0xdf), bs("11101"), d_st, fltreg]) + +addop("fcos", [bs8(0xd9), bs8(0xff)]) +addop("fdecstp", [bs8(0xd9), bs8(0xf6)]) + + +addop("fdiv", [bs("11011"), sd, bs("00")] + rmmod(d6, rm_arg_sd)) +addop("fdiv", [bs8(0xd8), bs("11110"), d_st, fltreg]) +addop("fdiv", [bs8(0xdc), bs("11111"), fltreg, d_st]) +addop("fdivp", [bs8(0xde), bs("11111"), fltreg, d_st]) +addop("fidiv", [bs("11011"), wd, bs("10")] + rmmod(d6, rm_arg_wd)) + +addop("fdivr", [bs("11011"), sd, bs("00")] + rmmod(d7, rm_arg_sd)) +addop("fdivr", [bs8(0xd8), bs("11111"), d_st, fltreg]) +addop("fdivr", [bs8(0xdc), bs("11110"), fltreg, d_st]) +addop("fdivrp", [bs8(0xde), bs("11110"), fltreg, d_st]) +addop("fidivr", [bs("11011"), wd, bs("10")] + rmmod(d7, rm_arg_wd)) + +addop("ffree", [bs8(0xdd), bs("11000"), fltreg]) +addop("ficom", [bs("11011"), wd, bs("10")] + rmmod(d2, rm_arg_wd)) +addop("ficomp", [bs("11011"), wd, bs("10")] + rmmod(d3, rm_arg_wd)) +addop("fild", [bs("11011"), wd, bs("11")] + rmmod(d0, rm_arg_wd)) +addop("fild", [bs8(0xdf)] + rmmod(d5, rm_arg_m64)) + +addop("fincstp", [bs8(0xd9), bs8(0xf7)]) + +addop("blsi", [pref_0f38, bs8(0xf3), vex_reg] + rmmod(bs("011"), rm_arg), [vex_reg, rm_arg]) +addop("andn", [pref_0f38, bs8(0xf2), vex_reg] + rmmod(rmreg, rm_arg), [rmreg, vex_reg, rm_arg]) +addop("bextr", [pref_0f38, bs8(0xf7), vex_reg] + rmmod(rmreg, rm_arg), [rmreg, rm_arg, vex_reg]) +addop("blsmsk", [pref_0f38, bs8(0xf3), vex_reg] + rmmod(bs("010"), rm_arg), [vex_reg, rm_arg]) +addop("blsr", [pref_0f38, bs8(0xf3), vex_reg] + rmmod(bs("001"), rm_arg), [vex_reg, rm_arg]) +addop("bzhi", [pref_0f38, bs8(0xf5), vex_reg] + rmmod(rmreg, rm_arg), [rmreg, rm_arg, vex_reg]) +addop("tzcnt", [bs8(0x0f), bs8(0xbc), pref_f3] + rmmod(rmreg, rm_arg), [rmreg, rm_arg]) + +# addop("finit", [bs8(0x9b), bs8(0xdb), bs8(0xe3)]) +addop("fninit", [bs8(0xdb), bs8(0xe3)]) + +addop("fist", [bs("11011"), wd, bs("11")] + rmmod(d2, rm_arg_wd)) +addop("fistp", [bs("11011"), wd, bs("11")] + rmmod(d3, rm_arg_wd)) +addop("fistp", [bs8(0xdf)] + rmmod(d7, rm_arg_m64)) + +addop("fisttp", [bs("11011"), wd, bs("11")] + rmmod(d1, rm_arg_wd)) +addop("fisttp", [bs8(0xdd)] + rmmod(d1, rm_arg_m64)) + +addop("fld", [bs("11011"), sd, bs("01")] + rmmod(d0, rm_arg_sd)) +addop("fld", [bs8(0xdb)] + rmmod(d5, rm_arg_m80)) +addop("fld", [bs8(0xd9), bs("11000"), fltreg]) + +addop("fld1", [bs8(0xd9), bs8(0xe8)]) +addop("fldl2t", [bs8(0xd9), bs8(0xe9)]) +addop("fldl2e", [bs8(0xd9), bs8(0xea)]) +addop("fldpi", [bs8(0xd9), bs8(0xeb)]) +addop("fldlg2", [bs8(0xd9), bs8(0xec)]) +addop("fldln2", [bs8(0xd9), bs8(0xed)]) +addop("fldz", [bs8(0xd9), bs8(0xee)]) + +addop("fldcw", [bs8(0xd9)] + rmmod(d5, rm_arg_m16)) +addop("fldenv", [bs8(0xd9)] + rmmod(d4, rm_arg_m80)) # XXX TODO: m14? + +addop("fmul", [bs("11011"), sd, bs("00")] + rmmod(d1, rm_arg_sd)) +addop("fmul", [bs("11011"), swapargs, bs("00"), + bs("11001"), d_st, fltreg], [d_st, fltreg]) +addop("fmulp", [bs8(0xde), bs("11001"), fltreg, d_st]) +addop("fimul", [bs("11011"), wd, bs("10")] + rmmod(d1, rm_arg_wd)) + +addop("fnop", [bs8(0xd9), bs8(0xd0)]) +addop("fpatan", [bs8(0xd9), bs8(0xf3)]) +addop("fprem", [bs8(0xd9), bs8(0xf8)]) +addop("fprem1", [bs8(0xd9), bs8(0xf5)]) +addop("fptan", [bs8(0xd9), bs8(0xf2)]) +addop("frndint", [bs8(0xd9), bs8(0xfc)]) +addop("frstor", [bs8(0xdd)] + rmmod(d4, rm_arg_m80)) # XXX TODO: m94 ? +# addop("fsave", [bs8(0x9b), bs8(0xdd)] + rmmod(d6, rm_arg_m80)) # XXX +# TODO: m94 ? +addop("fnsave", [bs8(0xdd)] + rmmod(d6, rm_arg_m80)) # XXX TODO: m94 ? + +addop("fscale", [bs8(0xd9), bs8(0xfd)]) +addop("fsin", [bs8(0xd9), bs8(0xfe)]) +addop("fsincos", [bs8(0xd9), bs8(0xfb)]) +addop("fsqrt", [bs8(0xd9), bs8(0xfa)]) + +addop("fst", [bs("11011"), sd, bs("01")] + rmmod(d2, rm_arg_sd)) +addop("fst", [bs8(0xdd), bs("11010"), fltreg]) +addop("fstp", [bs("11011"), sd, bs("01")] + rmmod(d3, rm_arg_sd)) +addop("fstp", [bs8(0xdb)] + rmmod(d7, rm_arg_m80)) +addop("fstp", [bs8(0xdd), bs("11011"), fltreg]) + +# addop("fstcw", [bs8(0x9b), bs8(0xd9)] + rmmod(d7, rm_arg_m16)) +addop("fnstcw", [bs8(0xd9)] + rmmod(d7, rm_arg_m16)) +# addop("fstenv", [bs8(0x9b), bs8(0xd9)] + rmmod(d6, rm_arg_m80)) # XXX +# TODO: m14? +addop("fnstenv", [bs8(0xd9)] + rmmod(d6, rm_arg_m80)) # XXX TODO: m14? +# addop("fstsw", [bs8(0x9b), bs8(0xdd)] + rmmod(d7, rm_arg_m16)) +addop("fnstsw", [bs8(0xdd)] + rmmod(d7, rm_arg_m16)) +# addop("fstsw", [bs8(0x9b), bs8(0xdf), bs8(0xe0), d_ax]) +addop("fnstsw", [bs8(0xdf), bs8(0xe0), d_ax]) + +addop("fsub", [bs("11011"), sd, bs("00")] + rmmod(d4, rm_arg_sd)) +addop("fsub", [bs8(0xd8), bs("11100"), d_st, fltreg]) +addop("fsub", [bs8(0xdc), bs("11101"), fltreg, d_st]) +addop("fsubp", [bs8(0xde), bs("11101"), fltreg, d_st]) +addop("fisub", [bs("11011"), wd, bs("10")] + rmmod(d4, rm_arg_wd)) + +addop("fsubr", [bs("11011"), sd, bs("00")] + rmmod(d5, rm_arg_sd)) +addop("fsubr", [bs8(0xd8), bs("11101"), d_st, fltreg]) +addop("fsubr", [bs8(0xdc), bs("11100"), fltreg, d_st]) +addop("fsubrp", [bs8(0xde), bs("11100"), fltreg, d_st]) +addop("fisubr", [bs("11011"), wd, bs("10")] + rmmod(d5, rm_arg_wd)) +addop("ftst", [bs8(0xd9), bs8(0xe4)]) + + +addop("fucom", [bs8(0xdd), bs("11100"), fltreg]) +addop("fucomp", [bs8(0xdd), bs("11101"), fltreg]) +addop("fucompp", [bs8(0xda), bs8(0xe9)]) + +addop("fxam", [bs8(0xd9), bs8(0xe5)]) +addop("fxch", [bs8(0xd9), bs("11001"), fltreg]) +addop("fxrstor", [bs8(0x0f), bs8(0xae)] + + rmmod(d1, rm_arg_m80)) # XXX TODO m512 +addop("fxsave", [bs8(0x0f), bs8(0xae)] + + rmmod(d0, rm_arg_m80)) # XXX TODO m512 +addop("stmxcsr", [bs8(0x0f), bs8(0xae)] + rmmod(d3)) +addop("ldmxcsr", [bs8(0x0f), bs8(0xae)] + rmmod(d2)) + +addop("fxtract", [bs8(0xd9), bs8(0xf4)]) +addop("fyl2x", [bs8(0xd9), bs8(0xf1)]) +addop("fyl2xp1", [bs8(0xd9), bs8(0xf9)]) + +addop("hlt", [bs8(0xf4)]) +addop("icebp", [bs8(0xf1)]) + +addop("idiv", [bs('1111011'), w8] + rmmod(d7, rm_arg_w8)) + +addop("imul", [bs('1111011'), w8] + rmmod(d5, rm_arg_w8)) +addop("imul", [bs8(0x0f), bs8(0xaf)] + rmmod(rmreg)) + +addop("imul", [bs("011010"), se, bs('1')] + rmmod(rmreg) + [d_imm]) + +addop("in", [bs("1110010"), w8, d_eax, u08]) +addop("in", [bs("1110110"), w8, d_eax, d_edx]) + +addop("inc", [bs('1111111'), w8] + rmmod(d0, rm_arg_w8)) +addop("inc", [bs('01000'), reg, bs_modeno64]) + +addop("insb", [bs8(0x6c)]) +addop("insw", [bs8(0x6d), bs_opmode16]) +addop("insd", [bs8(0x6d), bs_opmode32]) +addop("insd", [bs8(0x6d), bs_opmode64]) + +addop("int", [bs8(0xcc), u08_3]) +addop("int", [bs8(0xcd), u08]) +addop("into", [bs8(0xce)]) +addop("invd", [bs8(0x0f), bs8(0x08)]) +addop("invlpg", [bs8(0x0f), bs8(0x01)] + rmmod(d7)) + +addop("iret", [bs8(0xcf), bs_opmode16]) +addop("iretd", [bs8(0xcf), bs_opmode32]) +addop("iretq", [bs8(0xcf), bs_opmode64]) + +addop("j", [bs('0111'), cond, rel_off08]) + +addop("jcxz", [bs8(0xe3), rel_off08, bs_admode16]) +addop("jecxz", [bs8(0xe3), rel_off08, bs_admode32]) +addop("jrcxz", [bs8(0xe3), rel_off08, bs_admode64]) + +addop("j", [bs8(0x0f), bs('1000'), cond, rel_off]) +addop("jmp", [bs8(0xeb), rel_off08]) +addop("jmp", [bs8(0xe9), rel_off]) +# TODO XXX replace stk force64? +addop("jmp", [bs8(0xff), stk] + rmmod(d4)) +addop("jmp", [bs8(0xea), bs_modeno64, moff, msegoff]) + +addop("jmp", [bs8(0xff)] + rmmod(d5, rm_arg_x=rm_mem_far, modrm=mod_mem)) + +addop("lahf", [bs8(0x9f)]) +addop("lar", [bs8(0x0f), bs8(0x02)] + rmmod(rmreg)) + +addop("lea", [bs8(0x8d)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem)) +addop("les", [bs8(0xc4)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem)) +addop("lds", [bs8(0xc5)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem)) +addop("lss", [bs8(0x0f), bs8(0xb2)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem)) +addop("lfs", [bs8(0x0f), bs8(0xb4)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem)) +addop("lgs", [bs8(0x0f), bs8(0xb5)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem)) + +addop("lgdt", [bs8(0x0f), bs8(0x01)] + rmmod(d2, modrm=mod_mem)) +addop("lidt", [bs8(0x0f), bs8(0x01)] + rmmod(d3, modrm=mod_mem)) + +addop("lfence", [bs8(0x0f), bs8(0xae), bs8(0xe8), no_xmm_pref]) +addop("mfence", [bs8(0x0f), bs8(0xae), bs8(0xf0)]) +addop("sfence", [bs8(0x0f), bs8(0xae), bs8(0xf8)]) + +addop("leave", [bs8(0xc9), stk]) + +addop("lodsb", [bs8(0xac)]) +addop("lodsw", [bs8(0xad), bs_opmode16]) +addop("lodsd", [bs8(0xad), bs_opmode32]) +addop("lodsq", [bs8(0xad), bs_opmode64]) + +addop("loop", [bs8(0xe2), rel_off08]) +addop("loope", [bs8(0xe1), rel_off08]) +addop("loopne", [bs8(0xe0), rel_off08]) +addop("lsl", [bs8(0x0f), bs8(0x03)] + rmmod(rmreg)) +addop("monitor", [bs8(0x0f), bs8(0x01), bs8(0xc8)]) + +addop("mov", [bs("100010"), swapargs, w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) +addop("mov", [bs("100011"), swapargs, bs('0')] + rmmod(segm), [rm_arg, segm]) +addop("mov", [bs("101000"), swapargs, w8, d_eax, movoff], [d_eax, movoff]) +addop("mov", [bs("1011"), w8, reg, d_imm64]) +addop("mov", [bs("1100011"), w8] + rmmod(d0, rm_arg_w8) + [d_imm]) +addop("mov", [bs8(0x0f), bs("001000"), swapargs, bs('0')] + + rmmod(crreg), [rm_arg, crreg]) +addop("mov", [bs8(0x0f), bs("001000"), swapargs, bs('1')] + + rmmod(drreg), [rm_arg, drreg]) +addop("movsb", [bs8(0xa4)]) +addop("movsw", [bs8(0xa5), bs_opmode16]) +addop("movsd", [bs8(0xa5), bs_opmode32]) +addop("movsq", [bs8(0xa5), bs_opmode64]) + +addop("movsx", [bs8(0x0f), bs("1011111"), w8, sx] + rmmod(rmreg, rm_arg_sx)) +addop("movsxd", [bs8(0x63), sxd, bs_mode64] + rmmod(rmreg, rm_arg_sxd)) + +addop("movups", [bs8(0x0f), bs("0001000"), swapargs, no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) +addop("movsd", [bs8(0x0f), bs("0001000"), swapargs, pref_f2] + + rmmod(xmm_reg, rm_arg_xmm_m64), [xmm_reg, rm_arg_xmm_m64]) +addop("movss", [bs8(0x0f), bs("0001000"), swapargs, pref_f3] + + rmmod(xmm_reg, rm_arg_xmm_m32), [xmm_reg, rm_arg_xmm_m32]) +addop("movupd", [bs8(0x0f), bs8(0x10), pref_66] + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) +addop("movupd", [bs8(0x0f), bs8(0x11), pref_66] + rmmod(xmm_reg, rm_arg_xmm), [rm_arg_xmm, xmm_reg]) + + +addop("movd", [bs8(0x0f), bs('011'), swapargs, bs('1110'), no_xmm_pref] + + rmmod(mm_reg, rm_arg), [mm_reg, rm_arg]) +addop("movd", [bs8(0x0f), bs('011'), swapargs, bs('1110'), pref_66, bs_opmode32] + + rmmod(xmm_reg, rm_arg), [xmm_reg, rm_arg]) +addop("movq", [bs8(0x0f), bs('011'), swapargs, bs('1110'), pref_66, bs_opmode64] + + rmmod(xmm_reg, rm_arg), [xmm_reg, rm_arg]) + +addop("movq", [bs8(0x0f), bs('011'), swapargs, bs('1111'), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64), [mm_reg, rm_arg_mm_m64]) + +addop("movq", [bs8(0x0f), bs8(0x7e), pref_f3] + + rmmod(xmm_reg, rm_arg_xmm_m64), [xmm_reg, rm_arg_xmm_m64]) +addop("movq", [bs8(0x0f), bs8(0xd6), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m64), [rm_arg_xmm_m64, xmm_reg]) + +addop("movmskps", [bs8(0x0f), bs8(0x50), no_xmm_pref] + + rmmod(reg_modrm, rm_arg_xmm_reg)) +addop("movmskpd", [bs8(0x0f), bs8(0x50), pref_66] + + rmmod(reg_modrm, rm_arg_xmm_reg)) + +addop("movnti", [bs8(0x0f), bs8(0xc3)] + rmmod(rmreg), [rm_arg, rmreg]) + +addop("addss", [bs8(0x0f), bs8(0x58), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32)) +addop("addsd", [bs8(0x0f), bs8(0x58), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64)) + +addop("subss", [bs8(0x0f), bs8(0x5c), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32)) +addop("subsd", [bs8(0x0f), bs8(0x5c), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64)) + +addop("mulss", [bs8(0x0f), bs8(0x59), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32)) +addop("mulsd", [bs8(0x0f), bs8(0x59), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64)) + +addop("divss", [bs8(0x0f), bs8(0x5e), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32)) +addop("divsd", [bs8(0x0f), bs8(0x5e), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64)) + +addop("roundss", [bs8(0x0f), bs8(0x3a), bs8(0x0a), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m32) + [u08]) +addop("roundsd", [bs8(0x0f), bs8(0x3a), bs8(0x0b), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m64) + [u08]) + +addop("pminsw", [bs8(0x0f), bs8(0xea), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm)) +addop("pminsw", [bs8(0x0f), bs8(0xea), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +addop("ucomiss", [bs8(0x0f), bs8(0x2e), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm_m32)) +addop("ucomisd", [bs8(0x0f), bs8(0x2e), pref_66] + rmmod(xmm_reg, rm_arg_xmm_m64)) + + +addop("movzx", [bs8(0x0f), bs("1011011"), w8, sx] + rmmod(rmreg, rm_arg_sx)) +addop("mul", [bs('1111011'), w8] + rmmod(d4, rm_arg_w8)) + +addop("neg", [bs('1111011'), w8] + rmmod(d3, rm_arg_w8)) +addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d0, rm_arg)) # XXX TODO m512 +addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d1, rm_arg)) # XXX TODO m512 +addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d2, rm_arg)) # XXX TODO m512 +addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d3, rm_arg)) # XXX TODO m512 +addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d4, rm_arg)) # XXX TODO m512 +addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d5, rm_arg)) # XXX TODO m512 +addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d6, rm_arg)) # XXX TODO m512 +addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d7, rm_arg)) # XXX TODO m512 +addop("not", [bs('1111011'), w8] + rmmod(d2, rm_arg_w8)) +addop("or", [bs("0000110"), w8, d_eax, d_imm]) +addop("or", [bs("100000"), se, w8] + rmmod(d1, rm_arg_w8) + [d_imm]) +addop("or", [bs("000010"), swapargs, w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) +addop("out", [bs("1110011"), w8, u08, d_eax]) +addop("out", [bs("1110111"), w8, d_edx, d_eax]) + +addop("outsb", [bs8(0x6e)]) +addop("outsw", [bs8(0x6f), bs_opmode16]) +addop("outsd", [bs8(0x6f), bs_opmode32]) +addop("outsd", [bs8(0x6f), bs_opmode64]) + +addop("setalc", [bs8(0xD6)]) + +# addop("pause", [bs8(0xf3), bs8(0x90)]) + +addop("popw", [bs8(0x8f), stk, bs_opmode16] + rmmod(d0)) +addop("popw", [bs("01011"), stk, reg, bs_opmode16]) +addop("popw", [bs8(0x1f), stk, d_ds, bs_opmode16]) +addop("popw", [bs8(0x07), stk, d_es, bs_opmode16]) +addop("popw", [bs8(0x17), stk, d_ss, bs_opmode16]) +addop("popw", [bs8(0x0f), stk, bs8(0xa1), d_fs, bs_opmode16]) +addop("popw", [bs8(0x0f), stk, bs8(0xa9), d_gs, bs_opmode16]) + +addop("pop", [bs8(0x8f), stk, bs_opmode32] + rmmod(d0)) +addop("pop", [bs("01011"), stk, reg, bs_opmode32]) +addop("pop", [bs8(0x1f), stk, d_ds, bs_opmode32]) +addop("pop", [bs8(0x07), stk, d_es, bs_opmode32]) +addop("pop", [bs8(0x17), stk, d_ss, bs_opmode32]) +addop("pop", [bs8(0x0f), stk, bs8(0xa1), d_fs, bs_opmode32]) +addop("pop", [bs8(0x0f), stk, bs8(0xa9), d_gs, bs_opmode32]) + +addop("pop", [bs8(0x8f), stk, bs_opmode64] + rmmod(d0)) +addop("pop", [bs("01011"), stk, reg, bs_opmode64]) +addop("pop", [bs8(0x1f), stk, d_ds, bs_opmode64]) +addop("pop", [bs8(0x07), stk, d_es, bs_opmode64]) +addop("pop", [bs8(0x17), stk, d_ss, bs_opmode64]) +addop("pop", [bs8(0x0f), stk, bs8(0xa1), d_fs, bs_opmode64]) +addop("pop", [bs8(0x0f), stk, bs8(0xa9), d_gs, bs_opmode64]) + + +addop("popa", [bs8(0x61), stk, bs_opmode16]) +addop("popad", [bs8(0x61), stk, bs_opmode32]) + +addop("popfw", [bs8(0x9d), stk, bs_opmode16]) +addop("popfd", [bs8(0x9d), stk, bs_opmode32]) +addop("popfq", [bs8(0x9d), stk, bs_opmode64]) + +addop("prefetch0", [bs8(0x0f), bs8(0x18)] + rmmod(d1, rm_arg_m08)) +addop("prefetch1", [bs8(0x0f), bs8(0x18)] + rmmod(d2, rm_arg_m08)) +addop("prefetch2", [bs8(0x0f), bs8(0x18)] + rmmod(d3, rm_arg_m08)) +addop("prefetchnta", [bs8(0x0f), bs8(0x18)] + rmmod(d0, rm_arg_m08)) +addop("prefetchw", [bs8(0x0f), bs8(0x0d)] + rmmod(d1, rm_arg_m08)) + +addop("pushw", [bs8(0xff), stk, bs_opmode16] + rmmod(d6)) +addop("pushw", [bs("01010"), stk, reg, bs_opmode16]) +addop("pushw", [bs8(0x6a), s08, stk, bs_opmode16]) +addop("pushw", [bs8(0x68), d_imm, stk, bs_opmode16]) +addop("pushw", [bs8(0x0e), stk, d_cs, bs_opmode16]) +addop("pushw", [bs8(0x16), stk, d_ss, bs_opmode16]) +addop("pushw", [bs8(0x1e), stk, d_ds, bs_opmode16]) +addop("pushw", [bs8(0x06), stk, d_es, bs_opmode16]) +addop("pushw", [bs8(0x0f), stk, bs8(0xa0), d_fs, bs_opmode16]) +addop("pushw", [bs8(0x0f), stk, bs8(0xa8), d_gs, bs_opmode16]) + +addop("push", [bs8(0xff), stk, bs_opmode32] + rmmod(d6)) +addop("push", [bs("01010"), stk, reg, bs_opmode32]) +addop("push", [bs8(0x6a), s08, stk, bs_opmode32]) +addop("push", [bs8(0x68), d_imm, stk, bs_opmode32]) +addop("push", [bs8(0x0e), stk, d_cs, bs_opmode32]) +addop("push", [bs8(0x16), stk, d_ss, bs_opmode32]) +addop("push", [bs8(0x1e), stk, d_ds, bs_opmode32]) +addop("push", [bs8(0x06), stk, d_es, bs_opmode32]) +addop("push", [bs8(0x0f), stk, bs8(0xa0), d_fs, bs_opmode32]) +addop("push", [bs8(0x0f), stk, bs8(0xa8), d_gs, bs_opmode32]) + +addop("push", [bs8(0xff), stk, bs_opmode64] + rmmod(d6)) +addop("push", [bs("01010"), stk, reg, bs_opmode64]) +addop("push", [bs8(0x6a), s08, stk, bs_opmode64]) +addop("push", [bs8(0x68), d_imm, stk, bs_opmode64]) +addop("push", [bs8(0x0e), stk, d_cs, bs_opmode64]) +addop("push", [bs8(0x16), stk, d_ss, bs_opmode64]) +addop("push", [bs8(0x1e), stk, d_ds, bs_opmode64]) +addop("push", [bs8(0x06), stk, d_es, bs_opmode64]) +addop("push", [bs8(0x0f), stk, bs8(0xa0), d_fs, bs_opmode64]) +addop("push", [bs8(0x0f), stk, bs8(0xa8), d_gs, bs_opmode64]) + +addop("pusha", [bs8(0x60), stk, bs_opmode16_no64]) +addop("pushad", [bs8(0x60), stk, bs_opmode32_no64]) + + +addop("pushfw", [bs8(0x9c), stk, bs_opmode16]) +addop("pushfd", [bs8(0x9c), stk, bs_opmode32]) +addop("pushfq", [bs8(0x9c), stk, bs_opmode64]) + +addop("rcl", [bs('110100'), d_cl1, w8] + + rmmod(d2, rm_arg_w8), [rm_arg_w8, d_cl1]) +addop("rcl", [bs('1100000'), w8] + rmmod(d2, rm_arg_w8) + [u08]) +addop("rcr", [bs('110100'), d_cl1, w8] + + rmmod(d3, rm_arg_w8), [rm_arg_w8, d_cl1]) +addop("rcr", [bs('1100000'), w8] + rmmod(d3, rm_arg_w8) + [u08]) +addop("rol", [bs('110100'), d_cl1, w8] + + rmmod(d0, rm_arg_w8), [rm_arg_w8, d_cl1]) +addop("rol", [bs('1100000'), w8] + rmmod(d0, rm_arg_w8) + [u08]) +addop("ror", [bs('110100'), d_cl1, w8] + + rmmod(d1, rm_arg_w8), [rm_arg_w8, d_cl1]) +addop("ror", [bs('1100000'), w8] + rmmod(d1, rm_arg_w8) + [u08]) + +addop("rdmsr", [bs8(0x0f), bs8(0x32)]) +addop("rdpmc", [bs8(0x0f), bs8(0x33)]) +addop("rdtsc", [bs8(0x0f), bs8(0x31)]) +addop("ret", [bs8(0xc3), stk]) +addop("ret", [bs8(0xc2), stk, u16]) +addop("retf", [bs8(0xcb), stk]) +addop("retf", [bs8(0xca), stk, u16]) + +addop("rsm", [bs8(0x0f), bs8(0xaa)]) +addop("sahf", [bs8(0x9e)]) + +# XXX tipo in doc: /4 instead of /6 +addop("sal", [bs('110100'), d_cl1, w8] + + rmmod(d6, rm_arg_w8), [rm_arg_w8, d_cl1]) +addop("sal", [bs('1100000'), w8] + rmmod(d6, rm_arg_w8) + [u08]) +addop("sar", [bs('110100'), d_cl1, w8] + + rmmod(d7, rm_arg_w8), [rm_arg_w8, d_cl1]) +addop("sar", [bs('1100000'), w8] + rmmod(d7, rm_arg_w8) + [u08]) + +addop("scasb", [bs8(0xae)]) +addop("scasw", [bs8(0xaf), bs_opmode16]) +addop("scasd", [bs8(0xaf), bs_opmode32]) +addop("scasq", [bs8(0xaf), bs_opmode64]) + +addop("shl", [bs('110100'), d_cl1, w8] + + rmmod(d4, rm_arg_w8), [rm_arg_w8, d_cl1]) +addop("shl", [bs('1100000'), w8] + rmmod(d4, rm_arg_w8) + [u08]) +addop("shr", [bs('110100'), d_cl1, w8] + + rmmod(d5, rm_arg_w8), [rm_arg_w8, d_cl1]) +addop("shr", [bs('1100000'), w8] + rmmod(d5, rm_arg_w8) + [u08]) + +addop("sbb", [bs("0001110"), w8, d_eax, d_imm]) +addop("sbb", [bs("100000"), se, w8] + rmmod(d3, rm_arg_w8) + [d_imm]) +addop("sbb", [bs("000110"), swapargs, w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) + +addop("set", [bs8(0x0f), bs('1001'), cond] + rmmod(regnoarg, rm_arg_08)) +addop("sgdt", [bs8(0x0f), bs8(0x01)] + rmmod(d0, modrm=mod_mem)) +addop("shld", [bs8(0x0f), bs8(0xa4)] + + rmmod(rmreg) + [u08], [rm_arg, rmreg, u08]) +addop("shld", [bs8(0x0f), bs8(0xa5)] + + rmmod(rmreg) + [d_cl], [rm_arg, rmreg, d_cl]) +addop("shrd", [bs8(0x0f), bs8(0xac)] + + rmmod(rmreg) + [u08], [rm_arg, rmreg, u08]) +addop("shrd", [bs8(0x0f), bs8(0xad)] + + rmmod(rmreg) + [d_cl], [rm_arg, rmreg, d_cl]) +addop("sidt", [bs8(0x0f), bs8(0x01)] + rmmod(d1, modrm=mod_mem)) +addop("sldt", [bs8(0x0f), bs8(0x00)] + rmmod(d0, rm_arg_x=rm_arg_reg_m16)) +addop("smsw", [bs8(0x0f), bs8(0x01)] + rmmod(d4)) +addop("stc", [bs8(0xf9)]) +addop("std", [bs8(0xfd)]) +addop("sti", [bs8(0xfb)]) +addop("stosb", [bs8(0xaa)]) +addop("stosw", [bs8(0xab), bs_opmode16]) +addop("stosd", [bs8(0xab), bs_opmode32]) +addop("stosq", [bs8(0xab), bs_opmode64]) + +addop("str", [bs8(0x0f), bs8(0x00)] + rmmod(d1)) + +addop("sub", [bs("0010110"), w8, d_eax, d_imm]) +addop("sub", [bs("100000"), se, w8] + rmmod(d5, rm_arg_w8) + [d_imm]) +addop("sub", [bs("001010"), swapargs, w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) + +addop("syscall", [bs8(0x0f), bs8(0x05)]) +addop("sysenter", [bs8(0x0f), bs8(0x34)]) +addop("sysexit", [bs8(0x0f), bs8(0x35)]) +addop("sysret", [bs8(0x0f), bs8(0x07)]) +addop("test", [bs("1010100"), w8, d_eax, d_imm]) +addop("test", [bs("1111011"), w8] + rmmod(d0, rm_arg_w8) + [d_imm]) +addop("test", [bs("1000010"), w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) +addop("ud2", [bs8(0x0f), bs8(0x0b)]) +addop("verr", [bs8(0x0f), bs8(0x00)] + rmmod(d4)) +addop("verw", [bs8(0x0f), bs8(0x00)] + rmmod(d5)) +addop("wbinvd", [bs8(0x0f), bs8(0x09)]) +addop("wrmsr", [bs8(0x0f), bs8(0x30)]) +addop("xadd", [bs8(0x0f), bs("1100000"), w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) + +addop("nop", [bs8(0x90), no_rex], alias=True) + +addop("xchg", [bs('10010'), d_eax, reg]) +addop("xchg", [bs('1000011'), w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) +addop("xlat", [bs8(0xd7)]) + + +addop("xor", [bs("0011010"), w8, d_eax, d_imm]) +addop("xor", [bs("100000"), se, w8] + rmmod(d6, rm_arg_w8) + [d_imm]) +addop("xor", [bs("001100"), swapargs, w8] + + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg]) + + +addop("xgetbv", [bs8(0x0f), bs8(0x01), bs8(0xd0)]) + + + +#### MMX/SSE/AVX operations +####Â Categories are the same than here: https://software.intel.com/sites/landingpage/IntrinsicsGuide/ +#### + +### Arithmetic (integers) +### + +## Move +# SSE +addop("movapd", [bs8(0x0f), bs("0010100"), swapargs] + + rmmod(xmm_reg, rm_arg_xmm) + [bs_opmode16], [xmm_reg, rm_arg_xmm]) +addop("movaps", [bs8(0x0f), bs("0010100"), swapargs] + + rmmod(xmm_reg, rm_arg_xmm_m128) + [bs_opmode32], [xmm_reg, rm_arg_xmm_m128]) +addop("movaps", [bs8(0x0f), bs("0010100"), swapargs] + + rmmod(xmm_reg, rm_arg_xmm_m128) + [bs_opmode64], [xmm_reg, rm_arg_xmm_m128]) +addop("movdqu", [bs8(0x0f), bs("011"), swapargs, bs("1111"), pref_f3] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) +addop("movdqa", [bs8(0x0f), bs("011"), swapargs, bs("1111"), pref_66] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) + +addop("movhpd", [bs8(0x0f), bs("0001011"), swapargs, pref_66] + + rmmod(xmm_reg, rm_arg_m64), [xmm_reg, rm_arg_m64]) +addop("movhps", [bs8(0x0f), bs("0001011"), swapargs, no_xmm_pref] + + rmmod(xmm_reg, rm_arg_m64), [xmm_reg, rm_arg_m64]) +addop("movlpd", [bs8(0x0f), bs("0001001"), swapargs, pref_66] + + rmmod(xmm_reg, rm_arg_m64), [xmm_reg, rm_arg_m64]) +addop("movlps", [bs8(0x0f), bs("0001001"), swapargs, no_xmm_pref] + + rmmod(xmm_reg, rm_arg_m64), [xmm_reg, rm_arg_m64]) + +addop("movhlps", [bs8(0x0f), bs8(0x12), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm_reg), [xmm_reg, rm_arg_xmm_reg]) +addop("movlhps", [bs8(0x0f), bs8(0x16), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm_reg), [xmm_reg, rm_arg_xmm_reg]) + +addop("movdq2q", [bs8(0x0f), bs8(0xd6), pref_f2] + + rmmod(mm_reg, rm_arg_xmm_reg), [mm_reg, rm_arg_xmm_reg]) +addop("movq2dq", [bs8(0x0f), bs8(0xd6), pref_f3] + + rmmod(xmm_reg, rm_arg_mm)) + +## Additions +# SSE +addop("paddb", [bs8(0x0f), bs8(0xfc), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) +addop("paddw", [bs8(0x0f), bs8(0xfd), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) +addop("paddd", [bs8(0x0f), bs8(0xfe), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) +addop("paddq", [bs8(0x0f), bs8(0xd4), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +addop("paddb", [bs8(0x0f), bs8(0xfc), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm)) +addop("paddw", [bs8(0x0f), bs8(0xfd), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm)) +addop("paddd", [bs8(0x0f), bs8(0xfe), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm)) +addop("paddq", [bs8(0x0f), bs8(0xd4), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm)) + +## Substractions +# SSE +addop("psubb", [bs8(0x0f), bs8(0xf8), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) +addop("psubw", [bs8(0x0f), bs8(0xf9), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) +addop("psubd", [bs8(0x0f), bs8(0xfa), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) +addop("psubq", [bs8(0x0f), bs8(0xfb), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +addop("psubb", [bs8(0x0f), bs8(0xf8), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm)) +addop("psubw", [bs8(0x0f), bs8(0xf9), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm)) +addop("psubd", [bs8(0x0f), bs8(0xfa), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm)) +addop("psubq", [bs8(0x0f), bs8(0xfb), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm)) + +### Arithmetic (floating-point) +### + +## Additions +# SSE +addop("addps", [bs8(0x0f), bs8(0x58), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm)) +addop("addpd", [bs8(0x0f), bs8(0x58), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +## Substractions +# SSE +addop("subps", [bs8(0x0f), bs8(0x5c), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm)) +addop("subpd", [bs8(0x0f), bs8(0x5c), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +## Multiplications +# SSE +addop("mulps", [bs8(0x0f), bs8(0x59), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm)) +addop("mulpd", [bs8(0x0f), bs8(0x59), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +## Divisions +# SSE +addop("divps", [bs8(0x0f), bs8(0x5e), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm)) +addop("divpd", [bs8(0x0f), bs8(0x5e), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +### Logical (floating-point) +### + +## XOR +addop("xorps", [bs8(0x0f), bs8(0x57), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm)) +addop("xorpd", [bs8(0x0f), bs8(0x57), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +## AND +addop("andps", [bs8(0x0f), bs8(0x54), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm)) +addop("andpd", [bs8(0x0f), bs8(0x54), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +addop("andnps", [bs8(0x0f), bs8(0x55), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm)) +addop("andnpd", [bs8(0x0f), bs8(0x55), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +## OR +addop("orps", [bs8(0x0f), bs8(0x56), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm)) +addop("orpd", [bs8(0x0f), bs8(0x56), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +## AND +# MMX +addop("pand", [bs8(0x0f), bs8(0xdb), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm]) +# SSE +addop("pand", [bs8(0x0f), bs8(0xdb), pref_66] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) + +## ANDN +# MMX +addop("pandn", [bs8(0x0f), bs8(0xdf), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm]) +# SSE +addop("pandn", [bs8(0x0f), bs8(0xdf), pref_66] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) + +## OR +# MMX +addop("por", [bs8(0x0f), bs8(0xeb), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm]) +# SSE +addop("por", [bs8(0x0f), bs8(0xeb), pref_66] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) + +## XOR +# MMX +addop("pxor", [bs8(0x0f), bs8(0xef), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +# MMX +addop("pxor", [bs8(0x0f), bs8(0xef), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +### Comparisons (floating-point) +### +addop("minps", [bs8(0x0f), bs8(0x5d), no_xmm_pref] + rmmod(xmm_reg, + rm_arg_xmm_m128)) +addop("minss", [bs8(0x0f), bs8(0x5d), pref_f3] + rmmod(xmm_reg, + rm_arg_xmm_m32)) +addop("minpd", [bs8(0x0f), bs8(0x5d), pref_66] + rmmod(xmm_reg, + rm_arg_xmm_m128)) +addop("minsd", [bs8(0x0f), bs8(0x5d), pref_f2] + rmmod(xmm_reg, + rm_arg_xmm_m64)) +addop("maxps", [bs8(0x0f), bs8(0x5f), no_xmm_pref] + rmmod(xmm_reg, + rm_arg_xmm_m128)) +addop("maxpd", [bs8(0x0f), bs8(0x5f), pref_66] + rmmod(xmm_reg, + rm_arg_xmm_m128)) +addop("maxsd", [bs8(0x0f), bs8(0x5f), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64)) +addop("maxss", [bs8(0x0f), bs8(0x5f), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32)) + +for cond_name, value in [ + ("eq", 0x00), + ("lt", 0x01), + ("le", 0x02), + ("unord", 0x03), + ("neq", 0x04), + ("nlt", 0x05), + ("nle", 0x06), + ("ord", 0x07), +]: + addop("cmp%sps" % cond_name, [bs8(0x0f), bs8(0xc2), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm_m64) + [bs8(value)]) + addop("cmp%spd" % cond_name, [bs8(0x0f), bs8(0xc2), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m64) + [bs8(value)]) + addop("cmp%sss" % cond_name, [bs8(0x0f), bs8(0xc2), pref_f3] + + rmmod(xmm_reg, rm_arg_xmm_m32) + [bs8(value)]) + addop("cmp%ssd" % cond_name, [bs8(0x0f), bs8(0xc2), pref_f2] + + rmmod(xmm_reg, rm_arg_xmm_m32) + [bs8(value)]) + + + +addop("pshufb", [bs8(0x0f), bs8(0x38), bs8(0x00), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("pshufb", [bs8(0x0f), bs8(0x38), bs8(0x00), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("pshufd", [bs8(0x0f), bs8(0x70), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128) + [u08]) +addop("pshuflw", [bs8(0x0f), bs8(0x70), pref_f2] + + rmmod(xmm_reg, rm_arg_xmm_m128) + [u08]) +addop("pshufhw", [bs8(0x0f), bs8(0x70), pref_f3] + + rmmod(xmm_reg, rm_arg_xmm_m128) + [u08]) + + +### Convert +### SS = single precision +### SD = double precision +### + +## SS -> SD +## + +addop("cvtdq2pd", [bs8(0x0f), bs8(0xe6), pref_f3] + + rmmod(xmm_reg, rm_arg_xmm_m64)) +addop("cvtdq2ps", [bs8(0x0f), bs8(0x5b), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm)) +addop("cvtpd2dq", [bs8(0x0f), bs8(0xe6), pref_f2] + + rmmod(xmm_reg, rm_arg_xmm)) +addop("cvtpd2pi", [bs8(0x0f), bs8(0x2d), pref_66] + + rmmod(mm_reg, rm_arg_xmm)) +addop("cvtpd2ps", [bs8(0x0f), bs8(0x5a), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) +addop("cvtpi2pd", [bs8(0x0f), bs8(0x2a), pref_66] + + rmmod(xmm_reg, rm_arg_mm_m64)) +addop("cvtpi2ps", [bs8(0x0f), bs8(0x2a), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_mm_m64)) +addop("cvtps2dq", [bs8(0x0f), bs8(0x5b), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) +addop("cvtps2pd", [bs8(0x0f), bs8(0x5a), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm_m64)) +addop("cvtps2pi", [bs8(0x0f), bs8(0x2d), no_xmm_pref] + + rmmod(mm_reg, rm_arg_xmm_m64)) +addop("cvtsd2si", [bs8(0x0f), bs8(0x2d), pref_f2] + + rmmod(reg, rm_arg_xmm_m64)) +addop("cvtsd2ss", [bs8(0x0f), bs8(0x5a), pref_f2] + + rmmod(xmm_reg, rm_arg_xmm_m64)) +addop("cvtsi2sd", [bs8(0x0f), bs8(0x2a), pref_f2] + + rmmod(xmm_reg, rm_arg)) +addop("cvtsi2ss", [bs8(0x0f), bs8(0x2a), xmmreg, pref_f3] + + rmmod(xmm_reg, rm_arg)) +addop("cvtss2sd", [bs8(0x0f), bs8(0x5a), pref_f3] + + rmmod(xmm_reg, rm_arg_xmm_m32)) +addop("cvtss2si", [bs8(0x0f), bs8(0x2d), pref_f3] + + rmmod(rmreg, rm_arg_xmm_m32)) +addop("cvttpd2pi",[bs8(0x0f), bs8(0x2c), pref_66] + + rmmod(mm_reg, rm_arg_xmm)) +addop("cvttpd2dq",[bs8(0x0f), bs8(0xe6), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) +addop("cvttps2dq",[bs8(0x0f), bs8(0x5b), pref_f3] + + rmmod(xmm_reg, rm_arg_xmm)) +addop("cvttps2pi",[bs8(0x0f), bs8(0x2c), no_xmm_pref] + + rmmod(mm_reg, rm_arg_xmm_m64)) +addop("cvttsd2si",[bs8(0x0f), bs8(0x2c), pref_f2] + + rmmod(reg, rm_arg_xmm_m64)) +addop("cvttss2si",[bs8(0x0f), bs8(0x2c), pref_f3] + + rmmod(reg, rm_arg_xmm_m32)) + +addop("palignr", [bs8(0x0f), bs8(0x73), bs8(0x0f), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64) + [u08], [mm_reg, rm_arg_mm_m64, u08]) +addop("palignr", [bs8(0x0f), bs8(0x3a), bs8(0x0f), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128) + [u08], [xmm_reg, rm_arg_xmm_m128, u08]) + +addop("psrlq", [bs8(0x0f), bs8(0x73), no_xmm_pref] + + rmmod(d2, rm_arg_mm) + [u08], [rm_arg_mm, u08]) +addop("psrlq", [bs8(0x0f), bs8(0x73), pref_66] + + rmmod(d2, rm_arg_xmm) + [u08], [rm_arg_xmm, u08]) + +addop("psrlq", [bs8(0x0f), bs8(0xd3), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm]) +addop("psrlq", [bs8(0x0f), bs8(0xd3), pref_66] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) + + +addop("psrld", [bs8(0x0f), bs8(0x72), no_xmm_pref] + + rmmod(d2, rm_arg_mm) + [u08], [rm_arg_mm, u08]) +addop("psrld", [bs8(0x0f), bs8(0x72), pref_66] + + rmmod(d2, rm_arg_xmm) + [u08], [rm_arg_xmm, u08]) + +addop("psrld", [bs8(0x0f), bs8(0xd2), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm]) +addop("psrld", [bs8(0x0f), bs8(0xd2), pref_66] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) + +addop("psrldq", [bs8(0x0f), bs8(0x73), pref_66] + + rmmod(d3, rm_arg_xmm) + [u08], [rm_arg_xmm, u08]) + +addop("psrlw", [bs8(0x0f), bs8(0x71), no_xmm_pref] + + rmmod(d2, rm_arg_mm) + [u08], [rm_arg_mm, u08]) +addop("psrlw", [bs8(0x0f), bs8(0x71), pref_66] + + rmmod(d2, rm_arg_xmm) + [u08], [rm_arg_xmm, u08]) + +addop("psrlw", [bs8(0x0f), bs8(0xd1), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64), [mm_reg, rm_arg_mm_m64]) +addop("psrlw", [bs8(0x0f), bs8(0xd1), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128), [xmm_reg, rm_arg_xmm_m128]) + +addop("psraw", [bs8(0x0f), bs8(0xe1), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64), [mm_reg, rm_arg_mm_m64]) +addop("psraw", [bs8(0x0f), bs8(0xe1), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128), [xmm_reg, rm_arg_xmm_m128]) + +addop("psraw", [bs8(0x0f), bs8(0x71), no_xmm_pref] + + rmmod(d4, rm_arg_mm_m64) + [u08], [rm_arg_mm_m64, u08]) +addop("psraw", [bs8(0x0f), bs8(0x71), pref_66] + + rmmod(d4, rm_arg_xmm_m128) + [u08], [rm_arg_xmm_m128, u08]) + +addop("psrad", [bs8(0x0f), bs8(0xe2), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64), [mm_reg, rm_arg_mm_m64]) +addop("psrad", [bs8(0x0f), bs8(0xe2), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128), [xmm_reg, rm_arg_xmm_m128]) + +addop("psrad", [bs8(0x0f), bs8(0x72), no_xmm_pref] + + rmmod(d4, rm_arg_mm_m64) + [u08], [rm_arg_mm_m64, u08]) +addop("psrad", [bs8(0x0f), bs8(0x72), pref_66] + + rmmod(d4, rm_arg_xmm_m128) + [u08], [rm_arg_xmm_m128, u08]) + + +addop("psllq", [bs8(0x0f), bs8(0x73), no_xmm_pref] + + rmmod(d6, rm_arg_mm) + [u08], [rm_arg_mm, u08]) +addop("psllq", [bs8(0x0f), bs8(0x73), pref_66] + + rmmod(d6, rm_arg_xmm) + [u08], [rm_arg_xmm, u08]) + +addop("psllq", [bs8(0x0f), bs8(0xf3), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm]) +addop("psllq", [bs8(0x0f), bs8(0xf3), pref_66] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) + + +addop("pslld", [bs8(0x0f), bs8(0x72), no_xmm_pref] + + rmmod(d6, rm_arg_mm) + [u08], [rm_arg_mm, u08]) +addop("pslld", [bs8(0x0f), bs8(0x72), pref_66] + + rmmod(d6, rm_arg_xmm) + [u08], [rm_arg_xmm, u08]) + +addop("pslld", [bs8(0x0f), bs8(0xf2), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm]) +addop("pslld", [bs8(0x0f), bs8(0xf2), pref_66] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) + + +addop("psllw", [bs8(0x0f), bs8(0x71), no_xmm_pref] + + rmmod(d6, rm_arg_mm) + [u08], [rm_arg_mm, u08]) +addop("psllw", [bs8(0x0f), bs8(0x71), pref_66] + + rmmod(d6, rm_arg_xmm) + [u08], [rm_arg_xmm, u08]) + +addop("psllw", [bs8(0x0f), bs8(0xf1), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm]) +addop("psllw", [bs8(0x0f), bs8(0xf1), pref_66] + + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm]) + +addop("pslldq", [bs8(0x0f), bs8(0x73), pref_66] + + rmmod(d7, rm_arg_xmm) + [u08], [rm_arg_xmm, u08]) + + +addop("pmaxub", [bs8(0x0f), bs8(0xde), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("pmaxub", [bs8(0x0f), bs8(0xde), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pmaxuw", [bs8(0x0f), bs8(0x38), bs8(0x3e), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pmaxud", [bs8(0x0f), bs8(0x38), bs8(0x3f), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pmaxsw", [bs8(0x0f), bs8(0xee), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("pmaxsw", [bs8(0x0f), bs8(0xee), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) + +addop("pminub", [bs8(0x0f), bs8(0xda), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("pminub", [bs8(0x0f), bs8(0xda), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pminuw", [bs8(0x0f), bs8(0x38), bs8(0x3a), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pminud", [bs8(0x0f), bs8(0x38), bs8(0x3b), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + + +addop("pcmpeqb", [bs8(0x0f), bs8(0x74), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("pcmpeqb", [bs8(0x0f), bs8(0x74), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pcmpeqw", [bs8(0x0f), bs8(0x75), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("pcmpeqw", [bs8(0x0f), bs8(0x75), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pcmpeqd", [bs8(0x0f), bs8(0x76), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("pcmpeqd", [bs8(0x0f), bs8(0x76), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pcmpgtb", [bs8(0x0f), bs8(0x64), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("pcmpgtb", [bs8(0x0f), bs8(0x64), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pcmpgtw", [bs8(0x0f), bs8(0x65), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("pcmpgtw", [bs8(0x0f), bs8(0x65), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pcmpgtd", [bs8(0x0f), bs8(0x66), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("pcmpgtd", [bs8(0x0f), bs8(0x66), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("pcmpeqq", [bs8(0x0f), bs8(0x38), bs8(0x29), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) +addop("pcmpgtq", [bs8(0x0f), bs8(0x38), bs8(0x37), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +addop("punpckhbw", [bs8(0x0f), bs8(0x68), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("punpckhbw", [bs8(0x0f), bs8(0x68), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("punpckhwd", [bs8(0x0f), bs8(0x69), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("punpckhwd", [bs8(0x0f), bs8(0x69), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("punpckhdq", [bs8(0x0f), bs8(0x6a), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("punpckhdq", [bs8(0x0f), bs8(0x6a), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("punpckhqdq", [bs8(0x0f), bs8(0x6d), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + + + +addop("punpcklbw", [bs8(0x0f), bs8(0x60), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("punpcklbw", [bs8(0x0f), bs8(0x60), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("punpcklwd", [bs8(0x0f), bs8(0x61), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("punpcklwd", [bs8(0x0f), bs8(0x61), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("punpckldq", [bs8(0x0f), bs8(0x62), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm)) +addop("punpckldq", [bs8(0x0f), bs8(0x62), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + +addop("punpcklqdq", [bs8(0x0f), bs8(0x6c), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + + +addop("unpckhps", [bs8(0x0f), bs8(0x15), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm)) +addop("unpckhpd", [bs8(0x0f), bs8(0x15), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + + +addop("unpcklps", [bs8(0x0f), bs8(0x14), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm)) +addop("unpcklpd", [bs8(0x0f), bs8(0x14), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) + + + +addop("pinsrb", [bs8(0x0f), bs8(0x3a), bs8(0x20), pref_66] + + rmmod(xmm_reg, rm_arg_reg_m08) + [u08]) +addop("pinsrd", [bs8(0x0f), bs8(0x3a), bs8(0x22), pref_66, bs_opmode32] + + rmmod(xmm_reg, rm_arg) + [u08]) +addop("pinsrq", [bs8(0x0f), bs8(0x3a), bs8(0x22), pref_66] + + rmmod(xmm_reg, rm_arg_m64) + [bs_opmode64] + [u08]) + +addop("pinsrw", [bs8(0x0f), bs8(0xc4), no_xmm_pref] + + rmmod(mm_reg, rm_arg_reg_m16) + [u08]) +addop("pinsrw", [bs8(0x0f), bs8(0xc4), pref_66] + + rmmod(xmm_reg, rm_arg_reg_m16) + [u08]) + + +addop("pextrb", [bs8(0x0f), bs8(0x3a), bs8(0x14), pref_66] + + rmmod(xmm_reg, rm_arg_reg_m08) + [u08], [rm_arg_reg_m08, xmm_reg, u08]) +addop("pextrd", [bs8(0x0f), bs8(0x3a), bs8(0x16), pref_66, bs_opmode32] + + rmmod(xmm_reg, rm_arg) + [u08], [rm_arg, xmm_reg, u08]) +addop("pextrq", [bs8(0x0f), bs8(0x3a), bs8(0x16), pref_66] + + rmmod(xmm_reg, rm_arg_m64) + [bs_opmode64] + [u08], [rm_arg_m64, xmm_reg, u08]) + + +addop("pextrw", [bs8(0x0f), bs8(0x3a), bs8(0x15), pref_66] + + rmmod(xmm_reg, rm_arg_reg_m16) + [u08], [rm_arg_reg_m16, xmm_reg, u08]) +addop("pextrw", [bs8(0x0f), bs8(0xc5), no_xmm_pref] + + rmmod(rmreg, rm_arg_mm) + [u08], [rmreg, rm_arg_mm, u08]) +addop("pextrw", [bs8(0x0f), bs8(0xc5), pref_66] + + rmmod(rmreg, rm_arg_xmm) + [u08], [rmreg, rm_arg_xmm, u08]) + + +addop("sqrtpd", [bs8(0x0f), bs8(0x51), pref_66] + + rmmod(xmm_reg, rm_arg_xmm)) +addop("sqrtps", [bs8(0x0f), bs8(0x51), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm)) +addop("sqrtsd", [bs8(0x0f), bs8(0x51), pref_f2] + + rmmod(xmm_reg, rm_arg_xmm_m64)) +addop("sqrtss", [bs8(0x0f), bs8(0x51), pref_f3] + + rmmod(xmm_reg, rm_arg_xmm_m32)) + +addop("pmovmskb", [bs8(0x0f), bs8(0xd7), no_xmm_pref] + + rmmod(reg_modrm, rm_arg_mm_reg)) +addop("pmovmskb", [bs8(0x0f), bs8(0xd7), pref_66] + + rmmod(reg_modrm, rm_arg_xmm_reg)) + +addop("shufps", [bs8(0x0f), bs8(0xc6), no_xmm_pref] + + rmmod(xmm_reg, rm_arg_xmm) + [u08]) +addop("shufpd", [bs8(0x0f), bs8(0xc6), pref_66] + + rmmod(xmm_reg, rm_arg_xmm) + [u08]) + +addop("aesenc", [bs8(0x0f), bs8(0x38), bs8(0xdc), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) +addop("aesdec", [bs8(0x0f), bs8(0x38), bs8(0xde), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +addop("aesenclast", [bs8(0x0f), bs8(0x38), bs8(0xdd), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) +addop("aesdeclast", [bs8(0x0f), bs8(0x38), bs8(0xdf), pref_66] + rmmod(xmm_reg, rm_arg_xmm)) + +addop("packsswb", [bs8(0x0f), bs8(0x63), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("packsswb", [bs8(0x0f), bs8(0x63), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("packssdw", [bs8(0x0f), bs8(0x6b), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("packssdw", [bs8(0x0f), bs8(0x6b), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) + +addop("packuswb", [bs8(0x0f), bs8(0x67), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("packuswb", [bs8(0x0f), bs8(0x67), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) + +addop("pmullw", [bs8(0x0f), bs8(0xd5), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("pmullw", [bs8(0x0f), bs8(0xd5), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("pmulhuw", [bs8(0x0f), bs8(0xe4), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("pmulhuw", [bs8(0x0f), bs8(0xe4), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("pmulhw", [bs8(0x0f), bs8(0xe5), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("pmulhw", [bs8(0x0f), bs8(0xe5), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("pmuludq", [bs8(0x0f), bs8(0xf4), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("pmuludq", [bs8(0x0f), bs8(0xf4), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) + + +addop("psubusb", [bs8(0x0f), bs8(0xd8), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("psubusb", [bs8(0x0f), bs8(0xd8), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("psubusw", [bs8(0x0f), bs8(0xd9), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("psubusw", [bs8(0x0f), bs8(0xd9), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("psubsb", [bs8(0x0f), bs8(0xe8), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("psubsb", [bs8(0x0f), bs8(0xe8), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("psubsw", [bs8(0x0f), bs8(0xe9), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("psubsw", [bs8(0x0f), bs8(0xe9), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) + + +addop("paddusb", [bs8(0x0f), bs8(0xdc), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("paddusb", [bs8(0x0f), bs8(0xdc), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("paddusw", [bs8(0x0f), bs8(0xdd), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("paddusw", [bs8(0x0f), bs8(0xdd), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("paddsb", [bs8(0x0f), bs8(0xec), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("paddsb", [bs8(0x0f), bs8(0xec), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("paddsw", [bs8(0x0f), bs8(0xed), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("paddsw", [bs8(0x0f), bs8(0xed), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) + +addop("pmaddwd", [bs8(0x0f), bs8(0xf5), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("pmaddwd", [bs8(0x0f), bs8(0xf5), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) + +addop("psadbw", [bs8(0x0f), bs8(0xf6), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("psadbw", [bs8(0x0f), bs8(0xf6), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) + +addop("pavgb", [bs8(0x0f), bs8(0xe0), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("pavgb", [bs8(0x0f), bs8(0xe0), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) +addop("pavgw", [bs8(0x0f), bs8(0xe3), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_m64)) +addop("pavgw", [bs8(0x0f), bs8(0xe3), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_m128)) + +addop("maskmovq", [bs8(0x0f), bs8(0xf7), no_xmm_pref] + + rmmod(mm_reg, rm_arg_mm_reg)) +addop("maskmovdqu", [bs8(0x0f), bs8(0xf7), pref_66] + + rmmod(xmm_reg, rm_arg_xmm_reg)) + +addop("emms", [bs8(0x0f), bs8(0x77)]) + +addop("incssp", [pref_f3, bs8(0x0f), bs8(0xae)] + rmmod(d5)) +addop("rdssp", [pref_f3, bs8(0x0f), bs8(0x1e)] + rmmod(d1, modrm=mod_reg)) +addop("saveprevssp", [pref_f3, bs8(0x0f), bs8(0x01), bs8(0xea)]) +addop("rstorssp", [pref_f3, bs8(0x0f), bs8(0x01)] + rmmod(d5, rm_arg_xmm, modrm=mod_mem)) +addop("wrss", [bs8(0x0f), bs8(0x38), bs8(0xf6)] + rmmod(rmreg, rm_arg), [rm_arg, rmreg]) +addop("wruss", [pref_66, bs8(0x0f), bs8(0x38), bs8(0xf5)] + rmmod(rmreg, rm_arg), [rm_arg, rmreg]) +addop("setssbsy", [pref_f3, bs8(0x0f), bs8(0x01), bs8(0xe8)]) +addop("clrssbsy", [pref_f3, bs8(0x0f), bs8(0xae)] + rmmod(d6, rm_arg_xmm)) +addop("endbr64", [pref_f3, bs8(0x0f), bs8(0x1e), bs8(0xfa)]) +addop("endbr32", [pref_f3, bs8(0x0f), bs8(0x1e), bs8(0xfb)]) + +mn_x86.bintree = factor_one_bit(mn_x86.bintree) +# mn_x86.bintree = factor_fields_all(mn_x86.bintree) +""" +mod reg r/m + XX XXX XXX + +""" + + +def print_size(e): + print(e, e.size) + return e diff --git a/src/miasm/arch/x86/ctype.py b/src/miasm/arch/x86/ctype.py new file mode 100644 index 00000000..2a61689a --- /dev/null +++ b/src/miasm/arch/x86/ctype.py @@ -0,0 +1,137 @@ +from miasm.core.objc import CLeafTypes, ObjCDecl, PADDING_TYPE_NAME +from miasm.core.ctypesmngr import CTypeId, CTypePtr + + +class CTypeAMD64_unk(CLeafTypes): + """Define C types sizes/alignment for x86_64 architecture""" + + obj_pad = ObjCDecl(PADDING_TYPE_NAME, 1, 1) # __padding__ is size 1/align 1 + + obj_char = ObjCDecl("char", 1, 1) + obj_short = ObjCDecl("short", 2, 2) + obj_int = ObjCDecl("int", 4, 4) + obj_long = ObjCDecl("long", 8, 8) + + obj_uchar = ObjCDecl("uchar", 1, 1) + obj_ushort = ObjCDecl("ushort", 2, 2) + obj_uint = ObjCDecl("uint", 4, 4) + obj_ulong = ObjCDecl("ulong", 8, 8) + + obj_void = ObjCDecl("void", 1, 1) + + obj_enum = ObjCDecl("enum", 4, 4) + + obj_float = ObjCDecl("float", 4, 4) + obj_double = ObjCDecl("double", 8, 8) + obj_ldouble = ObjCDecl("ldouble", 16, 16) + + def __init__(self): + self.types = { + CTypeId(PADDING_TYPE_NAME): self.obj_pad, + + CTypeId('char'): self.obj_char, + CTypeId('short'): self.obj_short, + CTypeId('int'): self.obj_int, + CTypeId('void'): self.obj_void, + CTypeId('long',): self.obj_long, + CTypeId('float'): self.obj_float, + CTypeId('double'): self.obj_double, + + CTypeId('signed', 'char'): self.obj_char, + CTypeId('unsigned', 'char'): self.obj_uchar, + + CTypeId('short', 'int'): self.obj_short, + CTypeId('signed', 'short'): self.obj_short, + CTypeId('signed', 'short', 'int'): self.obj_short, + CTypeId('unsigned', 'short'): self.obj_ushort, + CTypeId('unsigned', 'short', 'int'): self.obj_ushort, + + CTypeId('unsigned', ): self.obj_uint, + CTypeId('unsigned', 'int'): self.obj_uint, + CTypeId('signed', 'int'): self.obj_int, + + CTypeId('long', 'int'): self.obj_long, + CTypeId('long', 'long'): self.obj_long, + CTypeId('long', 'long', 'int'): self.obj_long, + CTypeId('signed', 'long', 'long'): self.obj_long, + CTypeId('unsigned', 'long', 'long'): self.obj_ulong, + CTypeId('signed', 'long', 'long', 'int'): self.obj_long, + CTypeId('unsigned', 'long', 'long', 'int'): self.obj_ulong, + + CTypeId('signed', 'long'): self.obj_long, + CTypeId('unsigned', 'long'): self.obj_ulong, + CTypeId('signed', 'long', 'int'): self.obj_long, + CTypeId('unsigned', 'long', 'int'): self.obj_ulong, + + CTypeId('long', 'double'): self.obj_ldouble, + CTypePtr(CTypeId('void')): self.obj_ulong, + } + + + + + +class CTypeX86_unk(CLeafTypes): + """Define C types sizes/alignment for x86_32 architecture""" + + obj_pad = ObjCDecl(PADDING_TYPE_NAME, 1, 1) # __padding__ is size 1/align 1 + + obj_char = ObjCDecl("char", 1, 1) + obj_short = ObjCDecl("short", 2, 2) + obj_int = ObjCDecl("int", 4, 4) + obj_long = ObjCDecl("long", 4, 4) + + obj_uchar = ObjCDecl("uchar", 1, 1) + obj_ushort = ObjCDecl("ushort", 2, 2) + obj_uint = ObjCDecl("uint", 4, 4) + obj_ulong = ObjCDecl("ulong", 4, 4) + + obj_void = ObjCDecl("void", 1, 1) + + obj_enum = ObjCDecl("enum", 4, 4) + + obj_float = ObjCDecl("float", 4, 4) + obj_double = ObjCDecl("double", 8, 8) + obj_ldouble = ObjCDecl("ldouble", 16, 16) + + def __init__(self): + self.types = { + CTypeId(PADDING_TYPE_NAME): self.obj_pad, + + CTypeId('char'): self.obj_char, + CTypeId('short'): self.obj_short, + CTypeId('int'): self.obj_int, + CTypeId('void'): self.obj_void, + CTypeId('long',): self.obj_long, + CTypeId('float'): self.obj_float, + CTypeId('double'): self.obj_double, + + CTypeId('signed', 'char'): self.obj_char, + CTypeId('unsigned', 'char'): self.obj_uchar, + + CTypeId('short', 'int'): self.obj_short, + CTypeId('signed', 'short'): self.obj_short, + CTypeId('signed', 'short', 'int'): self.obj_short, + CTypeId('unsigned', 'short'): self.obj_ushort, + CTypeId('unsigned', 'short', 'int'): self.obj_ushort, + + CTypeId('unsigned', ): self.obj_uint, + CTypeId('unsigned', 'int'): self.obj_uint, + CTypeId('signed', 'int'): self.obj_int, + + CTypeId('long', 'int'): self.obj_long, + CTypeId('long', 'long'): self.obj_long, + CTypeId('long', 'long', 'int'): self.obj_long, + CTypeId('signed', 'long', 'long'): self.obj_long, + CTypeId('unsigned', 'long', 'long'): self.obj_ulong, + CTypeId('signed', 'long', 'long', 'int'): self.obj_long, + CTypeId('unsigned', 'long', 'long', 'int'): self.obj_ulong, + + CTypeId('signed', 'long'): self.obj_long, + CTypeId('unsigned', 'long'): self.obj_ulong, + CTypeId('signed', 'long', 'int'): self.obj_long, + CTypeId('unsigned', 'long', 'int'): self.obj_ulong, + + CTypeId('long', 'double'): self.obj_ldouble, + CTypePtr(CTypeId('void')): self.obj_uint, + } diff --git a/src/miasm/arch/x86/disasm.py b/src/miasm/arch/x86/disasm.py new file mode 100644 index 00000000..49b7158a --- /dev/null +++ b/src/miasm/arch/x86/disasm.py @@ -0,0 +1,30 @@ +from miasm.core.asmblock import disasmEngine +from miasm.arch.x86.arch import mn_x86 + + +cb_x86_funcs = [] + + +def cb_x86_disasm(mdis, cur_block, offset_to_dis): + for func in cb_x86_funcs: + func(mdis, cur_block, offset_to_dis) + + +class dis_x86(disasmEngine): + attrib = None + + def __init__(self, bs=None, **kwargs): + super(dis_x86, self).__init__(mn_x86, self.attrib, bs, **kwargs) + self.dis_block_callback = cb_x86_disasm + + +class dis_x86_16(dis_x86): + attrib = 16 + + +class dis_x86_32(dis_x86): + attrib = 32 + + +class dis_x86_64(dis_x86): + attrib = 64 diff --git a/src/miasm/arch/x86/jit.py b/src/miasm/arch/x86/jit.py new file mode 100644 index 00000000..a90dec07 --- /dev/null +++ b/src/miasm/arch/x86/jit.py @@ -0,0 +1,296 @@ +from builtins import range +import logging + +from miasm.jitter.jitload import Jitter, named_arguments +from miasm.arch.x86.sem import Lifter_X86_16, Lifter_X86_32, Lifter_X86_64 +from miasm.jitter.codegen import CGen +from miasm.ir.translators.C import TranslatorC + +log = logging.getLogger('jit_x86') +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) + + +class x86_32_CGen(CGen): + def __init__(self, lifter): + self.lifter = lifter + self.PC = self.lifter.arch.regs.RIP + self.translator = TranslatorC(self.lifter.loc_db) + self.init_arch_C() + + def gen_post_code(self, attrib, pc_value): + out = [] + if attrib.log_regs: + # Update PC for dump_gpregs + out.append("%s = %s;" % (self.C_PC, pc_value)) + out.append('dump_gpregs_32(jitcpu->cpu);') + return out + +class x86_64_CGen(x86_32_CGen): + def gen_post_code(self, attrib, pc_value): + out = [] + if attrib.log_regs: + # Update PC for dump_gpregs + out.append("%s = %s;" % (self.C_PC, pc_value)) + out.append('dump_gpregs_64(jitcpu->cpu);') + return out + +class jitter_x86_16(Jitter): + + C_Gen = x86_32_CGen + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_X86_16(loc_db), *args, **kwargs) + self.vm.set_little_endian() + self.lifter.do_stk_segm = False + self.orig_irbloc_fix_regs_for_mode = self.lifter.irbloc_fix_regs_for_mode + self.lifter.irbloc_fix_regs_for_mode = self.lifterbloc_fix_regs_for_mode + + def lifterbloc_fix_regs_for_mode(self, irblock, attrib=64): + return self.orig_irbloc_fix_regs_for_mode(irblock, 64) + + def push_uint16_t(self, value): + self.cpu.SP -= self.lifter.sp.size // 8 + self.vm.set_u16(self.cpu.SP, value) + + def pop_uint16_t(self): + value = self.vm.get_u16(self.cpu.SP) + self.cpu.SP += self.lifter.sp.size // 8 + return value + + def get_stack_arg(self, index): + return self.vm.get_u16(self.cpu.SP + 4 * index) + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.IP = self.pc + + +class jitter_x86_32(Jitter): + + C_Gen = x86_32_CGen + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_X86_32(loc_db), *args, **kwargs) + self.vm.set_little_endian() + self.lifter.do_stk_segm = False + + self.orig_irbloc_fix_regs_for_mode = self.lifter.irbloc_fix_regs_for_mode + self.lifter.irbloc_fix_regs_for_mode = self.lifterbloc_fix_regs_for_mode + + def lifterbloc_fix_regs_for_mode(self, irblock, attrib=64): + return self.orig_irbloc_fix_regs_for_mode(irblock, 64) + + def push_uint16_t(self, value): + self.cpu.ESP -= self.lifter.sp.size // 8 + self.vm.set_u16(self.cpu.ESP, value) + + def pop_uint16_t(self): + value = self.vm.get_u16(self.cpu.ESP) + self.cpu.ESP += self.lifter.sp.size // 8 + return value + + def push_uint32_t(self, value): + self.cpu.ESP -= self.lifter.sp.size // 8 + self.vm.set_u32(self.cpu.ESP, value) + + def pop_uint32_t(self): + value = self.vm.get_u32(self.cpu.ESP) + self.cpu.ESP += self.lifter.sp.size // 8 + return value + + def get_stack_arg(self, index): + return self.vm.get_u32(self.cpu.ESP + 4 * index) + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.EIP = self.pc + + # calling conventions + + # stdcall + @named_arguments + def func_args_stdcall(self, n_args): + ret_ad = self.pop_uint32_t() + args = [self.pop_uint32_t() for _ in range(n_args)] + return ret_ad, args + + def func_ret_stdcall(self, ret_addr, ret_value1=None, ret_value2=None): + self.pc = self.cpu.EIP = ret_addr + if ret_value1 is not None: + self.cpu.EAX = ret_value1 + if ret_value2 is not None: + self.cpu.EDX = ret_value2 + + def func_prepare_stdcall(self, ret_addr, *args): + for arg in reversed(args): + self.push_uint32_t(arg) + self.push_uint32_t(ret_addr) + + get_arg_n_stdcall = get_stack_arg + + # cdecl + @named_arguments + def func_args_cdecl(self, n_args): + ret_ad = self.pop_uint32_t() + args = [self.get_stack_arg(i) for i in range(n_args)] + return ret_ad, args + + def func_ret_cdecl(self, ret_addr, ret_value1=None, ret_value2=None): + self.pc = self.cpu.EIP = ret_addr + if ret_value1 is not None: + self.cpu.EAX = ret_value1 + if ret_value2 is not None: + self.cpu.EDX = ret_value2 + + get_arg_n_cdecl = get_stack_arg + + # System V + func_args_systemv = func_args_cdecl + func_ret_systemv = func_ret_cdecl + func_prepare_systemv = func_prepare_stdcall + get_arg_n_systemv = get_stack_arg + + + # fastcall + @named_arguments + def func_args_fastcall(self, n_args): + args_regs = ['ECX', 'EDX'] + ret_ad = self.pop_uint32_t() + args = [] + for i in range(n_args): + args.append(self.get_arg_n_fastcall(i)) + return ret_ad, args + + def func_prepare_fastcall(self, ret_addr, *args): + args_regs = ['ECX', 'EDX'] + for i in range(min(len(args), len(args_regs))): + setattr(self.cpu, args_regs[i], args[i]) + remaining_args = args[len(args_regs):] + for arg in reversed(remaining_args): + self.push_uint32_t(arg) + self.push_uint32_t(ret_addr) + + def get_arg_n_fastcall(self, index): + args_regs = ['ECX', 'EDX'] + if index < len(args_regs): + return getattr(self.cpu, args_regs[index]) + return self.get_stack_arg(index - len(args_regs)) + + def syscall_args_systemv(self, n_args): + # Documentation: http://man7.org/linux/man-pages/man2/syscall.2.html + # args: + # i386 ebx ecx edx esi edi ebp - + args = [self.cpu.EBX, self.cpu.ECX, self.cpu.EDX, self.cpu.ESI, + self.cpu.EDI, self.cpu.EBP][:n_args] + return args + + def syscall_ret_systemv(self, value): + # Documentation: http://man7.org/linux/man-pages/man2/syscall.2.html + self.cpu.EAX = value + + +class jitter_x86_64(Jitter): + + C_Gen = x86_64_CGen + args_regs_systemv = ['RDI', 'RSI', 'RDX', 'RCX', 'R8', 'R9'] + args_regs_stdcall = ['RCX', 'RDX', 'R8', 'R9'] + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_X86_64(loc_db), *args, **kwargs) + self.vm.set_little_endian() + self.lifter.do_stk_segm = False + + self.orig_irbloc_fix_regs_for_mode = self.lifter.irbloc_fix_regs_for_mode + self.lifter.irbloc_fix_regs_for_mode = self.lifterbloc_fix_regs_for_mode + + def lifterbloc_fix_regs_for_mode(self, irblock, attrib=64): + return self.orig_irbloc_fix_regs_for_mode(irblock, 64) + + def push_uint64_t(self, value): + self.cpu.RSP -= self.lifter.sp.size // 8 + self.vm.set_u64(self.cpu.RSP, value) + + def pop_uint64_t(self): + value = self.vm.get_u64(self.cpu.RSP) + self.cpu.RSP += self.lifter.sp.size // 8 + return value + + def get_stack_arg(self, index): + return self.vm.get_u64(self.cpu.RSP + 8 * index) + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.RIP = self.pc + + # calling conventions + + # stdcall + @named_arguments + def func_args_stdcall(self, n_args): + args_regs = self.args_regs_stdcall + ret_ad = self.pop_uint64_t() + args = [] + for i in range(min(n_args, 4)): + args.append(self.cpu.get_gpreg()[args_regs[i]]) + for i in range(max(0, n_args - 4)): + # Take into account the shadow registers on the stack + # (Microsoft 64bit stdcall ABI) + # => Skip the first 4 stack parameters + args.append(self.get_stack_arg(4 + i)) + return ret_ad, args + + def func_prepare_stdcall(self, ret_addr, *args): + args_regs = self.args_regs_stdcall + for i in range(min(len(args), len(args_regs))): + setattr(self.cpu, args_regs[i], args[i]) + remaining_args = args[len(args_regs):] + for arg in reversed(remaining_args): + self.push_uint64_t(arg) + self.push_uint64_t(ret_addr) + + def func_ret_stdcall(self, ret_addr, ret_value=None): + self.pc = self.cpu.RIP = ret_addr + if ret_value is not None: + self.cpu.RAX = ret_value + return True + + # cdecl + func_args_cdecl = func_args_stdcall + func_ret_cdecl = func_ret_stdcall + func_prepare_cdecl = func_prepare_stdcall + + # System V + + def get_arg_n_systemv(self, index): + args_regs = self.args_regs_systemv + if index < len(args_regs): + return getattr(self.cpu, args_regs[index]) + return self.get_stack_arg(index - len(args_regs)) + + @named_arguments + def func_args_systemv(self, n_args): + ret_ad = self.pop_uint64_t() + args = [self.get_arg_n_systemv(index) for index in range(n_args)] + return ret_ad, args + + func_ret_systemv = func_ret_cdecl + + def func_prepare_systemv(self, ret_addr, *args): + args_regs = self.args_regs_systemv + self.push_uint64_t(ret_addr) + for i in range(min(len(args), len(args_regs))): + setattr(self.cpu, args_regs[i], args[i]) + remaining_args = args[len(args_regs):] + for arg in reversed(remaining_args): + self.push_uint64_t(arg) + + def syscall_args_systemv(self, n_args): + args = [self.cpu.RDI, self.cpu.RSI, self.cpu.RDX, self.cpu.R10, + self.cpu.R8, self.cpu.R9][:n_args] + return args + + def syscall_ret_systemv(self, value): + self.cpu.RAX = value diff --git a/src/miasm/arch/x86/lifter_model_call.py b/src/miasm/arch/x86/lifter_model_call.py new file mode 100644 index 00000000..e75f8c69 --- /dev/null +++ b/src/miasm/arch/x86/lifter_model_call.py @@ -0,0 +1,80 @@ +#-*- coding:utf-8 -*- + +from miasm.expression.expression import ExprAssign, ExprOp +from miasm.ir.ir import AssignBlock +from miasm.ir.analysis import LifterModelCall +from miasm.arch.x86.sem import Lifter_X86_16, Lifter_X86_32, Lifter_X86_64 + + +class LifterModelCall_x86_16(Lifter_X86_16, LifterModelCall): + + def __init__(self, loc_db): + Lifter_X86_16.__init__(self, loc_db) + self.ret_reg = self.arch.regs.AX + + def get_out_regs(self, _): + return set([self.ret_reg, self.sp]) + +class LifterModelCall_x86_32(Lifter_X86_32, LifterModelCall_x86_16): + + def __init__(self, loc_db): + Lifter_X86_32.__init__(self, loc_db) + self.ret_reg = self.arch.regs.EAX + + def sizeof_char(self): + return 8 + + def sizeof_short(self): + return 16 + + def sizeof_int(self): + return 32 + + def sizeof_long(self): + return 32 + + def sizeof_pointer(self): + return 32 + + +class LifterModelCall_x86_64(Lifter_X86_64, LifterModelCall_x86_16): + + def __init__(self, loc_db): + Lifter_X86_64.__init__(self, loc_db) + self.ret_reg = self.arch.regs.RAX + + def call_effects(self, ad, instr): + call_assignblk = AssignBlock( + [ + ExprAssign( + self.ret_reg, + ExprOp( + 'call_func_ret', + ad, + self.sp, + self.arch.regs.RCX, + self.arch.regs.RDX, + self.arch.regs.R8, + self.arch.regs.R9, + ) + ), + ExprAssign(self.sp, ExprOp('call_func_stack', ad, self.sp)), + ], + instr + ) + return [call_assignblk], [] + + def sizeof_char(self): + return 8 + + def sizeof_short(self): + return 16 + + def sizeof_int(self): + return 32 + + def sizeof_long(self): + return 64 + + def sizeof_pointer(self): + return 64 diff --git a/src/miasm/arch/x86/regs.py b/src/miasm/arch/x86/regs.py new file mode 100644 index 00000000..dc0b9264 --- /dev/null +++ b/src/miasm/arch/x86/regs.py @@ -0,0 +1,454 @@ +from builtins import range +from miasm.expression.expression import ExprId +from miasm.core.cpu import reg_info + + +IP = ExprId('IP', 16) +EIP = ExprId('EIP', 32) +RIP = ExprId('RIP', 64) +exception_flags = ExprId('exception_flags', 32) +interrupt_num = ExprId('interrupt_num', 8) + +# GP + + +regs08_str = ["AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH"] + \ + ["R%dB" % (i + 8) for i in range(8)] +regs08_expr = [ExprId(x, 8) for x in regs08_str] + +regs08_64_str = ["AL", "CL", "DL", "BL", "SPL", "BPL", "SIL", "DIL"] + \ + ["R%dB" % (i + 8) for i in range(8)] +regs08_64_expr = [ExprId(x, 8) for x in regs08_64_str] + + +regs16_str = ["AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI"] + \ + ["R%dW" % (i + 8) for i in range(8)] +regs16_expr = [ExprId(x, 16) for x in regs16_str] + +regs32_str = ["EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"] + \ + ["R%dD" % (i + 8) for i in range(8)] + ["EIP"] +regs32_expr = [ExprId(x, 32) for x in regs32_str] + +regs64_str = ["RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", + "RIP"] +regs64_expr = [ExprId(x, 64) for x in regs64_str] + + +regs_xmm_str = ["XMM%d" % i for i in range(16)] +regs_xmm_expr = [ExprId(x, 128) for x in regs_xmm_str] + +regs_mm_str = ["MM%d" % i for i in range(16)] +regs_mm_expr = [ExprId(x, 64) for x in regs_mm_str] + +regs_bnd_str = ["BND%d" % i for i in range(4)] +regs_bnd_expr = [ExprId(x, 128) for x in regs_bnd_str] + +gpregs08 = reg_info(regs08_str, regs08_expr) +gpregs08_64 = reg_info(regs08_64_str, regs08_64_expr) +gpregs16 = reg_info(regs16_str, regs16_expr) +gpregs32 = reg_info(regs32_str, regs32_expr) +gpregs64 = reg_info(regs64_str, regs64_expr) + +gpregs_xmm = reg_info(regs_xmm_str, regs_xmm_expr) +gpregs_mm = reg_info(regs_mm_str, regs_mm_expr) +gpregs_bnd = reg_info(regs_bnd_str, regs_bnd_expr) + +r08_eax = reg_info([regs08_str[0]], [regs08_expr[0]]) +r16_eax = reg_info([regs16_str[0]], [regs16_expr[0]]) +r32_eax = reg_info([regs32_str[0]], [regs32_expr[0]]) +r64_eax = reg_info([regs64_str[0]], [regs64_expr[0]]) + +r08_ecx = reg_info([regs08_str[1]], [regs08_expr[1]]) + +r_eax_all = reg_info( + [regs08_str[0], regs16_str[0], regs32_str[0], regs64_str[0]], + [regs08_expr[0], regs16_expr[0], regs32_expr[0], regs64_expr[0]]) +r_edx_all = reg_info( + [regs08_str[2], regs16_str[2], regs32_str[2], regs64_str[2]], + [regs08_expr[2], regs16_expr[2], regs32_expr[2], regs64_expr[2]]) + +r16_edx = reg_info([regs16_str[2]], [regs16_expr[2]]) + + +selectr_str = ["ES", "CS", "SS", "DS", "FS", "GS"] +selectr_expr = [ExprId(x, 16) for x in selectr_str] +segmreg = reg_info(selectr_str, selectr_expr) + +crregs32_str = ["CR%d" % i for i in range(8)] +crregs32_expr = [ExprId(x, 32) for x in crregs32_str] +crregs = reg_info(crregs32_str, crregs32_expr) + + +drregs32_str = ["DR%d" % i for i in range(8)] +drregs32_expr = [ExprId(x, 32) for x in drregs32_str] +drregs = reg_info(drregs32_str, drregs32_expr) + + +fltregs32_str = ["ST(%d)" % i for i in range(8)] +fltregs32_expr = [ExprId(x, 64) for x in fltregs32_str] +fltregs = reg_info(fltregs32_str, fltregs32_expr) + +r_st_all = reg_info(['ST'], + [ExprId('ST', 64)]) + +r_cs_all = reg_info(['CS'], + [ExprId('CS', 16)]) +r_ds_all = reg_info(['DS'], + [ExprId('DS', 16)]) +r_es_all = reg_info(['ES'], + [ExprId('ES', 16)]) +r_ss_all = reg_info(['SS'], + [ExprId('SS', 16)]) +r_fs_all = reg_info(['FS'], + [ExprId('FS', 16)]) +r_gs_all = reg_info(['GS'], + [ExprId('GS', 16)]) + + +AL = regs08_expr[0] +CL = regs08_expr[1] +DL = regs08_expr[2] +BL = regs08_expr[3] +AH = regs08_expr[4] +CH = regs08_expr[5] +DH = regs08_expr[6] +BH = regs08_expr[7] +R8B = regs08_expr[8] +R9B = regs08_expr[9] +R10B = regs08_expr[10] +R11B = regs08_expr[11] +R12B = regs08_expr[12] +R13B = regs08_expr[13] +R14B = regs08_expr[14] +R15B = regs08_expr[15] + +SPL = regs08_64_expr[4] +BPL = regs08_64_expr[5] +SIL = regs08_64_expr[6] +DIL = regs08_64_expr[7] + + +AX = regs16_expr[0] +CX = regs16_expr[1] +DX = regs16_expr[2] +BX = regs16_expr[3] +SP = regs16_expr[4] +BP = regs16_expr[5] +SI = regs16_expr[6] +DI = regs16_expr[7] +R8W = regs16_expr[8] +R9W = regs16_expr[9] +R10W = regs16_expr[10] +R11W = regs16_expr[11] +R12W = regs16_expr[12] +R13W = regs16_expr[13] +R14W = regs16_expr[14] +R15W = regs16_expr[15] + + +EAX = regs32_expr[0] +ECX = regs32_expr[1] +EDX = regs32_expr[2] +EBX = regs32_expr[3] +ESP = regs32_expr[4] +EBP = regs32_expr[5] +ESI = regs32_expr[6] +EDI = regs32_expr[7] +R8D = regs32_expr[8] +R9D = regs32_expr[9] +R10D = regs32_expr[10] +R11D = regs32_expr[11] +R12D = regs32_expr[12] +R13D = regs32_expr[13] +R14D = regs32_expr[14] +R15D = regs32_expr[15] + + +RAX = regs64_expr[0] +RCX = regs64_expr[1] +RDX = regs64_expr[2] +RBX = regs64_expr[3] +RSP = regs64_expr[4] +RBP = regs64_expr[5] +RSI = regs64_expr[6] +RDI = regs64_expr[7] +R8 = regs64_expr[8] +R9 = regs64_expr[9] +R10 = regs64_expr[10] +R11 = regs64_expr[11] +R12 = regs64_expr[12] +R13 = regs64_expr[13] +R14 = regs64_expr[14] +R15 = regs64_expr[15] + + +reg_zf = 'zf' +reg_nf = 'nf' +reg_pf = 'pf' +reg_of = 'of' +reg_cf = 'cf' +reg_tf = 'tf' +reg_if = 'i_f' +reg_df = 'df' +reg_af = 'af' +reg_iopl = 'iopl_f' +reg_nt = 'nt' +reg_rf = 'rf' +reg_vm = 'vm' +reg_ac = 'ac' +reg_vif = 'vif' +reg_vip = 'vip' +reg_id = 'i_d' + + +reg_es = "ES" +reg_cs = "CS" +reg_ss = "SS" +reg_ds = "DS" +reg_fs = "FS" +reg_gs = "GS" + +reg_dr0 = 'DR0' +reg_dr1 = 'DR1' +reg_dr2 = 'DR2' +reg_dr3 = 'DR3' +reg_dr4 = 'DR4' +reg_dr5 = 'DR5' +reg_dr6 = 'DR6' +reg_dr7 = 'DR7' + +reg_cr0 = 'CR0' +reg_cr1 = 'CR1' +reg_cr2 = 'CR2' +reg_cr3 = 'CR3' +reg_cr4 = 'CR4' +reg_cr5 = 'CR5' +reg_cr6 = 'CR6' +reg_cr7 = 'CR7' + +reg_mm0 = 'MM0' +reg_mm1 = 'MM1' +reg_mm2 = 'MM2' +reg_mm3 = 'MM3' +reg_mm4 = 'MM4' +reg_mm5 = 'MM5' +reg_mm6 = 'MM6' +reg_mm7 = 'MM7' + +reg_tsc = "tsc" + +reg_float_c0 = 'float_c0' +reg_float_c1 = 'float_c1' +reg_float_c2 = 'float_c2' +reg_float_c3 = 'float_c3' +reg_float_stack_ptr = "float_stack_ptr" +reg_float_control = 'reg_float_control' +reg_float_eip = 'reg_float_eip' +reg_float_cs = 'reg_float_cs' +reg_float_address = 'reg_float_address' +reg_float_ds = 'reg_float_ds' + + +dr0 = ExprId(reg_dr0, 32) +dr1 = ExprId(reg_dr1, 32) +dr2 = ExprId(reg_dr2, 32) +dr3 = ExprId(reg_dr3, 32) +dr4 = ExprId(reg_dr4, 32) +dr5 = ExprId(reg_dr5, 32) +dr6 = ExprId(reg_dr6, 32) +dr7 = ExprId(reg_dr7, 32) + +cr0 = ExprId(reg_cr0, 32) +cr1 = ExprId(reg_cr1, 32) +cr2 = ExprId(reg_cr2, 32) +cr3 = ExprId(reg_cr3, 32) +cr4 = ExprId(reg_cr4, 32) +cr5 = ExprId(reg_cr5, 32) +cr6 = ExprId(reg_cr6, 32) +cr7 = ExprId(reg_cr7, 32) + +mm0 = ExprId(reg_mm0, 64) +mm1 = ExprId(reg_mm1, 64) +mm2 = ExprId(reg_mm2, 64) +mm3 = ExprId(reg_mm3, 64) +mm4 = ExprId(reg_mm4, 64) +mm5 = ExprId(reg_mm5, 64) +mm6 = ExprId(reg_mm6, 64) +mm7 = ExprId(reg_mm7, 64) + +XMM0 = regs_xmm_expr[0] +XMM1 = regs_xmm_expr[1] +XMM2 = regs_xmm_expr[2] +XMM3 = regs_xmm_expr[3] +XMM4 = regs_xmm_expr[4] +XMM5 = regs_xmm_expr[5] +XMM6 = regs_xmm_expr[6] +XMM7 = regs_xmm_expr[7] +XMM8 = regs_xmm_expr[8] +XMM9 = regs_xmm_expr[9] +XMM10 = regs_xmm_expr[10] +XMM11 = regs_xmm_expr[11] +XMM12 = regs_xmm_expr[12] +XMM13 = regs_xmm_expr[13] +XMM14 = regs_xmm_expr[14] +XMM15 = regs_xmm_expr[15] + +# tmp1= ExprId(reg_tmp1) +zf = ExprId(reg_zf, size=1) +nf = ExprId(reg_nf, size=1) +pf = ExprId(reg_pf, size=1) +of = ExprId(reg_of, size=1) +cf = ExprId(reg_cf, size=1) +tf = ExprId(reg_tf, size=1) +i_f = ExprId(reg_if, size=1) +df = ExprId(reg_df, size=1) +af = ExprId(reg_af, size=1) +iopl = ExprId(reg_iopl, size=2) +nt = ExprId(reg_nt, size=1) +rf = ExprId(reg_rf, size=1) +vm = ExprId(reg_vm, size=1) +ac = ExprId(reg_ac, size=1) +vif = ExprId(reg_vif, size=1) +vip = ExprId(reg_vip, size=1) +i_d = ExprId(reg_id, size=1) + +ES = ExprId(reg_es, size=16) +CS = ExprId(reg_cs, size=16) +SS = ExprId(reg_ss, size=16) +DS = ExprId(reg_ds, size=16) +FS = ExprId(reg_fs, size=16) +GS = ExprId(reg_gs, size=16) + +tsc = ExprId(reg_tsc, size=64) + +float_c0 = ExprId(reg_float_c0, size=1) +float_c1 = ExprId(reg_float_c1, size=1) +float_c2 = ExprId(reg_float_c2, size=1) +float_c3 = ExprId(reg_float_c3, size=1) +float_stack_ptr = ExprId(reg_float_stack_ptr, size=3) +float_control = ExprId(reg_float_control, 16) +float_eip = ExprId(reg_float_eip, 32) +float_cs = ExprId(reg_float_cs, size=16) +float_address = ExprId(reg_float_address, 32) +float_ds = ExprId(reg_float_ds, size=16) + +float_st0 = ExprId("float_st0", 64) +float_st1 = ExprId("float_st1", 64) +float_st2 = ExprId("float_st2", 64) +float_st3 = ExprId("float_st3", 64) +float_st4 = ExprId("float_st4", 64) +float_st5 = ExprId("float_st5", 64) +float_st6 = ExprId("float_st6", 64) +float_st7 = ExprId("float_st7", 64) + + +float_list = [float_st0, float_st1, float_st2, float_st3, + float_st4, float_st5, float_st6, float_st7] + +float_replace = {fltregs32_expr[i]: float_list[i] for i in range(8)} +float_replace[r_st_all.expr[0]] = float_st0 + + +EAX_init = ExprId('EAX_init', 32) +EBX_init = ExprId('EBX_init', 32) +ECX_init = ExprId('ECX_init', 32) +EDX_init = ExprId('EDX_init', 32) +ESI_init = ExprId('ESI_init', 32) +EDI_init = ExprId('EDI_init', 32) +ESP_init = ExprId('ESP_init', 32) +EBP_init = ExprId('EBP_init', 32) + + +RAX_init = ExprId('RAX_init', 64) +RBX_init = ExprId('RBX_init', 64) +RCX_init = ExprId('RCX_init', 64) +RDX_init = ExprId('RDX_init', 64) +RSI_init = ExprId('RSI_init', 64) +RDI_init = ExprId('RDI_init', 64) +RSP_init = ExprId('RSP_init', 64) +RBP_init = ExprId('RBP_init', 64) + + +all_regs_ids = [ + AL, CL, DL, BL, AH, CH, DH, BH, + R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B, + SPL, BPL, SIL, DIL, + AX, CX, DX, BX, SP, BP, SI, DI, + R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W, + IP, + EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, + R8D, R9D, R10D, R11D, R12D, R13D, R14D, R15D, + EIP, + + RAX, RBX, RCX, RDX, RSP, RBP, RIP, RSI, RDI, + R8, R9, R10, R11, R12, R13, R14, R15, + zf, nf, pf, of, cf, af, df, + tf, i_f, iopl, nt, rf, vm, ac, vif, vip, i_d, + float_control, float_eip, float_cs, float_address, float_ds, + tsc, + ES, CS, SS, DS, FS, GS, + float_st0, float_st1, float_st2, float_st3, + float_st4, float_st5, float_st6, float_st7, + float_c0, float_c1, float_c2, float_c3, + cr0, cr3, + dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7, + float_stack_ptr, + mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, + + XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, + + + exception_flags, interrupt_num, +] + fltregs32_expr + +all_regs_ids_no_alias = [ + RAX, RBX, RCX, RDX, RSP, RBP, RIP, RSI, RDI, + R8, R9, R10, R11, R12, R13, R14, R15, + zf, nf, pf, of, cf, af, df, + tf, i_f, iopl, nt, rf, vm, ac, vif, vip, i_d, + float_control, float_eip, float_cs, float_address, float_ds, + tsc, + ES, CS, SS, DS, FS, GS, + float_st0, float_st1, float_st2, float_st3, + float_st4, float_st5, float_st6, float_st7, + float_c0, float_c1, float_c2, float_c3, + cr0, cr3, + dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7, + float_stack_ptr, + mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, + XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, + + + exception_flags, interrupt_num, +] + fltregs32_expr + +attrib_to_regs = { + 16: regs16_expr + all_regs_ids_no_alias[all_regs_ids_no_alias.index(zf):] + [IP], + 32: regs32_expr + all_regs_ids_no_alias[all_regs_ids_no_alias.index(zf):] + [EIP], + 64: all_regs_ids_no_alias, +} + +all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) + +all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids] + +regs_init = {} +for i, r in enumerate(all_regs_ids): + regs_init[r] = all_regs_ids_init[i] + +regs_flt_expr = [float_st0, float_st1, float_st2, float_st3, + float_st4, float_st5, float_st6, float_st7, + ] + +mRAX = {16: AX, 32: EAX, 64: RAX} +mRBX = {16: BX, 32: EBX, 64: RBX} +mRCX = {16: CX, 32: ECX, 64: RCX} +mRDX = {16: DX, 32: EDX, 64: RDX} +mRSI = {16: SI, 32: ESI, 64: RSI} +mRDI = {16: DI, 32: EDI, 64: RDI} +mRBP = {16: BP, 32: EBP, 64: RBP} +mRSP = {16: SP, 32: ESP, 64: RSP} +mRIP = {16: IP, 32: EIP, 64: RIP} diff --git a/src/miasm/arch/x86/sem.py b/src/miasm/arch/x86/sem.py new file mode 100644 index 00000000..d19290b6 --- /dev/null +++ b/src/miasm/arch/x86/sem.py @@ -0,0 +1,6065 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +from builtins import range + +from future.utils import viewitems + +import logging +import miasm.expression.expression as m2_expr +from miasm.expression.simplifications import expr_simp +from miasm.arch.x86.regs import * +from miasm.arch.x86.arch import mn_x86, repeat_mn, replace_regs, is_mem_segm +from miasm.ir.ir import Lifter, IRBlock, AssignBlock +from miasm.core.sembuilder import SemBuilder +from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO, EXCEPT_ILLEGAL_INSN, \ + EXCEPT_PRIV_INSN, EXCEPT_SOFT_BP, EXCEPT_INT_XX, EXCEPT_INT_1, \ + EXCEPT_SYSCALL +import math +import struct + + +LOG_X86_SEM = logging.getLogger("x86_sem") +CONSOLE_HANDLER = logging.StreamHandler() +CONSOLE_HANDLER.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +LOG_X86_SEM.addHandler(CONSOLE_HANDLER) +LOG_X86_SEM.setLevel(logging.WARNING) + + +# SemBuilder context +ctx = {'mRAX': mRAX, + 'mRBX': mRBX, + 'mRCX': mRCX, + 'mRDX': mRDX, + 'zf': zf, + } +sbuild = SemBuilder(ctx) + + + +""" +http://www.emulators.com/docs/nx11_flags.htm + +CF(A+B) = (((A XOR B) XOR D) < 0) XOR (((A XOR D) AND NOT (A XOR B)) < 0) +CF(A-B) = (((A XOR B) XOR D) < 0) XOR (((A XOR D) AND (A XOR B)) < 0) + +OF(A+B) = ((A XOR D) AND NOT (A XOR B)) < 0 +OF(A-B) = ((A XOR D) AND (A XOR B)) < 0 +""" + + +# XXX TODO make default check against 0 or not 0 (same eq as in C) +def update_flag_zf_eq(a, b): + return [m2_expr.ExprAssign(zf, m2_expr.ExprOp("FLAG_EQ_CMP", a, b))] + + +def update_flag_zf(a): + return [ + m2_expr.ExprAssign( + zf, + m2_expr.ExprCond( + a, + m2_expr.ExprInt(0, zf.size), + m2_expr.ExprInt(1, zf.size) + ) + ) + ] + + +def update_flag_nf(arg): + return [ + m2_expr.ExprAssign( + nf, + m2_expr.ExprOp("FLAG_SIGN_SUB", arg, m2_expr.ExprInt(0, arg.size)) + ) + ] + + +def update_flag_pf(a): + return [m2_expr.ExprAssign(pf, + m2_expr.ExprOp('parity', + a & m2_expr.ExprInt(0xFF, a.size)))] + + +def update_flag_af(op1, op2, res): + return [m2_expr.ExprAssign(af, (op1 ^ op2 ^ res)[4:5])] + + +def update_flag_znp(a): + e = [] + e += update_flag_zf(a) + e += update_flag_nf(a) + e += update_flag_pf(a) + return e + + +def update_flag_np(result): + e = [] + e += update_flag_nf(result) + e += update_flag_pf(result) + return e + + +def null_flag_co(): + e = [] + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size))) + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprInt(0, cf.size))) + return e + + +def update_flag_arith(a): + e = [] + e += update_flag_znp(a) + return e + + +def update_flag_zfaddwc_eq(arg1, arg2, arg3): + return [m2_expr.ExprAssign(zf, m2_expr.ExprOp("FLAG_EQ_ADDWC", arg1, arg2, arg3))] + +def update_flag_zfsubwc_eq(arg1, arg2, arg3): + return [m2_expr.ExprAssign(zf, m2_expr.ExprOp("FLAG_EQ_SUBWC", arg1, arg2, arg3))] + + +def update_flag_arith_add_znp(arg1, arg2): + """ + Compute znp flags for (arg1 + arg2) + """ + e = [] + e += update_flag_zf_eq(arg1, -arg2) + e += [m2_expr.ExprAssign(nf, m2_expr.ExprOp("FLAG_SIGN_SUB", arg1, -arg2))] + e += update_flag_pf(arg1+arg2) + return e + + +def update_flag_arith_addwc_znp(arg1, arg2, arg3): + """ + Compute znp flags for (arg1 + arg2 + cf) + """ + e = [] + e += update_flag_zfaddwc_eq(arg1, arg2, arg3) + e += [m2_expr.ExprAssign(nf, m2_expr.ExprOp("FLAG_SIGN_ADDWC", arg1, arg2, arg3))] + e += update_flag_pf(arg1+arg2+arg3.zeroExtend(arg2.size)) + return e + + + + +def update_flag_arith_sub_znp(arg1, arg2): + """ + Compute znp flags for (arg1 - arg2) + """ + e = [] + e += update_flag_zf_eq(arg1, arg2) + e += [m2_expr.ExprAssign(nf, m2_expr.ExprOp("FLAG_SIGN_SUB", arg1, arg2))] + e += update_flag_pf(arg1 - arg2) + return e + + +def update_flag_arith_subwc_znp(arg1, arg2, arg3): + """ + Compute znp flags for (arg1 - (arg2 + cf)) + """ + e = [] + e += update_flag_zfsubwc_eq(arg1, arg2, arg3) + e += [m2_expr.ExprAssign(nf, m2_expr.ExprOp("FLAG_SIGN_SUBWC", arg1, arg2, arg3))] + e += update_flag_pf(arg1 - (arg2+arg3.zeroExtend(arg2.size))) + return e + + +def check_ops_msb(a, b, c): + if not a or not b or not c or a != b or a != c: + raise ValueError('bad ops size %s %s %s' % (a, b, c)) + + +def arith_flag(a, b, c): + a_s, b_s, c_s = a.size, b.size, c.size + check_ops_msb(a_s, b_s, c_s) + a_s, b_s, c_s = a.msb(), b.msb(), c.msb() + return a_s, b_s, c_s + +# checked: ok for adc add because b & c before +cf + + +def update_flag_add_cf(op1, op2, res): + "Compute cf in @res = @op1 + @op2" + #return [m2_expr.ExprAssign(cf, m2_expr.ExprOp("FLAG_SUB_CF", op1, -op2))] + return [m2_expr.ExprAssign(cf, m2_expr.ExprOp("FLAG_ADD_CF", op1, op2))] + + +def update_flag_add_of(op1, op2, res): + "Compute of in @res = @op1 + @op2" + return [m2_expr.ExprAssign(of, m2_expr.ExprOp("FLAG_ADD_OF", op1, op2))] + + +# checked: ok for sbb add because b & c before +cf +def update_flag_sub_cf(op1, op2, res): + "Compote CF in @res = @op1 - @op2" + return [m2_expr.ExprAssign(cf, m2_expr.ExprOp("FLAG_SUB_CF", op1, op2))] + + +def update_flag_sub_of(op1, op2, res): + "Compote OF in @res = @op1 - @op2" + return [m2_expr.ExprAssign(of, m2_expr.ExprOp("FLAG_SUB_OF", op1, op2))] + + +def update_flag_addwc_cf(op1, op2, op3): + "Compute cf in @res = @op1 + @op2 + @op3" + return [m2_expr.ExprAssign(cf, m2_expr.ExprOp("FLAG_ADDWC_CF", op1, op2, op3))] + + +def update_flag_addwc_of(op1, op2, op3): + "Compute of in @res = @op1 + @op2 + @op3" + return [m2_expr.ExprAssign(of, m2_expr.ExprOp("FLAG_ADDWC_OF", op1, op2, op3))] + + + +def update_flag_subwc_cf(op1, op2, op3): + "Compute cf in @res = @op1 + @op2 + @op3" + return [m2_expr.ExprAssign(cf, m2_expr.ExprOp("FLAG_SUBWC_CF", op1, op2, op3))] + + +def update_flag_subwc_of(op1, op2, op3): + "Compute of in @res = @op1 + @op2 + @op3" + return [m2_expr.ExprAssign(of, m2_expr.ExprOp("FLAG_SUBWC_OF", op1, op2, op3))] + + + + +def update_flag_arith_add_co(x, y, z): + e = [] + e += update_flag_add_cf(x, y, z) + e += update_flag_add_of(x, y, z) + return e + + +def update_flag_arith_sub_co(x, y, z): + e = [] + e += update_flag_sub_cf(x, y, z) + e += update_flag_sub_of(x, y, z) + return e + + + + +def update_flag_arith_addwc_co(arg1, arg2, arg3): + e = [] + e += update_flag_addwc_cf(arg1, arg2, arg3) + e += update_flag_addwc_of(arg1, arg2, arg3) + return e + + +def update_flag_arith_subwc_co(arg1, arg2, arg3): + e = [] + e += update_flag_subwc_cf(arg1, arg2, arg3) + e += update_flag_subwc_of(arg1, arg2, arg3) + return e + + + +def set_float_cs_eip(instr): + e = [] + # XXX TODO check float updt + e.append(m2_expr.ExprAssign(float_eip, + m2_expr.ExprInt(instr.offset, float_eip.size))) + e.append(m2_expr.ExprAssign(float_cs, CS)) + return e + + +def mode2addrsize(mode): + """Returns the address size for a given @mode""" + + mode2size = {16:32, 32:32, 64:64} + if mode not in mode2size: + raise RuntimeError("Unknown size %s", mode) + return mode2size[mode] + + +def instr2addrsize(instr): + """Returns the address size for a given @instr""" + + return mode2addrsize(instr.mode) + + +def expraddr(mode, ptr): + """Returns memory address pointer with size according to current @mode""" + return ptr.zeroExtend(mode2addrsize(mode)) + + +def fix_mem_args_size(instr, *args): + out = [] + for arg in args: + if not arg.is_mem(): + out.append(arg) + continue + ptr = arg.ptr + size = arg.size + if ptr.is_op('segm'): + ptr = m2_expr.ExprOp( + 'segm', ptr.args[0], expraddr(instr.mode, ptr.args[1])) + else: + ptr = expraddr(instr.mode, ptr) + out.append(m2_expr.ExprMem(ptr, size)) + return out + + +def mem2double(instr, arg): + """ + Add float conversion if argument is an ExprMem + @arg: argument to transform + """ + if isinstance(arg, m2_expr.ExprMem): + if arg.size > 64: + # TODO: move to 80 bits + arg = m2_expr.ExprMem(expraddr(instr.mode, arg.ptr), size=64) + return m2_expr.ExprOp('sint_to_fp', arg.signExtend(64)) + else: + return arg + + +def float_implicit_st0(arg1, arg2): + """ + Generate full float operators if one argument is implicit (float_st0) + """ + if arg2 is None: + arg2 = arg1 + arg1 = float_st0 + return arg1, arg2 + + +def gen_jcc(ir, instr, cond, dst, jmp_if): + """ + Macro to generate jcc semantic + @ir: ir instance + @instr: instruction + @cond: condition of the jcc + @dst: the destination if jcc is taken + @jmp_if: jump if/notif cond + """ + + e = [] + meip = mRIP[ir.IRDst.size] + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = m2_expr.ExprLoc(loc_next, dst.size) + + if jmp_if: + dstA, dstB = dst, loc_next_expr + else: + dstA, dstB = loc_next_expr, dst + mn_dst = m2_expr.ExprCond(cond, + dstA.zeroExtend(ir.IRDst.size), + dstB.zeroExtend(ir.IRDst.size)) + e.append(m2_expr.ExprAssign(meip, mn_dst)) + e.append(m2_expr.ExprAssign(ir.IRDst, mn_dst)) + return e, [] + + +def gen_fcmov(ir, instr, cond, arg1, arg2, mov_if): + """Generate fcmov + @ir: ir instance + @instr: instruction instance + @cond: condition + @mov_if: invert condition if False""" + + loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_skip = ir.get_next_loc_key(instr) + loc_skip_expr = m2_expr.ExprLoc(loc_skip, ir.IRDst.size) + if mov_if: + dstA, dstB = loc_do_expr, loc_skip_expr + else: + dstA, dstB = loc_skip_expr, loc_do_expr + e = [] + e_do, extra_irs = [m2_expr.ExprAssign(arg1, arg2)], [] + e_do.append(m2_expr.ExprAssign(ir.IRDst, loc_skip_expr)) + e.append(m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(cond, dstA, dstB))) + return e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])] + + +def gen_cmov(ir, instr, cond, dst, src, mov_if): + """Generate cmov + @ir: ir instance + @instr: instruction instance + @cond: condition + @mov_if: invert condition if False""" + + loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_skip = ir.get_next_loc_key(instr) + loc_skip_expr = m2_expr.ExprLoc(loc_skip, ir.IRDst.size) + if mov_if: + dstA, dstB = loc_do_expr, loc_skip_expr + else: + dstA, dstB = loc_skip_expr, loc_do_expr + e = [] + if instr.mode == 64: + # Force destination set in order to zero high bit orders + # In 64 bit: + # cmovz eax, ebx + # if zf == 0 => high part of RAX is set to zero + e.append(m2_expr.ExprAssign(dst, dst)) + e_do, extra_irs = mov(ir, instr, dst, src) + e_do.append(m2_expr.ExprAssign(ir.IRDst, loc_skip_expr)) + e.append(m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(cond, dstA, dstB))) + return e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])] + + +def mov(_, instr, dst, src): + if dst in [ES, CS, SS, DS, FS, GS]: + src = src[:dst.size] + if src in [ES, CS, SS, DS, FS, GS]: + src = src.zeroExtend(dst.size) + e = [m2_expr.ExprAssign(dst, src)] + return e, [] + + +def movq(_, instr, dst, src): + src_final = (src.zeroExtend(dst.size) + if dst.size >= src.size else + src[:dst.size]) + return [m2_expr.ExprAssign(dst, src_final)], [] + + +@sbuild.parse +def xchg(arg1, arg2): + arg1 = arg2 + arg2 = arg1 + + + +def movzx(_, instr, dst, src): + e = [m2_expr.ExprAssign(dst, src.zeroExtend(dst.size))] + return e, [] + + +def movsx(_, instr, dst, src): + e = [m2_expr.ExprAssign(dst, src.signExtend(dst.size))] + return e, [] + + +def lea(_, instr, dst, src): + ptr = src.ptr + if is_mem_segm(src): + # Do not use segmentation here + ptr = ptr.args[1] + + if ptr.size > dst.size: + ptr = ptr[:dst.size] + e = [m2_expr.ExprAssign(dst, ptr.zeroExtend(dst.size))] + return e, [] + + +def add(_, instr, dst, src): + e = [] + + result = dst + src + + e += update_flag_arith_add_znp(dst, src) + e += update_flag_arith_add_co(dst, src, result) + e += update_flag_af(dst, src, result) + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + + +def xadd(_, instr, dst, src): + e = [] + + result = dst + src + e += update_flag_arith_add_znp(dst, src) + e += update_flag_arith_add_co(src, dst, result) + e += update_flag_af(dst, src, result) + if dst != src: + e.append(m2_expr.ExprAssign(src, dst)) + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + + +def adc(_, instr, dst, src): + e = [] + + arg1 = dst + arg2 = src + result = arg1 + (arg2 + cf.zeroExtend(src.size)) + + e += update_flag_arith_addwc_znp(arg1, arg2, cf) + e += update_flag_arith_addwc_co(arg1, arg2, cf) + e += update_flag_af(arg1, arg2, result) + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + + +def sub(_, instr, dst, src): + e = [] + arg1, arg2 = dst, src + result = dst - src + + e += update_flag_arith_sub_znp(arg1, arg2) + e += update_flag_arith_sub_co(arg1, arg2, result) + e += update_flag_af(dst, src, result) + + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + +# a-(b+cf) + + +def sbb(_, instr, dst, src): + e = [] + arg1 = dst + arg2 = src + result = arg1 - (arg2 + cf.zeroExtend(src.size)) + + e += update_flag_arith_subwc_znp(arg1, arg2, cf) + e += update_flag_af(arg1, arg2, result) + e += update_flag_arith_subwc_co(arg1, arg2, cf) + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + + +def neg(_, instr, src): + e = [] + dst = m2_expr.ExprInt(0, src.size) + arg1, arg2 = dst, src + result = arg1 - arg2 + + e += update_flag_arith_sub_znp(arg1, arg2) + e += update_flag_arith_sub_co(arg1, arg2, result) + e += update_flag_af(arg1, arg2, result) + e.append(m2_expr.ExprAssign(src, result)) + return (e, []) + + +def l_not(_, instr, dst): + e = [] + result = (~dst) + e.append(m2_expr.ExprAssign(dst, result)) + return (e, []) + + +def l_cmp(_, instr, dst, src): + e = [] + arg1, arg2 = dst, src + result = dst - src + + e += update_flag_arith_sub_znp(arg1, arg2) + e += update_flag_arith_sub_co(arg1, arg2, result) + e += update_flag_af(dst, src, result) + return (e, []) + + +def xor(_, instr, dst, src): + e = [] + result = dst ^ src + e += [m2_expr.ExprAssign(zf, m2_expr.ExprOp('FLAG_EQ_CMP', dst, src))] + e += update_flag_np(result) + e += null_flag_co() + e.append(m2_expr.ExprAssign(dst, result)) + return (e, []) + + +def pxor(_, instr, dst, src): + e = [] + result = dst ^ src + e.append(m2_expr.ExprAssign(dst, result)) + return (e, []) + + +def l_or(_, instr, dst, src): + e = [] + result = dst | src + e += [m2_expr.ExprAssign(zf, m2_expr.ExprOp('FLAG_EQ', dst | src))] + e += update_flag_np(result) + e += null_flag_co() + e.append(m2_expr.ExprAssign(dst, result)) + return (e, []) + + +def l_and(_, instr, dst, src): + e = [] + result = dst & src + e += [m2_expr.ExprAssign(zf, m2_expr.ExprOp('FLAG_EQ_AND', dst, src))] + e += update_flag_np(result) + e += null_flag_co() + + e.append(m2_expr.ExprAssign(dst, result)) + return (e, []) + + +def l_test(_, instr, dst, src): + e = [] + result = dst & src + + e += [m2_expr.ExprAssign(zf, m2_expr.ExprOp('FLAG_EQ_CMP', result, m2_expr.ExprInt(0, result.size)))] + e += [m2_expr.ExprAssign(nf, m2_expr.ExprOp("FLAG_SIGN_SUB", result, m2_expr.ExprInt(0, result.size)))] + e += update_flag_pf(result) + e += null_flag_co() + + return (e, []) + + +def get_shift(dst, src): + if isinstance(src, m2_expr.ExprInt): + src = m2_expr.ExprInt(int(src), dst.size) + else: + src = src.zeroExtend(dst.size) + if dst.size == 64: + shift = src & m2_expr.ExprInt(63, src.size) + else: + shift = src & m2_expr.ExprInt(31, src.size) + shift = expr_simp(shift) + return shift + + +def _rotate_tpl(ir, instr, dst, src, op, left=False): + '''Template to generate a rotater with operation @op + A temporary basic block is generated to handle 0-rotate + @op: operation to execute + @left (optional): indicates a left rotate if set, default is False + ''' + # Compute results + shifter = get_shift(dst, src) + res = m2_expr.ExprOp(op, dst, shifter) + + # CF is computed with 1-less round than `res` + new_cf = m2_expr.ExprOp( + op, dst, shifter - m2_expr.ExprInt(1, size=shifter.size)) + new_cf = new_cf.msb() if left else new_cf[:1] + + # OF is defined only for @b == 1 + new_of = m2_expr.ExprCond(src - m2_expr.ExprInt(1, size=src.size), + m2_expr.ExprInt(0, size=of.size), + res.msb() ^ new_cf if left else (dst ^ res).msb()) + + # Build basic blocks + e_do = [m2_expr.ExprAssign(cf, new_cf), + m2_expr.ExprAssign(of, new_of), + m2_expr.ExprAssign(dst, res) + ] + e = [] + if instr.mode == 64: + # Force destination set in order to zero high bit orders + # In 64 bit: + # rol eax, cl + # if cl == 0 => high part of RAX is set to zero + e.append(m2_expr.ExprAssign(dst, dst)) + # Don't generate conditional shifter on constant + if isinstance(shifter, m2_expr.ExprInt): + if int(shifter) != 0: + return (e_do, []) + else: + return (e, []) + loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_skip = ir.get_next_loc_key(instr) + loc_skip_expr = m2_expr.ExprLoc(loc_skip, ir.IRDst.size) + e_do.append(m2_expr.ExprAssign(ir.IRDst, loc_skip_expr)) + e.append(m2_expr.ExprAssign( + ir.IRDst, m2_expr.ExprCond(shifter, loc_do_expr, loc_skip_expr))) + return (e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])]) + + +def l_rol(ir, instr, dst, src): + return _rotate_tpl(ir, instr, dst, src, '<<<', left=True) + + +def l_ror(ir, instr, dst, src): + return _rotate_tpl(ir, instr, dst, src, '>>>') + + +def rotate_with_carry_tpl(ir, instr, op, dst, src): + # Compute results + shifter = get_shift(dst, src).zeroExtend(dst.size + 1) + result = m2_expr.ExprOp(op, m2_expr.ExprCompose(dst, cf), shifter) + + new_cf = result[dst.size:dst.size +1] + new_dst = result[:dst.size] + + result_trunc = result[:dst.size] + if op == '<<<': + of_value = result_trunc.msb() ^ new_cf + else: + of_value = (dst ^ result_trunc).msb() + # OF is defined only for @b == 1 + new_of = m2_expr.ExprCond(src - m2_expr.ExprInt(1, size=src.size), + m2_expr.ExprInt(0, size=of.size), + of_value) + + + # Build basic blocks + e_do = [m2_expr.ExprAssign(cf, new_cf), + m2_expr.ExprAssign(of, new_of), + m2_expr.ExprAssign(dst, new_dst) + ] + e = [m2_expr.ExprAssign(dst, dst)] + # Don't generate conditional shifter on constant + if isinstance(shifter, m2_expr.ExprInt): + if int(shifter) != 0: + return (e_do, []) + else: + return (e, []) + loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_skip = ir.get_next_loc_key(instr) + loc_skip_expr = m2_expr.ExprLoc(loc_skip, ir.IRDst.size) + e_do.append(m2_expr.ExprAssign(ir.IRDst, loc_skip_expr)) + e.append(m2_expr.ExprAssign( + ir.IRDst, m2_expr.ExprCond(shifter, loc_do_expr, loc_skip_expr))) + return (e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])]) + +def rcl(ir, instr, dst, src): + return rotate_with_carry_tpl(ir, instr, '<<<', dst, src) + +def rcr(ir, instr, dst, src): + return rotate_with_carry_tpl(ir, instr, '>>>', dst, src) + + +def _shift_tpl(op, ir, instr, a, b, c=None, op_inv=None, left=False, + custom_of=None): + """Template to generate a shifter with operation @op + A temporary basic block is generated to handle 0-shift + @op: operation to execute + @c (optional): if set, instruction has a bit provider + @op_inv (optional): opposite operation of @op. Must be provided if @c + @left (optional): indicates a left shift if set, default is False + @custom_of (optional): if set, override the computed value of OF + """ + if c is not None: + shifter = get_shift(a, c) + else: + shifter = get_shift(a, b) + + res = m2_expr.ExprOp(op, a, shifter) + cf_from_dst = m2_expr.ExprOp(op, a, + (shifter - m2_expr.ExprInt(1, a.size))) + cf_from_dst = cf_from_dst.msb() if left else cf_from_dst[:1] + + new_cf = cf_from_dst + i1 = m2_expr.ExprInt(1, size=a.size) + if c is not None: + # There is a source for new bits + isize = m2_expr.ExprInt(a.size, size=a.size) + mask = m2_expr.ExprOp(op_inv, i1, (isize - shifter)) - i1 + + # An overflow can occurred, emulate the 'undefined behavior' + # Overflow behavior if (shift / size % 2) + base_cond_overflow = shifter if left else ( + shifter - m2_expr.ExprInt(1, size=shifter.size)) + cond_overflow = base_cond_overflow & m2_expr.ExprInt(a.size, shifter.size) + if left: + # Overflow occurs one round before right + mask = m2_expr.ExprCond(cond_overflow, mask, ~mask) + else: + mask = m2_expr.ExprCond(cond_overflow, ~mask, mask) + + # Build res with dst and src + res = ((m2_expr.ExprOp(op, a, shifter) & mask) | + (m2_expr.ExprOp(op_inv, b, (isize - shifter)) & ~mask)) + + # Overflow case: cf come from src (bit number shifter % size) + cf_from_src = m2_expr.ExprOp(op, b, + (shifter.zeroExtend(b.size) & + m2_expr.ExprInt(a.size - 1, b.size)) - i1) + cf_from_src = cf_from_src.msb() if left else cf_from_src[:1] + new_cf = m2_expr.ExprCond(cond_overflow, cf_from_src, cf_from_dst) + + # Overflow flag, only occurred when shifter is equal to 1 + if custom_of is None: + value_of = a.msb() ^ a[-2:-1] if left else b[:1] ^ a.msb() + else: + value_of = custom_of + + # Build basic blocks + e_do = [ + m2_expr.ExprAssign(cf, new_cf), + m2_expr.ExprAssign(of, m2_expr.ExprCond(shifter - i1, + m2_expr.ExprInt(0, of.size), + value_of)), + m2_expr.ExprAssign(a, res), + ] + e_do += update_flag_znp(res) + e = [] + if instr.mode == 64: + # Force destination set in order to zero high bit orders + # In 64 bit: + # shr eax, cl + # if cl == 0 => high part of RAX is set to zero + e.append(m2_expr.ExprAssign(a, a)) + # Don't generate conditional shifter on constant + if isinstance(shifter, m2_expr.ExprInt): + if int(shifter) != 0: + return (e_do, []) + else: + return (e, []) + loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_skip = ir.get_next_loc_key(instr) + loc_skip_expr = m2_expr.ExprLoc(loc_skip, ir.IRDst.size) + e_do.append(m2_expr.ExprAssign(ir.IRDst, loc_skip_expr)) + e.append(m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(shifter, loc_do_expr, + loc_skip_expr))) + return e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])] + + +def sar(ir, instr, dst, src): + # Fixup OF, always cleared if src != 0 + i0 = m2_expr.ExprInt(0, size=of.size) + return _shift_tpl("a>>", ir, instr, dst, src, custom_of=i0) + + +def shr(ir, instr, dst, src): + return _shift_tpl(">>", ir, instr, dst, src, custom_of=dst.msb()) + + +def shrd(ir, instr, dst, src1, src2): + return _shift_tpl(">>>", ir, instr, dst, src1, src2, "<<<") + + +def shl(ir, instr, dst, src): + return _shift_tpl("<<", ir, instr, dst, src, left=True) + + +def shld(ir, instr, dst, src1, src2): + return _shift_tpl("<<<", ir, instr, dst, src1, src2, ">>>", left=True) + + +# XXX todo ### +def cmc(_, instr): + e = [m2_expr.ExprAssign(cf, m2_expr.ExprCond(cf, m2_expr.ExprInt(0, cf.size), + m2_expr.ExprInt(1, cf.size)))] + return e, [] + + +def clc(_, instr): + e = [m2_expr.ExprAssign(cf, m2_expr.ExprInt(0, cf.size))] + return e, [] + + +def stc(_, instr): + e = [m2_expr.ExprAssign(cf, m2_expr.ExprInt(1, cf.size))] + return e, [] + + +def cld(_, instr): + e = [m2_expr.ExprAssign(df, m2_expr.ExprInt(0, df.size))] + return e, [] + + +def std(_, instr): + e = [m2_expr.ExprAssign(df, m2_expr.ExprInt(1, df.size))] + return e, [] + + +def cli(_, instr): + e = [m2_expr.ExprAssign(i_f, m2_expr.ExprInt(0, i_f.size))] + return e, [] + + +def sti(_, instr): + e = [m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32))] + return e, [] + + +def inc(_, instr, dst): + e = [] + src = m2_expr.ExprInt(1, dst.size) + arg1, arg2 = dst, src + result = dst + src + + e += update_flag_arith_add_znp(arg1, arg2) + e += update_flag_af(arg1, arg2, result) + e += update_flag_add_of(arg1, arg2, result) + + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + + +def dec(_, instr, dst): + e = [] + src = m2_expr.ExprInt(1, dst.size) + arg1, arg2 = dst, src + result = dst - src + + e += update_flag_arith_sub_znp(arg1, arg2) + e += update_flag_af(arg1, arg2, result) + e += update_flag_sub_of(arg1, arg2, result) + + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + + +def push_gen(ir, instr, src, size): + e = [] + if not size in [16, 32, 64]: + raise ValueError('bad size stacker!') + if src.size < size: + src = src.zeroExtend(size) + off_size = src.size + + sp = mRSP[instr.mode] + new_sp = sp - m2_expr.ExprInt(off_size // 8, sp.size) + e.append(m2_expr.ExprAssign(sp, new_sp)) + if ir.do_stk_segm: + new_sp = ir.gen_segm_expr(SS, new_sp) + e.append(m2_expr.ExprAssign(ir.ExprMem(new_sp, off_size), + src)) + return e, [] + + +def push(ir, instr, src): + return push_gen(ir, instr, src, instr.mode) + + +def pushw(ir, instr, src): + return push_gen(ir, instr, src, 16) + + +def pop_gen(ir, instr, src, size): + e = [] + if not size in [16, 32, 64]: + raise ValueError('bad size stacker!') + + sp = mRSP[instr.mode] + new_sp = sp + m2_expr.ExprInt(src.size // 8, sp.size) + # Don't generate SP/ESP/RSP incrementation on POP SP/ESP/RSP + if not (src in mRSP.values()): + e.append(m2_expr.ExprAssign(sp, new_sp)) + # XXX FIX XXX for pop [esp] + if isinstance(src, m2_expr.ExprMem): + src = expr_simp(src.replace_expr({sp: new_sp})) + result = sp + if ir.do_stk_segm: + result = ir.gen_segm_expr(SS, result) + + e.append(m2_expr.ExprAssign(src, ir.ExprMem(result, src.size))) + return e, [] + + +def pop(ir, instr, src): + return pop_gen(ir, instr, src, instr.mode) + + +def popw(ir, instr, src): + return pop_gen(ir, instr, src, 16) + + +def sete(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_EQ", zf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setnz(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_EQ", ~zf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setl(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_S<", nf, of).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setg(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_S>", nf, of, zf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setge(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_S>=", nf, of).zeroExtend(dst.size), + ) + ) + return e, [] + + +def seta(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_U>", cf, zf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setae(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_U>=", cf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setb(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_U<", cf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setbe(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_U<=", cf, zf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setns(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_NEG", ~nf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def sets(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_NEG", nf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def seto(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + of.zeroExtend(dst.size) + ) + ) + return e, [] + + +def setp(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + pf.zeroExtend(dst.size) + ) + ) + return e, [] + + +def setnp(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprCond( + pf, + m2_expr.ExprInt(0, dst.size), + m2_expr.ExprInt(1, dst.size) + ) + ) + ) + return e, [] + + +def setle(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_S<=", nf, of, zf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setna(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_U<=", cf, zf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setnbe(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_U>", cf, zf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setno(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprCond( + of, + m2_expr.ExprInt(0, dst.size), + m2_expr.ExprInt(1, dst.size) + ) + ) + ) + return e, [] + + +def setnb(_, instr, dst): + e = [] + e.append( + m2_expr.ExprAssign( + dst, + m2_expr.ExprOp("CC_U>=", cf).zeroExtend(dst.size), + ) + ) + return e, [] + + +def setalc(_, instr): + dst = mRAX[instr.mode][0:8] + e = [] + e.append( + m2_expr.ExprAssign(dst, m2_expr.ExprCond(cf, m2_expr.ExprInt(0xff, dst.size), + m2_expr.ExprInt(0, dst.size)))) + return e, [] + + +def bswap(_, instr, dst): + e = [] + if dst.size == 16: + # BSWAP referencing a 16-bit register is undefined + # Seems to return 0 actually + result = m2_expr.ExprInt(0, 16) + elif dst.size == 32: + result = m2_expr.ExprCompose( + dst[24:32], dst[16:24], dst[8:16], dst[:8]) + elif dst.size == 64: + result = m2_expr.ExprCompose(dst[56:64], dst[48:56], dst[40:48], dst[32:40], + dst[24:32], dst[16:24], dst[8:16], dst[:8]) + else: + raise ValueError('the size DOES matter') + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + + +def cmps(ir, instr, size): + loc_df_0, loc_df_0_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_df_1, loc_df_1_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next_expr = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + + src1 = mRSI[instr.mode][:instr.v_admode()] + src2 = mRDI[instr.mode][:instr.v_admode()] + + if ir.do_str_segm: + if instr.additional_info.g2.value: + raise NotImplementedError("add segm support") + src1_sgm = ir.gen_segm_expr(DS, src1) + src2_sgm = ir.gen_segm_expr(ES, src2) + else: + src1_sgm = src1 + src2_sgm = src2 + + offset = m2_expr.ExprInt(size // 8, src1.size) + + e, _ = l_cmp(ir, instr, + ir.ExprMem(src1_sgm, size), + ir.ExprMem(src2_sgm, size)) + + + e0 = [] + e0.append(m2_expr.ExprAssign(src1, src1 + offset)) + e0.append(m2_expr.ExprAssign(src2, src2 + offset)) + e0.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + e0 = IRBlock(ir.loc_db, loc_df_0, [AssignBlock(e0, instr)]) + + e1 = [] + e1.append(m2_expr.ExprAssign(src1, src1 - offset)) + e1.append(m2_expr.ExprAssign(src2, src2 - offset)) + e1.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + e1 = IRBlock(ir.loc_db, loc_df_1, [AssignBlock(e1, instr)]) + + e.append(m2_expr.ExprAssign(ir.IRDst, + m2_expr.ExprCond(df, loc_df_1_expr, loc_df_0_expr))) + return e, [e0, e1] + + +def scas(ir, instr, size): + loc_df_0, loc_df_0_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_df_1, loc_df_1_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next_expr = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + + src = mRDI[instr.mode][:instr.v_admode()] + + if ir.do_str_segm: + if instr.additional_info.g2.value: + raise NotImplementedError("add segm support") + src_sgm = ir.gen_segm_expr(ES, src) + + else: + src_sgm = src + + offset = m2_expr.ExprInt(size // 8, src.size) + e, extra = l_cmp(ir, instr, + mRAX[instr.mode][:size], + ir.ExprMem(src_sgm, size)) + + e0 = [] + e0.append(m2_expr.ExprAssign(src, src + offset)) + + e0.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + e0 = IRBlock(ir.loc_db, loc_df_0, [AssignBlock(e0, instr)]) + + e1 = [] + e1.append(m2_expr.ExprAssign(src, src - offset)) + e1.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + e1 = IRBlock(ir.loc_db, loc_df_1, [AssignBlock(e1, instr)]) + + e.append(m2_expr.ExprAssign(ir.IRDst, + m2_expr.ExprCond(df, loc_df_1_expr, loc_df_0_expr))) + + return e, [e0, e1] + + +def compose_eflag(s=32): + args = [] + + args = [cf, m2_expr.ExprInt(1, 1), pf, m2_expr.ExprInt(0, 1), af, + m2_expr.ExprInt(0, 1), zf, nf, tf, i_f, df, of, iopl] + + if s == 32: + args += [nt, m2_expr.ExprInt(0, 1), rf, vm, ac, vif, vip, i_d] + elif s == 16: + args += [nt, m2_expr.ExprInt(0, 1)] + else: + raise ValueError('unk size') + if s == 32: + args.append(m2_expr.ExprInt(0, 10)) + return m2_expr.ExprCompose(*args) + + +def pushfd(ir, instr): + return push(ir, instr, compose_eflag()) + + +def pushfq(ir, instr): + return push(ir, instr, compose_eflag().zeroExtend(64)) + + +def pushfw(ir, instr): + return pushw(ir, instr, compose_eflag(16)) + + +def popfd(ir, instr): + tmp = ir.ExprMem(mRSP[instr.mode], 32) + e = [] + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprSlice(tmp, 0, 1))) + e.append(m2_expr.ExprAssign(pf, m2_expr.ExprSlice(tmp, 2, 3))) + e.append(m2_expr.ExprAssign(af, m2_expr.ExprSlice(tmp, 4, 5))) + e.append(m2_expr.ExprAssign(zf, m2_expr.ExprSlice(tmp, 6, 7))) + e.append(m2_expr.ExprAssign(nf, m2_expr.ExprSlice(tmp, 7, 8))) + e.append(m2_expr.ExprAssign(tf, m2_expr.ExprSlice(tmp, 8, 9))) + e.append(m2_expr.ExprAssign(i_f, m2_expr.ExprSlice(tmp, 9, 10))) + e.append(m2_expr.ExprAssign(df, m2_expr.ExprSlice(tmp, 10, 11))) + e.append(m2_expr.ExprAssign(of, m2_expr.ExprSlice(tmp, 11, 12))) + e.append(m2_expr.ExprAssign(iopl, m2_expr.ExprSlice(tmp, 12, 14))) + e.append(m2_expr.ExprAssign(nt, m2_expr.ExprSlice(tmp, 14, 15))) + e.append(m2_expr.ExprAssign(rf, m2_expr.ExprSlice(tmp, 16, 17))) + e.append(m2_expr.ExprAssign(vm, m2_expr.ExprSlice(tmp, 17, 18))) + e.append(m2_expr.ExprAssign(ac, m2_expr.ExprSlice(tmp, 18, 19))) + e.append(m2_expr.ExprAssign(vif, m2_expr.ExprSlice(tmp, 19, 20))) + e.append(m2_expr.ExprAssign(vip, m2_expr.ExprSlice(tmp, 20, 21))) + e.append(m2_expr.ExprAssign(i_d, m2_expr.ExprSlice(tmp, 21, 22))) + e.append(m2_expr.ExprAssign(mRSP[instr.mode], + mRSP[instr.mode] + m2_expr.ExprInt(instr.mode // 8, mRSP[instr.mode].size))) + e.append(m2_expr.ExprAssign(exception_flags, + m2_expr.ExprCond(m2_expr.ExprSlice(tmp, 8, 9), + m2_expr.ExprInt( + EXCEPT_SOFT_BP, 32), + exception_flags + ) + ) + ) + return e, [] + + +def _tpl_eflags(tmp): + """Extract eflags from @tmp + @tmp: Expr instance with a size >= 16 + """ + return [m2_expr.ExprAssign(dest, tmp[base:base + dest.size]) + for base, dest in ((0, cf), (2, pf), (4, af), (6, zf), (7, nf), + (8, tf), (9, i_f), (10, df), (11, of), + (12, iopl), (14, nt))] + + +def popfw(ir, instr): + tmp = ir.ExprMem(mRSP[instr.mode], 16) + e = _tpl_eflags(tmp) + e.append( + m2_expr.ExprAssign(mRSP[instr.mode], mRSP[instr.mode] + m2_expr.ExprInt(2, mRSP[instr.mode].size))) + return e, [] + +pa_regs = [ + mRAX, mRCX, + mRDX, mRBX, + mRSP, mRBP, + mRSI, mRDI +] + + +def pusha_gen(ir, instr, size): + e = [] + cur_sp = mRSP[instr.mode] + for i, reg in enumerate(pa_regs): + stk_ptr = cur_sp + m2_expr.ExprInt(-(size // 8) * (i + 1), instr.mode) + e.append(m2_expr.ExprAssign(ir.ExprMem(stk_ptr, size), reg[size])) + e.append(m2_expr.ExprAssign(cur_sp, stk_ptr)) + return e, [] + + +def pusha(ir, instr): + return pusha_gen(ir, instr, 16) + + +def pushad(ir, instr): + return pusha_gen(ir, instr, 32) + + +def popa_gen(ir, instr, size): + e = [] + cur_sp = mRSP[instr.mode] + for i, reg in enumerate(reversed(pa_regs)): + if reg == mRSP: + continue + stk_ptr = cur_sp + m2_expr.ExprInt((size // 8) * i, instr.mode) + e.append(m2_expr.ExprAssign(reg[size], ir.ExprMem(stk_ptr, size))) + + stk_ptr = cur_sp + m2_expr.ExprInt((size // 8) * (i + 1), instr.mode) + e.append(m2_expr.ExprAssign(cur_sp, stk_ptr)) + + return e, [] + + +def popa(ir, instr): + return popa_gen(ir, instr, 16) + + +def popad(ir, instr): + return popa_gen(ir, instr, 32) + + +def call(ir, instr, dst): + e = [] + # opmode, admode = instr.opmode, instr.admode + s = dst.size + meip = mRIP[ir.IRDst.size] + opmode, admode = s, instr.v_admode() + myesp = mRSP[instr.mode][:opmode] + n = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + + if isinstance(dst, m2_expr.ExprOp): + if dst.op == "segm": + # Far call segm:addr + if instr.mode not in [16, 32]: + raise RuntimeError('not supported') + segm = dst.args[0] + base = dst.args[1] + m1 = segm.zeroExtend(CS.size) + m2 = base.zeroExtend(meip.size) + elif dst.op == "far": + # Far call far [eax] + addr = dst.args[0].ptr + m1 = ir.ExprMem(addr, CS.size) + m2 = ir.ExprMem(addr + m2_expr.ExprInt(2, addr.size), meip.size) + else: + raise RuntimeError("bad call operator") + + e.append(m2_expr.ExprAssign(CS, m1)) + e.append(m2_expr.ExprAssign(meip, m2)) + + e.append(m2_expr.ExprAssign(ir.IRDst, m2)) + + c = myesp + m2_expr.ExprInt(-s // 8, s) + e.append(m2_expr.ExprAssign(ir.ExprMem(c, size=s).zeroExtend(s), + CS.zeroExtend(s))) + + c = myesp + m2_expr.ExprInt((-2 * s) // 8, s) + e.append(m2_expr.ExprAssign(ir.ExprMem(c, size=s).zeroExtend(s), + meip.zeroExtend(s))) + + c = myesp + m2_expr.ExprInt((-2 * s) // 8, s) + e.append(m2_expr.ExprAssign(myesp, c)) + return e, [] + + c = myesp + m2_expr.ExprInt(-s // 8, s) + e.append(m2_expr.ExprAssign(myesp, c)) + if ir.do_stk_segm: + c = ir.gen_segm_expr(SS, c) + + e.append(m2_expr.ExprAssign(ir.ExprMem(c, size=s), n)) + e.append(m2_expr.ExprAssign(meip, dst.zeroExtend(ir.IRDst.size))) + e.append(m2_expr.ExprAssign(ir.IRDst, dst.zeroExtend(ir.IRDst.size))) + return e, [] + + +def ret(ir, instr, src=None): + e = [] + meip = mRIP[ir.IRDst.size] + size, admode = instr.v_opmode(), instr.v_admode() + myesp = mRSP[instr.mode][:size] + + if src is None: + value = (myesp + (m2_expr.ExprInt(size // 8, size))) + else: + src = m2_expr.ExprInt(int(src), size) + value = (myesp + (m2_expr.ExprInt(size // 8, size) + src)) + + e.append(m2_expr.ExprAssign(myesp, value)) + result = myesp + if ir.do_stk_segm: + result = ir.gen_segm_expr(SS, result) + + e.append(m2_expr.ExprAssign(meip, ir.ExprMem( + result, size=size).zeroExtend(size))) + e.append(m2_expr.ExprAssign(ir.IRDst, + ir.ExprMem(result, size=size).zeroExtend(size))) + return e, [] + + +def retf(ir, instr, src=None): + e = [] + meip = mRIP[ir.IRDst.size] + size, admode = instr.v_opmode(), instr.v_admode() + if src is None: + src = m2_expr.ExprInt(0, instr.mode) + myesp = mRSP[instr.mode][:size] + + src = src.zeroExtend(size) + + result = myesp + if ir.do_stk_segm: + result = ir.gen_segm_expr(SS, result) + + e.append(m2_expr.ExprAssign(meip, ir.ExprMem( + result, size=size).zeroExtend(size))) + e.append(m2_expr.ExprAssign(ir.IRDst, + ir.ExprMem(result, size=size).zeroExtend(size))) + # e.append(m2_expr.ExprAssign(meip, ir.ExprMem(c, size = s))) + result = myesp + m2_expr.ExprInt(size // 8, size) + if ir.do_stk_segm: + result = ir.gen_segm_expr(SS, result) + + e.append(m2_expr.ExprAssign(CS, ir.ExprMem(result, size=16))) + + value = myesp + (m2_expr.ExprInt((2 * size) // 8, size) + src) + e.append(m2_expr.ExprAssign(myesp, value)) + return e, [] + + +def leave(ir, instr): + size = instr.mode + myesp = mRSP[size] + e = [] + e.append(m2_expr.ExprAssign(mRBP[size], ir.ExprMem(mRBP[size], size=size))) + e.append(m2_expr.ExprAssign(myesp, + m2_expr.ExprInt(size // 8, size) + mRBP[size])) + return e, [] + + +def enter(ir, instr, src1, src2): + size, admode = instr.v_opmode(), instr.v_admode() + myesp = mRSP[instr.mode][:size] + myebp = mRBP[instr.mode][:size] + + src1 = src1.zeroExtend(size) + + e = [] + esp_tmp = myesp - m2_expr.ExprInt(size // 8, size) + e.append(m2_expr.ExprAssign(ir.ExprMem(esp_tmp, size=size), + myebp)) + e.append(m2_expr.ExprAssign(myebp, esp_tmp)) + e.append(m2_expr.ExprAssign(myesp, + myesp - (src1 + m2_expr.ExprInt(size // 8, size)))) + return e, [] + + +def jmp(ir, instr, dst): + e = [] + meip = mRIP[ir.IRDst.size] + + if isinstance(dst, m2_expr.ExprOp): + if dst.op == "segm": + # Far jmp segm:addr + segm = dst.args[0] + base = dst.args[1] + m1 = segm.zeroExtend(CS.size) + m2 = base.zeroExtend(meip.size) + elif dst.op == "far": + # Far jmp far [eax] + addr = dst.args[0].ptr + m1 = ir.ExprMem(addr, CS.size) + m2 = ir.ExprMem(addr + m2_expr.ExprInt(2, addr.size), meip.size) + else: + raise RuntimeError("bad jmp operator") + + e.append(m2_expr.ExprAssign(CS, m1)) + e.append(m2_expr.ExprAssign(meip, m2)) + e.append(m2_expr.ExprAssign(ir.IRDst, m2)) + + else: + # Classic jmp + e.append(m2_expr.ExprAssign(meip, dst)) + e.append(m2_expr.ExprAssign(ir.IRDst, dst)) + + if isinstance(dst, m2_expr.ExprMem): + dst = meip + return e, [] + + +def jz(ir, instr, dst): + #return gen_jcc(ir, instr, zf, dst, True) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_EQ", zf), dst, True) + + +def jcxz(ir, instr, dst): + return gen_jcc(ir, instr, mRCX[instr.mode][:16], dst, False) + + +def jecxz(ir, instr, dst): + return gen_jcc(ir, instr, mRCX[instr.mode][:32], dst, False) + + +def jrcxz(ir, instr, dst): + return gen_jcc(ir, instr, mRCX[instr.mode], dst, False) + + +def jnz(ir, instr, dst): + #return gen_jcc(ir, instr, zf, dst, False) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_EQ", zf), dst, False) + + + +def jp(ir, instr, dst): + return gen_jcc(ir, instr, pf, dst, True) + + +def jnp(ir, instr, dst): + return gen_jcc(ir, instr, pf, dst, False) + + +def ja(ir, instr, dst): + #return gen_jcc(ir, instr, cf | zf, dst, False) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_U>", cf, zf), dst, True) + + +def jae(ir, instr, dst): + #return gen_jcc(ir, instr, cf, dst, False) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_U>=", cf), dst, True) + + +def jb(ir, instr, dst): + #return gen_jcc(ir, instr, cf, dst, True) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_U<", cf), dst, True) + + +def jbe(ir, instr, dst): + #return gen_jcc(ir, instr, cf | zf, dst, True) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_U<=", cf, zf), dst, True) + + +def jge(ir, instr, dst): + #return gen_jcc(ir, instr, nf - of, dst, False) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_S>=", nf, of), dst, True) + + +def jg(ir, instr, dst): + #return gen_jcc(ir, instr, zf | (nf - of), dst, False) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_S>", nf, of, zf), dst, True) + + +def jl(ir, instr, dst): + #return gen_jcc(ir, instr, nf - of, dst, True) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_S<", nf, of), dst, True) + + +def jle(ir, instr, dst): + #return gen_jcc(ir, instr, zf | (nf - of), dst, True) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_S<=", nf, of, zf), dst, True) + + + +def js(ir, instr, dst): + #return gen_jcc(ir, instr, nf, dst, True) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_NEG", nf), dst, True) + + + +def jns(ir, instr, dst): + #return gen_jcc(ir, instr, nf, dst, False) + return gen_jcc(ir, instr, m2_expr.ExprOp("CC_NEG", nf), dst, False) + + +def jo(ir, instr, dst): + return gen_jcc(ir, instr, of, dst, True) + + +def jno(ir, instr, dst): + return gen_jcc(ir, instr, of, dst, False) + + +def loop(ir, instr, dst): + e = [] + meip = mRIP[ir.IRDst.size] + admode = instr.v_admode() + myecx = mRCX[instr.mode][:admode] + + n = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + c = myecx - m2_expr.ExprInt(1, myecx.size) + dst_o = m2_expr.ExprCond(c, + dst.zeroExtend(ir.IRDst.size), + n.zeroExtend(ir.IRDst.size)) + e.append(m2_expr.ExprAssign(myecx, c)) + e.append(m2_expr.ExprAssign(meip, dst_o)) + e.append(m2_expr.ExprAssign(ir.IRDst, dst_o)) + return e, [] + + +def loopne(ir, instr, dst): + e = [] + meip = mRIP[ir.IRDst.size] + admode = instr.v_admode() + myecx = mRCX[instr.mode][:admode] + + n = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + + c = m2_expr.ExprCond(myecx - m2_expr.ExprInt(1, size=myecx.size), + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)) + c &= zf ^ m2_expr.ExprInt(1, 1) + + e.append(m2_expr.ExprAssign(myecx, myecx - m2_expr.ExprInt(1, myecx.size))) + dst_o = m2_expr.ExprCond(c, + dst.zeroExtend(ir.IRDst.size), + n.zeroExtend(ir.IRDst.size)) + e.append(m2_expr.ExprAssign(meip, dst_o)) + e.append(m2_expr.ExprAssign(ir.IRDst, dst_o)) + return e, [] + + +def loope(ir, instr, dst): + e = [] + meip = mRIP[ir.IRDst.size] + admode = instr.v_admode() + myecx = mRCX[instr.mode][:admode] + + n = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + c = m2_expr.ExprCond(myecx - m2_expr.ExprInt(1, size=myecx.size), + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)) + c &= zf + e.append(m2_expr.ExprAssign(myecx, myecx - m2_expr.ExprInt(1, myecx.size))) + dst_o = m2_expr.ExprCond(c, + dst.zeroExtend(ir.IRDst.size), + n.zeroExtend(ir.IRDst.size)) + e.append(m2_expr.ExprAssign(meip, dst_o)) + e.append(m2_expr.ExprAssign(ir.IRDst, dst_o)) + return e, [] + +# XXX size to do; eflag + + +def div(ir, instr, src1): + e = [] + size = src1.size + if size == 8: + src2 = mRAX[instr.mode][:16] + elif size in [16, 32, 64]: + s1, s2 = mRDX[size], mRAX[size] + src2 = m2_expr.ExprCompose(s2, s1) + else: + raise ValueError('div arg not impl', src1) + + c_d = m2_expr.ExprOp('udiv', src2, src1.zeroExtend(src2.size)) + c_r = m2_expr.ExprOp('umod', src2, src1.zeroExtend(src2.size)) + + # if 8 bit div, only ax is assigned + if size == 8: + e.append(m2_expr.ExprAssign(src2, m2_expr.ExprCompose(c_d[:8], c_r[:8]))) + else: + e.append(m2_expr.ExprAssign(s1, c_r[:size])) + e.append(m2_expr.ExprAssign(s2, c_d[:size])) + + loc_div, loc_div_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_except, loc_except_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size) + + do_div = [] + do_div += e + do_div.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + blk_div = IRBlock(ir.loc_db, loc_div, [AssignBlock(do_div, instr)]) + + do_except = [] + do_except.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt( + EXCEPT_DIV_BY_ZERO, exception_flags.size))) + do_except.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + blk_except = IRBlock(ir.loc_db, loc_except, [AssignBlock(do_except, instr)]) + + e = [] + e.append(m2_expr.ExprAssign(ir.IRDst, + m2_expr.ExprCond(src1, loc_div_expr, loc_except_expr))) + + return e, [blk_div, blk_except] + + +# XXX size to do; eflag + +def idiv(ir, instr, src1): + e = [] + size = src1.size + + if size == 8: + src2 = mRAX[instr.mode][:16] + elif size in [16, 32, 64]: + s1, s2 = mRDX[size], mRAX[size] + src2 = m2_expr.ExprCompose(s2, s1) + else: + raise ValueError('div arg not impl', src1) + + c_d = m2_expr.ExprOp('sdiv', src2, src1.signExtend(src2.size)) + c_r = m2_expr.ExprOp('smod', src2, src1.signExtend(src2.size)) + + # if 8 bit div, only ax is assigned + if size == 8: + e.append(m2_expr.ExprAssign(src2, m2_expr.ExprCompose(c_d[:8], c_r[:8]))) + else: + e.append(m2_expr.ExprAssign(s1, c_r[:size])) + e.append(m2_expr.ExprAssign(s2, c_d[:size])) + + loc_div, loc_div_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_except, loc_except_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size) + + do_div = [] + do_div += e + do_div.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + blk_div = IRBlock(ir.loc_db, loc_div, [AssignBlock(do_div, instr)]) + + do_except = [] + do_except.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt( + EXCEPT_DIV_BY_ZERO, exception_flags.size))) + do_except.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + blk_except = IRBlock(ir.loc_db, loc_except, [AssignBlock(do_except, instr)]) + + e = [] + e.append(m2_expr.ExprAssign(ir.IRDst, + m2_expr.ExprCond(src1, loc_div_expr, loc_except_expr))) + + return e, [blk_div, blk_except] + + +# XXX size to do; eflag + + +def mul(_, instr, src1): + e = [] + size = src1.size + if src1.size in [16, 32, 64]: + result = m2_expr.ExprOp('*', + mRAX[size].zeroExtend(size * 2), + src1.zeroExtend(size * 2)) + e.append(m2_expr.ExprAssign(mRAX[size], result[:size])) + e.append(m2_expr.ExprAssign(mRDX[size], result[size:size * 2])) + + elif src1.size == 8: + result = m2_expr.ExprOp('*', + mRAX[instr.mode][:8].zeroExtend(16), + src1.zeroExtend(16)) + e.append(m2_expr.ExprAssign(mRAX[instr.mode][:16], result)) + else: + raise ValueError('unknow size') + + e.append(m2_expr.ExprAssign(of, m2_expr.ExprCond(result[size:size * 2], + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)))) + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(result[size:size * 2], + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)))) + + return e, [] + + +def imul(_, instr, src1, src2=None, src3=None): + e = [] + size = src1.size + if src2 is None: + if size in [16, 32, 64]: + result = m2_expr.ExprOp('*', + mRAX[size].signExtend(size * 2), + src1.signExtend(size * 2)) + e.append(m2_expr.ExprAssign(mRAX[size], result[:size])) + e.append(m2_expr.ExprAssign(mRDX[size], result[size:size * 2])) + elif size == 8: + dst = mRAX[instr.mode][:16] + result = m2_expr.ExprOp('*', + mRAX[instr.mode][:8].signExtend(16), + src1.signExtend(16)) + + e.append(m2_expr.ExprAssign(dst, result)) + value = m2_expr.ExprCond(result - result[:size].signExtend(size * 2), + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)) + e.append(m2_expr.ExprAssign(cf, value)) + value = m2_expr.ExprCond(result - result[:size].signExtend(size * 2), + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)) + e.append(m2_expr.ExprAssign(of, value)) + + else: + if src3 is None: + src3 = src2 + src2 = src1 + result = m2_expr.ExprOp('*', + src2.signExtend(size * 2), + src3.signExtend(size * 2)) + e.append(m2_expr.ExprAssign(src1, result[:size])) + + value = m2_expr.ExprCond(result - result[:size].signExtend(size * 2), + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)) + e.append(m2_expr.ExprAssign(cf, value)) + value = m2_expr.ExprCond(result - result[:size].signExtend(size * 2), + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)) + e.append(m2_expr.ExprAssign(of, value)) + return e, [] + + +def cbw(_, instr): + # Only in 16 bit + e = [] + tempAL = mRAX[instr.v_opmode()][:8] + tempAX = mRAX[instr.v_opmode()][:16] + e.append(m2_expr.ExprAssign(tempAX, tempAL.signExtend(16))) + return e, [] + + +def cwde(_, instr): + # Only in 32/64 bit + e = [] + tempAX = mRAX[instr.v_opmode()][:16] + tempEAX = mRAX[instr.v_opmode()][:32] + e.append(m2_expr.ExprAssign(tempEAX, tempAX.signExtend(32))) + return e, [] + + +def cdqe(_, instr): + # Only in 64 bit + e = [] + tempEAX = mRAX[instr.mode][:32] + tempRAX = mRAX[instr.mode][:64] + e.append(m2_expr.ExprAssign(tempRAX, tempEAX.signExtend(64))) + return e, [] + + +def cwd(_, instr): + # Only in 16 bit + e = [] + tempAX = mRAX[instr.mode][:16] + tempDX = mRDX[instr.mode][:16] + result = tempAX.signExtend(32) + e.append(m2_expr.ExprAssign(tempAX, result[:16])) + e.append(m2_expr.ExprAssign(tempDX, result[16:32])) + return e, [] + + +def cdq(_, instr): + # Only in 32/64 bit + e = [] + tempEAX = mRAX[instr.v_opmode()] + tempEDX = mRDX[instr.v_opmode()] + result = tempEAX.signExtend(64) + e.append(m2_expr.ExprAssign(tempEDX, result[32:64])) + return e, [] + + +def cqo(_, instr): + # Only in 64 bit + e = [] + tempRAX = mRAX[instr.mode][:64] + tempRDX = mRDX[instr.mode][:64] + result = tempRAX.signExtend(128) + e.append(m2_expr.ExprAssign(tempRAX, result[:64])) + e.append(m2_expr.ExprAssign(tempRDX, result[64:128])) + return e, [] + + +def stos(ir, instr, size): + loc_df_0, loc_df_0_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_df_1, loc_df_1_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next_expr = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + + addr_o = mRDI[instr.mode][:instr.v_admode()] + addr = addr_o + addr_p = addr + m2_expr.ExprInt(size // 8, addr.size) + addr_m = addr - m2_expr.ExprInt(size // 8, addr.size) + if ir.do_str_segm: + mss = ES + if instr.additional_info.g2.value: + raise NotImplementedError("add segm support") + addr = ir.gen_segm_expr(mss, addr) + + + b = mRAX[instr.mode][:size] + + e0 = [] + e0.append(m2_expr.ExprAssign(addr_o, addr_p)) + e0.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + e0 = IRBlock(ir.loc_db, loc_df_0, [AssignBlock(e0, instr)]) + + e1 = [] + e1.append(m2_expr.ExprAssign(addr_o, addr_m)) + e1.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + e1 = IRBlock(ir.loc_db, loc_df_1, [AssignBlock(e1, instr)]) + + e = [] + e.append(m2_expr.ExprAssign(ir.ExprMem(addr, size), b)) + e.append(m2_expr.ExprAssign(ir.IRDst, + m2_expr.ExprCond(df, loc_df_1_expr, loc_df_0_expr))) + return e, [e0, e1] + + +def lods(ir, instr, size): + loc_df_0, loc_df_0_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_df_1, loc_df_1_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next_expr = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + e = [] + + addr_o = mRSI[instr.mode][:instr.v_admode()] + addr = addr_o + addr_p = addr + m2_expr.ExprInt(size // 8, addr.size) + addr_m = addr - m2_expr.ExprInt(size // 8, addr.size) + if ir.do_str_segm: + mss = DS + if instr.additional_info.g2.value: + raise NotImplementedError("add segm support") + addr = ir.gen_segm_expr(mss, addr) + + + b = mRAX[instr.mode][:size] + + e0 = [] + e0.append(m2_expr.ExprAssign(addr_o, addr_p)) + e0.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + e0 = IRBlock(ir.loc_db, loc_df_0, [AssignBlock(e0, instr)]) + + e1 = [] + e1.append(m2_expr.ExprAssign(addr_o, addr_m)) + e1.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + e1 = IRBlock(ir.loc_db, loc_df_1, [AssignBlock(e1, instr)]) + + e = [] + if instr.mode == 64 and b.size == 32: + e.append(m2_expr.ExprAssign(mRAX[instr.mode], + ir.ExprMem(addr, size).zeroExtend(64))) + else: + e.append(m2_expr.ExprAssign(b, ir.ExprMem(addr, size))) + + e.append(m2_expr.ExprAssign(ir.IRDst, + m2_expr.ExprCond(df, loc_df_1_expr, loc_df_0_expr))) + return e, [e0, e1] + + +def movs(ir, instr, size): + loc_df_0, loc_df_0_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_df_1, loc_df_1_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next_expr = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) + + dst = mRDI[instr.mode][:instr.v_admode()] + src = mRSI[instr.mode][:instr.v_admode()] + + e = [] + if ir.do_str_segm: + if instr.additional_info.g2.value: + raise NotImplementedError("add segm support") + src_sgm = ir.gen_segm_expr(DS, src) + dst_sgm = ir.gen_segm_expr(ES, dst) + + else: + src_sgm = src + dst_sgm = dst + + offset = m2_expr.ExprInt(size // 8, src.size) + + e.append(m2_expr.ExprAssign(ir.ExprMem(dst_sgm, size), + ir.ExprMem(src_sgm, size))) + + e0 = [] + e0.append(m2_expr.ExprAssign(src, src + offset)) + e0.append(m2_expr.ExprAssign(dst, dst + offset)) + e0.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + e0 = IRBlock(ir.loc_db, loc_df_0, [AssignBlock(e0, instr)]) + + e1 = [] + e1.append(m2_expr.ExprAssign(src, src - offset)) + e1.append(m2_expr.ExprAssign(dst, dst - offset)) + e1.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) + e1 = IRBlock(ir.loc_db, loc_df_1, [AssignBlock(e1, instr)]) + + e.append(m2_expr.ExprAssign(ir.IRDst, + m2_expr.ExprCond(df, loc_df_1_expr, loc_df_0_expr))) + return e, [e0, e1] + + +def movsd(_, instr, dst, src): + # 64 bits access + if dst.is_id() and src.is_id(): + src = src[:64] + dst = dst[:64] + elif dst.is_mem() and src.is_id(): + dst = m2_expr.ExprMem(dst.ptr, 64) + src = src[:64] + else: + src = m2_expr.ExprMem(src.ptr, 64) + # Erase dst high bits + src = src.zeroExtend(dst.size) + return [m2_expr.ExprAssign(dst, src)], [] + + +def movsd_dispatch(ir, instr, dst=None, src=None): + if dst is None and src is None: + return movs(ir, instr, 32) + else: + return movsd(ir, instr, dst, src) + + +def float_prev(flt, popcount=1): + if not flt in float_list: + return None + i = float_list.index(flt) + if i < popcount: + # Drop value (ex: FSTP ST(0)) + return None + flt = float_list[i - popcount] + return flt + + +def float_pop(avoid_flt=None, popcount=1): + """ + Generate floatpop semantic (@popcount times), avoiding the avoid_flt@ float + @avoid_flt: float avoided in the generated semantic + @popcount: pop count + """ + avoid_flt = float_prev(avoid_flt, popcount) + e = [] + for i in range(8 - popcount): + if avoid_flt != float_list[i]: + e.append(m2_expr.ExprAssign(float_list[i], + float_list[i + popcount])) + fill_value = m2_expr.ExprOp("sint_to_fp", m2_expr.ExprInt(0, 64)) + for i in range(8 - popcount, 8): + e.append(m2_expr.ExprAssign(float_list[i], + fill_value)) + e.append( + m2_expr.ExprAssign(float_stack_ptr, + float_stack_ptr - m2_expr.ExprInt(popcount, 3))) + return e + +# XXX TODO + + +def fcom(_, instr, dst=None, src=None): + + if dst is None and src is None: + dst, src = float_st0, float_st1 + elif src is None: + src = mem2double(instr, dst) + dst = float_st0 + + e = [] + + e.append(m2_expr.ExprAssign(float_c0, m2_expr.ExprOp('fcom_c0', dst, src))) + e.append(m2_expr.ExprAssign(float_c1, m2_expr.ExprOp('fcom_c1', dst, src))) + e.append(m2_expr.ExprAssign(float_c2, m2_expr.ExprOp('fcom_c2', dst, src))) + e.append(m2_expr.ExprAssign(float_c3, m2_expr.ExprOp('fcom_c3', dst, src))) + + e += set_float_cs_eip(instr) + return e, [] + + +def ftst(_, instr): + dst = float_st0 + + e = [] + src = m2_expr.ExprOp('sint_to_fp', m2_expr.ExprInt(0, 64)) + e.append(m2_expr.ExprAssign(float_c0, m2_expr.ExprOp('fcom_c0', dst, src))) + e.append(m2_expr.ExprAssign(float_c1, m2_expr.ExprOp('fcom_c1', dst, src))) + e.append(m2_expr.ExprAssign(float_c2, m2_expr.ExprOp('fcom_c2', dst, src))) + e.append(m2_expr.ExprAssign(float_c3, m2_expr.ExprOp('fcom_c3', dst, src))) + + e += set_float_cs_eip(instr) + return e, [] + + +def fxam(ir, instr): + """ + NaN: + C3, C2, C0 = 001; + Normal: + C3, C2, C0 = 010; + Infinity: + C3, C2, C0 = 011; + Zero: + C3, C2, C0 = 100; + Empty: + C3, C2, C0 = 101; + Denormal: + C3, C2, C0 = 110; + + C1 = sign bit of ST; (* 0 for positive, 1 for negative *) + """ + dst = float_st0 + + # Empty not handled + locs = {} + for name in ["NaN", "Normal", "Infinity", "Zero", "Denormal"]: + locs[name] = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size) + + # if Denormal: + # if zero: + # do_zero + # else: + # do_denormal + # else: + # if Nan: + # do_nan + # else: + # if infinity: + # do_infinity + # else: + # do_normal + + irdst = m2_expr.ExprCond( + m2_expr.expr_is_IEEE754_denormal(dst), + m2_expr.ExprCond(m2_expr.expr_is_IEEE754_zero(dst), + locs["Zero"][1], + locs["Denormal"][1], + ), + m2_expr.ExprCond(m2_expr.expr_is_NaN(dst), + locs["NaN"][1], + m2_expr.ExprCond(m2_expr.expr_is_infinite(dst), + locs["Infinity"][1], + locs["Normal"][1], + ) + ) + ) + base = [m2_expr.ExprAssign(ir.IRDst, irdst), + m2_expr.ExprAssign(float_c1, dst.msb()) + ] + base += set_float_cs_eip(instr) + + out = [ + IRBlock(ir.loc_db, locs["Zero"][0], [AssignBlock({ + float_c0: m2_expr.ExprInt(0, float_c0.size), + float_c2: m2_expr.ExprInt(0, float_c2.size), + float_c3: m2_expr.ExprInt(1, float_c3.size), + ir.IRDst: loc_next_expr, + }, instr)]), + IRBlock(ir.loc_db, locs["Denormal"][0], [AssignBlock({ + float_c0: m2_expr.ExprInt(0, float_c0.size), + float_c2: m2_expr.ExprInt(1, float_c2.size), + float_c3: m2_expr.ExprInt(1, float_c3.size), + ir.IRDst: loc_next_expr, + }, instr)]), + IRBlock(ir.loc_db, locs["NaN"][0], [AssignBlock({ + float_c0: m2_expr.ExprInt(1, float_c0.size), + float_c2: m2_expr.ExprInt(0, float_c2.size), + float_c3: m2_expr.ExprInt(0, float_c3.size), + ir.IRDst: loc_next_expr, + }, instr)]), + IRBlock(ir.loc_db, locs["Infinity"][0], [AssignBlock({ + float_c0: m2_expr.ExprInt(1, float_c0.size), + float_c2: m2_expr.ExprInt(1, float_c2.size), + float_c3: m2_expr.ExprInt(0, float_c3.size), + ir.IRDst: loc_next_expr, + }, instr)]), + IRBlock(ir.loc_db, locs["Normal"][0], [AssignBlock({ + float_c0: m2_expr.ExprInt(0, float_c0.size), + float_c2: m2_expr.ExprInt(1, float_c2.size), + float_c3: m2_expr.ExprInt(0, float_c3.size), + ir.IRDst: loc_next_expr, + }, instr)]), + ] + return base, out + + +def ficom(_, instr, dst, src=None): + + dst, src = float_implicit_st0(dst, src) + + e = [] + + e.append(m2_expr.ExprAssign(float_c0, + m2_expr.ExprOp('fcom_c0', dst, + src.zeroExtend(dst.size)))) + e.append(m2_expr.ExprAssign(float_c1, + m2_expr.ExprOp('fcom_c1', dst, + src.zeroExtend(dst.size)))) + e.append(m2_expr.ExprAssign(float_c2, + m2_expr.ExprOp('fcom_c2', dst, + src.zeroExtend(dst.size)))) + e.append(m2_expr.ExprAssign(float_c3, + m2_expr.ExprOp('fcom_c3', dst, + src.zeroExtend(dst.size)))) + + e += set_float_cs_eip(instr) + return e, [] + + +def fcomi(_, instr, dst=None, src=None): + # TODO unordered float + if dst is None and src is None: + dst, src = float_st0, float_st1 + elif src is None: + src = dst + dst = float_st0 + + e = [] + + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprOp('fcom_c0', dst, src))) + e.append(m2_expr.ExprAssign(pf, m2_expr.ExprOp('fcom_c2', dst, src))) + e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp('fcom_c3', dst, src))) + + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, 1))) + e.append(m2_expr.ExprAssign(nf, m2_expr.ExprInt(0, 1))) + e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1))) + + e += set_float_cs_eip(instr) + return e, [] + + +def fcomip(ir, instr, dst=None, src=None): + e, extra = fcomi(ir, instr, dst, src) + e += float_pop() + e += set_float_cs_eip(instr) + return e, extra + + +def fucomi(ir, instr, dst=None, src=None): + # TODO unordered float + return fcomi(ir, instr, dst, src) + + +def fucomip(ir, instr, dst=None, src=None): + # TODO unordered float + return fcomip(ir, instr, dst, src) + + +def fcomp(ir, instr, dst=None, src=None): + e, extra = fcom(ir, instr, dst, src) + e += float_pop() + e += set_float_cs_eip(instr) + return e, extra + + +def fcompp(ir, instr, dst=None, src=None): + e, extra = fcom(ir, instr, dst, src) + e += float_pop(popcount=2) + e += set_float_cs_eip(instr) + return e, extra + + +def ficomp(ir, instr, dst, src=None): + e, extra = ficom(ir, instr, dst, src) + e += float_pop() + e += set_float_cs_eip(instr) + return e, extra + + +def fucom(ir, instr, dst=None, src=None): + # TODO unordered float + return fcom(ir, instr, dst, src) + + +def fucomp(ir, instr, dst=None, src=None): + # TODO unordered float + return fcomp(ir, instr, dst, src) + + +def fucompp(ir, instr, dst=None, src=None): + # TODO unordered float + return fcompp(ir, instr, dst, src) + + +def comiss(_, instr, dst, src): + # TODO unordered float + + e = [] + + dst = m2_expr.ExprOp('sint_to_fp', dst[:32]) + src = m2_expr.ExprOp('sint_to_fp', src[:32]) + + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprOp('fcom_c0', dst, src))) + e.append(m2_expr.ExprAssign(pf, m2_expr.ExprOp('fcom_c2', dst, src))) + e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp('fcom_c3', dst, src))) + + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, 1))) + e.append(m2_expr.ExprAssign(nf, m2_expr.ExprInt(0, 1))) + e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1))) + + e += set_float_cs_eip(instr) + return e, [] + + +def comisd(_, instr, dst, src): + # TODO unordered float + + e = [] + + dst = m2_expr.ExprOp('sint_to_fp', dst[:64]) + src = m2_expr.ExprOp('sint_to_fp', src[:64]) + + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprOp('fcom_c0', dst, src))) + e.append(m2_expr.ExprAssign(pf, m2_expr.ExprOp('fcom_c2', dst, src))) + e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp('fcom_c3', dst, src))) + + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, 1))) + e.append(m2_expr.ExprAssign(nf, m2_expr.ExprInt(0, 1))) + e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1))) + + e += set_float_cs_eip(instr) + return e, [] + + +def fld(_, instr, src): + + if src.size == 32: + src = m2_expr.ExprOp("fpconvert_fp64", src) + if isinstance(src, m2_expr.ExprMem) and src.size > 64: + raise NotImplementedError('convert from 80bits') + + e = [] + e.append(m2_expr.ExprAssign(float_st7, float_st6)) + e.append(m2_expr.ExprAssign(float_st6, float_st5)) + e.append(m2_expr.ExprAssign(float_st5, float_st4)) + e.append(m2_expr.ExprAssign(float_st4, float_st3)) + e.append(m2_expr.ExprAssign(float_st3, float_st2)) + e.append(m2_expr.ExprAssign(float_st2, float_st1)) + e.append(m2_expr.ExprAssign(float_st1, float_st0)) + e.append(m2_expr.ExprAssign(float_st0, src)) + e.append( + m2_expr.ExprAssign(float_stack_ptr, + float_stack_ptr + m2_expr.ExprInt(1, 3))) + + e += set_float_cs_eip(instr) + return e, [] + + +def fst(_, instr, dst): + e = [] + + if isinstance(dst, m2_expr.ExprMem) and dst.size > 64: + raise NotImplementedError('convert to 80bits') + src = float_st0 + + if dst.size == 32: + src = m2_expr.ExprOp("fpconvert_fp32", src) + e.append(m2_expr.ExprAssign(dst, src)) + e += set_float_cs_eip(instr) + return e, [] + + +def fstp(ir, instr, dst): + e = [] + + if isinstance(dst, m2_expr.ExprMem) and dst.size > 64: + raise NotImplementedError('convert to 80bits') + + if isinstance(dst, m2_expr.ExprMem): + src = float_st0 + if dst.size == 32: + src = m2_expr.ExprOp("fpconvert_fp32", src) + e.append(m2_expr.ExprAssign(dst, src)) + else: + src = float_st0 + if float_list.index(dst) > 1: + # a = st0 -> st0 is dropped + # a = st1 -> st0 = st0, useless + e.append(m2_expr.ExprAssign(float_prev(dst), src)) + + e += set_float_cs_eip(instr) + e += float_pop(dst) + return e, [] + + +def fist(_, instr, dst): + e = [] + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fp_to_sint%d' % dst.size, + float_st0))) + + e += set_float_cs_eip(instr) + return e, [] + + +def fistp(ir, instr, dst): + e, extra = fist(ir, instr, dst) + e += float_pop(dst) + return e, extra + + +def fisttp(_, instr, dst): + e = [] + e.append(m2_expr.ExprAssign( + dst, + m2_expr.ExprOp('fp_to_sint%d' % dst.size, + m2_expr.ExprOp('fpround_towardszero', float_st0) + ))) + + e += set_float_cs_eip(instr) + e += float_pop(dst) + return e, [] + + +def fild(ir, instr, src): + # XXXXX + src = m2_expr.ExprOp('sint_to_fp', src.signExtend(64)) + e = [] + e += set_float_cs_eip(instr) + e_fld, extra = fld(ir, instr, src) + e += e_fld + return e, extra + + +def fldz(ir, instr): + return fld(ir, instr, m2_expr.ExprOp('sint_to_fp', m2_expr.ExprInt(0, 64))) + + +def fld1(ir, instr): + return fld(ir, instr, m2_expr.ExprOp('sint_to_fp', m2_expr.ExprInt(1, 64))) + + +def fldl2t(ir, instr): + value_f = math.log(10) / math.log(2) + value = struct.unpack('Q', struct.pack('d', value_f))[0] + return fld(ir, instr, m2_expr.ExprOp( + 'sint_to_fp', + m2_expr.ExprInt(value, 64) + )) + + +def fldpi(ir, instr): + value_f = math.pi + value = struct.unpack('Q', struct.pack('d', value_f))[0] + return fld(ir, instr, m2_expr.ExprOp( + 'sint_to_fp', + m2_expr.ExprInt(value, 64) + )) + + +def fldln2(ir, instr): + value_f = math.log(2) + value = struct.unpack('Q', struct.pack('d', value_f))[0] + return fld(ir, instr, m2_expr.ExprOp('mem_64_to_double', + m2_expr.ExprInt(value, 64))) + + +def fldl2e(ir, instr): + x = struct.pack('d', 1 / math.log(2)) + x = struct.unpack('Q', x)[0] + return fld(ir, instr, m2_expr.ExprOp('mem_64_to_double', + m2_expr.ExprInt(x, 64))) + + +def fldlg2(ir, instr): + x = struct.pack('d', math.log10(2)) + x = struct.unpack('Q', x)[0] + return fld(ir, instr, m2_expr.ExprOp('mem_64_to_double', + m2_expr.ExprInt(x, 64))) + + +def fadd(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fadd', dst, src))) + + e += set_float_cs_eip(instr) + return e, [] + + +def fiadd(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fiadd', dst, src))) + e += set_float_cs_eip(instr) + return e, [] + + +def fisub(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fisub', dst, src))) + e += set_float_cs_eip(instr) + return e, [] + + +def fisubr(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fisub', src, dst))) + e += set_float_cs_eip(instr) + return e, [] + + +def fpatan(_, instr): + e = [] + a = float_st1 + e.append(m2_expr.ExprAssign(float_prev(a), + m2_expr.ExprOp('fpatan', float_st0, float_st1))) + e += set_float_cs_eip(instr) + e += float_pop(a) + return e, [] + + +def fprem(_, instr): + e = [] + e.append( + m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fprem', float_st0, float_st1))) + # Remaining bits (ex: used in argument reduction in tan) + quotient = m2_expr.ExprOp('fp_to_sint32', m2_expr.ExprOp('fpround_towardszero', m2_expr.ExprOp('fdiv', float_st0, float_st1))) + e += [m2_expr.ExprAssign(float_c0, quotient[2:3]), + m2_expr.ExprAssign(float_c3, quotient[1:2]), + m2_expr.ExprAssign(float_c1, quotient[0:1]), + # Consider the reduction is always completed + m2_expr.ExprAssign(float_c2, m2_expr.ExprInt(0, 1)), + ] + e += set_float_cs_eip(instr) + return e, [] + + +def fprem1(_, instr): + e = [] + e.append( + m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fprem1', float_st0, float_st1))) + e += set_float_cs_eip(instr) + return e, [] + + +def faddp(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fadd', dst, src))) + e += set_float_cs_eip(instr) + e += float_pop(dst) + return e, [] + + +def fninit(_, instr): + e = [] + e += set_float_cs_eip(instr) + return e, [] + + +def fyl2x(_, instr): + e = [] + a = float_st1 + e.append( + m2_expr.ExprAssign(float_prev(a), m2_expr.ExprOp('fyl2x', float_st0, float_st1))) + e += set_float_cs_eip(instr) + e += float_pop(a) + return e, [] + + +def fnstenv(ir, instr, dst): + e = [] + # XXX TODO tag word, ... + status_word = m2_expr.ExprCompose(m2_expr.ExprInt(0, 8), + float_c0, float_c1, float_c2, + float_stack_ptr, float_c3, + m2_expr.ExprInt(0, 1)) + + s = instr.mode + # The behaviour in 64bit is identical to 32 bit + # This will truncate addresses + size = min(32, s) + ad = ir.ExprMem(dst.ptr, size=16) + e.append(m2_expr.ExprAssign(ad, float_control)) + ad = ir.ExprMem( + dst.ptr + m2_expr.ExprInt( + (size // 8) * 1, + dst.ptr.size + ), + size=16 + ) + e.append(m2_expr.ExprAssign(ad, status_word)) + ad = ir.ExprMem( + dst.ptr + m2_expr.ExprInt( + (size // 8) * 3, + dst.ptr.size + ), + size=size + ) + e.append(m2_expr.ExprAssign(ad, float_eip[:size])) + ad = ir.ExprMem( + dst.ptr + m2_expr.ExprInt( + (size // 8) * 4, + dst.ptr.size + ), + size=16 + ) + e.append(m2_expr.ExprAssign(ad, float_cs)) + ad = ir.ExprMem( + dst.ptr + m2_expr.ExprInt( + (size // 8) * 5, + dst.ptr.size + ), + size=size + ) + e.append(m2_expr.ExprAssign(ad, float_address[:size])) + ad = ir.ExprMem( + dst.ptr + m2_expr.ExprInt( + (size // 8) * 6, + dst.ptr.size + ), + size=16 + ) + e.append(m2_expr.ExprAssign(ad, float_ds)) + return e, [] + + +def fldenv(ir, instr, src): + e = [] + # Inspired from fnstenv (same TODOs / issues) + + s = instr.mode + # The behaviour in 64bit is identical to 32 bit + # This will truncate addresses + size = min(32, s) + + # Float control + ad = ir.ExprMem(src.ptr, size=16) + e.append(m2_expr.ExprAssign(float_control, ad)) + + # Status word + ad = ir.ExprMem( + src.ptr + m2_expr.ExprInt( + size // (8 * 1), + size=src.ptr.size + ), + size=16 + ) + e += [ + m2_expr.ExprAssign(x, y) for x, y in ((float_c0, ad[8:9]), + (float_c1, ad[9:10]), + (float_c2, ad[10:11]), + (float_stack_ptr, ad[11:14]), + (float_c3, ad[14:15])) + ] + + # EIP, CS, Address, DS + for offset, target in ( + (3, float_eip[:size]), + (4, float_cs), + (5, float_address[:size]), + (6, float_ds) + ): + ad = ir.ExprMem( + src.ptr + m2_expr.ExprInt( + size // ( 8 * offset), + size=src.ptr.size + ), + size=target.size + ) + e.append(m2_expr.ExprAssign(target, ad)) + + return e, [] + + +def fsub(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fsub', dst, src))) + e += set_float_cs_eip(instr) + return e, [] + + +def fsubp(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fsub', dst, src))) + e += set_float_cs_eip(instr) + e += float_pop(dst) + return e, [] + + +def fsubr(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fsub', src, dst))) + e += set_float_cs_eip(instr) + return e, [] + + +def fsubrp(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fsub', src, dst))) + e += set_float_cs_eip(instr) + e += float_pop(dst) + return e, [] + + +def fmul(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fmul', dst, src))) + e += set_float_cs_eip(instr) + return e, [] + + +def fimul(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fimul', dst, src))) + e += set_float_cs_eip(instr) + return e, [] + + +def fdiv(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fdiv', dst, src))) + e += set_float_cs_eip(instr) + return e, [] + + +def fdivr(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fdiv', src, dst))) + e += set_float_cs_eip(instr) + return e, [] + + +def fdivrp(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fdiv', src, dst))) + e += set_float_cs_eip(instr) + e += float_pop(dst) + return e, [] + + +def fidiv(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fidiv', dst, src))) + e += set_float_cs_eip(instr) + return e, [] + + +def fidivr(_, instr, dst, src=None): + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fidiv', src, dst))) + e += set_float_cs_eip(instr) + return e, [] + + +def fdivp(_, instr, dst, src=None): + # Invalid emulation + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fdiv', dst, src))) + e += set_float_cs_eip(instr) + e += float_pop(dst) + return e, [] + + +def fmulp(_, instr, dst, src=None): + # Invalid emulation + dst, src = float_implicit_st0(dst, src) + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fmul', dst, src))) + e += set_float_cs_eip(instr) + e += float_pop(dst) + return e, [] + + +def ftan(_, instr, src): + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('ftan', src))) + e += set_float_cs_eip(instr) + return e, [] + + +def fxch(_, instr, src): + e = [] + src = mem2double(instr, src) + e.append(m2_expr.ExprAssign(float_st0, src)) + e.append(m2_expr.ExprAssign(src, float_st0)) + e += set_float_cs_eip(instr) + return e, [] + + +def fptan(_, instr): + e = [] + e.append(m2_expr.ExprAssign(float_st7, float_st6)) + e.append(m2_expr.ExprAssign(float_st6, float_st5)) + e.append(m2_expr.ExprAssign(float_st5, float_st4)) + e.append(m2_expr.ExprAssign(float_st4, float_st3)) + e.append(m2_expr.ExprAssign(float_st3, float_st2)) + e.append(m2_expr.ExprAssign(float_st2, float_st1)) + e.append(m2_expr.ExprAssign(float_st1, m2_expr.ExprOp('ftan', float_st0))) + e.append( + m2_expr.ExprAssign( + float_st0, + m2_expr.ExprOp( + 'sint_to_fp', + m2_expr.ExprInt(1, 64) + ) + ) + ) + e.append( + m2_expr.ExprAssign(float_stack_ptr, + float_stack_ptr + m2_expr.ExprInt(1, 3))) + return e, [] + + +def frndint(_, instr): + e = [] + e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('frndint', float_st0))) + e += set_float_cs_eip(instr) + return e, [] + + +def fsin(_, instr): + e = [] + e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fsin', float_st0))) + e += set_float_cs_eip(instr) + return e, [] + + +def fcos(_, instr): + e = [] + e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fcos', float_st0))) + e += set_float_cs_eip(instr) + return e, [] + + +def fsincos(_, instr): + e = [] + e.append(m2_expr.ExprAssign(float_st7, float_st6)) + e.append(m2_expr.ExprAssign(float_st6, float_st5)) + e.append(m2_expr.ExprAssign(float_st5, float_st4)) + e.append(m2_expr.ExprAssign(float_st4, float_st3)) + e.append(m2_expr.ExprAssign(float_st3, float_st2)) + e.append(m2_expr.ExprAssign(float_st2, float_st1)) + e.append(m2_expr.ExprAssign(float_st1, m2_expr.ExprOp('fsin', float_st0))) + e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fcos', float_st0))) + e.append( + m2_expr.ExprAssign(float_stack_ptr, + float_stack_ptr + m2_expr.ExprInt(1, 3))) + return e, [] + + +def fscale(_, instr): + e = [] + e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fscale', float_st0, + float_st1))) + e += set_float_cs_eip(instr) + return e, [] + + +def f2xm1(_, instr): + e = [] + e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('f2xm1', float_st0))) + e += set_float_cs_eip(instr) + return e, [] + + +def fchs(_, instr): + e = [] + e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fchs', float_st0))) + e += set_float_cs_eip(instr) + return e, [] + + +def fsqrt(_, instr): + e = [] + e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fsqrt', float_st0))) + e += set_float_cs_eip(instr) + return e, [] + + +def fabs(_, instr): + e = [] + e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fabs', float_st0))) + e += set_float_cs_eip(instr) + return e, [] + + +def fnstsw(_, instr, dst): + args = [ + # Exceptions -> 0 + m2_expr.ExprInt(0, 8), + float_c0, + float_c1, + float_c2, + float_stack_ptr, + float_c3, + # B: FPU is not busy -> 0 + m2_expr.ExprInt(0, 1)] + e = [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*args))] + return e, [] + + +def fnstcw(_, instr, dst): + e = [] + e.append(m2_expr.ExprAssign(dst, float_control)) + return e, [] + + +def fldcw(_, instr, src): + e = [] + e.append(m2_expr.ExprAssign(float_control, src)) + return e, [] + + +def fwait(_, instr): + return [], [] + + +def fcmovb(ir, instr, arg1, arg2): + return gen_fcmov(ir, instr, cf, arg1, arg2, True) + + +def fcmove(ir, instr, arg1, arg2): + return gen_fcmov(ir, instr, zf, arg1, arg2, True) + + +def fcmovbe(ir, instr, arg1, arg2): + return gen_fcmov(ir, instr, cf | zf, arg1, arg2, True) + + +def fcmovu(ir, instr, arg1, arg2): + return gen_fcmov(ir, instr, pf, arg1, arg2, True) + + +def fcmovnb(ir, instr, arg1, arg2): + return gen_fcmov(ir, instr, cf, arg1, arg2, False) + + +def fcmovne(ir, instr, arg1, arg2): + return gen_fcmov(ir, instr, zf, arg1, arg2, False) + + +def fcmovnbe(ir, instr, arg1, arg2): + return gen_fcmov(ir, instr, cf | zf, arg1, arg2, False) + + +def fcmovnu(ir, instr, arg1, arg2): + return gen_fcmov(ir, instr, pf, arg1, arg2, False) + + +def nop(_, instr, a=None): + return [], [] + + +def prefetch0(_, instr, src=None): + # see 4-198 on this documentation + # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + return [], [] + + +def prefetch1(_, instr, src=None): + # see 4-198 on this documentation + # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + return [], [] + + +def prefetch2(_, instr, src=None): + # see 4-198 on this documentation + # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + return [], [] + + +def prefetchw(_, instr, src=None): + # see 4-201 on this documentation + # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + return [], [] + +def prefetchnta(_, instr, src=None): + # see 4-201 on this documentation + # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + return [], [] + + +def lfence(_, instr, src=None): + # see 3-485 on this documentation + # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + return [], [] + + +def mfence(_, instr, src=None): + # see 3-516 on this documentation + # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + return [], [] + + +def sfence(_, instr, src=None): + # see 3-356 on this documentation + # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + return [], [] + + +def ud2(_, instr, src=None): + e = [m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt( + EXCEPT_ILLEGAL_INSN, exception_flags.size))] + return e, [] + + +def hlt(_, instr): + e = [] + except_int = EXCEPT_PRIV_INSN + e.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(except_int, 32))) + return e, [] + + +def rdtsc(_, instr): + e = [] + e.append(m2_expr.ExprAssign(tsc, tsc + m2_expr.ExprInt(1, 64))) + e.append(m2_expr.ExprAssign(mRAX[32], tsc[:32])) + e.append(m2_expr.ExprAssign(mRDX[32], tsc[32:])) + return e, [] + + +def daa(_, instr): + e = [] + r_al = mRAX[instr.mode][:8] + + cond1 = m2_expr.expr_is_unsigned_greater(r_al[:4], m2_expr.ExprInt(0x9, 4)) | af + e.append(m2_expr.ExprAssign(af, cond1)) + + cond2 = m2_expr.expr_is_unsigned_greater(m2_expr.ExprInt(6, 8), r_al) + cond3 = m2_expr.expr_is_unsigned_greater(r_al, m2_expr.ExprInt(0x99, 8)) | cf + + cf_c1 = m2_expr.ExprCond(cond1, + cf | (cond2), + m2_expr.ExprInt(0, 1)) + new_cf = m2_expr.ExprCond(cond3, + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)) + e.append(m2_expr.ExprAssign(cf, new_cf)) + + al_c1 = m2_expr.ExprCond(cond1, + r_al + m2_expr.ExprInt(6, 8), + r_al) + + new_al = m2_expr.ExprCond(cond3, + al_c1 + m2_expr.ExprInt(0x60, 8), + al_c1) + e.append(m2_expr.ExprAssign(r_al, new_al)) + e += update_flag_znp(new_al) + return e, [] + + +def das(_, instr): + e = [] + r_al = mRAX[instr.mode][:8] + + cond1 = m2_expr.expr_is_unsigned_greater(r_al[:4], m2_expr.ExprInt(0x9, 4)) | af + e.append(m2_expr.ExprAssign(af, cond1)) + + cond2 = m2_expr.expr_is_unsigned_greater(m2_expr.ExprInt(6, 8), r_al) + cond3 = m2_expr.expr_is_unsigned_greater(r_al, m2_expr.ExprInt(0x99, 8)) | cf + + cf_c1 = m2_expr.ExprCond(cond1, + cf | (cond2), + m2_expr.ExprInt(0, 1)) + new_cf = m2_expr.ExprCond(cond3, + m2_expr.ExprInt(1, 1), + cf_c1) + e.append(m2_expr.ExprAssign(cf, new_cf)) + + al_c1 = m2_expr.ExprCond(cond1, + r_al - m2_expr.ExprInt(6, 8), + r_al) + + new_al = m2_expr.ExprCond(cond3, + al_c1 - m2_expr.ExprInt(0x60, 8), + al_c1) + e.append(m2_expr.ExprAssign(r_al, new_al)) + e += update_flag_znp(new_al) + return e, [] + + +def aam(ir, instr, src): + e = [] + assert src.is_int() + + value = int(src) + if value: + tempAL = mRAX[instr.mode][0:8] + newEAX = m2_expr.ExprCompose( + m2_expr.ExprOp("umod", tempAL, src), + m2_expr.ExprOp("udiv", tempAL, src), + mRAX[instr.mode][16:] + ) + e += [m2_expr.ExprAssign(mRAX[instr.mode], newEAX)] + e += update_flag_arith(newEAX) + e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1))) + else: + e.append( + m2_expr.ExprAssign( + exception_flags, + m2_expr.ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size) + ) + ) + return e, [] + + +def aad(_, instr, src): + e = [] + tempAL = mRAX[instr.mode][0:8] + tempAH = mRAX[instr.mode][8:16] + newEAX = m2_expr.ExprCompose((tempAL + (tempAH * src)) & m2_expr.ExprInt(0xFF, 8), + m2_expr.ExprInt(0, 8), + mRAX[instr.mode][16:]) + e += [m2_expr.ExprAssign(mRAX[instr.mode], newEAX)] + e += update_flag_arith(newEAX) + e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1))) + return e, [] + + +def _tpl_aaa(_, instr, op): + """Templating for aaa, aas with operation @op + @op: operation to apply + """ + e = [] + r_al = mRAX[instr.mode][:8] + r_ah = mRAX[instr.mode][8:16] + r_ax = mRAX[instr.mode][:16] + i0 = m2_expr.ExprInt(0, 1) + i1 = m2_expr.ExprInt(1, 1) + # cond: if (al & 0xf) > 9 OR af == 1 + cond = (r_al & m2_expr.ExprInt(0xf, 8)) - m2_expr.ExprInt(9, 8) + cond = ~cond.msb() & m2_expr.ExprCond(cond, i1, i0) + cond |= af & i1 + + to_add = m2_expr.ExprInt(0x106, size=r_ax.size) + if op == "-": + # Avoid ExprOp("-", A, B), should be ExprOp("+", A, ExprOp("-", B)) + first_part = r_ax - to_add + else: + first_part = m2_expr.ExprOp(op, r_ax, to_add) + new_ax = first_part & m2_expr.ExprInt(0xff0f, + size=r_ax.size) + # set AL + e.append(m2_expr.ExprAssign(r_ax, m2_expr.ExprCond(cond, new_ax, r_ax))) + e.append(m2_expr.ExprAssign(af, cond)) + e.append(m2_expr.ExprAssign(cf, cond)) + return e, [] + + +def aaa(ir, instr): + return _tpl_aaa(ir, instr, "+") + + +def aas(ir, instr): + return _tpl_aaa(ir, instr, "-") + + +def bsr_bsf(ir, instr, dst, src, op_func): + """ + IF SRC == 0 + ZF = 1 + DEST is left unchanged + ELSE + ZF = 0 + DEST = @op_func(SRC) + """ + loc_src_null, loc_src_null_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_src_not_null, loc_src_not_null_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size) + + aff_dst = m2_expr.ExprAssign(ir.IRDst, loc_next_expr) + e = [m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(src, + loc_src_not_null_expr, + loc_src_null_expr))] + e_src_null = [] + e_src_null.append(m2_expr.ExprAssign(zf, m2_expr.ExprInt(1, zf.size))) + # XXX destination is undefined + e_src_null.append(aff_dst) + + e_src_not_null = [] + e_src_not_null.append(m2_expr.ExprAssign(zf, m2_expr.ExprInt(0, zf.size))) + e_src_not_null.append(m2_expr.ExprAssign(dst, op_func(src))) + e_src_not_null.append(aff_dst) + + return e, [IRBlock(ir.loc_db, loc_src_null, [AssignBlock(e_src_null, instr)]), + IRBlock(ir.loc_db, loc_src_not_null, [AssignBlock(e_src_not_null, instr)])] + + +def bsf(ir, instr, dst, src): + return bsr_bsf(ir, instr, dst, src, + lambda src: m2_expr.ExprOp("cnttrailzeros", src)) + + +def bsr(ir, instr, dst, src): + return bsr_bsf( + ir, instr, dst, src, + lambda src: m2_expr.ExprInt(src.size - 1, src.size) - m2_expr.ExprOp("cntleadzeros", src) + ) + + +def arpl(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(1 << 7, 32))) + return e, [] + + +def ins(_, instr, size): + e = [] + e.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(1 << 7, 32))) + return e, [] + + +def sidt(ir, instr, dst): + e = [] + if not isinstance(dst, m2_expr.ExprMem) or dst.size != 32: + raise ValueError('not exprmem 32bit instance!!') + ptr = dst.ptr + LOG_X86_SEM.warning("DEFAULT SIDT ADDRESS %s!!", dst) + e.append(m2_expr.ExprAssign(ir.ExprMem(ptr, 32), + m2_expr.ExprInt(0xe40007ff, 32))) + e.append( + m2_expr.ExprAssign(ir.ExprMem(ptr + m2_expr.ExprInt(4, ptr.size), 16), + m2_expr.ExprInt(0x8245, 16))) + return e, [] + + +def sldt(_, instr, dst): + LOG_X86_SEM.warning("DEFAULT SLDT ADDRESS %s!!", dst) + e = [m2_expr.ExprAssign(dst, m2_expr.ExprInt(0, dst.size))] + return e, [] + + +def cmovz(ir, instr, dst, src): + #return gen_cmov(ir, instr, zf, dst, src, True) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_EQ", zf), dst, src, True) + + +def cmovnz(ir, instr, dst, src): + #return gen_cmov(ir, instr, zf, dst, src, False) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_EQ", zf), dst, src, False) + + +def cmovpe(ir, instr, dst, src): + return gen_cmov(ir, instr, pf, dst, src, True) + + +def cmovnp(ir, instr, dst, src): + return gen_cmov(ir, instr, pf, dst, src, False) + + +def cmovge(ir, instr, dst, src): + #return gen_cmov(ir, instr, nf ^ of, dst, src, False) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_S>=", nf, of), dst, src, True) + + +def cmovg(ir, instr, dst, src): + #return gen_cmov(ir, instr, zf | (nf ^ of), dst, src, False) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_S>", nf, of, zf), dst, src, True) + + +def cmovl(ir, instr, dst, src): + #return gen_cmov(ir, instr, nf ^ of, dst, src, True) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_S<", nf, of), dst, src, True) + + +def cmovle(ir, instr, dst, src): + #return gen_cmov(ir, instr, zf | (nf ^ of), dst, src, True) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_S<=", nf, of, zf), dst, src, True) + + +def cmova(ir, instr, dst, src): + #return gen_cmov(ir, instr, cf | zf, dst, src, False) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_U>", cf, zf), dst, src, True) + + +def cmovae(ir, instr, dst, src): + #return gen_cmov(ir, instr, cf, dst, src, False) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_U>=", cf), dst, src, True) + + +def cmovbe(ir, instr, dst, src): + #return gen_cmov(ir, instr, cf | zf, dst, src, True) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_U<=", cf, zf), dst, src, True) + + +def cmovb(ir, instr, dst, src): + #return gen_cmov(ir, instr, cf, dst, src, True) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_U<", cf), dst, src, True) + + +def cmovo(ir, instr, dst, src): + return gen_cmov(ir, instr, of, dst, src, True) + + +def cmovno(ir, instr, dst, src): + return gen_cmov(ir, instr, of, dst, src, False) + + +def cmovs(ir, instr, dst, src): + #return gen_cmov(ir, instr, nf, dst, src, True) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_NEG", nf), dst, src, True) + + +def cmovns(ir, instr, dst, src): + #return gen_cmov(ir, instr, nf, dst, src, False) + return gen_cmov(ir, instr, m2_expr.ExprOp("CC_NEG", nf), dst, src, False) + + +def icebp(_, instr): + e = [] + e.append(m2_expr.ExprAssign(exception_flags, + m2_expr.ExprInt(EXCEPT_SOFT_BP, 32))) + return e, [] +# XXX + + +def l_int(_, instr, src): + e = [] + # XXX + assert src.is_int() + value = int(src) + if value == 1: + except_int = EXCEPT_INT_1 + elif value == 3: + except_int = EXCEPT_SOFT_BP + else: + except_int = EXCEPT_INT_XX + e.append(m2_expr.ExprAssign(exception_flags, + m2_expr.ExprInt(except_int, 32))) + e.append(m2_expr.ExprAssign(interrupt_num, src)) + return e, [] + + +def l_sysenter(_, instr): + e = [] + e.append(m2_expr.ExprAssign(exception_flags, + m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32))) + return e, [] + + +def l_syscall(_, instr): + e = [] + e.append(m2_expr.ExprAssign(exception_flags, + m2_expr.ExprInt(EXCEPT_SYSCALL, 32))) + return e, [] + +# XXX + + +def l_out(_, instr, src1, src2): + e = [] + e.append(m2_expr.ExprAssign(exception_flags, + m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32))) + return e, [] + +# XXX + + +def l_outs(_, instr, size): + e = [] + e.append(m2_expr.ExprAssign(exception_flags, + m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32))) + return e, [] + +# XXX actually, xlat performs al = (ds:[e]bx + ZeroExtend(al)) + + +def xlat(ir, instr): + e = [] + ptr = mRAX[instr.mode][0:8].zeroExtend(mRBX[instr.mode].size) + src = ir.ExprMem(mRBX[instr.mode] + ptr, 8) + e.append(m2_expr.ExprAssign(mRAX[instr.mode][0:8], src)) + return e, [] + + +def cpuid(_, instr): + e = [] + e.append( + m2_expr.ExprAssign(mRAX[instr.mode], + m2_expr.ExprOp('x86_cpuid', mRAX[instr.mode], m2_expr.ExprInt(0, instr.mode)))) + e.append( + m2_expr.ExprAssign(mRBX[instr.mode], + m2_expr.ExprOp('x86_cpuid', mRAX[instr.mode], m2_expr.ExprInt(1, instr.mode)))) + e.append( + m2_expr.ExprAssign(mRCX[instr.mode], + m2_expr.ExprOp('x86_cpuid', mRAX[instr.mode], m2_expr.ExprInt(2, instr.mode)))) + e.append( + m2_expr.ExprAssign(mRDX[instr.mode], + m2_expr.ExprOp('x86_cpuid', mRAX[instr.mode], m2_expr.ExprInt(3, instr.mode)))) + return e, [] + + +def bittest_get(ir, instr, src, index): + index = index.zeroExtend(src.size) + if isinstance(src, m2_expr.ExprMem): + b_mask = {16: 4, 32: 5, 64: 6} + b_decal = {16: 1, 32: 3, 64: 7} + ptr = src.ptr + segm = is_mem_segm(src) + if segm: + ptr = ptr.args[1] + + off_bit = index.zeroExtend( + src.size) & m2_expr.ExprInt((1 << b_mask[src.size]) - 1, + src.size) + off_byte = ((index.zeroExtend(ptr.size) >> m2_expr.ExprInt(3, ptr.size)) & + m2_expr.ExprInt(((1 << src.size) - 1) ^ b_decal[src.size], ptr.size)) + + addr = ptr + off_byte + if segm: + addr = ir.gen_segm_expr(src.ptr.args[0], addr) + + d = ir.ExprMem(addr, src.size) + else: + off_bit = m2_expr.ExprOp( + '&', index, m2_expr.ExprInt(src.size - 1, src.size)) + d = src + return d, off_bit + + +def bt(ir, instr, src, index): + e = [] + index = index.zeroExtend(src.size) + d, off_bit = bittest_get(ir, instr, src, index) + d = d >> off_bit + e.append(m2_expr.ExprAssign(cf, d[:1])) + return e, [] + + +def btc(ir, instr, src, index): + e = [] + d, off_bit = bittest_get(ir, instr, src, index) + e.append(m2_expr.ExprAssign(cf, (d >> off_bit)[:1])) + + m = m2_expr.ExprInt(1, src.size) << off_bit + e.append(m2_expr.ExprAssign(d, d ^ m)) + + return e, [] + + +def bts(ir, instr, src, index): + e = [] + d, off_bit = bittest_get(ir, instr, src, index) + e.append(m2_expr.ExprAssign(cf, (d >> off_bit)[:1])) + m = m2_expr.ExprInt(1, src.size) << off_bit + e.append(m2_expr.ExprAssign(d, d | m)) + + return e, [] + + +def btr(ir, instr, src, index): + e = [] + d, off_bit = bittest_get(ir, instr, src, index) + e.append(m2_expr.ExprAssign(cf, (d >> off_bit)[:1])) + m = ~(m2_expr.ExprInt(1, src.size) << off_bit) + e.append(m2_expr.ExprAssign(d, d & m)) + + return e, [] + + +def into(_, instr): + return [], [] + + +def l_in(_, instr, src1, src2): + e = [] + e.append(m2_expr.ExprAssign(exception_flags, + m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32))) + return e, [] + + +@sbuild.parse +def cmpxchg(arg1, arg2): + accumulator = mRAX[instr.v_opmode()][:arg1.size] + if (accumulator - arg1): + zf = i1(0) + accumulator = arg1 + else: + zf = i1(1) + arg1 = arg2 + + +@sbuild.parse +def cmpxchg8b(arg1): + accumulator = {mRAX[32], mRDX[32]} + if accumulator - arg1: + zf = i1(0) + mRAX[32] = arg1[:32] + mRDX[32] = arg1[32:] + else: + zf = i1(1) + arg1 = {mRBX[32], mRCX[32]} + + +@sbuild.parse +def cmpxchg16b(arg1): + accumulator = {mRAX[64], mRDX[64]} + if accumulator - arg1: + zf = i1(0) + mRAX[64] = arg1[:64] + mRDX[64] = arg1[64:] + else: + zf = i1(1) + arg1 = {mRBX[64], mRCX[64]} + + +def lds(ir, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, ir.ExprMem(src.ptr, size=dst.size))) + DS_value = ir.ExprMem(src.ptr + m2_expr.ExprInt(dst.size // 8, src.ptr.size), + size=16) + e.append(m2_expr.ExprAssign(DS, DS_value)) + return e, [] + + +def les(ir, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, ir.ExprMem(src.ptr, size=dst.size))) + ES_value = ir.ExprMem(src.ptr + m2_expr.ExprInt(dst.size // 8, src.ptr.size), + size=16) + e.append(m2_expr.ExprAssign(ES, ES_value)) + return e, [] + + +def lss(ir, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, ir.ExprMem(src.ptr, size=dst.size))) + SS_value = ir.ExprMem(src.ptr + m2_expr.ExprInt(dst.size // 8, src.ptr.size), + size=16) + e.append(m2_expr.ExprAssign(SS, SS_value)) + return e, [] + + +def lfs(ir, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, ir.ExprMem(src.ptr, size=dst.size))) + FS_value = ir.ExprMem(src.ptr + m2_expr.ExprInt(dst.size // 8, src.ptr.size), + size=16) + e.append(m2_expr.ExprAssign(FS, FS_value)) + return e, [] + + +def lgs(ir, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, ir.ExprMem(src.ptr, size=dst.size))) + GS_value = ir.ExprMem(src.ptr + m2_expr.ExprInt(dst.size // 8, src.ptr.size), + size=16) + e.append(m2_expr.ExprAssign(GS, GS_value)) + return e, [] + + +def lahf(_, instr): + e = [] + args = [cf, m2_expr.ExprInt(1, 1), pf, m2_expr.ExprInt(0, 1), af, + m2_expr.ExprInt(0, 1), zf, nf] + e.append( + m2_expr.ExprAssign(mRAX[instr.mode][8:16], m2_expr.ExprCompose(*args))) + return e, [] + + +def sahf(_, instr): + tmp = mRAX[instr.mode][8:16] + e = [] + e.append(m2_expr.ExprAssign(cf, tmp[0:1])) + e.append(m2_expr.ExprAssign(pf, tmp[2:3])) + e.append(m2_expr.ExprAssign(af, tmp[4:5])) + e.append(m2_expr.ExprAssign(zf, tmp[6:7])) + e.append(m2_expr.ExprAssign(nf, tmp[7:8])) + return e, [] + + +def lar(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('access_segment', src))) + e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp('access_segment_ok', src))) + return e, [] + + +def lsl(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('load_segment_limit', src))) + e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp('load_segment_limit_ok', src))) + return e, [] + + +def fclex(_, instr): + # XXX TODO + return [], [] + + +def fnclex(_, instr): + # XXX TODO + return [], [] + + +def l_str(_, instr, dst): + e = [] + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('load_tr_segment_selector', + m2_expr.ExprInt(0, 32)))) + return e, [] + + +def movd(_, instr, dst, src): + e = [] + if dst in regs_mm_expr: + e.append(m2_expr.ExprAssign( + dst, m2_expr.ExprCompose(src, m2_expr.ExprInt(0, 32)))) + elif dst in regs_xmm_expr: + e.append(m2_expr.ExprAssign( + dst, m2_expr.ExprCompose(src, m2_expr.ExprInt(0, 96)))) + else: + e.append(m2_expr.ExprAssign(dst, src[:32])) + return e, [] + + +def movdqu(_, instr, dst, src): + # XXX TODO alignment check + return [m2_expr.ExprAssign(dst, src)], [] + + +def movapd(_, instr, dst, src): + # XXX TODO alignment check + return [m2_expr.ExprAssign(dst, src)], [] + + +def andps(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('&', dst, src))) + return e, [] + + +def andnps(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('&', dst ^ dst.mask, src))) + return e, [] + + +def orps(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('|', dst, src))) + return e, [] + + +def xorps(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('^', dst, src))) + return e, [] + + +def rdmsr(ir, instr): + e = [m2_expr.ExprAssign(exception_flags,m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32))] + return e, [] + + +def wrmsr(ir, instr): + e = [m2_expr.ExprAssign(exception_flags,m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32))] + return e, [] + +# MMX/SSE/AVX operations +# + +def vec_op_clip(op, size, callback=None): + """ + Generate simd operations + @op: the operator + @size: size of an element + """ + def vec_op_clip_instr(ir, instr, dst, src): + if op == '-': + result = dst[:size] - src[:size] + else: + result = m2_expr.ExprOp(op, dst[:size], src[:size]) + if callback is not None: + result = callback(result) + return [m2_expr.ExprAssign(dst[:size], result)], [] + return vec_op_clip_instr + +# Generic vertical operation + + +def vec_vertical_sem(op, elt_size, reg_size, dst, src, apply_on_output): + assert reg_size % elt_size == 0 + n = reg_size // elt_size + if op == '-': + ops = [ + apply_on_output((dst[i * elt_size:(i + 1) * elt_size] + - src[i * elt_size:(i + 1) * elt_size])) + for i in range(0, n) + ] + else: + ops = [ + apply_on_output(m2_expr.ExprOp(op, dst[i * elt_size:(i + 1) * elt_size], + src[i * elt_size:(i + 1) * elt_size])) + for i in range(0, n) + ] + + return m2_expr.ExprCompose(*ops) + + +def __vec_vertical_instr_gen(op, elt_size, sem, apply_on_output): + def vec_instr(ir, instr, dst, src): + e = [] + if isinstance(src, m2_expr.ExprMem): + src = ir.ExprMem(src.ptr, dst.size) + reg_size = dst.size + e.append(m2_expr.ExprAssign(dst, sem(op, elt_size, reg_size, dst, src, + apply_on_output))) + return e, [] + return vec_instr + + +def vec_vertical_instr(op, elt_size, apply_on_output=lambda x: x): + return __vec_vertical_instr_gen(op, elt_size, vec_vertical_sem, + apply_on_output) + + +def _keep_mul_high(expr, signed=False): + assert expr.is_op("*") and len(expr.args) == 2 + + if signed: + arg1 = expr.args[0].signExtend(expr.size * 2) + arg2 = expr.args[1].signExtend(expr.size * 2) + else: + arg1 = expr.args[0].zeroExtend(expr.size * 2) + arg2 = expr.args[1].zeroExtend(expr.size * 2) + return m2_expr.ExprOp("*", arg1, arg2)[expr.size:] + +# Op, signed => associated comparison +_min_max_func = { + ("min", False): m2_expr.expr_is_unsigned_lower, + ("min", True): m2_expr.expr_is_signed_lower, + ("max", False): m2_expr.expr_is_unsigned_greater, + ("max", True): m2_expr.expr_is_signed_greater, +} +def _min_max(expr, signed): + assert (expr.is_op("min") or expr.is_op("max")) and len(expr.args) == 2 + return m2_expr.ExprCond( + _min_max_func[(expr.op, signed)](expr.args[1], expr.args[0]), + expr.args[1], + expr.args[0], + ) + +def _float_min_max(expr): + assert (expr.is_op("fmin") or expr.is_op("fmax")) and len(expr.args) == 2 + src1 = expr.args[0] + src2 = expr.args[1] + if expr.is_op("fmin"): + comp = m2_expr.expr_is_float_lower(src1, src2) + elif expr.is_op("fmax"): + comp = m2_expr.expr_is_float_lower(src2, src1) + + # x86 documentation (for MIN): + # IF ((SRC1 = 0.0) and (SRC2 = 0.0)) THEN DEST <-SRC2; + # ELSE IF (SRC1 = SNaN) THEN DEST <-SRC2; FI; + # ELSE IF (SRC2 = SNaN) THEN DEST <-SRC2; FI; + # ELSE IF (SRC1 < SRC2) THEN DEST <-SRC1; + # ELSE DEST<-SRC2; + # + # But this includes the NaN output of "SRC1 < SRC2" + # Associated text is more detailed, and this is the version impl here + return m2_expr.ExprCond( + m2_expr.expr_is_sNaN(src2), src2, + m2_expr.ExprCond( + m2_expr.expr_is_NaN(src2) | m2_expr.expr_is_NaN(src1), src2, + m2_expr.ExprCond(comp, src1, src2) + ) + ) + + +# Integer arithmetic +# + +# Additions +# + +# SSE +paddb = vec_vertical_instr('+', 8) +paddw = vec_vertical_instr('+', 16) +paddd = vec_vertical_instr('+', 32) +paddq = vec_vertical_instr('+', 64) + +# Substractions +# + +# SSE +psubb = vec_vertical_instr('-', 8) +psubw = vec_vertical_instr('-', 16) +psubd = vec_vertical_instr('-', 32) +psubq = vec_vertical_instr('-', 64) + +# Multiplications +# + +# SSE +pmullb = vec_vertical_instr('*', 8) +pmullw = vec_vertical_instr('*', 16) +pmulld = vec_vertical_instr('*', 32) +pmullq = vec_vertical_instr('*', 64) +pmulhub = vec_vertical_instr('*', 8, _keep_mul_high) +pmulhuw = vec_vertical_instr('*', 16, _keep_mul_high) +pmulhud = vec_vertical_instr('*', 32, _keep_mul_high) +pmulhuq = vec_vertical_instr('*', 64, _keep_mul_high) +pmulhb = vec_vertical_instr('*', 8, lambda x: _keep_mul_high(x, signed=True)) +pmulhw = vec_vertical_instr('*', 16, lambda x: _keep_mul_high(x, signed=True)) +pmulhd = vec_vertical_instr('*', 32, lambda x: _keep_mul_high(x, signed=True)) +pmulhq = vec_vertical_instr('*', 64, lambda x: _keep_mul_high(x, signed=True)) + +def pmuludq(ir, instr, dst, src): + e = [] + if dst.size == 64: + e.append(m2_expr.ExprAssign( + dst, + src[:32].zeroExtend(64) * dst[:32].zeroExtend(64) + )) + elif dst.size == 128: + e.append(m2_expr.ExprAssign( + dst[:64], + src[:32].zeroExtend(64) * dst[:32].zeroExtend(64) + )) + e.append(m2_expr.ExprAssign( + dst[64:], + src[64:96].zeroExtend(64) * dst[64:96].zeroExtend(64) + )) + else: + raise RuntimeError("Unsupported size %d" % dst.size) + return e, [] + +# Mix +# + +# SSE +def pmaddwd(ir, instr, dst, src): + sizedst = 32 + sizesrc = 16 + out = [] + for start in range(0, dst.size, sizedst): + base = start + mul1 = src[base: base + sizesrc].signExtend(sizedst) * dst[base: base + sizesrc].signExtend(sizedst) + base += sizesrc + mul2 = src[base: base + sizesrc].signExtend(sizedst) * dst[base: base + sizesrc].signExtend(sizedst) + out.append(mul1 + mul2) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] + + +def _absolute(expr): + """Return abs(@expr)""" + signed = expr.msb() + value_unsigned = (expr ^ expr.mask) + m2_expr.ExprInt(1, expr.size) + return m2_expr.ExprCond(signed, value_unsigned, expr) + + +def psadbw(ir, instr, dst, src): + sizedst = 16 + sizesrc = 8 + out_dst = [] + for start in range(0, dst.size, 64): + out = [] + for src_start in range(0, 64, sizesrc): + beg = start + src_start + end = beg + sizesrc + # Not clear in the doc equations, but in the text, src and dst are: + # "8 unsigned byte integers" + out.append(_absolute(dst[beg: end].zeroExtend(sizedst) - src[beg: end].zeroExtend(sizedst))) + out_dst.append(m2_expr.ExprOp("+", *out)) + out_dst.append(m2_expr.ExprInt(0, 64 - sizedst)) + + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out_dst))], [] + +def _average(expr): + assert expr.is_op("avg") and len(expr.args) == 2 + + arg1 = expr.args[0].zeroExtend(expr.size * 2) + arg2 = expr.args[1].zeroExtend(expr.size * 2) + one = m2_expr.ExprInt(1, arg1.size) + # avg(unsigned) = (a + b + 1) >> 1, addition being at least on one more bit + return ((arg1 + arg2 + one) >> one)[:expr.size] + +pavgb = vec_vertical_instr('avg', 8, _average) +pavgw = vec_vertical_instr('avg', 16, _average) + +# Comparisons +# + +# SSE +pminsw = vec_vertical_instr('min', 16, lambda x: _min_max(x, signed=True)) +pminub = vec_vertical_instr('min', 8, lambda x: _min_max(x, signed=False)) +pminuw = vec_vertical_instr('min', 16, lambda x: _min_max(x, signed=False)) +pminud = vec_vertical_instr('min', 32, lambda x: _min_max(x, signed=False)) +pmaxub = vec_vertical_instr('max', 8, lambda x: _min_max(x, signed=False)) +pmaxuw = vec_vertical_instr('max', 16, lambda x: _min_max(x, signed=False)) +pmaxud = vec_vertical_instr('max', 32, lambda x: _min_max(x, signed=False)) +pmaxsw = vec_vertical_instr('max', 16, lambda x: _min_max(x, signed=True)) + +# Floating-point arithmetic +# + +# SSE +addss = vec_op_clip('fadd', 32) +addsd = vec_op_clip('fadd', 64) +addps = vec_vertical_instr('fadd', 32) +addpd = vec_vertical_instr('fadd', 64) +subss = vec_op_clip('fsub', 32) +subsd = vec_op_clip('fsub', 64) +subps = vec_vertical_instr('fsub', 32) +subpd = vec_vertical_instr('fsub', 64) +mulss = vec_op_clip('fmul', 32) +mulsd = vec_op_clip('fmul', 64) +mulps = vec_vertical_instr('fmul', 32) +mulpd = vec_vertical_instr('fmul', 64) +divss = vec_op_clip('fdiv', 32) +divsd = vec_op_clip('fdiv', 64) +divps = vec_vertical_instr('fdiv', 32) +divpd = vec_vertical_instr('fdiv', 64) + +# Comparisons (floating-point) + +minps = vec_vertical_instr('fmin', 32, _float_min_max) +minpd = vec_vertical_instr('fmin', 64, _float_min_max) +minss = vec_op_clip('fmin', 32, _float_min_max) +minsd = vec_op_clip('fmin', 64, _float_min_max) +maxps = vec_vertical_instr('fmax', 32, _float_min_max) +maxpd = vec_vertical_instr('fmax', 64, _float_min_max) +maxss = vec_op_clip('fmax', 32, _float_min_max) +maxsd = vec_op_clip('fmax', 64, _float_min_max) + +def _float_compare_to_mask(expr): + if expr.op == 'unord': + to_ext = m2_expr.expr_is_NaN(expr.args[0]) | m2_expr.expr_is_NaN(expr.args[1]) + elif expr.op == 'ord': + to_ext = ~m2_expr.expr_is_NaN(expr.args[0]) & ~m2_expr.expr_is_NaN(expr.args[1]) + else: + if expr.op == '==fu': + to_ext = m2_expr.expr_is_float_equal(expr.args[0], expr.args[1]) + on_NaN = m2_expr.ExprInt(0, 1) + elif expr.op == '<fu': + to_ext = m2_expr.expr_is_float_lower(expr.args[0], expr.args[1]) + on_NaN = m2_expr.ExprInt(0, 1) + elif expr.op == '<=fu': + to_ext = (m2_expr.expr_is_float_equal(expr.args[0], expr.args[1]) | + m2_expr.expr_is_float_lower(expr.args[0], expr.args[1])) + on_NaN = m2_expr.ExprInt(0, 1) + elif expr.op == '!=fu': + to_ext = ~m2_expr.expr_is_float_equal(expr.args[0], expr.args[1]) + on_NaN = m2_expr.ExprInt(1, 1) + elif expr.op == '!<fu': + to_ext = ~m2_expr.expr_is_float_lower(expr.args[0], expr.args[1]) + on_NaN = m2_expr.ExprInt(1, 1) + elif expr.op == '!<=fu': + to_ext = ~(m2_expr.expr_is_float_equal(expr.args[0], expr.args[1]) | + m2_expr.expr_is_float_lower(expr.args[0], expr.args[1])) + on_NaN = m2_expr.ExprInt(1, 1) + + to_ext = m2_expr.ExprCond( + m2_expr.expr_is_NaN(expr.args[0]) | m2_expr.expr_is_NaN(expr.args[1]), + on_NaN, + to_ext + ) + return to_ext.signExtend(expr.size) + +cmpeqps = vec_vertical_instr('==fu', 32, lambda x: _float_compare_to_mask(x)) +cmpeqpd = vec_vertical_instr('==fu', 64, lambda x: _float_compare_to_mask(x)) +cmpeqss = vec_op_clip('==fu', 32, lambda x: _float_compare_to_mask(x)) +cmpeqsd = vec_op_clip('==fu', 64, lambda x: _float_compare_to_mask(x)) +cmpltps = vec_vertical_instr('<fu', 32, lambda x: _float_compare_to_mask(x)) +cmpltpd = vec_vertical_instr('<fu', 64, lambda x: _float_compare_to_mask(x)) +cmpltss = vec_op_clip('<fu', 32, lambda x: _float_compare_to_mask(x)) +cmpltsd = vec_op_clip('<fu', 64, lambda x: _float_compare_to_mask(x)) +cmpleps = vec_vertical_instr('<=fu', 32, lambda x: _float_compare_to_mask(x)) +cmplepd = vec_vertical_instr('<=fu', 64, lambda x: _float_compare_to_mask(x)) +cmpless = vec_op_clip('<=fu', 32, lambda x: _float_compare_to_mask(x)) +cmplesd = vec_op_clip('<=fu', 64, lambda x: _float_compare_to_mask(x)) +cmpunordps = vec_vertical_instr('unord', 32, lambda x: _float_compare_to_mask(x)) +cmpunordpd = vec_vertical_instr('unord', 64, lambda x: _float_compare_to_mask(x)) +cmpunordss = vec_op_clip('unord', 32, lambda x: _float_compare_to_mask(x)) +cmpunordsd = vec_op_clip('unord', 64, lambda x: _float_compare_to_mask(x)) +cmpneqps = vec_vertical_instr('!=fu', 32, lambda x: _float_compare_to_mask(x)) +cmpneqpd = vec_vertical_instr('!=fu', 64, lambda x: _float_compare_to_mask(x)) +cmpneqss = vec_op_clip('!=fu', 32, lambda x: _float_compare_to_mask(x)) +cmpneqsd = vec_op_clip('!=fu', 64, lambda x: _float_compare_to_mask(x)) +cmpnltps = vec_vertical_instr('!<fu', 32, lambda x: _float_compare_to_mask(x)) +cmpnltpd = vec_vertical_instr('!<fu', 64, lambda x: _float_compare_to_mask(x)) +cmpnltss = vec_op_clip('!<fu', 32, lambda x: _float_compare_to_mask(x)) +cmpnltsd = vec_op_clip('!<fu', 64, lambda x: _float_compare_to_mask(x)) +cmpnleps = vec_vertical_instr('!<=fu', 32, lambda x: _float_compare_to_mask(x)) +cmpnlepd = vec_vertical_instr('!<=fu', 64, lambda x: _float_compare_to_mask(x)) +cmpnless = vec_op_clip('!<=fu', 32, lambda x: _float_compare_to_mask(x)) +cmpnlesd = vec_op_clip('!<=fu', 64, lambda x: _float_compare_to_mask(x)) +cmpordps = vec_vertical_instr('ord', 32, lambda x: _float_compare_to_mask(x)) +cmpordpd = vec_vertical_instr('ord', 64, lambda x: _float_compare_to_mask(x)) +cmpordss = vec_op_clip('ord', 32, lambda x: _float_compare_to_mask(x)) +cmpordsd = vec_op_clip('ord', 64, lambda x: _float_compare_to_mask(x)) + +# Logical (floating-point) +# + +# MMX/SSE/AVX + + +def pand(_, instr, dst, src): + e = [] + result = dst & src + # No flag assigned + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + + +def pandn(_, instr, dst, src): + e = [] + result = (dst ^ dst.mask) & src + # No flag assigned + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + + +def por(_, instr, dst, src): + e = [] + result = dst | src + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + + +def cvtdq2pd(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign( + dst[:64], + m2_expr.ExprOp( + 'sint_to_fp', + src[:32].signExtend(64) + ) + ) + ) + e.append( + m2_expr.ExprAssign( + dst[64:128], + m2_expr.ExprOp( + 'sint_to_fp', + src[32:64].signExtend(64) + ) + ) + ) + return e, [] + + +def cvtdq2ps(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('sint_to_fp', src[:32]))) + e.append( + m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('sint_to_fp', src[32:64]))) + e.append( + m2_expr.ExprAssign(dst[64:96], m2_expr.ExprOp('sint_to_fp', src[64:96]))) + e.append( + m2_expr.ExprAssign(dst[96:128], m2_expr.ExprOp('sint_to_fp', src[96:128]))) + return e, [] + + +def cvtpd2dq(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:64]))) + e.append( + m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('fp_to_sint32', src[64:128]))) + e.append(m2_expr.ExprAssign(dst[64:128], m2_expr.ExprInt(0, 64))) + return e, [] + + +def cvtpd2pi(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:64]))) + e.append( + m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('fp_to_sint32', src[64:128]))) + return e, [] + + +def cvtpd2ps(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fpconvert_fp32', src[:64]))) + e.append( + m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('fpconvert_fp32', src[64:128]))) + e.append(m2_expr.ExprAssign(dst[64:128], m2_expr.ExprInt(0, 64))) + return e, [] + + +def cvtpi2pd(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign( + dst[:64], + m2_expr.ExprOp( + 'sint_to_fp', + src[:32].signExtend(64) + ) + ) + ) + e.append( + m2_expr.ExprAssign( + dst[64:128], + m2_expr.ExprOp( + 'sint_to_fp', + src[32:64].signExtend(64)) + ) + ) + return e, [] + + +def cvtpi2ps(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('sint_to_fp', src[:32]))) + e.append( + m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('sint_to_fp', src[32:64]))) + return e, [] + + +def cvtps2dq(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:32]))) + e.append( + m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('fp_to_sint32', src[32:64]))) + e.append( + m2_expr.ExprAssign(dst[64:96], m2_expr.ExprOp('fp_to_sint32', src[64:96]))) + e.append( + m2_expr.ExprAssign(dst[96:128], m2_expr.ExprOp('fp_to_sint32', src[96:128]))) + return e, [] + + +def cvtps2pd(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:64], m2_expr.ExprOp('fpconvert_fp64', src[:32]))) + e.append( + m2_expr.ExprAssign(dst[64:128], m2_expr.ExprOp('fpconvert_fp64', src[32:64]))) + return e, [] + + +def cvtps2pi(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:32]))) + e.append( + m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('fp_to_sint32', src[32:64]))) + return e, [] + + +def cvtsd2si(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:64]))) + return e, [] + + +def cvtsd2ss(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fpconvert_fp32', src[:64]))) + return e, [] + + +def cvtsi2sd(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign( + dst[:64], + m2_expr.ExprOp( + 'sint_to_fp', + src[:32].signExtend(64) + ) + ) + ) + return e, [] + + +def cvtsi2ss(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('sint_to_fp', src[:32]))) + return e, [] + + +def cvtss2sd(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:64], m2_expr.ExprOp('fpconvert_fp64', src[:32]))) + return e, [] + + +def cvtss2si(_, instr, dst, src): + e = [] + e.append( + m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:32]))) + return e, [] + + +def _cvtt_tpl(dst, src, numbers, double): + e = [] + for i in numbers: + # For CVTT*D2* (Convert with Truncation ... Double-Precision) to work, + # a first conversion fp64 -> fp32 is needed + if double: + tmp_src = m2_expr.ExprOp('fpconvert_fp32', src[i*64:i*64 + 64]) + else: + tmp_src = src[i*32:i*32 + 32] + + e.append(m2_expr.ExprAssign( + dst[i*32:i*32 + 32], + m2_expr.ExprOp('fp_to_sint32', m2_expr.ExprOp( + 'fpround_towardszero', + tmp_src + )))) + return e + +def cvttpd2pi(_, instr, dst, src): + return _cvtt_tpl(dst, src, [0, 1], double=True), [] + +def cvttpd2dq(_, instr, dst, src): + e = _cvtt_tpl(dst, src, [0, 1], double=True) + e.append(m2_expr.ExprAssign(dst[64:128], m2_expr.ExprInt(0, 64))) + return e, [] + +def cvttsd2si(_, instr, dst, src): + return _cvtt_tpl(dst, src, [0], double=True), [] + +def cvttps2dq(_, instr, dst, src): + return _cvtt_tpl(dst, src, [0, 1, 2, 3], double=False), [] + +def cvttps2pi(_, instr, dst, src): + return _cvtt_tpl(dst, src, [0, 1], double=False), [] + +def cvttss2si(_, instr, dst, src): + return _cvtt_tpl(dst, src, [0], double=False), [] + +def movss(_, instr, dst, src): + e = [] + if not isinstance(dst, m2_expr.ExprMem) and not isinstance(src, m2_expr.ExprMem): + # Source and Destination xmm + e.append(m2_expr.ExprAssign(dst[:32], src[:32])) + elif not isinstance(src, m2_expr.ExprMem) and isinstance(dst, m2_expr.ExprMem): + # Source XMM Destination Mem + e.append(m2_expr.ExprAssign(dst, src[:32])) + else: + # Source Mem Destination XMM + e.append(m2_expr.ExprAssign( + dst, m2_expr.ExprCompose(src, m2_expr.ExprInt(0, 96)))) + return e, [] + + +def ucomiss(_, instr, src1, src2): + e = [] + e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp( + 'ucomiss_zf', src1[:32], src2[:32]))) + e.append(m2_expr.ExprAssign(pf, m2_expr.ExprOp( + 'ucomiss_pf', src1[:32], src2[:32]))) + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprOp( + 'ucomiss_cf', src1[:32], src2[:32]))) + + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, 1))) + e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1))) + e.append(m2_expr.ExprAssign(nf, m2_expr.ExprInt(0, 1))) + + return e, [] + +def ucomisd(_, instr, src1, src2): + e = [] + e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp( + 'ucomisd_zf', src1[:64], src2[:64]))) + e.append(m2_expr.ExprAssign(pf, m2_expr.ExprOp( + 'ucomisd_pf', src1[:64], src2[:64]))) + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprOp( + 'ucomisd_cf', src1[:64], src2[:64]))) + + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, 1))) + e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1))) + e.append(m2_expr.ExprAssign(nf, m2_expr.ExprInt(0, 1))) + + return e, [] + +def blsi(_, instr, dst, src): + e = [] + + arg1 = m2_expr.ExprInt(0, src.size) + neg_src = arg1 - src + result = neg_src & src + + e += update_flag_zf(result) + e += update_flag_nf(result) + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size))) + + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(src, + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)))) + + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + +def andn(_, instr, dst, src1, src2): + e = [] + + arg1 = m2_expr.ExprInt(0, src1.size) + neg_src1 = arg1 - src1 + result = neg_src1 & src2 + + e += update_flag_zf(result) + e += update_flag_nf(result) + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size))) + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprInt(0, cf.size))) + + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + +def bextr(_, instr, dst, src1, src2): + e = [] + + # TODO: change zero extension to 512 bits when AVX is supported + start = (src2 & m2_expr.ExprInt(0xFF, src2.size)).zeroExtend(256) + length = ((src2 & m2_expr.ExprInt(0xFF00, src2.size)) >> m2_expr.ExprInt(8, src2.size)).zeroExtend(256) + + tmp = src1.zeroExtend(256) >> start + mask = m2_expr.ExprInt(0, 256).mask >> (m2_expr.ExprInt(256, 256) - length) + + tmp = tmp & mask + result = tmp[:dst.size] + + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + +def blsmsk(_, instr, dst, src): + e = [] + + tmp = src - m2_expr.ExprInt(1, src.size) + result = src ^ tmp + + e += update_flag_nf(result) + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size))) + e.append(m2_expr.ExprAssign(zf, m2_expr.ExprInt(0, zf.size))) + + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(src, + m2_expr.ExprInt(0, 1), + m2_expr.ExprInt(1, 1)))) + + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + +def blsr(_, instr, dst, src): + e = [] + + tmp = src - m2_expr.ExprInt(1, src.size) + result = tmp & src + + e += update_flag_zf(result) + e += update_flag_nf(result) + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size))) + + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(src, + m2_expr.ExprInt(0, 1), + m2_expr.ExprInt(1, 1)))) + + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + +def tzcnt(ir, instr, dst, src): + e = [] + + operand_size = m2_expr.ExprInt(dst.size, dst.size) + + result = m2_expr.ExprCond(src, m2_expr.ExprOp("cnttrailzeros", src), operand_size) + + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(m2_expr.ExprOp("FLAG_EQ_CMP", result, operand_size), + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)))) + + e += update_flag_zf(result) + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + +def bzhi(_, instr, dst, src1, src2): + e = [] + + operand_size = m2_expr.ExprInt(dst.size, dst.size) + index = src2[:7].zeroExtend(dst.size) + mask = m2_expr.ExprInt(0, dst.size).mask >> (operand_size + - index + - m2_expr.ExprInt(1, dst.size)) + + result = m2_expr.ExprCond(m2_expr.ExprOp("FLAG_SIGN_SUB", index, operand_size), + src1 & mask, src1) + + + operand_size_dec = operand_size - m2_expr.ExprInt(1, dst.size) + e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(m2_expr.ExprOp("FLAG_SIGN_SUB", operand_size_dec, index), + m2_expr.ExprInt(1, 1), + m2_expr.ExprInt(0, 1)))) + + e += update_flag_zf(result) + e += update_flag_nf(result) + e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size))) + e.append(m2_expr.ExprAssign(dst, result)) + return e, [] + +def pshufb(_, instr, dst, src): + e = [] + if dst.size == 64: + bit_l = 3 + elif dst.size == 128: + bit_l = 4 + else: + raise NotImplementedError("bad size") + for i in range(0, src.size, 8): + index = src[ + i:i + bit_l].zeroExtend(dst.size) << m2_expr.ExprInt(3, dst.size) + value = (dst >> index)[:8] + e.append(m2_expr.ExprAssign(dst[i:i + 8], + m2_expr.ExprCond(src[i + 7:i + 8], + m2_expr.ExprInt(0, 8), + value))) + return e, [] + + +def pshufd(_, instr, dst, src, imm): + control = int(imm) + out = [] + for i in range(4): + shift = ((control >> (i * 2)) & 3) * 32 + # shift is 2 bits long, expr.size is 128 + # => shift + 32 <= src.size + out.append(src[shift: shift + 32]) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] + + +def pshuflw(_, instr, dst, src, imm): + control = int(imm) + out = [] + for i in range(4): + shift = ((control >> (i * 2)) & 3) * 16 + out.append(src[shift: shift + 16]) + out.append(src[64:]) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] + + +def pshufhw(_, instr, dst, src, imm): + control = int(imm) + out = [src[:64]] + for i in range(4): + shift = ((control >> (i * 2)) & 3) * 16 + out.append(src[shift + 64: shift + 16 + 64]) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] + + +def ps_rl_ll(ir, instr, dst, src, op, size): + mask = {16: 0xF, + 32: 0x1F, + 64: 0x3F}[size] + mask = m2_expr.ExprInt(mask, dst.size) + + # Saturate the counter to 2**size + count = src.zeroExtend(dst.size) + count = m2_expr.ExprCond(count & expr_simp(~mask), + m2_expr.ExprInt(size, dst.size), # saturation + count, # count < 2**size + ) + count = count[:size] + if src.is_int(): + count = expr_simp(count) + + out = [] + for i in range(0, dst.size, size): + out.append(m2_expr.ExprOp(op, dst[i:i + size], count)) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] + + +def psrlw(ir, instr, dst, src): + return ps_rl_ll(ir, instr, dst, src, ">>", 16) + + +def psrld(ir, instr, dst, src): + return ps_rl_ll(ir, instr, dst, src, ">>", 32) + + +def psrlq(ir, instr, dst, src): + return ps_rl_ll(ir, instr, dst, src, ">>", 64) + + +def psllw(ir, instr, dst, src): + return ps_rl_ll(ir, instr, dst, src, "<<", 16) + + +def pslld(ir, instr, dst, src): + return ps_rl_ll(ir, instr, dst, src, "<<", 32) + + +def psllq(ir, instr, dst, src): + return ps_rl_ll(ir, instr, dst, src, "<<", 64) + + +def psraw(ir, instr, dst, src): + return ps_rl_ll(ir, instr, dst, src, "a>>", 16) + + +def psrad(ir, instr, dst, src): + return ps_rl_ll(ir, instr, dst, src, "a>>", 32) + + +def pslldq(_, instr, dst, src): + assert src.is_int() + e = [] + count = int(src) + if count > 15: + return [m2_expr.ExprAssign(dst, m2_expr.ExprInt(0, dst.size))], [] + else: + return [m2_expr.ExprAssign(dst, dst << m2_expr.ExprInt(8 * count, dst.size))], [] + + +def psrldq(_, instr, dst, src): + assert src.is_int() + count = int(src) + if count > 15: + return [m2_expr.ExprAssign(dst, m2_expr.ExprInt(0, dst.size))], [] + else: + return [m2_expr.ExprAssign(dst, dst >> m2_expr.ExprInt(8 * count, dst.size))], [] + + +def iret(ir, instr): + """IRET implementation + XXX: only support "no-privilege change" + """ + size = instr.v_opmode() + exprs, _ = retf(ir, instr, m2_expr.ExprInt(size // 8, size=size)) + tmp = mRSP[instr.mode][:size] + m2_expr.ExprInt((2 * size) // 8, size=size) + exprs += _tpl_eflags(tmp) + return exprs, [] + + +def pcmpeq(_, instr, dst, src, size): + e = [] + for i in range(0, dst.size, size): + test = m2_expr.expr_is_equal(dst[i:i + size], src[i:i + size]) + e.append(m2_expr.ExprAssign(dst[i:i + size], + m2_expr.ExprCond(test, + m2_expr.ExprInt(-1, size), + m2_expr.ExprInt(0, size)))) + return e, [] + + +def pcmpgt(_, instr, dst, src, size): + e = [] + for i in range(0, dst.size, size): + test = m2_expr.expr_is_signed_greater(dst[i:i + size], src[i:i + size]) + e.append(m2_expr.ExprAssign(dst[i:i + size], + m2_expr.ExprCond(test, + m2_expr.ExprInt(-1, size), + m2_expr.ExprInt(0, size)))) + return e, [] + + +def pcmpeqb(ir, instr, dst, src): + return pcmpeq(ir, instr, dst, src, 8) + +def pcmpeqw(ir, instr, dst, src): + return pcmpeq(ir, instr, dst, src, 16) + +def pcmpeqd(ir, instr, dst, src): + return pcmpeq(ir, instr, dst, src, 32) + +def pcmpeqq(ir, instr, dst, src): + return pcmpeq(ir, instr, dst, src, 64) + + + + +def pcmpgtb(ir, instr, dst, src): + return pcmpgt(ir, instr, dst, src, 8) + +def pcmpgtw(ir, instr, dst, src): + return pcmpgt(ir, instr, dst, src, 16) + +def pcmpgtd(ir, instr, dst, src): + return pcmpgt(ir, instr, dst, src, 32) + +def pcmpgtq(ir, instr, dst, src): + return pcmpgt(ir, instr, dst, src, 64) + + + +def punpck(_, instr, dst, src, size, off): + e = [] + slices = [] + for i in range(dst.size // (2 * size)): + slices.append(dst[size * i + off: size * i + off + size]) + slices.append(src[size * i + off: size * i + off + size]) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*slices))) + return e, [] + + +def punpckhbw(ir, instr, dst, src): + return punpck(ir, instr, dst, src, 8, dst.size // 2) + + +def punpckhwd(ir, instr, dst, src): + return punpck(ir, instr, dst, src, 16, dst.size // 2) + + +def punpckhdq(ir, instr, dst, src): + return punpck(ir, instr, dst, src, 32, dst.size // 2) + + +def punpckhqdq(ir, instr, dst, src): + return punpck(ir, instr, dst, src, 64, dst.size // 2) + + +def punpcklbw(ir, instr, dst, src): + return punpck(ir, instr, dst, src, 8, 0) + + +def punpcklwd(ir, instr, dst, src): + return punpck(ir, instr, dst, src, 16, 0) + + +def punpckldq(ir, instr, dst, src): + return punpck(ir, instr, dst, src, 32, 0) + + +def punpcklqdq(ir, instr, dst, src): + return punpck(ir, instr, dst, src, 64, 0) + + +def pinsr(_, instr, dst, src, imm, size): + e = [] + + mask = {8: 0xF, + 16: 0x7, + 32: 0x3, + 64: 0x1}[size] + + sel = (int(imm) & mask) * size + e.append(m2_expr.ExprAssign(dst[sel:sel + size], src[:size])) + + return e, [] + + +def pinsrb(ir, instr, dst, src, imm): + return pinsr(ir, instr, dst, src, imm, 8) + + +def pinsrw(ir, instr, dst, src, imm): + return pinsr(ir, instr, dst, src, imm, 16) + + +def pinsrd(ir, instr, dst, src, imm): + return pinsr(ir, instr, dst, src, imm, 32) + + +def pinsrq(ir, instr, dst, src, imm): + return pinsr(ir, instr, dst, src, imm, 64) + + +def pextr(_, instr, dst, src, imm, size): + e = [] + + mask = {8: 0xF, + 16: 0x7, + 32: 0x3, + 64: 0x1}[size] + + sel = (int(imm) & mask) * size + e.append(m2_expr.ExprAssign(dst, src[sel:sel + size].zeroExtend(dst.size))) + + return e, [] + + +def pextrb(ir, instr, dst, src, imm): + return pextr(ir, instr, dst, src, imm, 8) + + +def pextrw(ir, instr, dst, src, imm): + return pextr(ir, instr, dst, src, imm, 16) + + +def pextrd(ir, instr, dst, src, imm): + return pextr(ir, instr, dst, src, imm, 32) + + +def pextrq(ir, instr, dst, src, imm): + return pextr(ir, instr, dst, src, imm, 64) + + +def unpckhps(_, instr, dst, src): + e = [] + src = m2_expr.ExprCompose(dst[64:96], src[64:96], dst[96:128], src[96:128]) + e.append(m2_expr.ExprAssign(dst, src)) + return e, [] + + +def unpckhpd(_, instr, dst, src): + e = [] + src = m2_expr.ExprCompose(dst[64:128], src[64:128]) + e.append(m2_expr.ExprAssign(dst, src)) + return e, [] + + +def unpcklps(_, instr, dst, src): + e = [] + src = m2_expr.ExprCompose(dst[0:32], src[0:32], dst[32:64], src[32:64]) + e.append(m2_expr.ExprAssign(dst, src)) + return e, [] + + +def unpcklpd(_, instr, dst, src): + e = [] + src = m2_expr.ExprCompose(dst[0:64], src[0:64]) + e.append(m2_expr.ExprAssign(dst, src)) + return e, [] + + +def movlpd(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst[:64], src[:64])) + return e, [] + + +def movlps(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst[:64], src[:64])) + return e, [] + + +def movhpd(_, instr, dst, src): + e = [] + if src.size == 64: + e.append(m2_expr.ExprAssign(dst[64:128], src)) + elif dst.size == 64: + e.append(m2_expr.ExprAssign(dst, src[64:128])) + else: + raise RuntimeError("bad encoding!") + return e, [] + + +def movlhps(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst[64:128], src[:64])) + return e, [] + + +def movhlps(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst[:64], src[64:128])) + return e, [] + + +def movdq2q(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, src[:64])) + return e, [] + + +def movq2dq(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst, src[:64].zeroExtend(dst.size))) + return e, [] + + +def sqrt_gen(_, instr, dst, src, size): + e = [] + out = [] + for i in range(src.size // size): + out.append(m2_expr.ExprOp('fsqrt', + src[i * size: (i + 1) * size])) + src = m2_expr.ExprCompose(*out) + e.append(m2_expr.ExprAssign(dst, src)) + return e, [] + + +def sqrtpd(ir, instr, dst, src): + return sqrt_gen(ir, instr, dst, src, 64) + + +def sqrtps(ir, instr, dst, src): + return sqrt_gen(ir, instr, dst, src, 32) + + +def sqrtsd(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst[:64], + m2_expr.ExprOp('fsqrt', + src[:64]))) + return e, [] + + +def sqrtss(_, instr, dst, src): + e = [] + e.append(m2_expr.ExprAssign(dst[:32], + m2_expr.ExprOp('fsqrt', + src[:32]))) + return e, [] + + +def pmovmskb(_, instr, dst, src): + e = [] + out = [] + for i in range(src.size // 8): + out.append(src[8 * i + 7:8 * (i + 1)]) + src = m2_expr.ExprCompose(*out) + e.append(m2_expr.ExprAssign(dst, src.zeroExtend(dst.size))) + return e, [] + + +def smsw(ir, instr, dst): + e = [] + LOG_X86_SEM.warning("DEFAULT SMSW %s!!", str(dst)) + e.append(m2_expr.ExprAssign(dst, m2_expr.ExprInt(0x80050033, 32)[:dst.size])) + return e, [] + + +def bndmov(ir, instr, dst, src): + # Implemented as a NOP, because BND side effects are not yet supported + return [], [] + +def palignr(ir, instr, dst, src, imm): + # dst.src >> imm * 8 [:dst.size] + + shift = int(imm) * 8 + if shift == 0: + result = src + elif shift == src.size: + result = dst + elif shift > src.size: + result = dst >> m2_expr.ExprInt(shift - src.size, dst.size) + else: + # shift < src.size + result = m2_expr.ExprCompose( + src[shift:], + dst[:shift], + ) + + return [m2_expr.ExprAssign(dst, result)], [] + + +def _signed_to_signed_saturation(expr, dst_size): + """Saturate the expr @expr for @dst_size bit + Signed saturation return MAX_INT / MIN_INT or value depending on the value + """ + assert expr.size > dst_size + + median = 1 << (dst_size - 1) + + min_int = m2_expr.ExprInt(- median, dst_size) + max_int = m2_expr.ExprInt(median - 1, dst_size) + + test_min_int = min_int.signExtend(expr.size) + test_max_int = max_int.signExtend(expr.size) + + value = expr[:dst_size] + + return m2_expr.ExprCond( + m2_expr.ExprOp( + m2_expr.TOK_INF_EQUAL_SIGNED, + expr, + test_min_int + ), + min_int, + m2_expr.ExprCond( + m2_expr.ExprOp( + m2_expr.TOK_INF_SIGNED, + expr, + test_max_int + ), + value, + max_int + ) + ) + + +def _signed_to_unsigned_saturation(expr, dst_size): + """Saturate the expr @expr for @dst_size bit + Unsigned saturation return MAX_INT or value depending on the value + """ + assert expr.size > dst_size + + zero = m2_expr.ExprInt(0, dst_size) + test_zero = m2_expr.ExprInt(0, expr.size) + + max_int = m2_expr.ExprInt(-1, dst_size) + test_max_int = max_int.zeroExtend(expr.size) + + value = expr[:dst_size] + + return m2_expr.ExprCond( + m2_expr.ExprOp( + m2_expr.TOK_INF_EQUAL_SIGNED, + expr, + test_zero + ), + zero, + m2_expr.ExprCond( + m2_expr.ExprOp( + m2_expr.TOK_INF_SIGNED, + expr, + test_max_int + ), + value, + max_int + ) + ) + + + +def packsswb(ir, instr, dst, src): + out = [] + for source in [dst, src]: + for start in range(0, dst.size, 16): + out.append(_signed_to_signed_saturation(source[start:start + 16], 8)) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] + + +def packssdw(ir, instr, dst, src): + out = [] + for source in [dst, src]: + for start in range(0, dst.size, 32): + out.append(_signed_to_signed_saturation(source[start:start + 32], 16)) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] + + +def packuswb(ir, instr, dst, src): + out = [] + for source in [dst, src]: + for start in range(0, dst.size, 16): + out.append(_signed_to_unsigned_saturation(source[start:start + 16], 8)) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] + + +def _saturation_sub_unsigned(expr): + assert expr.is_op("+") and len(expr.args) == 2 and expr.args[-1].is_op("-") + + # Compute the soustraction on one more bit to be able to distinguish cases: + # 0x48 - 0xd7 in 8 bit, should saturate + arg1 = expr.args[0].zeroExtend(expr.size + 1) + arg2 = expr.args[1].args[0].zeroExtend(expr.size + 1) + return _signed_to_unsigned_saturation(arg1 - arg2, expr.size) + +def _saturation_sub_signed(expr): + assert expr.is_op("+") and len(expr.args) == 2 and expr.args[-1].is_op("-") + + # Compute the subtraction on two more bits, see _saturation_sub_unsigned + arg1 = expr.args[0].signExtend(expr.size + 2) + arg2 = expr.args[1].args[0].signExtend(expr.size + 2) + return _signed_to_signed_saturation(arg1 - arg2, expr.size) + +def _saturation_add(expr): + assert expr.is_op("+") and len(expr.args) == 2 + + # Compute the addition on one more bit to be able to distinguish cases: + # 0x48 + 0xd7 in 8 bit, should saturate + + arg1 = expr.args[0].zeroExtend(expr.size + 1) + arg2 = expr.args[1].zeroExtend(expr.size + 1) + + # We can also use _signed_to_unsigned_saturation with two additional bits (to + # distinguish minus and overflow case) + # The resulting expression being more complicated with an impossible case + # (signed=True), we rewrite the rule here + + return m2_expr.ExprCond((arg1 + arg2).msb(), m2_expr.ExprInt(-1, expr.size), + expr) + +def _saturation_add_signed(expr): + assert expr.is_op("+") and len(expr.args) == 2 + + # Compute the subtraction on two more bits, see _saturation_add_unsigned + + arg1 = expr.args[0].signExtend(expr.size + 2) + arg2 = expr.args[1].signExtend(expr.size + 2) + + return _signed_to_signed_saturation(arg1 + arg2, expr.size) + + +# Saturate SSE operations + +psubusb = vec_vertical_instr('-', 8, _saturation_sub_unsigned) +psubusw = vec_vertical_instr('-', 16, _saturation_sub_unsigned) +paddusb = vec_vertical_instr('+', 8, _saturation_add) +paddusw = vec_vertical_instr('+', 16, _saturation_add) +psubsb = vec_vertical_instr('-', 8, _saturation_sub_signed) +psubsw = vec_vertical_instr('-', 16, _saturation_sub_signed) +paddsb = vec_vertical_instr('+', 8, _saturation_add_signed) +paddsw = vec_vertical_instr('+', 16, _saturation_add_signed) + + +# Others SSE operations + +def maskmovq(ir, instr, src, mask): + loc_next = ir.get_next_loc_key(instr) + loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size) + blks = [] + + # For each possibility, check if a write is necessary + check_labels = [m2_expr.ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) + for _ in range(0, mask.size, 8)] + # If the write has to be done, do it (otherwise, nothing happen) + write_labels = [m2_expr.ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) + for _ in range(0, mask.size, 8)] + + # Build check blocks + for i, start in enumerate(range(0, mask.size, 8)): + bit = mask[start + 7: start + 8] + cur_label = check_labels[i] + next_check_label = check_labels[i + 1] if (i + 1) < len(check_labels) else loc_next_expr + write_label = write_labels[i] + check = m2_expr.ExprAssign(ir.IRDst, + m2_expr.ExprCond(bit, + write_label, + next_check_label)) + blks.append(IRBlock(ir.loc_db, cur_label.loc_key, [AssignBlock([check], instr)])) + + # Build write blocks + dst_addr = mRDI[instr.mode] + for i, start in enumerate(range(0, mask.size, 8)): + cur_label = write_labels[i] + next_check_label = check_labels[i + 1] if (i + 1) < len(check_labels) else loc_next_expr + write_addr = dst_addr + m2_expr.ExprInt(i, dst_addr.size) + + # @8[DI/EDI/RDI + i] = src[byte i] + write_mem = m2_expr.ExprAssign(m2_expr.ExprMem(write_addr, 8), + src[start: start + 8]) + jump = m2_expr.ExprAssign(ir.IRDst, next_check_label) + blks.append(IRBlock(ir.loc_db, cur_label.loc_key, [AssignBlock([write_mem, jump], instr)])) + + # If mask is null, bypass all + e = [m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(mask, + check_labels[0], + loc_next_expr))] + return e, blks + + +def emms(ir, instr): + # Implemented as a NOP + return [], [] + +def incssp(ir, instr, dst): + # Implemented as a NOP + return [], [] + +def rdssp(ir, instr, dst): + # Implemented as a NOP + return [], [] + +def saveprevssp(ir, instr): + # Implemented as a NOP + return [], [] + +def rstorssp(ir, instr, dst): + # Implemented as a NOP + return [], [] + +def wrss(ir, instr, src, dst): + # Implemented as a NOP + return [], [] + +def wruss(ir, instr, src, dst): + # Implemented as a NOP + return [], [] + +def setssbsy(ir, instr): + # Implemented as a NOP + return [], [] + +def clrssbsy(ir, instr, dst): + # Implemented as a NOP + return [], [] + +def endbr64(ir, instr): + # Implemented as a NOP + return [], [] + +def endbr32(ir, instr): + # Implemented as a NOP + return [], [] + +# Common value without too many option, 0x1fa0 +STMXCSR_VALUE = 0x1fa0 +def stmxcsr(ir, instr, dst): + return [m2_expr.ExprAssign(dst, m2_expr.ExprInt(STMXCSR_VALUE, dst.size))], [] + +def ldmxcsr(ir, instr, dst): + # Implemented as a NOP + return [], [] + + +def _select4(src, control): + # Implementation inspired from Intel Intrinsics Guide + # @control is already resolved (was an immediate) + + if control == 0: + return src[:32] # 0 + elif control == 1: + return src[32:64] + elif control == 2: + return src[64:96] + elif control == 3: + return src[96:] + else: + raise ValueError("Control must be on 2 bits") + + +def shufps(ir, instr, dst, src, imm8): + out = [] + control = int(imm8) + for i in range(4): + if i < 2: + source = dst + else: + source = src + out.append(_select4(source, (control >> (i * 2)) & 3)) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] + + +def shufpd(ir, instr, dst, src, imm8): + out = [] + control = int(imm8) + out.append(dst[64:] if control & 1 else dst[:64]) + out.append(src[64:] if control & 2 else src[:64]) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] + +def movmskps(ir, instr, dst, src): + out = [] + for i in range(4): + out.append(src[(32 * i) + 31:(32 * i) + 32]) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out).zeroExtend(dst.size))], [] + +def movmskpd(ir, instr, dst, src): + out = [] + for i in range(2): + out.append(src[(64 * i) + 63:(64 * i) + 64]) + return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out).zeroExtend(dst.size))], [] + +def _roundscalar(ir, inst, dst, src, imm8, double): + res = None + ctl = int(imm8) + dst_expr = dst[:64] if double else dst[:32] + src_expr = src[:64] if double else src[:32] + if ctl & 0x4 != 0: + # Use MXCSR rounding config + # TODO: here we assume it's round to nearest, ties to even + res = m2_expr.ExprOp('fpround_towardsnearest', src_expr) + else: + # Use encoded rounding mechanism + rounding_mechanism = ctl & 0x3 + ROUNDING_MODE = { + 0x0: 'fpround_towardsnearest', + 0x1: 'fpround_down', + 0x2: 'fpround_up', + 0x3: 'fpround_towardszero' + } + res = m2_expr.ExprOp(ROUNDING_MODE[rounding_mechanism], src_expr) + return [m2_expr.ExprAssign(dst_expr, res)], [] + +def roundss(ir, inst, dst, src, imm8): + return _roundscalar(ir, inst, dst, src, imm8, False) + +def roundsd(ir, inst, dst, src, imm8): + return _roundscalar(ir, inst, dst, src, imm8, True) + +def fxsave(_ir, _instr, _src): + # Implemented as a NOP for now + return [], [] + +def fxrstor(_ir, _instr, _dst): + # Implemented as a NOP for now + return [], [] + + +mnemo_func = {'mov': mov, + 'xchg': xchg, + 'movzx': movzx, + 'movsx': movsx, + 'movsxd': movsx, + 'lea': lea, + 'add': add, + 'xadd': xadd, + 'adc': adc, + 'sub': sub, + 'sbb': sbb, + 'neg': neg, + 'not': l_not, + 'cmp': l_cmp, + 'xor': xor, + 'pxor': pxor, + 'or': l_or, + 'and': l_and, + 'test': l_test, + 'rol': l_rol, + 'ror': l_ror, + 'rcl': rcl, + 'rcr': rcr, + 'sar': sar, + 'shr': shr, + 'sal': shl, + 'shl': shl, + 'shld': shld, + 'cmc': cmc, + 'clc': clc, + 'stc': stc, + 'cld': cld, + 'std': std, + 'cli': cli, + 'sti': sti, + 'bsf': bsf, + 'bsr': bsr, + 'inc': inc, + 'dec': dec, + 'push': push, + 'pushw': pushw, + 'pop': pop, + 'popw': popw, + 'sete': sete, + 'setnz': setnz, + 'setl': setl, + 'setg': setg, + 'setge': setge, + 'seta': seta, + 'setae': setae, + 'setb': setb, + 'setbe': setbe, + 'setns': setns, + 'sets': sets, + 'seto': seto, + 'setp': setp, + 'setpe': setp, + 'setnp': setnp, + 'setpo': setnp, + 'setle': setle, + 'setng': setle, + 'setna': setna, + 'setnbe': setnbe, + 'setno': setno, + 'setnc': setnb, + 'setz': sete, + 'setne': setnz, + 'setnb': setae, + 'setnae': setb, + 'setc': setb, + 'setnge': setl, + 'setnl': setge, + 'setnle': setg, + 'setalc': setalc, + 'bswap': bswap, + 'cmpsb': lambda ir, instr: cmps(ir, instr, 8), + 'cmpsw': lambda ir, instr: cmps(ir, instr, 16), + 'cmpsd': lambda ir, instr: cmps(ir, instr, 32), + 'cmpsq': lambda ir, instr: cmps(ir, instr, 64), + 'scasb': lambda ir, instr: scas(ir, instr, 8), + 'scasw': lambda ir, instr: scas(ir, instr, 16), + 'scasd': lambda ir, instr: scas(ir, instr, 32), + 'scasq': lambda ir, instr: scas(ir, instr, 64), + 'pushfd': pushfd, + 'pushfq': pushfq, + 'pushfw': pushfw, + 'popfd': popfd, + 'popfq': popfd, + 'popfw': popfw, + 'pusha': pusha, + 'pushad': pushad, + 'popad': popad, + 'popa': popa, + 'call': call, + 'ret': ret, + 'retf': retf, + 'iret': iret, + 'iretd': iret, + 'leave': leave, + 'enter': enter, + 'jmp': jmp, + 'jz': jz, + 'je': jz, + 'jcxz': jcxz, + 'jecxz': jecxz, + 'jrcxz': jrcxz, + 'jnz': jnz, + 'jp': jp, + 'jpe': jp, + 'jnp': jnp, + 'ja': ja, + 'jae': jae, + 'jb': jb, + 'jbe': jbe, + 'jg': jg, + 'jge': jge, + 'jl': jl, + 'jle': jle, + 'js': js, + 'jns': jns, + 'jo': jo, + 'jno': jno, + 'loop': loop, + 'loopne': loopne, + 'loope': loope, + 'div': div, + 'mul': mul, + 'imul': imul, + 'idiv': idiv, + + 'cbw': cbw, + 'cwde': cwde, + 'cdqe': cdqe, + + 'cwd': cwd, + 'cdq': cdq, + 'cqo': cqo, + + 'daa': daa, + 'das': das, + 'aam': aam, + 'aad': aad, + 'aaa': aaa, + 'aas': aas, + 'shrd': shrd, + 'stosb': lambda ir, instr: stos(ir, instr, 8), + 'stosw': lambda ir, instr: stos(ir, instr, 16), + 'stosd': lambda ir, instr: stos(ir, instr, 32), + 'stosq': lambda ir, instr: stos(ir, instr, 64), + + 'lodsb': lambda ir, instr: lods(ir, instr, 8), + 'lodsw': lambda ir, instr: lods(ir, instr, 16), + 'lodsd': lambda ir, instr: lods(ir, instr, 32), + 'lodsq': lambda ir, instr: lods(ir, instr, 64), + + 'movsb': lambda ir, instr: movs(ir, instr, 8), + 'movsw': lambda ir, instr: movs(ir, instr, 16), + 'movsd': movsd_dispatch, + 'movsq': lambda ir, instr: movs(ir, instr, 64), + 'fcomp': fcomp, + 'fcompp': fcompp, + 'ficomp': ficomp, + 'fucom': fucom, + 'fucomp': fucomp, + 'fucompp': fucompp, + 'comiss': comiss, + 'comisd': comisd, + 'nop': nop, + 'ud2': ud2, + 'prefetch0': prefetch0, + 'prefetch1': prefetch1, + 'prefetch2': prefetch2, + 'prefetchw': prefetchw, + 'prefetchnta': prefetchnta, + 'lfence': lfence, + 'mfence': mfence, + 'sfence': sfence, + 'fnop': nop, # XXX + 'hlt': hlt, + 'rdtsc': rdtsc, + 'fst': fst, + 'fstp': fstp, + 'fist': fist, + 'fistp': fistp, + 'fisttp': fisttp, + 'fld': fld, + 'fldz': fldz, + 'fld1': fld1, + 'fldl2t': fldl2t, + 'fldpi': fldpi, + 'fldln2': fldln2, + 'fldl2e': fldl2e, + 'fldlg2': fldlg2, + 'fild': fild, + 'fadd': fadd, + 'fiadd': fiadd, + 'fisub': fisub, + 'fisubr': fisubr, + 'fpatan': fpatan, + 'fprem': fprem, + 'fprem1': fprem1, + 'fninit': fninit, + 'fyl2x': fyl2x, + 'faddp': faddp, + 'fsub': fsub, + 'fsubp': fsubp, + 'fsubr': fsubr, + 'fsubrp': fsubrp, + 'fmul': fmul, + 'fimul': fimul, + 'fmulp': fmulp, + 'fdiv': fdiv, + 'fdivr': fdivr, + 'fdivrp': fdivrp, + 'fidiv': fidiv, + 'fidivr': fidivr, + 'fdivp': fdivp, + 'fxch': fxch, + 'fptan': fptan, + 'frndint': frndint, + 'fsin': fsin, + 'fcos': fcos, + 'fsincos': fsincos, + 'fscale': fscale, + 'f2xm1': f2xm1, + 'fchs': fchs, + 'fsqrt': fsqrt, + 'fabs': fabs, + 'fnstsw': fnstsw, + 'fnstcw': fnstcw, + 'fldcw': fldcw, + 'fwait': fwait, + 'fcmovb': fcmovb, + 'fcmove': fcmove, + 'fcmovbe': fcmovbe, + 'fcmovu': fcmovu, + 'fcmovnb': fcmovnb, + 'fcmovne': fcmovne, + 'fcmovnbe': fcmovnbe, + 'fcmovnu': fcmovnu, + 'fnstenv': fnstenv, + 'fldenv': fldenv, + 'sidt': sidt, + 'sldt': sldt, + 'arpl': arpl, + 'cmovz': cmovz, + 'cmove': cmovz, + 'cmovnz': cmovnz, + 'cmovpe': cmovpe, + 'cmovnp': cmovnp, + 'cmovge': cmovge, + 'cmovnl': cmovge, + 'cmovg': cmovg, + 'cmovl': cmovl, + 'cmova': cmova, + 'cmovae': cmovae, + 'cmovbe': cmovbe, + 'cmovb': cmovb, + 'cmovnge': cmovl, + 'cmovle': cmovle, + 'cmovng': cmovle, + 'cmovo': cmovo, + 'cmovno': cmovno, + 'cmovs': cmovs, + 'cmovns': cmovns, + 'icebp': icebp, + 'int': l_int, + 'xlat': xlat, + 'bt': bt, + 'cpuid': cpuid, + 'fcom': fcom, + 'ftst': ftst, + 'fxam': fxam, + 'ficom': ficom, + 'fcomi': fcomi, + 'fcomip': fcomip, + 'fucomi': fucomi, + 'fucomip': fucomip, + 'insb': lambda ir, instr: ins(ir, instr, 8), + 'insw': lambda ir, instr: ins(ir, instr, 16), + 'insd': lambda ir, instr: ins(ir, instr, 32), + 'btc': btc, + 'bts': bts, + 'btr': btr, + 'into': into, + 'in': l_in, + 'outsb': lambda ir, instr: l_outs(ir, instr, 8), + 'outsw': lambda ir, instr: l_outs(ir, instr, 16), + 'outsd': lambda ir, instr: l_outs(ir, instr, 32), + + 'out': l_out, + "sysenter": l_sysenter, + "syscall": l_syscall, + "cmpxchg": cmpxchg, + "cmpxchg8b": cmpxchg8b, + "lds": lds, + "les": les, + "lss": lss, + "lfs": lfs, + "lgs": lgs, + "lahf": lahf, + "sahf": sahf, + "lar": lar, + "lsl": lsl, + "fclex": fclex, + "fnclex": fnclex, + "str": l_str, + "movd": movd, + "movdqu": movdqu, + "movdqa": movdqu, + "movapd": movapd, # XXX TODO alignment check + "movupd": movapd, # XXX TODO alignment check + "movaps": movapd, # XXX TODO alignment check + "movups": movapd, # XXX TODO alignment check + "andps": andps, + "andpd": andps, + "andnps": andnps, + "andnpd": andnps, + "orps": orps, + "orpd": orps, + "xorps": xorps, + "xorpd": xorps, + + "movq": movq, + + "pminsw": pminsw, + "cvtdq2pd": cvtdq2pd, + "cvtdq2ps": cvtdq2ps, + "cvtpd2dq": cvtpd2dq, + "cvtpd2pi": cvtpd2pi, + "cvtpd2ps": cvtpd2ps, + "cvtpi2pd": cvtpi2pd, + "cvtpi2ps": cvtpi2ps, + "cvtps2dq": cvtps2dq, + "cvtps2pd": cvtps2pd, + "cvtps2pi": cvtps2pi, + "cvtsd2si": cvtsd2si, + "cvtsd2ss": cvtsd2ss, + "cvtsi2sd": cvtsi2sd, + "cvtsi2ss": cvtsi2ss, + "cvtss2sd": cvtss2sd, + "cvtss2si": cvtss2si, + "cvttpd2pi": cvttpd2pi, + "cvttpd2dq": cvttpd2dq, + "cvttps2dq": cvttps2dq, + "cvttps2pi": cvttps2pi, + "cvttsd2si": cvttsd2si, + "cvttss2si": cvttss2si, + + + "bndmov": bndmov, + + + + + "movss": movss, + + "ucomiss": ucomiss, + "ucomisd": ucomisd, + + # BMI operations + "blsi": blsi, + "andn": andn, + "bextr": bextr, + "blsmsk": blsmsk, + "blsr": blsr, + "tzcnt": tzcnt, + "bzhi": bzhi, + + # + # MMX/AVX/SSE operations + + # Arithmetic (integers) + # + + # Additions + # SSE + "paddb": paddb, + "paddw": paddw, + "paddd": paddd, + "paddq": paddq, + + # Substractions + # SSE + "psubb": psubb, + "psubw": psubw, + "psubd": psubd, + "psubq": psubq, + + # Multiplications + # SSE + "pmullb": pmullb, + "pmullw": pmullw, + "pmulld": pmulld, + "pmullq": pmullq, + "pmulhub": pmulhub, + "pmulhuw": pmulhuw, + "pmulhud": pmulhud, + "pmulhuq": pmulhuq, + "pmulhb": pmulhb, + "pmulhw": pmulhw, + "pmulhd": pmulhd, + "pmulhq": pmulhq, + "pmuludq": pmuludq, + + # Mix + # SSE + "pmaddwd": pmaddwd, + "psadbw": psadbw, + "pavgb": pavgb, + "pavgw": pavgw, + + # Arithmetic (floating-point) + # + + # Additions + # SSE + "addss": addss, + "addsd": addsd, + "addps": addps, + "addpd": addpd, + + # Substractions + # SSE + "subss": subss, + "subsd": subsd, + "subps": subps, + "subpd": subpd, + + # Multiplications + # SSE + "mulss": mulss, + "mulsd": mulsd, + "mulps": mulps, + "mulpd": mulpd, + + # Divisions + # SSE + "divss": divss, + "divsd": divsd, + "divps": divps, + "divpd": divpd, + + # Rounding + "roundss": roundss, + "roundsd": roundsd, + + # Comparisons (floating-point) + # + "minps": minps, + "minpd": minpd, + "minss": minss, + "minsd": minsd, + "maxps": maxps, + "maxpd": maxpd, + "maxss": maxss, + "maxsd": maxsd, + "cmpeqps": cmpeqps, + "cmpeqpd": cmpeqpd, + "cmpeqss": cmpeqss, + "cmpeqsd": cmpeqsd, + "cmpltps": cmpltps, + "cmpltpd": cmpltpd, + "cmpltss": cmpltss, + "cmpltsd": cmpltsd, + "cmpleps": cmpleps, + "cmplepd": cmplepd, + "cmpless": cmpless, + "cmplesd": cmplesd, + "cmpunordps": cmpunordps, + "cmpunordpd": cmpunordpd, + "cmpunordss": cmpunordss, + "cmpunordsd": cmpunordsd, + "cmpneqps": cmpneqps, + "cmpneqpd": cmpneqpd, + "cmpneqss": cmpneqss, + "cmpneqsd": cmpneqsd, + "cmpnltps": cmpnltps, + "cmpnltpd": cmpnltpd, + "cmpnltss": cmpnltss, + "cmpnltsd": cmpnltsd, + "cmpnleps": cmpnleps, + "cmpnlepd": cmpnlepd, + "cmpnless": cmpnless, + "cmpnlesd": cmpnlesd, + "cmpordps": cmpordps, + "cmpordpd": cmpordpd, + "cmpordss": cmpordss, + "cmpordsd": cmpordsd, + + # Logical (floating-point) + # + + "pand": pand, + "pandn": pandn, + "por": por, + + "rdmsr": rdmsr, + "wrmsr": wrmsr, + "pshufb": pshufb, + "pshufd": pshufd, + "pshuflw": pshuflw, + "pshufhw": pshufhw, + + "psrlw": psrlw, + "psrld": psrld, + "psrlq": psrlq, + "psllw": psllw, + "pslld": pslld, + "psllq": psllq, + "pslldq": pslldq, + "psrldq": psrldq, + "psraw": psraw, + "psrad": psrad, + + "palignr": palignr, + + "pmaxub": pmaxub, + "pmaxuw": pmaxuw, + "pmaxud": pmaxud, + "pmaxsw": pmaxsw, + + "pminub": pminub, + "pminuw": pminuw, + "pminud": pminud, + + "pcmpeqb": pcmpeqb, + "pcmpeqw": pcmpeqw, + "pcmpeqd": pcmpeqd, + "pcmpeqq": pcmpeqq, + + "pcmpgtb": pcmpgtb, + "pcmpgtw": pcmpgtw, + "pcmpgtd": pcmpgtd, + "pcmpgtq": pcmpgtq, + + "punpckhbw": punpckhbw, + "punpckhwd": punpckhwd, + "punpckhdq": punpckhdq, + "punpckhqdq": punpckhqdq, + + + "punpcklbw": punpcklbw, + "punpcklwd": punpcklwd, + "punpckldq": punpckldq, + "punpcklqdq": punpcklqdq, + + "pinsrb": pinsrb, + "pinsrw": pinsrw, + "pinsrd": pinsrd, + "pinsrq": pinsrq, + + "pextrb": pextrb, + "pextrw": pextrw, + "pextrd": pextrd, + "pextrq": pextrq, + + "unpckhps": unpckhps, + "unpckhpd": unpckhpd, + "unpcklps": unpcklps, + "unpcklpd": unpcklpd, + + "movlpd": movlpd, + "movlps": movlps, + "movhpd": movhpd, + "movhps": movhpd, + "movlhps": movlhps, + "movhlps": movhlps, + "movdq2q": movdq2q, + "movq2dq": movq2dq, + + "sqrtpd": sqrtpd, + "sqrtps": sqrtps, + "sqrtsd": sqrtsd, + "sqrtss": sqrtss, + + "pmovmskb": pmovmskb, + + "packsswb": packsswb, + "packssdw": packssdw, + "packuswb": packuswb, + + "psubusb": psubusb, + "psubusw": psubusw, + "paddusb": paddusb, + "paddusw": paddusw, + "psubsb": psubsb, + "psubsw": psubsw, + "paddsb": paddsb, + "paddsw": paddsw, + + "smsw": smsw, + "maskmovq": maskmovq, + "maskmovdqu": maskmovq, + "emms": emms, + "shufps": shufps, + "shufpd": shufpd, + "movmskps": movmskps, + "movmskpd": movmskpd, + "stmxcsr": stmxcsr, + "ldmxcsr": ldmxcsr, + + # CET (Control-flow Enforcement Technology) + "incssp": incssp, + "rdssp": rdssp, + "saveprevssp": saveprevssp, + "rstorssp": rstorssp, + "wrss": wrss, + "wruss": wruss, + "setssbsy": setssbsy, + "clrssbsy": clrssbsy, + "endbr64": endbr64, + "endbr32": endbr32, + "fxsave": fxsave, + "fxrstor": fxrstor, + } + + +class Lifter_X86_16(Lifter): + + def __init__(self, loc_db): + Lifter.__init__(self, mn_x86, 16, loc_db) + self.do_stk_segm = False + self.do_ds_segm = False + self.do_str_segm = False + self.do_all_segm = False + self.pc = IP + self.sp = SP + self.IRDst = m2_expr.ExprId('IRDst', 16) + # Size of memory pointer access in IR + # 16 bit mode memory accesses may be greater than 16 bits + # 32 bit size may be enough + self.addrsize = 32 + + def mod_pc(self, instr, instr_ir, extra_ir): + pass + + def ExprMem(self, ptr, size): + """Generate a memory access to @ptr + The ptr is resized to a fixed size self.addrsize + + @ptr: Expr instance to the memory address + @size: size of the memory""" + + return m2_expr.ExprMem(expraddr(self.addrsize, ptr), size) + + def gen_segm_expr(self, selector, addr): + ptr = m2_expr.ExprOp( + 'segm', + selector, + addr.zeroExtend(self.addrsize) + ) + + return ptr + + def get_ir(self, instr): + args = instr.args[:] + args = [arg.replace_expr(float_replace) for arg in args] + args = fix_mem_args_size(instr, *args) + my_ss = None + if self.do_ds_segm: + my_ss = DS + if self.do_all_segm and instr.additional_info.g2.value: + my_ss = {1: CS, 2: SS, 3: DS, 4: ES, 5: FS, 6: GS}[ + instr.additional_info.g2.value] + if my_ss is not None: + for i, a in enumerate(args): + if a.is_mem() and not is_mem_segm(a): + args[i] = self.ExprMem(m2_expr.ExprOp('segm', my_ss, + a.ptr), a.size) + + if not instr.name.lower() in mnemo_func: + raise NotImplementedError( + "Mnemonic %s not implemented" % instr.name) + + instr_ir, extra_ir = mnemo_func[ + instr.name.lower()](self, instr, *args) + self.mod_pc(instr, instr_ir, extra_ir) + instr.additional_info.except_on_instr = False + if instr.additional_info.g1.value & 14 == 0 or \ + not instr.name in repeat_mn: + return instr_ir, extra_ir + if instr.name == "MOVSD" and len(instr.args) == 2: + return instr_ir, extra_ir + + instr.additional_info.except_on_instr = True + admode = instr.v_admode() + c_reg = mRCX[instr.mode][:admode] + + zf_val = None + # set if zf is tested (cmps, scas) + for e in instr_ir: # +[updt_c]: + if e.dst == zf: + zf_val = e.src + + cond_dec = m2_expr.ExprCond(c_reg - m2_expr.ExprInt(1, c_reg.size), + m2_expr.ExprInt(0, 1), m2_expr.ExprInt(1, 1)) + # end condition + if zf_val is None: + c_cond = cond_dec + elif instr.additional_info.g1.value & 2: # REPNE and REPNZ + c_cond = cond_dec | zf + elif instr.additional_info.g1.value & 12: # REPE, REP and REPZ + c_cond = cond_dec | (zf ^ m2_expr.ExprInt(1, 1)) + + # gen while + loc_do, loc_do_expr = self.gen_loc_key_and_expr(self.IRDst.size) + loc_end, loc_end_expr = self.gen_loc_key_and_expr(self.IRDst.size) + loc_skip = self.get_next_loc_key(instr) + loc_skip_expr = m2_expr.ExprLoc(loc_skip, self.IRDst.size) + loc_next = self.get_next_loc_key(instr) + loc_next_expr = m2_expr.ExprLoc(loc_next, self.IRDst.size) + + fix_next_loc = {loc_next_expr: loc_end_expr} + new_extra_ir = [irblock.modify_exprs(mod_src=lambda expr: expr.replace_expr(fix_next_loc)) + for irblock in extra_ir] + + cond_bloc = [] + cond_bloc.append(m2_expr.ExprAssign(c_reg, + c_reg - m2_expr.ExprInt(1, + c_reg.size))) + cond_bloc.append(m2_expr.ExprAssign(self.IRDst, m2_expr.ExprCond(c_cond, + loc_skip_expr, + loc_do_expr))) + cond_bloc = IRBlock(self.loc_db, loc_end, [AssignBlock(cond_bloc, instr)]) + e_do = instr_ir + + c = IRBlock(self.loc_db, loc_do, [AssignBlock(e_do, instr)]) + e_n = [m2_expr.ExprAssign(self.IRDst, m2_expr.ExprCond(c_reg, loc_do_expr, + loc_skip_expr))] + return e_n, [cond_bloc, c] + new_extra_ir + + def expr_fix_regs_for_mode(self, e, mode=64): + return e.replace_expr(replace_regs[mode]) + + def expraff_fix_regs_for_mode(self, e, mode=64): + dst = self.expr_fix_regs_for_mode(e.dst, mode) + src = self.expr_fix_regs_for_mode(e.src, mode) + return m2_expr.ExprAssign(dst, src) + + def irbloc_fix_regs_for_mode(self, irblock, mode=64): + irs = [] + for assignblk in irblock: + new_assignblk = dict(assignblk) + for dst, src in viewitems(assignblk): + del new_assignblk[dst] + # Special case for 64 bits: + # If destination is a 32 bit reg, zero extend the 64 bit reg + if mode == 64: + if (isinstance(dst, m2_expr.ExprId) and + dst.size == 32 and + dst in replace_regs[64]): + src = src.zeroExtend(64) + dst = replace_regs[64][dst].arg + dst = self.expr_fix_regs_for_mode(dst, mode) + src = self.expr_fix_regs_for_mode(src, mode) + new_assignblk[dst] = src + irs.append(AssignBlock(new_assignblk, assignblk.instr)) + return IRBlock(self.loc_db, irblock.loc_key, irs) + + +class Lifter_X86_32(Lifter_X86_16): + + def __init__(self, loc_db): + Lifter.__init__(self, mn_x86, 32, loc_db) + self.do_stk_segm = False + self.do_ds_segm = False + self.do_str_segm = False + self.do_all_segm = False + self.pc = EIP + self.sp = ESP + self.IRDst = m2_expr.ExprId('IRDst', 32) + self.addrsize = 32 + + +class Lifter_X86_64(Lifter_X86_16): + + def __init__(self, loc_db): + Lifter.__init__(self, mn_x86, 64, loc_db) + self.do_stk_segm = False + self.do_ds_segm = False + self.do_str_segm = False + self.do_all_segm = False + self.pc = RIP + self.sp = RSP + self.IRDst = m2_expr.ExprId('IRDst', 64) + self.addrsize = 64 + + def mod_pc(self, instr, instr_ir, extra_ir): + # fix RIP for 64 bit + pc_fixed = {self.pc: m2_expr.ExprInt(instr.offset + instr.l, 64)} + + for i, expr in enumerate(instr_ir): + dst, src = expr.dst, expr.src + if dst != self.pc: + dst = dst.replace_expr(pc_fixed) + src = src.replace_expr(pc_fixed) + instr_ir[i] = m2_expr.ExprAssign(dst, src) + + for idx, irblock in enumerate(extra_ir): + extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \ + if expr != self.pc else expr, + lambda expr: expr.replace_expr(pc_fixed)) |