diff options
Diffstat (limited to '')
| -rw-r--r-- | miasm2/arch/msp430/__init__.py | 1 | ||||
| -rw-r--r-- | miasm2/arch/msp430/arch.py | 601 | ||||
| -rw-r--r-- | miasm2/arch/msp430/disasm.py | 8 | ||||
| -rw-r--r-- | miasm2/arch/msp430/ira.py | 75 | ||||
| -rw-r--r-- | miasm2/arch/msp430/regs.py | 105 | ||||
| -rw-r--r-- | miasm2/arch/msp430/sem.py | 440 |
6 files changed, 1230 insertions, 0 deletions
diff --git a/miasm2/arch/msp430/__init__.py b/miasm2/arch/msp430/__init__.py new file mode 100644 index 00000000..bbad893b --- /dev/null +++ b/miasm2/arch/msp430/__init__.py @@ -0,0 +1 @@ +__all__ = ["arch", "disasm", "regs", "sem"] diff --git a/miasm2/arch/msp430/arch.py b/miasm2/arch/msp430/arch.py new file mode 100644 index 00000000..74cce9ea --- /dev/null +++ b/miasm2/arch/msp430/arch.py @@ -0,0 +1,601 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +import logging +from pyparsing import * +from miasm2.expression.expression import * +from miasm2.core.cpu import * +from collections import defaultdict +from miasm2.core.bin_stream import bin_stream +import regs as regs_module +from regs import * + +log = logging.getLogger("armdis") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.DEBUG) + + +def deref2expr_nooff(s, l, t): + t = t[0] + if len(t) == 1 and isinstance(t[0], ExprId): + return ExprMem(t[0], 16) + elif len(t) == 1 and isinstance(t[0], ExprInt): + return ExprMem(t[0], 16) + raise NotImplementedError('not fully functional') + + +def deref2expr_pinc(s, l, t): + t = t[0] + if len(t) == 1 and isinstance(t[0], ExprId): + return ExprOp('autoinc', t[0]) + raise NotImplementedError('not fully functional') + + +def deref2expr_off(s, l, t): + t = t[0] + if len(t) == 2 and isinstance(t[1], ExprId): + return ExprMem(t[1] + t[0], 16) + raise NotImplementedError('not fully functional') + + +def deref_expr(s, l, t): + t = t[0] + assert(len(t) == 1) + t = t[0] + if isinstance(t, ExprId): + return t + elif isinstance(t, ExprInt): + return t + elif isinstance(t, ExprMem): + return t + elif isinstance(t, ExprOp) and t.op == "autoinc": + return t + raise NotImplementedError('not fully functional') + if t[-1] == '!': + return ExprOp('wback', *t[:-1]) + return t[0] + + +def f_reg2expr(t): + t = t[0] + i = regs16_str.index(t) + r = regs16_expr[i] + return r + +# gpregs.parser.setParseAction(f_reg2expr) + +ARO = Suppress("@") +LPARENT = Suppress("(") +RPARENT = Suppress(")") + +PINC = Suppress("+") + + +def ast_id2expr(t): + if not t in mn_msp430.regs.all_regs_ids_byname: + r = ExprId(t, 16) + else: + r = mn_msp430.regs.all_regs_ids_byname[t] + return r + + +def ast_int2expr(a): + return ExprInt16(a) + + +variable, operand, base_expr = gen_base_expr() + +my_var_parser = parse_ast(ast_id2expr, ast_int2expr) +base_expr.setParseAction(my_var_parser) + + +deref_nooff = Group(ARO + base_expr).setParseAction(deref2expr_nooff) +deref_pinc = Group(ARO + base_expr + PINC).setParseAction(deref2expr_pinc) +deref_off = Group(base_expr + LPARENT + + gpregs.parser + RPARENT).setParseAction(deref2expr_off) + + +sreg_p = Group(deref_pinc | deref_nooff | + deref_off | base_expr).setParseAction(deref_expr) + + +class additional_info: + + def __init__(self): + self.except_on_instr = False + + +class instruction_msp430(instruction): + delayslot = 0 + + def dstflow(self): + if self.name.startswith('j'): + return True + return self.name in ['call'] + + def dstflow2label(self, symbol_pool): + e = self.args[0] + if not isinstance(e, ExprInt): + return + if self.name == "call": + ad = e.arg + else: + ad = e.arg + int(self.offset) + self.l + + l = symbol_pool.getby_offset_create(ad) + s = ExprId(l, e.size) + self.args[0] = s + + def breakflow(self): + if self.name.startswith('j'): + 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.startswith('jmp'): + return False + if self.name.startswith('j'): + return True + return self.name in ['call'] + + def setdstflow(self, a): + return + + def is_subcall(self): + return self.name in ['call'] + + def getdstflow(self, symbol_pool): + return [self.args[0]] + + def get_symbol_size(self, symbol, symbol_pool): + return self.mode + + 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 + # return ExprInt32(e.arg - (self.offset + self.l)) + self.args[0] = ExprInt_fromsize(self.mode, e.arg) + + 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: + # a = a.replace_expr(replace_regs[self.mode]) + 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, start, n): + if not n: + return 0 + o = 0 + if n > bs.getlen() * 8: + raise ValueError('not enought 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 = "" + for _ in xrange(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 = "" + 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, symbol_pool): + raise NotImplementedError('not fully functional') + return self.offset + 4 + + +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, m_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_fromsize(size, 0) + else: + self.expr = e + elif self.parent.a_s.value == 0b01: + if e == SR: + self.expr = ExprMem(ExprInt16(self.parent.off_s.value), size) + elif e == R3: + self.expr = ExprInt_fromsize(size, 1) + else: + self.expr = ExprMem( + e + ExprInt16(self.parent.off_s.value), size) + elif self.parent.a_s.value == 0b10: + if e == SR: + self.expr = ExprInt_fromsize(size, 4) + elif e == R3: + self.expr = ExprInt_fromsize(size, 2) + else: + self.expr = ExprMem(e, size) + elif self.parent.a_s.value == 0b11: + if e == SR: + self.expr = ExprInt_fromsize(size, 8) + elif e == R3: + if self.parent.size.value == 0: + self.expr = ExprInt_fromsize(size, 0xffff) + else: + self.expr = ExprInt_fromsize(size, 0xff) + elif e == PC: + self.expr = ExprInt_fromsize(size, self.parent.off_s.value) + 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.arg) + 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.arg, ExprId): + self.parent.a_s.value = 0b10 + self.value = self.reg_info.expr.index(e.arg) + elif isinstance(e.arg, ExprInt): + self.parent.a_s.value = 0b01 + self.value = self.reg_info.expr.index(SR) + self.parent.off_s.value = int(e.arg.arg) + elif isinstance(e.arg, ExprOp): + self.parent.a_s.value = 0b01 + self.value = self.reg_info.expr.index(e.arg.args[0]) + self.parent.off_s.value = int(e.arg.args[1].arg) + else: + raise NotImplementedError( + 'unknown instance e.arg = %s' % type(e.arg)) + 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 + + @staticmethod + def arg2str(e): + if isinstance(e, ExprId): + o = str(e) + elif isinstance(e, ExprInt): + o = str(e) + elif isinstance(e, ExprOp) and e.op == "autoinc": + o = "@%s+" % str(e.args[0]) + elif isinstance(e, ExprMem): + if isinstance(e.arg, ExprId): + o = "@%s" % e.arg + elif isinstance(e.arg, ExprInt): + o = "@%s" % e.arg + elif isinstance(e.arg, ExprOp): + o = "%s(%s)" % (e.arg.args[1], e.arg.args[0]) + else: + raise NotImplementedError('unknown instance e = %s' % type(e)) + return o + + +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 = ExprInt16(self.parent.off_d.value) + else: + x = e + ExprInt16(self.parent.off_d.value) + 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.arg, ExprId): + r, i = e.arg, ExprInt16(0) + elif isinstance(e.arg, ExprOp): + r, i = e.arg.args[0], e.arg.args[1] + elif isinstance(e.arg, ExprInt): + r, i = SR, e.arg + else: + raise NotImplementedError( + 'unknown instance e.arg = %s' % type(e.arg)) + self.parent.a_d.value = 1 + self.value = self.reg_info.expr.index(r) + self.parent.off_d.value = int(i.arg) + else: + raise NotImplementedError('unknown instance e = %s' % type(e)) + return True + + @staticmethod + def arg2str(e): + if isinstance(e, ExprId): + o = str(e) + elif isinstance(e, ExprMem): + if isinstance(e.arg, ExprId): + o = "0x0(%s)" % e.arg + elif isinstance(e.arg, ExprInt): + o = "@%s" % e.arg + elif isinstance(e.arg, ExprOp): + o = "%s(%s)" % (e.arg.args[1], e.arg.args[0]) + else: + raise NotImplementedError( + 'unknown instance e.arg = %s' % type(e.arg)) + else: + raise NotImplementedError('unknown instance e = %s' % type(e)) + return o + + +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, 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, m_arg): + parser = base_expr + + def int2expr(self, v): + if v & ~self.intmask != 0: + return None + return ExprInt_fromsize(16, v) + + def decodeval(self, v): + return v << 1 + + def encodeval(self, v): + 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 = ExprInt16(v) + return True + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr.arg) + 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]) + + +offimm = bs(l=10, cls=(msp430_offs,), fname="offs") + +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/miasm2/arch/msp430/disasm.py b/miasm2/arch/msp430/disasm.py new file mode 100644 index 00000000..f0138bdf --- /dev/null +++ b/miasm2/arch/msp430/disasm.py @@ -0,0 +1,8 @@ +from miasm2.core.asmbloc import disasmEngine +from 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/miasm2/arch/msp430/ira.py b/miasm2/arch/msp430/ira.py new file mode 100644 index 00000000..8e9a70dd --- /dev/null +++ b/miasm2/arch/msp430/ira.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +from miasm2.expression.expression import * +from miasm2.ir.ir import ir, irbloc +from miasm2.ir.analysis import ira +from miasm2.arch.msp430.sem import ir_msp430 +from miasm2.arch.msp430.regs import * +# from miasm2.core.graph import DiGraph + + +class ir_a_msp430_base(ir_msp430, ira): + + def __init__(self, symbol_pool=None): + ir_msp430.__init__(self, symbol_pool) + self.ret_reg = self.arch.regs.R15 + + +class ir_a_msp430(ir_a_msp430_base): + + def __init__(self, symbol_pool=None): + ir_a_msp430_base.__init__(self, symbol_pool) + + # for test XXX TODO + def set_dead_regs(self, b): + b.rw[-1][1].add(self.arch.regs.zf) + b.rw[-1][1].add(self.arch.regs.nf) + b.rw[-1][1].add(self.arch.regs.of) + b.rw[-1][1].add(self.arch.regs.cf) + + b.rw[-1][1].add(self.arch.regs.res) + b.rw[-1][1].add(self.arch.regs.scg1) + b.rw[-1][1].add(self.arch.regs.scg0) + b.rw[-1][1].add(self.arch.regs.osc) + b.rw[-1][1].add(self.arch.regs.cpuoff) + b.rw[-1][1].add(self.arch.regs.gie) + + def call_effects(self, ad): + irs = [[ExprAff(self.ret_reg, ExprOp('call_func_ret', ad, self.sp)), + ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)), + ]] + return irs + + def post_add_bloc(self, bloc, ir_blocs): + ir.post_add_bloc(self, bloc, ir_blocs) + # flow_graph = DiGraph() + + l = bloc.lines[-1] + if not l.is_subcall(): + return + + for irb in ir_blocs: + # print 'X'*40 + # print irb + pc_val = None + for exprs in irb.irs: + for e in exprs: + if e.dst == PC: + pc_val = e.src + if pc_val is None: + continue + + l = bloc.lines[-1] + # print str(l), 'IS CALL!' + lbl = bloc.get_next() + new_lbl = self.gen_label() + irs = self.call_effects(pc_val) + nbloc = irbloc(new_lbl, ExprId(lbl, size=self.pc.size), irs) + nbloc.lines = [l] + self.blocs[new_lbl] = nbloc + irb.dst = ExprId(new_lbl, size=self.pc.size) + + def get_out_regs(self, b): + return set([self.ret_reg, self.sp]) + diff --git a/miasm2/arch/msp430/regs.py b/miasm2/arch/msp430/regs.py new file mode 100644 index 00000000..7a389ae1 --- /dev/null +++ b/miasm2/arch/msp430/regs.py @@ -0,0 +1,105 @@ +from miasm2.expression.expression import * +from miasm2.core.cpu import reg_info + + +# GP + +regs16_str = ["PC", "SP", "SR"] + ["R%d" % i for i in xrange(3, 16)] +regs16_expr = [ExprId(x, 16) for x in regs16_str] + + +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_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] diff --git a/miasm2/arch/msp430/sem.py b/miasm2/arch/msp430/sem.py new file mode 100644 index 00000000..6fea2c21 --- /dev/null +++ b/miasm2/arch/msp430/sem.py @@ -0,0 +1,440 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +from miasm2.expression.expression import * +from miasm2.arch.msp430.regs import * +from miasm2.arch.msp430.arch import mn_msp430 +from miasm2.ir.ir import ir +from regs import * + + +# 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 [ExprAff(res, ExprInt_fromsize(7, 0))] + + +def update_flag_zf(a): + return [ExprAff(zf, ExprCond(a, ExprInt_from(zf, 0), ExprInt_from(zf, 1)))] + + +def update_flag_nf(a): + return [ExprAff(nf, a.msb())] + + +def update_flag_pf(a): + return [ExprAff(pf, ExprOp('parity', a & ExprInt_from(a, 0xFF)))] + + +def update_flag_cf_inv_zf(a): + return [ExprAff(cf, ExprCond(a, ExprInt_from(cf, 1), ExprInt_from(cf, 0)))] + + +def update_flag_zn_r(a): + e = [] + e += update_flag_zf(a) + e += update_flag_nf(a) + e += reset_sr_res() + return e + + +def update_flag_sub_cf(a, b, c): + return [ExprAff(cf, + ((((a ^ b) ^ c) ^ ((a ^ c) & (a ^ b))).msb()) ^ ExprInt1(1))] + + +def update_flag_add_cf(a, b, c): + return [ExprAff(cf, (((a ^ b) ^ c) ^ ((a ^ c) & (~(a ^ b)))).msb())] + + +def update_flag_add_of(a, b, c): + return [ExprAff(of, (((a ^ c) & (~(a ^ b)))).msb())] + + +def update_flag_sub_of(a, b, c): + return [ExprAff(of, (((a ^ c) & (a ^ b))).msb())] + + +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(ExprAff(a_r, a_r + ExprInt_from(a_r, size / 8))) + a = ExprMem(a_r, size) + if isinstance(b, ExprMem) and a_r in b.arg: + b = ExprMem(b.arg + ExprInt16(size / 8), 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(ExprAff(b, a)) + return None, e, [] + + +def mov_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + e.append(ExprAff(b, a)) + if b == ir.pc: + dst = PC + else: + dst = None + return dst, e, [] + + +def and_b(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 8) + c = a[:8] & b[:8] + e.append(ExprAff(b, c.zeroExtend(16))) + e += update_flag_zn_r(c) + e += update_flag_cf_inv_zf(c) + e += [ExprAff(of, ExprInt1(0))] + return None, e, [] + + +def and_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + c = a & b + e.append(ExprAff(b, c)) + e += update_flag_zn_r(c) + e += update_flag_cf_inv_zf(c) + e += [ExprAff(of, ExprInt1(0))] + return None, e, [] + + +def bic_b(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 8) + c = (a[:8] ^ ExprInt8(0xff)) & b[:8] + c = c.zeroExtend(b.size) + e.append(ExprAff(b, c)) + return None, e, [] + + +def bic_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + c = (a ^ ExprInt16(0xffff)) & b + e.append(ExprAff(b, c)) + return None, e, [] + + +def bis_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + c = a | b + e.append(ExprAff(b, c)) + return None, e, [] + + +def bit_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + c = a & b + e += update_flag_zn_r(c) + e += update_flag_cf_inv_zf(c) + e.append(ExprAff(of, ExprInt1(0))) + return None, e, [] + +""" +def sub_b(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 8) + c = b - a + e.append(ExprAff(b, c)) + e += update_flag_zn_r(c) + e += update_flag_sub_cf(b, a, c) + return None, e, [] +""" + + +def sub_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + c = b - a + e.append(ExprAff(b, c)) + e += update_flag_zn_r(c) + e += update_flag_sub_cf(b, a, c) + # micrcorruption + # e += update_flag_sub_of(a, b, c) + # e += update_flag_sub_of(b, a, c) + return None, e, [] + + +def add_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + c = b + a + e.append(ExprAff(b, c)) + e += update_flag_zn_r(c) + e += update_flag_add_cf(a, b, c) + e += update_flag_add_of(a, b, c) + return None, 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(ExprAff(b, c)) + # e += update_flag_zn_r(c) + + # micrcorruption + e += update_flag_zf(a) + # e += update_flag_nf(a) + e += reset_sr_res() + + e.append(ExprAff(cf, ExprOp("bcdadd_cf", b, a))) # +zeroExtend(cf, 16)))) + + # of : undefined + return None, e, [] + + +def xor_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + c = b ^ a + e.append(ExprAff(b, c)) + e += update_flag_zn_r(c) + e += update_flag_cf_inv_zf(c) + e.append(ExprAff(of, b.msb() & a.msb())) + return None, e, [] + + +def push_w(ir, instr, a): + e = [] + e.append(ExprAff(ExprMem(SP - ExprInt16(2), 16), a)) + e.append(ExprAff(SP, SP - ExprInt16(2))) + return None, e, [] + + +def call(ir, instr, a): + e, a, dummy = mng_autoinc(a, None, 16) + n = ExprId(ir.get_next_label(instr), 16) + e.append(ExprAff(ExprMem(SP - ExprInt16(2), 16), n)) + e.append(ExprAff(SP, SP - ExprInt16(2))) + e.append(ExprAff(PC, a)) + return PC, e, [] + + +def swpb(ir, instr, a): + e = [] + x, y = a[:8], a[8:16] + e.append(ExprAff(a, ExprCompose([(y, 0, 8), + (x, 8, 16)]))) + return None, e, [] + + +def cmp_w(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 16) + c = b - a + e += update_flag_zn_r(c) + e += update_flag_sub_cf(a, b, c) + e += update_flag_sub_of(a, b, c) + return None, e, [] + + +def cmp_b(ir, instr, a, b): + e, a, b = mng_autoinc(a, b, 8) + c = b[:8] - a[:8] + e += update_flag_zn_r(c) + e += update_flag_sub_cf(a[:8], b[:8], c) + e += update_flag_sub_of(a[:8], b[:8], c) + return None, e, [] + + +def jz(ir, instr, a): + n = ExprId(ir.get_next_label(instr), 16) + e = [] + e.append(ExprAff(PC, ExprCond(zf, a, n))) + return PC, e, [] + + +def jnz(ir, instr, a): + n = ExprId(ir.get_next_label(instr), 16) + e = [] + e.append(ExprAff(PC, ExprCond(zf, n, a))) + return PC, e, [] + + +def jl(ir, instr, a): + n = ExprId(ir.get_next_label(instr), 16) + e = [] + e.append(ExprAff(PC, ExprCond(nf ^ of, a, n))) + return PC, e, [] + + +def jc(ir, instr, a): + n = ExprId(ir.get_next_label(instr), 16) + e = [] + e.append(ExprAff(PC, ExprCond(cf, a, n))) + return PC, e, [] + + +def jnc(ir, instr, a): + n = ExprId(ir.get_next_label(instr), 16) + e = [] + e.append(ExprAff(PC, ExprCond(cf, n, a))) + return PC, e, [] + + +def jge(ir, instr, a): + n = ExprId(ir.get_next_label(instr), 16) + e = [] + e.append(ExprAff(PC, ExprCond(nf ^ of, n, a))) + return PC, e, [] + + +def jmp(ir, instr, a): + e = [] + e.append(ExprAff(PC, a)) + return PC, e, [] + + +def rrc_w(ir, instr, a): + e = [] + c = ExprCompose([(a[1:16], 0, 15), + (cf, 15, 16)]) + e.append(ExprAff(a, c)) + e.append(ExprAff(cf, a[:1])) + # e += update_flag_zn_r(c) + + # micrcorruption + e += update_flag_zf(a) + # e += update_flag_nf(a) + e += reset_sr_res() + + e.append(ExprAff(of, ExprInt1(0))) + return None, e, [] + + +def rra_w(ir, instr, a): + e = [] + c = ExprCompose([(a[1:16], 0, 15), + (a[15:16], 15, 16)]) + e.append(ExprAff(a, c)) + # TODO: error in disasm microcorruption? + # e.append(ExprAff(cf, a[:1])) + # e += update_flag_zn_r(c) + + # micrcorruption + e += update_flag_zf(a) + # e += update_flag_nf(a) + e += reset_sr_res() + + e.append(ExprAff(of, ExprInt1(0))) + return None, e, [] + + +def sxt(ir, instr, a): + e = [] + c = a[:8].signExtend(16) + e.append(ExprAff(a, c)) + + e += update_flag_zn_r(c) + e += update_flag_cf_inv_zf(c) + e.append(ExprAff(of, ExprInt1(0))) + + return None, 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.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, 0, 1), + (zf, 1, 2), + (nf, 2, 3), + (gie, 3, 4), + (cpuoff, 4, 5), + (osc, 5, 6), + (scg0, 6, 7), + (scg1, 7, 8), + (of, 8, 9), + (res, 9, 16), +]) + + +def ComposeExprAff(dst, src): + e = [] + for x, start, stop in dst.args: + e.append(ExprAff(x, src[start:stop])) + return e + + +class ir_msp430(ir): + + def __init__(self, symbol_pool=None): + ir.__init__(self, mn_msp430, None, symbol_pool) + self.pc = PC + self.sp = SP + + def mod_pc(self, instr, instr_ir, extra_ir): + pass + + def get_ir(self, instr): + # print instr#, args + args = instr.args + dst, instr_ir, extra_ir = mnemo_func[instr.name](self, instr, *args) + self.mod_sr(instr, instr_ir, extra_ir) + + return dst, instr_ir, extra_ir + + def mod_sr(self, instr, instr_ir, extra_ir): + for i, x in enumerate(instr_ir): + x.src = x.src.replace_expr({SR: composed_sr}) + if x.dst != SR: + continue + xx = ComposeExprAff(composed_sr, x.src) + instr_ir[i:i + 1] = xx + for i, x in enumerate(instr_ir): + x = ExprAff(x.dst, x.src.replace_expr( + {self.pc: ExprInt16(instr.offset + instr.l)})) + instr_ir[i] = x + + if extra_ir: + raise NotImplementedError('not fully functional') |