about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--miasm2/expression/expression.py225
1 files changed, 137 insertions, 88 deletions
diff --git a/miasm2/expression/expression.py b/miasm2/expression/expression.py
index 74d67b5d..a9fafe5e 100644
--- a/miasm2/expression/expression.py
+++ b/miasm2/expression/expression.py
@@ -32,6 +32,27 @@ import itertools
 from miasm2.expression.modint import *
 from miasm2.core.graph import DiGraph
 
+# Define tokens
+TOK_INF = "<"
+TOK_INF_SIGNED = TOK_INF + "s"
+TOK_INF_UNSIGNED = TOK_INF + "u"
+TOK_INF_EQUAL = "<="
+TOK_INF_EQUAL_SIGNED = TOK_INF_EQUAL + "s"
+TOK_INF_EQUAL_UNSIGNED = TOK_INF_EQUAL + "u"
+TOK_EQUAL = "=="
+TOK_POS = "pos"
+TOK_POS_STRICT = "Spos"
+
+# Hashing constants
+EXPRINT = 1
+EXPRID = 2
+EXPRAFF = 3
+EXPRCOND = 4
+EXPRMEM = 5
+EXPROP = 6
+EXPRSLICE = 5
+EXPRCOMPOSE = 5
+
 
 def visit_chk(visitor):
     "Function decorator launching callback on Expression visit"
@@ -45,15 +66,6 @@ def visit_chk(visitor):
         return e_new2
     return wrapped
 
-# Hashing constants
-EXPRINT = 1
-EXPRID = 2
-EXPRAFF = 3
-EXPRCOND = 4
-EXPRMEM = 5
-EXPROP = 6
-EXPRSLICE = 5
-EXPRCOMPOSE = 5
 
 # Expression display
 
@@ -108,12 +120,12 @@ class Expr(object):
 
     def set_size(self, value):
         raise ValueError('size is not mutable')
-    size = property(lambda self: self._size)
 
     def __init__(self, arg):
         self.arg = arg
 
     # Common operations
+
     def __str__(self):
         return str(self.arg)
 
@@ -201,17 +213,17 @@ class Expr(object):
             if e in dct:
                 return dct[e]
             return e
+
         return self.visit(lambda e: my_replace(e, dct))
 
     def canonize(self):
         "Canonize the Expression"
 
         def must_canon(e):
-            # print 'test VISIT', e
-            return not e.is_simp
+            return not e.is_canon
 
-        def my_canon(e):
-            if e.is_simp:
+        def canonize_visitor(e):
+            if e.is_canon:
                 return e
             if isinstance(e, ExprOp):
                 if e.is_associative():
@@ -230,8 +242,10 @@ class Expr(object):
                 new_e = ExprCompose(canonize_expr_list_compose(e.args))
             else:
                 new_e = e
+            new_e.is_canon = True
             return new_e
-        return self.visit(my_canon, must_canon)
+
+        return self.visit(canonize_visitor, must_canon)
 
     def msb(self):
         "Return the Most Significant Bit"
@@ -288,6 +302,7 @@ class Expr(object):
 
     def set_mask(self, value):
         raise ValueError('mask is not mutable')
+
     mask = property(lambda self: ExprInt_fromsize(self.size, -1))
 
 
@@ -308,9 +323,12 @@ class ExprInt(Expr):
         if not is_modint(arg):
             raise ValueError('arg must by numpy int! %s' % arg)
 
-        self.arg = arg
-        self._size = self.arg.size
-        self._hash = self.myhash()
+        self.__arg = arg
+        self.__size = self.arg.size
+        self._hash = self.exprhash()
+
+    size = property(lambda self: self.__size)
+    arg = property(lambda self: self.__arg)
 
     def __get_int(self):
         "Return self integer representation"
@@ -331,12 +349,12 @@ class ExprInt(Expr):
     def get_w(self):
         return set()
 
+    def exprhash(self):
+        return hash((EXPRINT, self.arg, self.size))
+
     def __contains__(self, e):
         return self == e
 
