diff options
| author | Camille Mougey <commial@gmail.com> | 2016-11-07 12:24:51 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-11-07 12:24:51 +0100 |
| commit | 3af8c4a5a6668cc89a4df3fb66222f4147a896b9 (patch) | |
| tree | 21a7d7ad5d6da120e8e23e0b92725073d4d4e27c /miasm2/expression/expression.py | |
| parent | a15e0faca425c6e2591448e510bf14f1c3f04e14 (diff) | |
| parent | f0fbc59a663774dc4f4861308bee3f91ccd9746d (diff) | |
| download | miasm-3af8c4a5a6668cc89a4df3fb66222f4147a896b9.tar.gz miasm-3af8c4a5a6668cc89a4df3fb66222f4147a896b9.zip | |
Merge pull request #445 from serpilliere/symb_exec_clean
Symb exec clean
Diffstat (limited to 'miasm2/expression/expression.py')
| -rw-r--r-- | miasm2/expression/expression.py | 623 |
1 files changed, 341 insertions, 282 deletions
diff --git a/miasm2/expression/expression.py b/miasm2/expression/expression.py index d04530c3..324d5fea 100644 --- a/miasm2/expression/expression.py +++ b/miasm2/expression/expression.py @@ -114,28 +114,52 @@ class Expr(object): "Parent class for Miasm Expressions" - __slots__ = ["is_term", "is_simp", "is_canon", - "is_eval", "_hash", "_repr", "_size", - "is_var_ident"] + __slots__ = ["__hash", "__repr", "__size"] + all_exprs = set() + args2expr = {} + canon_exprs = set() + use_singleton = True def set_size(self, value): raise ValueError('size is not mutable') def __init__(self): - self.is_term = False # Terminal expression - self.is_simp = False # Expression already simplified - self.is_canon = False # Expression already canonised - self.is_eval = False # Expression already evalued - self.is_var_ident = False # Expression not identifier + self.__hash = None + self.__repr = None + self.__size = None - self._hash = None - self._repr = None + size = property(lambda self: self.__size) - size = property(lambda self: self._size) + @staticmethod + def get_object(cls, args): + if not cls.use_singleton: + return object.__new__(cls, args) + + expr = Expr.args2expr.get((cls, args)) + if expr is None: + expr = object.__new__(cls, args) + Expr.args2expr[(cls, args)] = expr + return expr + + def __new__(cls, *args, **kwargs): + expr = object.__new__(cls, *args, **kwargs) + return expr + + def get_is_canon(self): + return self in Expr.canon_exprs + + def set_is_canon(self, value): + assert(value is True) + Expr.canon_exprs.add(self) + + is_canon = property(get_is_canon, set_is_canon) # Common operations + def __str__(self): + raise NotImplementedError("Abstract Method") + def __getitem__(self, i): if not isinstance(i, slice): raise TypeError("Expression: Bad slice: %s" % i) @@ -153,14 +177,14 @@ class Expr(object): return False def __repr__(self): - if self._repr is None: - self._repr = self._exprrepr() - return self._repr + if self.__repr is None: + self.__repr = self._exprrepr() + return self.__repr def __hash__(self): - if self._hash is None: - self._hash = self._exprhash() - return self._hash + if self.__hash is None: + self.__hash = self._exprhash() + return self.__hash def pre_eq(self, other): """Return True if ids are equal; @@ -264,8 +288,6 @@ class Expr(object): new_e = ExprOp(e.op, *args) else: new_e = e - elif isinstance(e, ExprCompose): - new_e = ExprCompose(canonize_expr_list_compose(e.args)) else: new_e = e new_e.is_canon = True @@ -287,8 +309,7 @@ class Expr(object): return self ad_size = size - self.size n = ExprInt(0, ad_size) - return ExprCompose([(self, 0, self.size), - (n, self.size, size)]) + return ExprCompose(self, n) def signExtend(self, size): """Sign extend to size @@ -298,12 +319,10 @@ class Expr(object): if self.size == size: return self ad_size = size - self.size - c = ExprCompose([(self, 0, self.size), - (ExprCond(self.msb(), - ExprInt(size2mask(ad_size), ad_size), - ExprInt(0, ad_size)), - self.size, size) - ]) + c = ExprCompose(self, + ExprCond(self.msb(), + ExprInt(size2mask(ad_size), ad_size), + ExprInt(0, ad_size))) return c def graph_recursive(self, graph): @@ -341,7 +360,8 @@ class ExprInt(Expr): - Constant 0x12345678 on 32bits """ - __slots__ = ["_arg"] + __slots__ = Expr.__slots__ + ["__arg"] + def __init__(self, num, size=None): """Create an ExprInt from a modint or num/size @@ -351,31 +371,36 @@ class ExprInt(Expr): super(ExprInt, self).__init__() if is_modint(num): - self._arg = num - self._size = self.arg.size + self.__arg = num + self.__size = self.arg.size if size is not None and num.size != size: raise RuntimeError("size must match modint size") elif size is not None: - self._arg = mod_size2uint[size](num) - self._size = self.arg.size + self.__arg = mod_size2uint[size](num) + self.__size = self.arg.size else: raise ValueError('arg must by modint or (int,size)! %s' % num) - arg = property(lambda self: self._arg) + size = property(lambda self: self.__size) + arg = property(lambda self: self.__arg) - def __eq__(self, other): - res = self.pre_eq(other) - if res is not None: - return res - return (self._arg == other._arg and - self._size == other._size) + def __getstate__(self): + return int(self.__arg), self.__size + + def __setstate__(self, state): + self.__init__(*state) + + def __new__(cls, arg, size=None): + if size is None: + size = arg.size + return Expr.get_object(cls, (arg, size)) def __get_int(self): "Return self integer representation" - return int(self._arg & size2mask(self._size)) + return int(self.__arg & size2mask(self.__size)) def __str__(self): - if self._arg < 0: + if self.__arg < 0: return str("-0x%X" % (- self.__get_int())) else: return str("0x%X" % self.__get_int()) @@ -390,10 +415,10 @@ class ExprInt(Expr): return set() def _exprhash(self): - return hash((EXPRINT, self._arg, self._size)) + return hash((EXPRINT, self.__arg, self.__size)) def _exprrepr(self): - return "%s(%r)" % (self.__class__.__name__, self._arg) + return "%s(0x%X)" % (self.__class__.__name__, self.__get_int()) def __contains__(self, e): return self == e @@ -403,7 +428,7 @@ class ExprInt(Expr): return self def copy(self): - return ExprInt(self._arg) + return ExprInt(self.__arg) def depth(self): return 1 @@ -428,7 +453,7 @@ class ExprId(Expr): - variable v1 """ - __slots__ = ["_name"] + __slots__ = Expr.__slots__ + ["__name"] def __init__(self, name, size=32): """Create an identifier @@ -437,19 +462,22 @@ class ExprId(Expr): """ super(ExprId, self).__init__() - self._name, self._size = name, size + self.__name, self.__size = name, size - name = property(lambda self: self._name) + size = property(lambda self: self.__size) + name = property(lambda self: self.__name) - def __eq__(self, other): - res = self.pre_eq(other) - if res is not None: - return res - return (self._name == other._name and - self._size == other._size) + def __getstate__(self): + return self.__name, self.__size + + def __setstate__(self, state): + self.__init__(*state) + + def __new__(cls, name, size=32): + return Expr.get_object(cls, (name, size)) def __str__(self): - return str(self._name) + return str(self.__name) def get_r(self, mem_read=False, cst_read=False): return set([self]) @@ -459,10 +487,10 @@ class ExprId(Expr): def _exprhash(self): # TODO XXX: hash size ?? - return hash((EXPRID, self._name, self._size)) + return hash((EXPRID, self.__name, self.__size)) def _exprrepr(self): - return "%s(%r, %d)" % (self.__class__.__name__, self._name, self._size) + return "%s(%r, %d)" % (self.__class__.__name__, self.__name, self.__size) def __contains__(self, e): return self == e @@ -472,7 +500,7 @@ class ExprId(Expr): return self def copy(self): - return ExprId(self._name, self._size) + return ExprId(self.__name, self.__size) def depth(self): return 1 @@ -489,7 +517,7 @@ class ExprAff(Expr): - var1 <- 2 """ - __slots__ = ["_src", "_dst"] + __slots__ = Expr.__slots__ + ["__dst", "__src"] def __init__(self, dst, src): """Create an ExprAff for dst <- src @@ -506,80 +534,75 @@ class ExprAff(Expr): if isinstance(dst, ExprSlice): # Complete the source with missing slice parts - self._dst = dst.arg + self.__dst = dst.arg rest = [(ExprSlice(dst.arg, r[0], r[1]), r[0], r[1]) for r in dst.slice_rest()] all_a = [(src, dst.start, dst.stop)] + rest all_a.sort(key=lambda x: x[1]) - self._src = ExprCompose(all_a) + args = [expr for (expr, _, _) in all_a] + self.__src = ExprCompose(*args) else: - self._dst, self._src = dst, src + self.__dst, self.__src = dst, src + + self.__size = self.dst.size - self._size = self.dst.size + size = property(lambda self: self.__size) + dst = property(lambda self: self.__dst) + src = property(lambda self: self.__src) - dst = property(lambda self: self._dst) - src = property(lambda self: self._src) + def __getstate__(self): + return self.__dst, self.__src + + def __setstate__(self, state): + self.__init__(*state) + + def __new__(cls, dst, src): + return Expr.get_object(cls, (dst, src)) def __str__(self): - return "%s = %s" % (str(self._dst), str(self._src)) + return "%s = %s" % (str(self.__dst), str(self.__src)) def get_r(self, mem_read=False, cst_read=False): - elements = self._src.get_r(mem_read, cst_read) - if isinstance(self._dst, ExprMem) and mem_read: - elements.update(self._dst.arg.get_r(mem_read, cst_read)) + elements = self.__src.get_r(mem_read, cst_read) + if isinstance(self.__dst, ExprMem) and mem_read: + elements.update(self.__dst.arg.get_r(mem_read, cst_read)) return elements def get_w(self): - if isinstance(self._dst, ExprMem): - return set([self._dst]) # [memreg] + if isinstance(self.__dst, ExprMem): + return set([self.__dst]) # [memreg] else: - return self._dst.get_w() + return self.__dst.get_w() def _exprhash(self): - return hash((EXPRAFF, hash(self._dst), hash(self._src))) + return hash((EXPRAFF, hash(self.__dst), hash(self.__src))) def _exprrepr(self): - return "%s(%r, %r)" % (self.__class__.__name__, self._dst, self._src) + return "%s(%r, %r)" % (self.__class__.__name__, self.__dst, self.__src) - def __contains__(self, e): - return self == e or self._src.__contains__(e) or self._dst.__contains__(e) - - # XXX /!\ for hackish expraff to slice - def get_modified_slice(self): - """Return an Expr list of extra expressions needed during the - object instanciation""" - - dst = self._dst - if not isinstance(self._src, ExprCompose): - raise ValueError("Get mod slice not on expraff slice", str(self)) - modified_s = [] - for arg in self._src.args: - if (not isinstance(arg[0], ExprSlice) or - arg[0].arg != dst or - arg[1] != arg[0].start or - arg[2] != arg[0].stop): - # If x is not the initial expression - modified_s.append(arg) - return modified_s + def __contains__(self, expr): + return (self == expr or + self.__src.__contains__(expr) or + self.__dst.__contains__(expr)) @visit_chk def visit(self, cb, tv=None): - dst, src = self._dst.visit(cb, tv), self._src.visit(cb, tv) - if dst == self._dst and src == self._src: + dst, src = self.__dst.visit(cb, tv), self.__src.visit(cb, tv) + if dst == self.__dst and src == self.__src: return self else: return ExprAff(dst, src) def copy(self): - return ExprAff(self._dst.copy(), self._src.copy()) + return ExprAff(self.__dst.copy(), self.__src.copy()) def depth(self): - return max(self._src.depth(), self._dst.depth()) + 1 + return max(self.__src.depth(), self.__dst.depth()) + 1 def graph_recursive(self, graph): graph.add_node(self) - for arg in [self._src, self._dst]: + for arg in [self.__src, self.__dst]: arg.graph_recursive(graph) graph.add_uniq_edge(self, arg) @@ -594,7 +617,7 @@ class ExprCond(Expr): - if (cond) then ... else ... """ - __slots__ = ["_cond", "_src1", "_src2"] + __slots__ = Expr.__slots__ + ["__cond", "__src1", "__src2"] def __init__(self, cond, src1, src2): """Create an ExprCond @@ -605,65 +628,74 @@ class ExprCond(Expr): super(ExprCond, self).__init__() + self.__cond, self.__src1, self.__src2 = cond, src1, src2 assert(src1.size == src2.size) + self.__size = self.src1.size - self._cond, self._src1, self._src2 = cond, src1, src2 - self._size = self.src1.size + size = property(lambda self: self.__size) + cond = property(lambda self: self.__cond) + src1 = property(lambda self: self.__src1) + src2 = property(lambda self: self.__src2) - cond = property(lambda self: self._cond) - src1 = property(lambda self: self._src1) - src2 = property(lambda self: self._src2) + def __getstate__(self): + return self.__cond, self.__src1, self.__src2 + + def __setstate__(self, state): + self.__init__(*state) + + def __new__(cls, cond, src1, src2): + return Expr.get_object(cls, (cond, src1, src2)) def __str__(self): - return "(%s?(%s,%s))" % (str(self._cond), str(self._src1), str(self._src2)) + return "(%s?(%s,%s))" % (str(self.__cond), str(self.__src1), str(self.__src2)) def get_r(self, mem_read=False, cst_read=False): - out_src1 = self._src1.get_r(mem_read, cst_read) - out_src2 = self._src2.get_r(mem_read, cst_read) - return self._cond.get_r(mem_read, - cst_read).union(out_src1).union(out_src2) + out_src1 = self.src1.get_r(mem_read, cst_read) + out_src2 = self.src2.get_r(mem_read, cst_read) + return self.cond.get_r(mem_read, + cst_read).union(out_src1).union(out_src2) def get_w(self): return set() def _exprhash(self): return hash((EXPRCOND, hash(self.cond), - hash(self._src1), hash(self._src2))) + hash(self.__src1), hash(self.__src2))) def _exprrepr(self): return "%s(%r, %r, %r)" % (self.__class__.__name__, - self._cond, self._src1, self._src2) + self.__cond, self.__src1, self.__src2) def __contains__(self, e): return (self == e or - self._cond.__contains__(e) or - self._src1.__contains__(e) or - self._src2.__contains__(e)) + self.cond.__contains__(e) or + self.src1.__contains__(e) or + self.src2.__contains__(e)) @visit_chk def visit(self, cb, tv=None): - cond = self._cond.visit(cb, tv) - src1 = self._src1.visit(cb, tv) - src2 = self._src2.visit(cb, tv) - if (cond == self._cond and - src1 == self._src1 and - src2 == self._src2): + cond = self.__cond.visit(cb, tv) + src1 = self.__src1.visit(cb, tv) + src2 = self.__src2.visit(cb, tv) + if (cond == self.__cond and + src1 == self.__src1 and + src2 == self.__src2): return self return ExprCond(cond, src1, src2) def copy(self): - return ExprCond(self._cond.copy(), - self._src1.copy(), - self._src2.copy()) + return ExprCond(self.__cond.copy(), + self.__src1.copy(), + self.__src2.copy()) def depth(self): - return max(self._cond.depth(), - self._src1.depth(), - self._src2.depth()) + 1 + return max(self.__cond.depth(), + self.__src1.depth(), + self.__src2.depth()) + 1 def graph_recursive(self, graph): graph.add_node(self) - for arg in [self._cond, self._src1, self._src2]: + for arg in [self.__cond, self.__src1, self.__src2]: arg.graph_recursive(graph) graph.add_uniq_edge(self, arg) @@ -677,7 +709,7 @@ class ExprMem(Expr): - Memory write """ - __slots__ = ["_arg", "_size"] + __slots__ = Expr.__slots__ + ["__arg"] def __init__(self, arg, size=32): """Create an ExprMem @@ -691,16 +723,26 @@ class ExprMem(Expr): raise ValueError( 'ExprMem: arg must be an Expr (not %s)' % type(arg)) - self._arg, self._size = arg, size + self.__arg, self.__size = arg, size + + size = property(lambda self: self.__size) + arg = property(lambda self: self.__arg) - arg = property(lambda self: self._arg) + def __getstate__(self): + return self.__arg, self.__size + + def __setstate__(self, state): + self.__init__(*state) + + def __new__(cls, arg, size=32): + return Expr.get_object(cls, (arg, size)) def __str__(self): - return "@%d[%s]" % (self._size, str(self._arg)) + return "@%d[%s]" % (self.size, str(self.arg)) def get_r(self, mem_read=False, cst_read=False): if mem_read: - return set(self._arg.get_r(mem_read, cst_read).union(set([self]))) + return set(self.__arg.get_r(mem_read, cst_read).union(set([self]))) else: return set([self]) @@ -708,36 +750,36 @@ class ExprMem(Expr): return set([self]) # [memreg] def _exprhash(self): - return hash((EXPRMEM, hash(self._arg), self._size)) + return hash((EXPRMEM, hash(self.__arg), self.__size)) def _exprrepr(self): return "%s(%r, %r)" % (self.__class__.__name__, - self._arg, self._size) + self.__arg, self.__size) - def __contains__(self, e): - return self == e or self._arg.__contains__(e) + def __contains__(self, expr): + return self == expr or self.__arg.__contains__(expr) @visit_chk def visit(self, cb, tv=None): - arg = self._arg.visit(cb, tv) - if arg == self._arg: + arg = self.__arg.visit(cb, tv) + if arg == self.__arg: return self - return ExprMem(arg, self._size) + return ExprMem(arg, self.size) def copy(self): - arg = self._arg.copy() - return ExprMem(arg, size=self._size) + arg = self.arg.copy() + return ExprMem(arg, size=self.size) def is_op_segm(self): - return isinstance(self._arg, ExprOp) and self._arg.op == 'segm' + return isinstance(self.__arg, ExprOp) and self.__arg.op == 'segm' def depth(self): - return self._arg.depth() + 1 + return self.__arg.depth() + 1 def graph_recursive(self, graph): graph.add_node(self) - self._arg.graph_recursive(graph) - graph.add_uniq_edge(self, self._arg) + self.__arg.graph_recursive(graph) + graph.add_uniq_edge(self, self.__arg) class ExprOp(Expr): @@ -750,7 +792,7 @@ class ExprOp(Expr): - parity bit(var1) """ - __slots__ = ["_op", "_args"] + __slots__ = Expr.__slots__ + ["__op", "__args"] def __init__(self, op, *args): """Create an ExprOp @@ -772,44 +814,44 @@ class ExprOp(Expr): if not isinstance(op, str): raise ValueError("ExprOp: 'op' argument must be a string") - self._op, self._args = op, tuple(args) + self.__op, self.__args = op, tuple(args) # Set size for special cases - if self._op in [ + if self.__op in [ '==', 'parity', 'fcom_c0', 'fcom_c1', 'fcom_c2', 'fcom_c3', 'fxam_c0', 'fxam_c1', 'fxam_c2', 'fxam_c3', "access_segment_ok", "load_segment_limit_ok", "bcdadd_cf", "ucomiss_zf", "ucomiss_pf", "ucomiss_cf"]: sz = 1 - elif self._op in [TOK_INF, TOK_INF_SIGNED, - TOK_INF_UNSIGNED, TOK_INF_EQUAL, - TOK_INF_EQUAL_SIGNED, TOK_INF_EQUAL_UNSIGNED, - TOK_EQUAL, TOK_POS, - TOK_POS_STRICT, - ]: + elif self.__op in [TOK_INF, TOK_INF_SIGNED, + TOK_INF_UNSIGNED, TOK_INF_EQUAL, + TOK_INF_EQUAL_SIGNED, TOK_INF_EQUAL_UNSIGNED, + TOK_EQUAL, TOK_POS, + TOK_POS_STRICT, + ]: sz = 1 - elif self._op in ['mem_16_to_double', 'mem_32_to_double', - 'mem_64_to_double', 'mem_80_to_double', - 'int_16_to_double', 'int_32_to_double', - 'int_64_to_double', 'int_80_to_double']: + elif self.__op in ['mem_16_to_double', 'mem_32_to_double', + 'mem_64_to_double', 'mem_80_to_double', + 'int_16_to_double', 'int_32_to_double', + 'int_64_to_double', 'int_80_to_double']: sz = 64 - elif self._op in ['double_to_mem_16', 'double_to_int_16', - 'float_trunc_to_int_16', 'double_trunc_to_int_16']: + elif self.__op in ['double_to_mem_16', 'double_to_int_16', + 'float_trunc_to_int_16', 'double_trunc_to_int_16']: sz = 16 - elif self._op in ['double_to_mem_32', 'double_to_int_32', - 'float_trunc_to_int_32', 'double_trunc_to_int_32', - 'double_to_float']: + elif self.__op in ['double_to_mem_32', 'double_to_int_32', + 'float_trunc_to_int_32', 'double_trunc_to_int_32', + 'double_to_float']: sz = 32 - elif self._op in ['double_to_mem_64', 'double_to_int_64', - 'float_trunc_to_int_64', 'double_trunc_to_int_64', - 'float_to_double']: + elif self.__op in ['double_to_mem_64', 'double_to_int_64', + 'float_trunc_to_int_64', 'double_trunc_to_int_64', + 'float_to_double']: sz = 64 - elif self._op in ['double_to_mem_80', 'double_to_int_80', - 'float_trunc_to_int_80', - 'double_trunc_to_int_80']: + elif self.__op in ['double_to_mem_80', 'double_to_int_80', + 'float_trunc_to_int_80', + 'double_trunc_to_int_80']: sz = 80 - elif self._op in ['segm']: - sz = self._args[1].size + elif self.__op in ['segm']: + sz = self.__args[1].size else: if None in sizes: sz = None @@ -817,256 +859,275 @@ class ExprOp(Expr): # All arguments have the same size sz = list(sizes)[0] - self._size = sz + self.__size = sz - op = property(lambda self: self._op) - args = property(lambda self: self._args) + size = property(lambda self: self.__size) + op = property(lambda self: self.__op) + args = property(lambda self: self.__args) + + def __getstate__(self): + return self.__op, self.__args + + def __setstate__(self, state): + op, args = state + self.__init__(op, *args) + + def __new__(cls, op, *args): + return Expr.get_object(cls, (op, args)) def __str__(self): if self.is_associative(): - return '(' + self._op.join([str(arg) for arg in self._args]) + ')' - if (self._op.startswith('call_func_') or - self._op == 'cpuid' or - len(self._args) > 2 or - self._op in ['parity', 'segm']): - return self._op + '(' + ', '.join([str(arg) for arg in self._args]) + ')' - if len(self._args) == 2: - return ('(' + str(self._args[0]) + - ' ' + self.op + ' ' + str(self._args[1]) + ')') + return '(' + self.__op.join([str(arg) for arg in self.__args]) + ')' + if (self.__op.startswith('call_func_') or + self.__op == 'cpuid' or + len(self.__args) > 2 or + self.__op in ['parity', 'segm']): + return self.__op + '(' + ', '.join([str(arg) for arg in self.__args]) + ')' + if len(self.__args) == 2: + return ('(' + str(self.__args[0]) + + ' ' + self.op + ' ' + str(self.__args[1]) + ')') else: return reduce(lambda x, y: x + ' ' + str(y), - self._args, - '(' + str(self._op)) + ')' + self.__args, + '(' + str(self.__op)) + ')' def get_r(self, mem_read=False, cst_read=False): return reduce(lambda elements, arg: - elements.union(arg.get_r(mem_read, cst_read)), self._args, set()) + elements.union(arg.get_r(mem_read, cst_read)), self.__args, set()) def get_w(self): raise ValueError('op cannot be written!', self) def _exprhash(self): - h_hargs = [hash(arg) for arg in self._args] - return hash((EXPROP, self._op, tuple(h_hargs))) + h_hargs = [hash(arg) for arg in self.__args] + return hash((EXPROP, self.__op, tuple(h_hargs))) def _exprrepr(self): - return "%s(%r, %s)" % (self.__class__.__name__, self._op, - ', '.join(repr(arg) for arg in self._args)) + return "%s(%r, %s)" % (self.__class__.__name__, self.__op, + ', '.join(repr(arg) for arg in self.__args)) def __contains__(self, e): if self == e: return True - for arg in self._args: + for arg in self.__args: if arg.__contains__(e): return True return False def is_function_call(self): - return self._op.startswith('call') + return self.__op.startswith('call') def is_associative(self): "Return True iff current operation is associative" - return (self._op in ['+', '*', '^', '&', '|']) + return (self.__op in ['+', '*', '^', '&', '|']) def is_commutative(self): "Return True iff current operation is commutative" - return (self._op in ['+', '*', '^', '&', '|']) + return (self.__op in ['+', '*', '^', '&', '|']) @visit_chk def visit(self, cb, tv=None): - args = [arg.visit(cb, tv) for arg in self._args] - modified = any([arg[0] != arg[1] for arg in zip(self._args, args)]) + args = [arg.visit(cb, tv) for arg in self.__args] + modified = any([arg[0] != arg[1] for arg in zip(self.__args, args)]) if modified: - return ExprOp(self._op, *args) + return ExprOp(self.__op, *args) return self def copy(self): - args = [arg.copy() for arg in self._args] - return ExprOp(self._op, *args) + args = [arg.copy() for arg in self.__args] + return ExprOp(self.__op, *args) def depth(self): - depth = [arg.depth() for arg in self._args] + depth = [arg.depth() for arg in self.__args] return max(depth) + 1 def graph_recursive(self, graph): graph.add_node(self) - for arg in self._args: + for arg in self.__args: arg.graph_recursive(graph) graph.add_uniq_edge(self, arg) class ExprSlice(Expr): - __slots__ = ["_arg", "_start", "_stop"] + __slots__ = Expr.__slots__ + ["__arg", "__start", "__stop"] def __init__(self, arg, start, stop): super(ExprSlice, self).__init__() assert(start < stop) + self.__arg, self.__start, self.__stop = arg, start, stop + self.__size = self.__stop - self.__start - self._arg, self._start, self._stop = arg, start, stop - self._size = self._stop - self._start + size = property(lambda self: self.__size) + arg = property(lambda self: self.__arg) + start = property(lambda self: self.__start) + stop = property(lambda self: self.__stop) - arg = property(lambda self: self._arg) - start = property(lambda self: self._start) - stop = property(lambda self: self._stop) + def __getstate__(self): + return self.__arg, self.__start, self.__stop + + def __setstate__(self, state): + self.__init__(*state) + + def __new__(cls, arg, start, stop): + return Expr.get_object(cls, (arg, start, stop)) def __str__(self): - return "%s[%d:%d]" % (str(self._arg), self._start, self._stop) + return "%s[%d:%d]" % (str(self.__arg), self.__start, self.__stop) def get_r(self, mem_read=False, cst_read=False): - return self._arg.get_r(mem_read, cst_read) + return self.__arg.get_r(mem_read, cst_read) def get_w(self): - return self._arg.get_w() + return self.__arg.get_w() def _exprhash(self): - return hash((EXPRSLICE, hash(self._arg), self._start, self._stop)) + return hash((EXPRSLICE, hash(self.__arg), self.__start, self.__stop)) def _exprrepr(self): - return "%s(%r, %d, %d)" % (self.__class__.__name__, self._arg, - self._start, self._stop) + return "%s(%r, %d, %d)" % (self.__class__.__name__, self.__arg, + self.__start, self.__stop) - def __contains__(self, e): - if self == e: + def __contains__(self, expr): + if self == expr: return True - return self._arg.__contains__(e) + return self.__arg.__contains__(expr) @visit_chk def visit(self, cb, tv=None): - arg = self._arg.visit(cb, tv) - if arg == self._arg: + arg = self.__arg.visit(cb, tv) + if arg == self.__arg: return self - return ExprSlice(arg, self._start, self._stop) + return ExprSlice(arg, self.__start, self.__stop) def copy(self): - return ExprSlice(self._arg.copy(), self._start, self._stop) + return ExprSlice(self.__arg.copy(), self.__start, self.__stop) def depth(self): - return self._arg.depth() + 1 + return self.__arg.depth() + 1 def slice_rest(self): "Return the completion of the current slice" - size = self._arg.size - if self._start >= size or self._stop > size: + size = self.__arg.size + if self.__start >= size or self.__stop > size: raise ValueError('bad slice rest %s %s %s' % - (size, self._start, self._stop)) + (size, self.__start, self.__stop)) - if self._start == self._stop: + if self.__start == self.__stop: return [(0, size)] rest = [] - if self._start != 0: - rest.append((0, self._start)) - if self._stop < size: - rest.append((self._stop, size)) + if self.__start != 0: + rest.append((0, self.__start)) + if self.__stop < size: + rest.append((self.__stop, size)) return rest def graph_recursive(self, graph): graph.add_node(self) - self._arg.graph_recursive(graph) - graph.add_uniq_edge(self, self._arg) + self.__arg.graph_recursive(graph) + graph.add_uniq_edge(self, self.__arg) class ExprCompose(Expr): """ - Compose is like a hambuger. - It's arguments are tuple of: (Expression, start, stop) - start and stop are intergers, determining Expression position in the compose. - - Burger Example: - ExprCompose([(salad, 0, 3), (cheese, 3, 10), (beacon, 10, 16)]) - In the example, salad.size == 3. + Compose is like a hambuger. It concatenate Expressions """ - __slots__ = ["_args"] + __slots__ = Expr.__slots__ + ["__args"] - def __init__(self, args): + def __init__(self, *args): """Create an ExprCompose The ExprCompose is contiguous and starts at 0 - @args: tuple(Expr, int, int) + @args: [Expr, Expr, ...] + DEPRECATED: + @args: [(Expr, int, int), (Expr, int, int), ...] """ super(ExprCompose, self).__init__() - last_stop = 0 - args = sorted(args, key=itemgetter(1)) - for e, start, stop in args: - if e.size != stop - start: - raise ValueError( - "sanitycheck: ExprCompose args must have correct size!" + - " %r %r %r" % (e, e.size, stop - start)) - if last_stop != start: - raise ValueError( - "sanitycheck: ExprCompose args must be contiguous!" + - " %r" % (args)) - last_stop = stop + is_new_style = args and isinstance(args[0], Expr) + if not is_new_style: + warnings.warn('DEPRECATION WARNING: use "ExprCompose(a, b) instead of'+ + 'ExprCemul_ir_block(self, addr, step=False)" instead of emul_ir_bloc') + + self.__args = tuple(args) + self.__size = sum([arg.size for arg in args]) + + size = property(lambda self: self.__size) + args = property(lambda self: self.__args) - # Transform args to lists - o = [] - for e, a, b in args: - assert(a >= 0 and b >= 0) - o.append(tuple([e, a, b])) - self._args = tuple(o) + def __getstate__(self): + return self.__args - self._size = self._args[-1][2] + def __setstate__(self, state): + self.__init__(state) - args = property(lambda self: self._args) + def __new__(cls, *args): + is_new_style = args and isinstance(args[0], Expr) + if not is_new_style: + assert len(args) == 1 + args = args[0] + return Expr.get_object(cls, tuple(args)) def __str__(self): - return '{' + ', '.join(['%s,%d,%d' % - (str(arg[0]), arg[1], arg[2]) for arg in self._args]) + '}' + return '{' + ', '.join([str(arg) for arg in self.__args]) + '}' def get_r(self, mem_read=False, cst_read=False): return reduce(lambda elements, arg: - elements.union(arg[0].get_r(mem_read, cst_read)), self._args, set()) + elements.union(arg.get_r(mem_read, cst_read)), self.__args, set()) def get_w(self): return reduce(lambda elements, arg: - elements.union(arg[0].get_w()), self._args, set()) + elements.union(arg.get_w()), self.__args, set()) def _exprhash(self): - h_args = [EXPRCOMPOSE] + [(hash(arg[0]), arg[1], arg[2]) - for arg in self._args] + h_args = [EXPRCOMPOSE] + [hash(arg) for arg in self.__args] return hash(tuple(h_args)) def _exprrepr(self): - return "%s(%r)" % (self.__class__.__name__, self._args) + return "%s([%r])" % (self.__class__.__name__, self.__args) def __contains__(self, e): if self == e: return True - for arg in self._args: + for arg in self.__args: if arg == e: return True - if arg[0].__contains__(e): + if arg.__contains__(e): return True return False @visit_chk def visit(self, cb, tv=None): - args = [(arg[0].visit(cb, tv), arg[1], arg[2]) for arg in self._args] - modified = any([arg[0] != arg[1] for arg in zip(self._args, args)]) + args = [arg.visit(cb, tv) for arg in self.__args] + modified = any([arg != arg_new for arg, arg_new in zip(self.__args, args)]) if modified: - return ExprCompose(args) + return ExprCompose(*args) return self def copy(self): - args = [(arg[0].copy(), arg[1], arg[2]) for arg in self._args] - return ExprCompose(args) + args = [arg.copy() for arg in self.__args] + return ExprCompose(*args) def depth(self): - depth = [arg[0].depth() for arg in self._args] + depth = [arg.depth() for arg in self.__args] return max(depth) + 1 def graph_recursive(self, graph): graph.add_node(self) for arg in self.args: - arg[0].graph_recursive(graph) - graph.add_uniq_edge(self, arg[0]) + arg.graph_recursive(graph) + graph.add_uniq_edge(self, arg) + def iter_args(self): + index = 0 + for arg in self.__args: + yield index, arg + index += arg.size # Expression order for comparaison expr_order_dict = {ExprId: 1, @@ -1094,7 +1155,7 @@ def compare_exprs_compose(e1, e2): def compare_expr_list_compose(l1_e, l2_e): # Sort by list elements in incremental order, then by list size for i in xrange(min(len(l1_e), len(l2_e))): - x = compare_exprs_compose(l1_e[i], l2_e[i]) + x = compare_exprs(l1_e[i], l2_e[i]) if x: return x return cmp(len(l1_e), len(l2_e)) @@ -1325,9 +1386,7 @@ def MatchExpr(e, m, tks, result=None): if not isinstance(m, ExprCompose): return False for a1, a2 in zip(e.args, m.args): - if a1[1] != a2[1] or a1[2] != a2[2]: - return False - r = MatchExpr(a1[0], a2[0], tks, result) + r = MatchExpr(a1, a2, tks, result) if r is False: return False return result |