diff options
Diffstat (limited to 'src/miasm/arch/msp430')
| -rw-r--r-- | src/miasm/arch/msp430/__init__.py | 1 | ||||
| -rw-r--r-- | src/miasm/arch/msp430/arch.py | 610 | ||||
| -rw-r--r-- | src/miasm/arch/msp430/ctype.py | 68 | ||||
| -rw-r--r-- | src/miasm/arch/msp430/disasm.py | 8 | ||||
| -rw-r--r-- | src/miasm/arch/msp430/jit.py | 41 | ||||
| -rw-r--r-- | src/miasm/arch/msp430/lifter_model_call.py | 31 | ||||
| -rw-r--r-- | src/miasm/arch/msp430/regs.py | 116 | ||||
| -rw-r--r-- | src/miasm/arch/msp430/sem.py | 509 |
8 files changed, 1384 insertions, 0 deletions
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') |