-    def myhash(self):
-        return hash((EXPRINT, self.arg, self.size))
-
     def __repr__(self):
         return Expr.__repr__(self)[:-1] + " 0x%X>" % self.__get_int()
 
@@ -364,16 +382,17 @@ class ExprId(Expr):
      - variable v1
      """
 
-    def __init__(self, name, size=32, is_term=False):
+    def __init__(self, name, size=32):
         """Create an identifier
         @name: str, identifier's name
         @size: int, identifier's size
-        @is_term: boolean, is the identifier a terminal expression ?
         """
 
-        self.name, self._size = name, size
-        self.is_term = is_term
-        self._hash = self.myhash()
+        self.__name, self.__size = name, size
+        self._hash = self.exprhash()
+
+    size = property(lambda self: self.__size)
+    name = property(lambda self: self.__name)
 
     def __str__(self):
         return str(self.name)
@@ -384,13 +403,13 @@ class ExprId(Expr):
     def get_w(self):
         return set([self])
 
+    def exprhash(self):
+        # TODO XXX: hash size ??
+        return hash((EXPRID, self.name, self.__size))
+
     def __contains__(self, e):
         return self == e
 
-    def myhash(self):
-        # TODO XXX: hash size ??
-        return hash((EXPRID, self.name, self._size))
-
     def __repr__(self):
         return Expr.__repr__(self)[:-1] + " %s>" % self.name
 
@@ -399,7 +418,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
@@ -421,7 +440,6 @@ class ExprAff(Expr):
         @dst: Expr, affectation destination
         @src: Expr, affectation source
         """
-
         if dst.size != src.size:
             raise ValueError(
                 "sanitycheck: ExprAff args must have same size! %s" %
@@ -429,18 +447,22 @@ 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)
+            self.__src = ExprCompose(all_a)
 
         else:
-            self.dst, self.src = dst, src
+            self.__dst, self.__src = dst, src
+
+        self.__size = self.dst.size
+        self._hash = self.exprhash()
 
-        self._hash = self.myhash()
-        self._size = self.dst.size
+    size = property(lambda self: self.__size)
+    dst = property(lambda self: self.__dst)
+    src = property(lambda self: self.__src)
 
     def __str__(self):
         return "%s = %s" % (str(self.dst), str(self.src))
@@ -457,12 +479,12 @@ class ExprAff(Expr):
         else:
             return self.dst.get_w()
 
+    def exprhash(self):
+        return hash((EXPRAFF, self.dst._hash, self.src._hash))
+
     def __contains__(self, e):
         return self == e or self.src.__contains__(e) or self.dst.__contains__(e)
 
-    def myhash(self):
-        return hash((EXPRAFF, self.dst._hash, self.src._hash))
-
     # XXX /!\ for hackish expraff to slice
     def get_modified_slice(self):
         """Return an Expr list of extra expressions needed during the
@@ -474,9 +496,9 @@ class ExprAff(Expr):
         modified_s = []
         for x in self.src.args:
             if (not isinstance(x[0], ExprSlice) or
-                x[0].arg != dst    or
+                x[0].arg != dst or
                 x[1] != x[0].start or
-                x[2] != x[0].stop):
+                    x[2] != x[0].stop):
                 # If x is not the initial expression
                 modified_s.append(x)
         return modified_s
@@ -519,10 +541,15 @@ class ExprCond(Expr):
         @src2: Expr, value if condition is evaled zero
         """
 
-        self.cond, self.src1, self.src2 = cond, src1, src2
+        self.__cond, self.__src1, self.__src2 = cond, src1, src2
         assert(src1.size == src2.size)
-        self._hash = self.myhash()
-        self._size = self.src1.size
+        self.__size = self.src1.size
+        self._hash = self.exprhash()
+
+    size = property(lambda self: self.__size)
+    cond = property(lambda self: self.__cond)
+    src1 = property(lambda self: self.__src1)
+    src2 = property(lambda self: self.__src2)
 
     def __str__(self):
         return "(%s?(%s,%s))" % (str(self.cond), str(self.src1), str(self.src2))
