diff options
| -rw-r--r-- | miasm2/arch/x86/sem.py | 11 | ||||
| -rw-r--r-- | miasm2/ir/ir2C.py | 32 | ||||
| -rw-r--r-- | miasm2/ir/translators/C.py | 96 | ||||
| -rw-r--r-- | miasm2/ir/translators/miasm.py | 42 | ||||
| -rw-r--r-- | miasm2/ir/translators/python.py | 44 | ||||
| -rw-r--r-- | miasm2/ir/translators/translator.py | 66 | ||||
| -rw-r--r-- | miasm2/ir/translators/z3_ir.py | 83 | ||||
| -rw-r--r-- | test/ir/ir2C.py | 15 | ||||
| -rw-r--r-- | test/ir/translators/z3_ir.py | 4 |
9 files changed, 181 insertions, 212 deletions
diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py index 94066519..8c3a351d 100644 --- a/miasm2/arch/x86/sem.py +++ b/miasm2/arch/x86/sem.py @@ -302,6 +302,16 @@ def xor(ir, instr, a, b): return e, [] +def pxor(ir, instr, a, b): + e = [] + if isinstance(a, m2_expr.ExprMem): + a = m2_expr.ExprMem(a.arg, b.size) + if isinstance(b, m2_expr.ExprMem): + b = m2_expr.ExprMem(b.arg, a.size) + c = a ^ b + e.append(m2_expr.ExprAff(a, c)) + return e, [] + def l_or(ir, instr, a, b): e = [] c = a | b @@ -3138,6 +3148,7 @@ mnemo_func = {'mov': mov, 'not': l_not, 'cmp': l_cmp, 'xor': xor, + 'pxor': pxor, 'or': l_or, 'and': l_and, 'test': l_test, diff --git a/miasm2/ir/ir2C.py b/miasm2/ir/ir2C.py index 1e4e653e..4c9dff8c 100644 --- a/miasm2/ir/ir2C.py +++ b/miasm2/ir/ir2C.py @@ -1,7 +1,7 @@ import miasm2.expression.expression as m2_expr from miasm2.expression.simplifications import expr_simp from miasm2.core import asmbloc -from miasm2.ir.translators.C import TranslatorC +from miasm2.ir.translators import Translator import logging @@ -11,6 +11,8 @@ console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s")) log_to_c_h.addHandler(console_handler) log_to_c_h.setLevel(logging.WARN) +# Miasm to C translator +translator = Translator.to_language("C") prefetch_id = [] prefetch_id_size = {} @@ -164,13 +166,13 @@ def gen_resolve_id_lbl(ir_arch, e): return 'Resolve_dst(BlockDst, 0x%X, 0)'%(e.name.offset) def gen_resolve_id(ir_arch, e): - return 'Resolve_dst(BlockDst, %s, 0)'%(TranslatorC.from_expr(patch_c_id(ir_arch.arch, e))) + return 'Resolve_dst(BlockDst, %s, 0)'%(translator.from_expr(patch_c_id(ir_arch.arch, e))) def gen_resolve_mem(ir_arch, e): - return 'Resolve_dst(BlockDst, %s, 0)'%(TranslatorC.from_expr(patch_c_id(ir_arch.arch, e))) + return 'Resolve_dst(BlockDst, %s, 0)'%(translator.from_expr(patch_c_id(ir_arch.arch, e))) def gen_resolve_other(ir_arch, e): - return 'Resolve_dst(BlockDst, %s, 0)'%(TranslatorC.from_expr(patch_c_id(ir_arch.arch, e))) + return 'Resolve_dst(BlockDst, %s, 0)'%(translator.from_expr(patch_c_id(ir_arch.arch, e))) def gen_resolve_dst_simple(ir_arch, e): if isinstance(e, m2_expr.ExprInt): @@ -189,7 +191,7 @@ def gen_resolve_dst_simple(ir_arch, e): def gen_irdst(ir_arch, e): out = [] if isinstance(e, m2_expr.ExprCond): - dst_cond_c = TranslatorC.from_expr(patch_c_id(ir_arch.arch, e.cond)) + dst_cond_c = translator.from_expr(patch_c_id(ir_arch.arch, e.cond)) out.append("if (%s)"%dst_cond_c) out.append(' %s;'%(gen_resolve_dst_simple(ir_arch, e.src1))) out.append("else") @@ -257,8 +259,8 @@ def Expr2C(ir_arch, l, exprs, gen_exception_code=False): mem_k = src_mem.keys() mem_k.sort() for k in mem_k: - str_src = TranslatorC.from_expr(patch_c_id(ir_arch.arch, k)) - str_dst = TranslatorC.from_expr(patch_c_id(ir_arch.arch, src_mem[k])) + str_src = translator.from_expr(patch_c_id(ir_arch.arch, k)) + str_dst = translator.from_expr(patch_c_id(ir_arch.arch, src_mem[k])) out.append('%s = %s;' % (str_dst, str_src)) src_w_len = {} for k, v in src_mem.items(): @@ -273,8 +275,8 @@ def Expr2C(ir_arch, l, exprs, gen_exception_code=False): continue - str_src = TranslatorC.from_expr(patch_c_id(ir_arch.arch, src)) - str_dst = TranslatorC.from_expr(patch_c_id(ir_arch.arch, dst)) + str_src = translator.from_expr(patch_c_id(ir_arch.arch, src)) + str_dst = translator.from_expr(patch_c_id(ir_arch.arch, dst)) @@ -304,12 +306,12 @@ def Expr2C(ir_arch, l, exprs, gen_exception_code=False): if gen_exception_code: if fetch_mem: e = set_pc(ir_arch, l.offset & mask_int) - s1 = "%s" % TranslatorC.from_expr(patch_c_id(ir_arch.arch, e)) + s1 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e)) s1 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%(l.offset & mask_int) out.append(code_exception_fetch_mem_at_instr_noautomod % s1) if set_exception_flags: e = set_pc(ir_arch, l.offset & mask_int) - s1 = "%s" % TranslatorC.from_expr(patch_c_id(ir_arch.arch, e)) + s1 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e)) s1 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%(l.offset & mask_int) out.append(code_exception_at_instr_noautomod % s1) @@ -328,10 +330,10 @@ def Expr2C(ir_arch, l, exprs, gen_exception_code=False): "/*pc = 0x%X; */return; }" % (l.offset)) else: e = set_pc(ir_arch, l.offset & mask_int) - s1 = "%s" % TranslatorC.from_expr(patch_c_id(ir_arch.arch, e)) + s1 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e)) s1 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%(l.offset & mask_int) e = set_pc(ir_arch, (l.offset + l.l) & mask_int) - s2 = "%s" % TranslatorC.from_expr(patch_c_id(ir_arch.arch, e)) + s2 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e)) s2 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%((l.offset + l.l) & mask_int) post_instr.append( code_exception_post_instr_noautomod % (s1, s2)) @@ -343,7 +345,7 @@ def Expr2C(ir_arch, l, exprs, gen_exception_code=False): offset = l.offset + l.l e = set_pc(ir_arch, offset & mask_int) - s1 = "%s" % TranslatorC.from_expr(patch_c_id(ir_arch.arch, e)) + s1 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e)) s1 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%(offset & mask_int) post_instr.append( code_exception_fetch_mem_post_instr_noautomod % (s1)) @@ -383,7 +385,7 @@ def ir2C(ir_arch, irbloc, lbl_done, for l, exprs in zip(irbloc.lines, irbloc.irs): if l.offset not in lbl_done: e = set_pc(ir_arch, l.offset & mask_int) - s1 = "%s" % TranslatorC.from_expr(patch_c_id(ir_arch.arch, e)) + s1 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e)) s1 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%(l.offset & mask_int) out.append([pre_instr_test_exception % (s1)]) lbl_done.add(l.offset) diff --git a/miasm2/ir/translators/C.py b/miasm2/ir/translators/C.py index feb7539b..8ec4af7a 100644 --- a/miasm2/ir/translators/C.py +++ b/miasm2/ir/translators/C.py @@ -29,113 +29,107 @@ class TranslatorC(Translator): } - @classmethod - def from_ExprId(cls, expr): + def from_ExprId(self, expr): if isinstance(expr.name, asmbloc.asm_label): return "0x%x" % expr.name.offset return str(expr) - @classmethod - def from_ExprInt(cls, expr): + def from_ExprInt(self, expr): return "0x%x" % expr.arg.arg - @classmethod - def from_ExprAff(cls, expr): - return "%s = %s" % tuple(map(cls.from_expr, (expr.dst, expr.src))) + def from_ExprAff(self, expr): + return "%s = %s" % tuple(map(self.from_expr, (expr.dst, expr.src))) - @classmethod - def from_ExprCond(cls, expr): - return "(%s?%s:%s)" % tuple(map(cls.from_expr, + def from_ExprCond(self, expr): + return "(%s?%s:%s)" % tuple(map(self.from_expr, (expr.cond, expr.src1, expr.src2))) - @classmethod - def from_ExprMem(cls, expr): + def from_ExprMem(self, expr): return "MEM_LOOKUP_%.2d(vm_mngr, %s)" % (expr.size, - cls.from_expr(expr.arg)) + self.from_expr(expr.arg)) - @classmethod - def from_ExprOp(cls, expr): + def from_ExprOp(self, expr): if len(expr.args) == 1: if expr.op == 'parity': - return "parity(%s&0x%x)" % (cls.from_expr(expr.args[0]), + return "parity(%s&0x%x)" % (self.from_expr(expr.args[0]), size2mask(expr.args[0].size)) elif expr.op in ['bsr', 'bsf']: return "x86_%s(%s, 0x%x)" % (expr.op, - cls.from_expr(expr.args[0]), + self.from_expr(expr.args[0]), expr.args[0].size) elif expr.op == '!': - return "(~ %s)&0x%x" % (cls.from_expr(expr.args[0]), + return "(~ %s)&0x%x" % (self.from_expr(expr.args[0]), size2mask(expr.args[0].size)) elif expr.op in ["hex2bcd", "bcd2hex"]: return "%s_%d(%s)" % (expr.op, expr.args[0].size, - cls.from_expr(expr.args[0])) + self.from_expr(expr.args[0])) elif (expr.op.startswith("double_to_") or expr.op.endswith("_to_double") or expr.op.startswith("access_") or expr.op.startswith("load_") or expr.op in ["-", "ftan", "frndint", "f2xm1", "fsin", "fsqrt", "fabs", "fcos"]): - return "%s(%s)" % (expr.op, cls.from_expr(expr.args[0])) + return "%s(%s)" % (expr.op, self.from_expr(expr.args[0])) else: raise NotImplementedError('Unknown op: %r' % expr.op) elif len(expr.args) == 2: if expr.op == "==": return '(((%s&0x%x) == (%s&0x%x))?1:0)' % ( - cls.from_expr(expr.args[0]), size2mask(expr.args[0].size), - cls.from_expr(expr.args[1]), size2mask(expr.args[1].size)) - elif expr.op in cls.dct_shift: - return 'shift_%s_%.2d(%s , %s)' % (cls.dct_shift[expr.op], + self.from_expr(expr.args[0]), size2mask(expr.args[0].size), + self.from_expr(expr.args[1]), size2mask(expr.args[1].size)) + elif expr.op in self.dct_shift: + return 'shift_%s_%.2d(%s , %s)' % (self.dct_shift[expr.op], expr.args[0].size, - cls.from_expr(expr.args[0]), - cls.from_expr(expr.args[1])) + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1])) elif expr.is_associative() or expr.op in ["%", "/"]: - oper = ['(%s&0x%x)' % (cls.from_expr(arg), size2mask(arg.size)) + oper = ['(%s&0x%x)' % (self.from_expr(arg), size2mask(arg.size)) for arg in expr.args] oper = str(expr.op).join(oper) return "((%s)&0x%x)" % (oper, size2mask(expr.args[0].size)) elif expr.op in ['-']: return '(((%s&0x%x) %s (%s&0x%x))&0x%x)' % ( - cls.from_expr(expr.args[0]), size2mask(expr.args[0].size), + self.from_expr(expr.args[0]), size2mask(expr.args[0].size), str(expr.op), - cls.from_expr(expr.args[1]), size2mask(expr.args[1].size), + self.from_expr(expr.args[1]), size2mask(expr.args[1].size), size2mask(expr.args[0].size)) - elif expr.op in cls.dct_rot: - return '(%s(%s, %s, %s) &0x%x)' % (cls.dct_rot[expr.op], + elif expr.op in self.dct_rot: + return '(%s(%s, %s, %s) &0x%x)' % (self.dct_rot[expr.op], expr.args[0].size, - cls.from_expr(expr.args[0]), - cls.from_expr(expr.args[1]), + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1]), size2mask(expr.args[0].size)) elif (expr.op.startswith('cpuid') or expr.op.startswith("fcom") or expr.op in ["fadd", "fsub", "fdiv", 'fmul', "fscale"]): - return "%s(%s, %s)" % (expr.op, cls.from_expr(expr.args[0]), - cls.from_expr(expr.args[1])) + return "%s(%s, %s)" % (expr.op, self.from_expr(expr.args[0]), + self.from_expr(expr.args[1])) elif expr.op == "segm": return "segm2addr(vmcpu, %s, %s)" % ( - cls.from_expr(expr.args[0]), cls.from_expr(expr.args[1])) + self.from_expr(expr.args[0]), self.from_expr(expr.args[1])) elif expr.op in ['udiv', 'umod', 'idiv', 'imod']: return '%s%d(vmcpu, %s, %s)' % (expr.op, expr.args[0].size, - cls.from_expr(expr.args[0]), - cls.from_expr(expr.args[1])) + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1])) elif expr.op in ["bcdadd", "bcdadd_cf"]: return "%s_%d(%s, %s)" % (expr.op, expr.args[0].size, - cls.from_expr(expr.args[0]), - cls.from_expr(expr.args[1])) + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1])) else: raise NotImplementedError('Unknown op: %r' % expr.op) - elif len(expr.args) == 3 and expr.op in cls.dct_div: - return '(%s(%s, %s, %s, %s) &0x%x)' % (cls.dct_div[expr.op], + elif len(expr.args) == 3 and expr.op in self.dct_div: + return '(%s(%s, %s, %s, %s) &0x%x)' % (self.dct_div[expr.op], expr.args[0].size, - cls.from_expr(expr.args[0]), - cls.from_expr(expr.args[1]), - cls.from_expr(expr.args[2]), + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1]), + self.from_expr(expr.args[2]), size2mask(expr.args[0].size)) elif len(expr.args) >= 3 and expr.is_associative(): # ????? - oper = ['(%s&0x%x)' % (cls.from_expr(arg), size2mask(arg.size)) + oper = ['(%s&0x%x)' % (self.from_expr(arg), size2mask(arg.size)) for arg in expr.args] oper = str(expr.op).join(oper) return "((%s)&0x%x)" % (oper, size2mask(expr.args[0].size)) @@ -143,21 +137,19 @@ class TranslatorC(Translator): else: raise NotImplementedError('Unknown op: %s' % expr.op) - @classmethod - def from_ExprSlice(cls, expr): + def from_ExprSlice(self, expr): # XXX check mask for 64 bit & 32 bit compat - return "((%s>>%d) & 0x%X)" % (cls.from_expr(expr.arg), + return "((%s>>%d) & 0x%X)" % (self.from_expr(expr.arg), expr.start, (1 << (expr.stop - expr.start)) - 1) - @classmethod - def from_ExprCompose(cls, expr): + def from_ExprCompose(self, expr): out = [] # XXX check mask for 64 bit & 32 bit compat dst_cast = "uint%d_t" % expr.size for x in expr.args: out.append("(((%s)(%s & 0x%X)) << %d)" % (dst_cast, - cls.from_expr(x[0]), + self.from_expr(x[0]), (1 << (x[2] - x[1])) - 1, x[1])) out = ' | '.join(out) diff --git a/miasm2/ir/translators/miasm.py b/miasm2/ir/translators/miasm.py index 8f61fa96..004a1ba9 100644 --- a/miasm2/ir/translators/miasm.py +++ b/miasm2/ir/translators/miasm.py @@ -6,45 +6,37 @@ class TranslatorMiasm(Translator): __LANG__ = "Miasm" - @classmethod - def from_ExprId(cls, expr): + def from_ExprId(self, expr): return "ExprId(%s, size=%d)" % (repr(expr.name), expr.size) - @classmethod - def from_ExprInt(cls, expr): + def from_ExprInt(self, expr): return "ExprInt_fromsize(%d, 0x%x)" % (expr.size, int(expr.arg)) - @classmethod - def from_ExprCond(cls, expr): - return "ExprCond(%s, %s, %s)" % (cls.from_expr(expr.cond), - cls.from_expr(expr.src1), - cls.from_expr(expr.src2)) + def from_ExprCond(self, expr): + return "ExprCond(%s, %s, %s)" % (self.from_expr(expr.cond), + self.from_expr(expr.src1), + self.from_expr(expr.src2)) - @classmethod - def from_ExprSlice(cls, expr): - return "ExprSlice(%s, %d, %d)" % (cls.from_expr(expr.arg), + def from_ExprSlice(self, expr): + return "ExprSlice(%s, %d, %d)" % (self.from_expr(expr.arg), expr.start, expr.stop) - @classmethod - def from_ExprOp(cls, expr): + def from_ExprOp(self, expr): return "ExprOp(%s, %s)" % (repr(expr.op), - ", ".join(map(cls.from_expr, expr.args))) + ", ".join(map(self.from_expr, expr.args))) - @classmethod - def from_ExprCompose(cls, expr): - args = ["(%s, %d, %d)" % (cls.from_expr(arg), start, stop) + def from_ExprCompose(self, expr): + args = ["(%s, %d, %d)" % (self.from_expr(arg), start, stop) for arg, start, stop in expr.args] return "ExprCompose([%s])" % ", ".join(args) - @classmethod - def from_ExprAff(cls, expr): - return "ExprAff(%s, %s)" % (cls.from_expr(expr.dst), - cls.from_expr(expr.src)) + def from_ExprAff(self, expr): + return "ExprAff(%s, %s)" % (self.from_expr(expr.dst), + self.from_expr(expr.src)) - @classmethod - def from_ExprMem(cls, expr): - return "ExprMem(%s, size=%d)" % (cls.from_expr(expr.arg), expr.size) + def from_ExprMem(self, expr): + return "ExprMem(%s, size=%d)" % (self.from_expr(expr.arg), expr.size) # Register the class diff --git a/miasm2/ir/translators/python.py b/miasm2/ir/translators/python.py index c3386980..f745d2df 100644 --- a/miasm2/ir/translators/python.py +++ b/miasm2/ir/translators/python.py @@ -13,45 +13,38 @@ class TranslatorPython(Translator): # Operations translation op_no_translate = ["+", "-", "/", "%", ">>", "<<", "&", "^", "|", "*"] - @classmethod - def from_ExprInt(cls, expr): + def from_ExprInt(self, expr): return str(expr) - @classmethod - def from_ExprId(cls, expr): + def from_ExprId(self, expr): return str(expr) - @classmethod - def from_ExprMem(cls, expr): - return "memory(%s, 0x%x)" % (cls.from_expr(expr.arg), + def from_ExprMem(self, expr): + return "memory(%s, 0x%x)" % (self.from_expr(expr.arg), expr.size / 8) - @classmethod - def from_ExprSlice(cls, expr): - out = cls.from_expr(expr.arg) + def from_ExprSlice(self, expr): + out = self.from_expr(expr.arg) if expr.start != 0: out = "(%s >> %d)" % (out, expr.start) return "(%s & 0x%x)" % (out, (1 << (expr.stop - expr.start)) - 1) - @classmethod - def from_ExprCompose(cls, expr): + def from_ExprCompose(self, expr): out = [] for subexpr, start, stop in expr.args: - out.append("((%s & 0x%x) << %d)" % (cls.from_expr(subexpr), + out.append("((%s & 0x%x) << %d)" % (self.from_expr(subexpr), (1 << (stop - start)) - 1, start)) return "(%s)" % ' | '.join(out) - @classmethod - def from_ExprCond(cls, expr): - return "(%s if (%s) else %s)" % (cls.from_expr(expr.src1), - cls.from_expr(expr.cond), - cls.from_expr(expr.src2)) + def from_ExprCond(self, expr): + return "(%s if (%s) else %s)" % (self.from_expr(expr.src1), + self.from_expr(expr.cond), + self.from_expr(expr.src2)) - @classmethod - def from_ExprOp(cls, expr): - if expr.op in cls.op_no_translate: - args = map(cls.from_expr, expr.args) + def from_ExprOp(self, expr): + if expr.op in self.op_no_translate: + args = map(self.from_expr, expr.args) if len(expr.args) == 1: return "((%s %s) & 0x%x)" % (expr.op, args[0], @@ -60,13 +53,12 @@ class TranslatorPython(Translator): return "((%s) & 0x%x)" % ((" %s " % expr.op).join(args), (1 << expr.size) - 1) elif expr.op == "parity": - return "(%s & 0x1)" % cls.from_expr(expr.args[0]) + return "(%s & 0x1)" % self.from_expr(expr.args[0]) raise NotImplementedError("Unknown operator: %s" % expr.op) - @classmethod - def from_ExprAff(cls, expr): - return "%s = %s" % tuple(map(cls.from_expr, (expr.dst, expr.src))) + def from_ExprAff(self, expr): + return "%s = %s" % tuple(map(self.from_expr, (expr.dst, expr.src))) # Register the class diff --git a/miasm2/ir/translators/translator.py b/miasm2/ir/translators/translator.py index 2a971130..e3641843 100644 --- a/miasm2/ir/translators/translator.py +++ b/miasm2/ir/translators/translator.py @@ -1,4 +1,5 @@ import miasm2.expression.expression as m2_expr +from miasm2.core.utils import BoundedDict class Translator(object): @@ -17,15 +18,15 @@ class Translator(object): cls.available_translators.append(translator) @classmethod - def to_language(cls, target_lang): - """Return the corresponding translator + def to_language(cls, target_lang, *args, **kwargs): + """Return the corresponding translator instance @target_lang: str (case insensitive) wanted language Raise a NotImplementedError in case of unmatched language """ target_lang = target_lang.lower() for translator in cls.available_translators: if translator.__LANG__.lower() == target_lang: - return translator + return translator(*args, **kwargs) raise NotImplementedError("Unknown target language: %s" % target_lang) @@ -34,78 +35,83 @@ class Translator(object): "Return the list of registered languages" return [translator.__LANG__ for translator in cls.available_translators] - @classmethod - def from_ExprInt(cls, expr): + def __init__(self, cache_size=1000): + """Instance a translator + @cache_size: (optional) Expr cache size + """ + self._cache = BoundedDict(cache_size) + + def from_ExprInt(self, expr): """Translate an ExprInt @expr: ExprInt to translate """ raise NotImplementedError("Abstract method") - @classmethod - def from_ExprId(cls, expr): + def from_ExprId(self, expr): """Translate an ExprId @expr: ExprId to translate """ raise NotImplementedError("Abstract method") - @classmethod - def from_ExprCompose(cls, expr): + def from_ExprCompose(self, expr): """Translate an ExprCompose @expr: ExprCompose to translate """ raise NotImplementedError("Abstract method") - @classmethod - def from_ExprSlice(cls, expr): + def from_ExprSlice(self, expr): """Translate an ExprSlice @expr: ExprSlice to translate """ raise NotImplementedError("Abstract method") - @classmethod - def from_ExprOp(cls, expr): + def from_ExprOp(self, expr): """Translate an ExprOp @expr: ExprOp to translate """ raise NotImplementedError("Abstract method") - @classmethod - def from_ExprMem(cls, expr): + def from_ExprMem(self, expr): """Translate an ExprMem @expr: ExprMem to translate """ raise NotImplementedError("Abstract method") - @classmethod - def from_ExprAff(cls, expr): + def from_ExprAff(self, expr): """Translate an ExprAff @expr: ExprAff to translate """ raise NotImplementedError("Abstract method") - @classmethod - def from_ExprCond(cls, expr): + def from_ExprCond(self, expr): """Translate an ExprCond @expr: ExprCond to translate """ raise NotImplementedError("Abstract method") - @classmethod - def from_expr(cls, expr): + def from_expr(self, expr): """Translate an expression according to its type @expr: expression to translate """ - handlers = {m2_expr.ExprInt: cls.from_ExprInt, - m2_expr.ExprId: cls.from_ExprId, - m2_expr.ExprCompose: cls.from_ExprCompose, - m2_expr.ExprSlice: cls.from_ExprSlice, - m2_expr.ExprOp: cls.from_ExprOp, - m2_expr.ExprMem: cls.from_ExprMem, - m2_expr.ExprAff: cls.from_ExprAff, - m2_expr.ExprCond: cls.from_ExprCond + # Use cache + if expr in self._cache: + return self._cache[expr] + + # Handle Expr type + handlers = {m2_expr.ExprInt: self.from_ExprInt, + m2_expr.ExprId: self.from_ExprId, + m2_expr.ExprCompose: self.from_ExprCompose, + m2_expr.ExprSlice: self.from_ExprSlice, + m2_expr.ExprOp: self.from_ExprOp, + m2_expr.ExprMem: self.from_ExprMem, + m2_expr.ExprAff: self.from_ExprAff, + m2_expr.ExprCond: self.from_ExprCond } for target, handler in handlers.iteritems(): if isinstance(expr, target): - return handler(expr) + ## Compute value and update the internal cache + ret = handler(expr) + self._cache[expr] = ret + return ret raise ValueError("Unhandled type for %s" % expr) diff --git a/miasm2/ir/translators/z3_ir.py b/miasm2/ir/translators/z3_ir.py index 55713a23..d908ac5a 100644 --- a/miasm2/ir/translators/z3_ir.py +++ b/miasm2/ir/translators/z3_ir.py @@ -109,37 +109,37 @@ class TranslatorZ3(Translator): __LANG__ = "z3" # Operations translation trivial_ops = ["+", "-", "/", "%", "&", "^", "|", "*", "<<"] - _cache = None - _mem = None - @classmethod - def from_ExprInt(cls, expr): + def __init__(self, endianness="<", **kwargs): + """Instance a Z3 translator + @endianness: (optional) memory endianness + """ + super(TranslatorZ3, self).__init__(**kwargs) + self._mem = Z3Mem(endianness) + + def from_ExprInt(self, expr): return z3.BitVecVal(expr.arg.arg, expr.size) - @classmethod - def from_ExprId(cls, expr): + def from_ExprId(self, expr): if isinstance(expr.name, asm_label) and expr.name.offset is not None: return z3.BitVecVal(expr.name.offset, expr.size) else: return z3.BitVec(str(expr), expr.size) - @classmethod - def from_ExprMem(cls, expr): - addr = cls.from_expr(expr.arg) - return cls._mem.get(addr, expr.size) + def from_ExprMem(self, expr): + addr = self.from_expr(expr.arg) + return self._mem.get(addr, expr.size) - @classmethod - def from_ExprSlice(cls, expr): - res = cls.from_expr(expr.arg) + def from_ExprSlice(self, expr): + res = self.from_expr(expr.arg) res = z3.Extract(expr.stop-1, expr.start, res) return res - @classmethod - def from_ExprCompose(cls, expr): + def from_ExprCompose(self, expr): res = None args = sorted(expr.args, key=operator.itemgetter(2)) # sort by start off for subexpr, start, stop in args: - sube = cls.from_expr(subexpr) + sube = self.from_expr(subexpr) e = z3.Extract(stop-start-1, 0, sube) if res: res = z3.Concat(e, res) @@ -147,20 +147,19 @@ class TranslatorZ3(Translator): res = e return res - @classmethod - def from_ExprCond(cls, expr): - cond = cls.from_expr(expr.cond) - src1 = cls.from_expr(expr.src1) - src2 = cls.from_expr(expr.src2) + def from_ExprCond(self, expr): + cond = self.from_expr(expr.cond) + src1 = self.from_expr(expr.src1) + src2 = self.from_expr(expr.src2) return z3.If(cond != 0, src1, src2) - @classmethod - def from_ExprOp(cls, expr): - args = map(cls.from_expr, expr.args) + def from_ExprOp(self, expr): + args = map(self.from_expr, expr.args) res = args[0] + if len(args) > 1: for arg in args[1:]: - if expr.op in cls.trivial_ops: + if expr.op in self.trivial_ops: res = eval("res %s arg" % expr.op) elif expr.op == ">>": res = z3.LShR(res, arg) @@ -181,40 +180,14 @@ class TranslatorZ3(Translator): res = -res else: raise NotImplementedError("Unsupported OP yet: %s" % expr.op) + return res - @classmethod - def from_ExprAff(cls, expr): - src = cls.from_expr(expr.src) - dst = cls.from_expr(expr.dst) + def from_ExprAff(self, expr): + src = self.from_expr(expr.src) + dst = self.from_expr(expr.dst) return (src == dst) - @classmethod - def from_expr(cls, expr, endianness="<"): - # This mess is just to handle cache and Z3Mem instance management - # Might be improved in the future - del_cache = False - del_mem = False - if cls._cache is None: - cls._cache = {} - del_cache = True - if cls._mem is None: - cls._mem = Z3Mem(endianness) - del_mem = True - - try: - if expr in cls._cache: - return cls._cache[expr] - else: - ret = super(TranslatorZ3, cls).from_expr(expr) - cls._cache[expr] = ret - return ret - finally: - # Clean cache and Z3Mem if this call is the root call - if del_cache: - cls._cache = None - if del_mem: - cls._mem = None # Register the class Translator.register(TranslatorZ3) diff --git a/test/ir/ir2C.py b/test/ir/ir2C.py index 11b9b10e..48518c50 100644 --- a/test/ir/ir2C.py +++ b/test/ir/ir2C.py @@ -7,16 +7,17 @@ import unittest class TestIrIr2C(unittest.TestCase): def translationTest(self, expr, expected): - from miasm2.ir.translators.C import TranslatorC + from miasm2.ir.translators import Translator - self.assertEqual(TranslatorC.from_expr(expr), expected) + translator = Translator.to_language("C") + self.assertEqual(translator.from_expr(expr), expected) def test_ExprOp_toC(self): from miasm2.expression.expression import ExprInt32, ExprOp - from miasm2.ir.translators.C import TranslatorC + from miasm2.ir.translators.C import Translator args = [ExprInt32(i) for i in xrange(9)] - + translator = Translator.to_language("C") # Unary operators self.translationTest( @@ -26,7 +27,7 @@ class TestIrIr2C(unittest.TestCase): self.translationTest( ExprOp('hex2bcd', *args[:1]), r'hex2bcd_32(0x0)') self.translationTest(ExprOp('fabs', *args[:1]), r'fabs(0x0)') - self.assertRaises(NotImplementedError, TranslatorC.from_expr, + self.assertRaises(NotImplementedError, translator.from_expr, ExprOp('X', *args[:1])) # Binary operators @@ -50,7 +51,7 @@ class TestIrIr2C(unittest.TestCase): ExprOp('imod', *args[:2]), r'imod32(vmcpu, 0x0, 0x1)') self.translationTest( ExprOp('bcdadd', *args[:2]), r'bcdadd_32(0x0, 0x1)') - self.assertRaises(NotImplementedError, TranslatorC.from_expr, + self.assertRaises(NotImplementedError, translator.from_expr, ExprOp('X', *args[:2])) # Ternary operators @@ -60,7 +61,7 @@ class TestIrIr2C(unittest.TestCase): # Other cases self.translationTest( ExprOp('+', *args[:3]), r'(((0x0&0xffffffff)+(0x1&0xffffffff)+(0x2&0xffffffff))&0xffffffff)') - self.assertRaises(NotImplementedError, TranslatorC.from_expr, + self.assertRaises(NotImplementedError, translator.from_expr, ExprOp('X', *args[:3])) if __name__ == '__main__': diff --git a/test/ir/translators/z3_ir.py b/test/ir/translators/z3_ir.py index 6e483d61..a4fa7410 100644 --- a/test/ir/translators/z3_ir.py +++ b/test/ir/translators/z3_ir.py @@ -3,7 +3,7 @@ import z3 from miasm2.core.asmbloc import asm_label from miasm2.expression.expression import * from miasm2.ir.translators.translator import Translator -from miasm2.ir.translators.z3_ir import TranslatorZ3, Z3Mem +from miasm2.ir.translators.z3_ir import Z3Mem # Some examples of use/unit tests. @@ -98,7 +98,7 @@ check_interp(model[mem.get_mem_array(32)], [(0xdeadbeef, 2), (0xdeadbeef + 3, 0)]) # -------------------------------------------------------------------------- -ez3 = TranslatorZ3.from_expr(e4, endianness=">") +ez3 = Translator.to_language("z3", endianness=">").from_expr(e4) memb = Z3Mem(endianness=">") z3_emem = memb.get(z3.BitVecVal(0xdeadbeef, 32), 32) |