@@ -531,21 +558,21 @@ class ExprCond(Expr):
         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)
+                               cst_read).union(out_src1).union(out_src2)
 
     def get_w(self):
         return set()
 
+    def exprhash(self):
+        return hash((EXPRCOND, self.cond._hash,
+                     self.src1._hash, self.src2._hash))
+
     def __contains__(self, e):
         return (self == e or
                 self.cond.__contains__(e) or
                 self.src1.__contains__(e) or
                 self.src2.__contains__(e))
 
-    def myhash(self):
-        return hash((EXPRCOND, self.cond._hash,
-            self.src1._hash, self.src2._hash))
-
     @visit_chk
     def visit(self, cb, tv=None):
         cond = self.cond.visit(cb, tv)
@@ -592,11 +619,14 @@ class ExprMem(Expr):
             raise ValueError(
                 'ExprMem: arg must be an Expr (not %s)' % type(arg))
 
-        self.arg, self._size = arg, size
-        self._hash = self.myhash()
+        self.__arg, self.__size = arg, size
+        self._hash = self.exprhash()
+
+    size = property(lambda self: self.__size)
+    arg = property(lambda self: self.__arg)
 
     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:
@@ -607,22 +637,22 @@ class ExprMem(Expr):
     def get_w(self):
         return set([self])  # [memreg]
 
+    def exprhash(self):
+        return hash((EXPRMEM, self.arg._hash, self.__size))
+
     def __contains__(self, e):
         return self == e or self.arg.__contains__(e)
 
-    def myhash(self):
-        return hash((EXPRMEM, self.arg._hash, self._size))
-
     @visit_chk
     def visit(self, cb, tv=None):
         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)
+        return ExprMem(arg, size=self.size)
 
     def is_op_segm(self):
         return isinstance(self.arg, ExprOp) and self.arg.op == 'segm'
@@ -664,15 +694,21 @@ 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._hash = self.myhash()
+        self.__op, self.__args = op, tuple(args)
 
         # Set size for special cases
         if self.op in [
-            '==', 'parity', 'fcom_c0', 'fcom_c1', 'fcom_c2', 'fcom_c3',
-            "access_segment_ok", "load_segment_limit_ok", "bcdadd_cf",
+                '==', 'parity', 'fcom_c0', 'fcom_c1', 'fcom_c2', 'fcom_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,
+                         ]:
+            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',
@@ -695,7 +731,12 @@ class ExprOp(Expr):
                 # All arguments have the same size
                 sz = list(sizes)[0]
 
-        self._size = sz
+        self.__size = sz
+        self._hash = self.exprhash()
+
+    size = property(lambda self: self.__size)
+    op = property(lambda self: self.__op)
+    args = property(lambda self: self.__args)
 
     def __str__(self):
         if self.is_associative():
@@ -712,11 +753,15 @@ class ExprOp(Expr):
 
     def get_r(self, mem_read=False, cst_read=False):
         return reduce(lambda x, y:
-            x.union(y.get_r(mem_read, cst_read)), self.args, set())
+                      x.union(y.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 = [x._hash for x in self.args]
+        return hash((EXPROP, self.op, tuple(h_hargs)))
+
     def __contains__(self, e):
         if self == e:
             return True
@@ -725,10 +770,6 @@ class ExprOp(Expr):
                 return True
         return False
 
-    def myhash(self):
-        h_hargs = [x._hash for x in self.args]
-        return hash((EXPROP, self.op, tuple(h_hargs)))
-
     def is_associative(self):
         "Return True iff current operation is associative"
         return (self.op in ['+', '*', '^', '&', '|'])
@@ -764,9 +805,14 @@ class ExprSlice(Expr):
 
     def __init__(self, arg, start, stop):
         assert(start < stop)
-        self.arg, self.start, self.stop = arg, start, stop
-        self._hash = self.myhash()
-        self._size = self.stop - self.start
+        self.__arg, self.__start, self.__stop = arg, start, stop
+        self.__size = self.__stop - self.__start
+        self._hash = self.exprhash()
+
+    size = property(lambda self: self.__size)
+    arg = property(lambda self: self.__arg)
+    start = property(lambda self: self.__start)
+    stop = property(lambda self: self.__stop)
 
     def __str__(self):
         return "%s[%d:%d]" % (str(self.arg), self.start, self.stop)
@@ -777,14 +823,14 @@ class ExprSlice(Expr):
     def get_w(self):
         return self.arg.get_w()
 
+    def exprhash(self):
+        return hash((EXPRSLICE, self.arg._hash, self.start, self.stop))
+
     def __contains__(self, e):
         if self == e:
             return True
         return self.arg.__contains__(e)
 
-    def myhash(self):
-        return hash((EXPRSLICE, self.arg._hash, self.start, self.stop))
-
     @visit_chk
     def visit(self, cb, tv=None):
         arg = self.arg.visit(cb, tv)
@@ -850,23 +896,30 @@ class ExprCompose(Expr):
         for e, a, b in args:
             assert(a >= 0 and b >= 0)
             o.append(tuple([e, a, b]))
-        self.args = tuple(o)
+        self.__args = tuple(o)
+
+        self.__size = max([x[2]
+                           for x in self.args]) - min([x[1] for x in self.args])
+        self._hash = self.exprhash()
 
-        self._hash = self.myhash()
-        self._size = max([x[2]
-                         for x in self.args]) - min([x[1] for x in self.args])
+    size = property(lambda self: self.__size)
+    args = property(lambda self: self.__args)
 
     def __str__(self):
         return '{' + ', '.join(['%s,%d,%d' %
-            (str(x[0]), x[1], x[2]) for x in self.args]) + '}'
+                                (str(x[0]), x[1], x[2]) for x in self.args]) + '}'
 
     def get_r(self, mem_read=False, cst_read=False):
         return reduce(lambda x, y:
-            x.union(y[0].get_r(mem_read, cst_read)), self.args, set())
+                      x.union(y[0].get_r(mem_read, cst_read)), self.args, set())
 
     def get_w(self):
         return reduce(lambda x, y:
-            x.union(y[0].get_w()), self.args, set())
+                      x.union(y[0].get_w()), self.args, set())
+
+    def exprhash(self):
+        h_args = [EXPRCOMPOSE] + [(x[0]._hash, x[1], x[2]) for x in self.args]
+        return hash(tuple(h_args))
 
     def __contains__(self, e):
         if self == e:
@@ -878,10 +931,6 @@ class ExprCompose(Expr):
                 return True
         return False
 
-    def myhash(self):
-        h_args = [EXPRCOMPOSE] + [(x[0]._hash, x[1], x[2]) for x in self.args]
-        return hash(tuple(h_args))
-
     @visit_chk
     def visit(self, cb, tv=None):
         args = [(a[0].visit(cb, tv), a[1], a[2]) for a in self.args]
@@ -966,7 +1015,7 @@ def compare_exprs(e1, e2):
         x = cmp(e1.name, e2.name)
         if x:
             return x
-        return cmp(e1._size, e2._size)
+        return cmp(e1.size, e2.size)
     elif c1 == ExprAff:
         raise NotImplementedError(
             "Comparaison from an ExprAff not yet implemented")
@@ -983,7 +1032,7 @@ def compare_exprs(e1, e2):
         x = compare_exprs(e1.arg, e2.arg)
         if x:
             return x
-        return cmp(e1._size, e2._size)
+        return cmp(e1.size, e2.size)
     elif c1 == ExprOp:
         if e1.op != e2.op:
             return cmp(e1.op, e2.op)
@@ -1138,7 +1187,7 @@ def MatchExpr(e, m, tks, result=None):
     elif isinstance(e, ExprMem):
         if not isinstance(m, ExprMem):
             return False
-        if e._size != m._size:
+        if e.size != m.size:
             return False
         return MatchExpr(e.arg, m.arg, tks, result)