32 from operator
import itemgetter
38 TOK_INF_SIGNED = TOK_INF +
"s"
39 TOK_INF_UNSIGNED = TOK_INF +
"u"
41 TOK_INF_EQUAL_SIGNED = TOK_INF_EQUAL +
"s"
42 TOK_INF_EQUAL_UNSIGNED = TOK_INF_EQUAL +
"u"
45 TOK_POS_STRICT =
"Spos"
59 "Function decorator launching callback on Expression visit"
60 def wrapped(e, cb, test_visit=lambda x:
True):
61 if (test_visit
is not None)
and (
not test_visit(e)):
63 e_new = visitor(e, cb, test_visit)
76 """Enhanced graph for Expression diplay
77 Expression are displayed as a tree with node and edge labeled
78 with only relevant information"""
81 if isinstance(node, ExprOp):
83 elif isinstance(node, ExprId):
85 elif isinstance(node, ExprMem):
86 return "@%d" % node.size
87 elif isinstance(node, ExprCompose):
88 return "{ %d }" % node.size
89 elif isinstance(node, ExprCond):
90 return "? %d" % node.size
91 elif isinstance(node, ExprSlice):
92 return "[%d:%d]" % (node.start, node.stop)
96 if isinstance(nfrom, ExprCompose):
99 return "[%s, %s]" % (i[1], i[2])
100 elif isinstance(nfrom, ExprCond):
101 if nfrom.cond == nto:
103 elif nfrom.src1 == nto:
105 elif nfrom.src2 == nto:
115 "Parent class for Miasm Expressions"
126 raise ValueError(
'size is not mutable')
131 size = property(
lambda self: self._size)
139 if not isinstance(i, slice):
140 raise TypeError(
"Expression: Bad slice: %s" % i)
141 start, stop, step = i.indices(self.
size)
143 raise ValueError(
"Expression: Bad slice: %s" % i)
147 raise DeprecationWarning(
"use X.size instead of X.get_size()")
149 def get_r(self, mem_read=False, cst_read=False):
150 return self.arg.get_r(mem_read, cst_read)
153 return self.arg.get_w()
156 """Returns true if the considered Expr is a function call
161 if self.
_repr is None:
162 self.
_repr = self._exprrepr()
166 if self.
_hash is None:
167 self.
_hash = self._exprhash()
171 """Return True if ids are equal;
172 False if instances are obviously not equal
173 None if we cannot simply decide"""
175 if id(self) == id(other):
177 if self.__class__
is not other.__class__:
179 if hash(self) != hash(other):
187 return repr(self) == repr(other)
193 return ExprOp(
'+', self, a)
199 return ExprOp(
'/', self, a)
202 return ExprOp(
'%', self, a)
205 return ExprOp(
'*', self, a)
208 return ExprOp(
'<<', self, a)
211 return ExprOp(
'>>', self, a)
214 return ExprOp(
'^', self, a)
217 return ExprOp(
'|', self, a)
220 return ExprOp(
'&', self, a)
230 "Deep copy of the expression"
231 return self.visit(
lambda x: x)
234 """Find and replace sub expression using dct
235 @dct: dictionnary of Expr -> *
240 def my_replace(e, dct):
245 return self.visit(
lambda e: my_replace(e, dct))
248 "Canonize the Expression"
251 return not e.is_canon
253 def canonize_visitor(e):
256 if isinstance(e, ExprOp):
257 if e.is_associative():
261 if isinstance(arg, ExprOp)
and e.op == arg.op:
266 new_e =
ExprOp(e.op, *args)
269 elif isinstance(e, ExprCompose):
273 new_e.is_canon =
True
276 return self.visit(canonize_visitor, must_canon)
279 "Return the Most Significant Bit"
284 """Zero extend to size
287 assert(self.
size <= size)
288 if self.
size == size:
290 ad_size = size - self.
size
293 (n, self.
size, size)])
296 """Sign extend to size
299 assert(self.
size <= size)
300 if self.
size == size:
302 ad_size = size - self.
size
312 """Recursive method used by graph
313 @graph: miasm2.core.graph.DiGraph instance
314 Update @graph instance to include sons
315 This is an Abstract method"""
317 raise ValueError(
"Abstract method")
320 """Return a DiGraph instance standing for Expr tree
321 Instance's display functions have been override for better visibility
322 Wrapper on graph_recursive"""
331 raise ValueError(
'mask is not mutable')
338 """An ExprInt represent a constant in Miasm IR.
343 - Constant 0x12345678 on 32bits
347 """Create an ExprInt from a modint or num/size
349 @size: (optionnal) int size"""
354 if size
is not None and num.size != size:
355 raise RuntimeError(
"size must match modint size")
356 elif size
is not None:
357 self.
_arg = mod_size2uint[size](num)
358 self.
_size = self.arg.size
360 raise ValueError(
'arg must by modint or (int,size)! %s' % num)
362 arg = property(
lambda self: self.
_arg)
368 return (self.
_arg == other._arg
and
369 self.
_size == other._size)
372 "Return self integer representation"
377 return str(
"-0x%X" % (- self.
__get_int()))
381 def get_r(self, mem_read=False, cst_read=False):
391 return hash((EXPRINT, self.
_arg, self.
_size))
394 return "%s(%r)" % (self.__class__.__name__, self.
_arg)
415 """An ExprId represent an identifier in Miasm IR.
424 """Create an identifier
425 @name: str, identifier's name
426 @size: int, identifier's size
431 name = property(
lambda self: self.
_name)
437 return (self.
_name == other._name
and
438 self.
_size == other._size)
441 return str(self.
_name)
443 def get_r(self, mem_read=False, cst_read=False):
454 return "%s(%r, %d)" % (self.__class__.__name__, self.
_name, self.
_size)
475 """An ExprAff represent an affection from an Expression to another one.
482 """Create an ExprAff for dst <- src
483 @dst: Expr, affectation destination
484 @src: Expr, affectation source
486 if dst.size != src.size:
488 "sanitycheck: ExprAff args must have same size! %s" %
489 ([(str(arg), arg.size)
for arg
in [dst, src]]))
491 if isinstance(dst, ExprSlice):
494 rest = [(
ExprSlice(dst.arg, r[0], r[1]), r[0], r[1])
495 for r
in dst.slice_rest()]
496 all_a = [(src, dst.start, dst.stop)] + rest
497 all_a.sort(key=
lambda x: x[1])
505 dst = property(
lambda self: self.
_dst)
506 src = property(
lambda self: self.
_src)
509 return "%s = %s" % (str(self.
_dst), str(self.
_src))
511 def get_r(self, mem_read=False, cst_read=False):
512 elements = self._src.get_r(mem_read, cst_read)
513 if isinstance(self.
_dst, ExprMem):
514 elements.update(self._dst.arg.get_r(mem_read, cst_read))
518 if isinstance(self.
_dst, ExprMem):
519 return set([self.
_dst])
521 return self._dst.get_w()
524 return hash((EXPRAFF, hash(self.
_dst), hash(self.
_src)))
527 return "%s(%r, %r)" % (self.__class__.__name__, self.
_dst, self.
_src)
530 return self == e
or self._src.__contains__(e)
or self._dst.__contains__(e)
534 """Return an Expr list of extra expressions needed during the
535 object instanciation"""
538 if not isinstance(self.
_src, ExprCompose):
539 raise ValueError(
"Get mod slice not on expraff slice", str(self))
541 for arg
in self._src.args:
542 if (
not isinstance(arg[0], ExprSlice)
or
544 arg[1] != arg[0].start
or
545 arg[2] != arg[0].stop):
547 modified_s.append(arg)
552 dst, src = self._dst.visit(cb, tv), self._src.visit(cb, tv)
553 if dst == self.
_dst and src == self.
_src:
559 return ExprAff(self._dst.copy(), self._src.copy())
562 return max(self._src.depth(), self._dst.depth()) + 1
567 arg.graph_recursive(graph)
568 graph.add_uniq_edge(self, arg)
573 """An ExprCond stand for a condition on an Expr
578 - if (cond) then ... else ...
582 """Create an ExprCond
583 @cond: Expr, condition
584 @src1: Expr, value if condition is evaled to not zero
585 @src2: Expr, value if condition is evaled zero
588 assert(src1.size == src2.size)
590 self._cond, self._src1, self.
_src2 = cond, src1, src2
593 cond = property(
lambda self: self._cond)
594 src1 = property(
lambda self: self._src1)
595 src2 = property(
lambda self: self.
_src2)
598 return "(%s?(%s,%s))" % (str(self._cond), str(self._src1), str(self.
_src2))
600 def get_r(self, mem_read=False, cst_read=False):
601 out_src1 = self._src1.get_r(mem_read, cst_read)
602 out_src2 = self._src2.get_r(mem_read, cst_read)
603 return self._cond.get_r(mem_read,
604 cst_read).union(out_src1).union(out_src2)
610 return hash((EXPRCOND, hash(self.
cond),
611 hash(self._src1), hash(self.
_src2)))
614 return "%s(%r, %r, %r)" % (self.__class__.__name__,
615 self._cond, self._src1, self.
_src2)
619 self._cond.__contains__(e)
or
620 self._src1.__contains__(e)
or
621 self._src2.__contains__(e))
625 cond = self._cond.visit(cb, tv)
626 src1 = self._src1.visit(cb, tv)
627 src2 = self._src2.visit(cb, tv)
628 if (cond == self._cond
and
629 src1 == self._src1
and
640 return max(self._cond.depth(),
642 self._src2.depth()) + 1
646 for arg
in [self._cond, self._src1, self.
_src2]:
647 arg.graph_recursive(graph)
648 graph.add_uniq_edge(self, arg)
653 """An ExprMem stand for a memory access
662 @arg: Expr, memory access address
663 @size: int, memory access size
665 if not isinstance(arg, Expr):
667 'ExprMem: arg must be an Expr (not %s)' %
type(arg))
671 arg = property(
lambda self: self._arg)
674 return "@%d[%s]" % (self.
_size, str(self._arg))
676 def get_r(self, mem_read=False, cst_read=False):
678 return set(self._arg.get_r(mem_read, cst_read).union(set([self])))
686 return hash((EXPRMEM, hash(self._arg), self.
_size))
689 return "%s(%r, %r)" % (self.__class__.__name__,
690 self._arg, self.
_size)
693 return self == e
or self._arg.__contains__(e)
697 arg = self._arg.visit(cb, tv)
703 arg = self._arg.copy()
707 return isinstance(self._arg, ExprOp)
and self._arg.op ==
'segm'
710 return self._arg.depth() + 1
714 self._arg.graph_recursive(graph)
715 graph.add_uniq_edge(self, self._arg)
720 """An ExprOp stand for an operation between Expr
731 @*args: Expr, operand list
734 sizes = set([arg.size
for arg
in args])
738 if op
not in [
"segm"]:
740 "sanitycheck: ExprOp args must have same size! %s" %
741 ([(str(arg), arg.size)
for arg
in args]))
743 if not isinstance(op, str):
744 raise ValueError(
"ExprOp: 'op' argument must be a string")
746 self._op, self.
_args = op, tuple(args)
750 '==',
'parity',
'fcom_c0',
'fcom_c1',
'fcom_c2',
'fcom_c3',
751 'fxam_c0',
'fxam_c1',
'fxam_c2',
'fxam_c3',
752 "access_segment_ok",
"load_segment_limit_ok",
"bcdadd_cf",
753 "ucomiss_zf",
"ucomiss_pf",
"ucomiss_cf"]:
755 elif self._op
in [TOK_INF, TOK_INF_SIGNED,
756 TOK_INF_UNSIGNED, TOK_INF_EQUAL,
757 TOK_INF_EQUAL_SIGNED, TOK_INF_EQUAL_UNSIGNED,
762 elif self._op
in [
'mem_16_to_double',
'mem_32_to_double',
763 'mem_64_to_double',
'mem_80_to_double',
764 'int_16_to_double',
'int_32_to_double',
765 'int_64_to_double',
'int_80_to_double']:
767 elif self._op
in [
'double_to_mem_16',
'double_to_int_16',
768 'float_trunc_to_int_16',
'double_trunc_to_int_16']:
770 elif self._op
in [
'double_to_mem_32',
'double_to_int_32',
771 'float_trunc_to_int_32',
'double_trunc_to_int_32',
774 elif self._op
in [
'double_to_mem_64',
'double_to_int_64',
775 'float_trunc_to_int_64',
'double_trunc_to_int_64',
778 elif self._op
in [
'double_to_mem_80',
'double_to_int_80',
779 'float_trunc_to_int_80',
780 'double_trunc_to_int_80']:
782 elif self._op
in [
'segm']:
783 sz = self.
_args[1].size
793 op = property(
lambda self: self._op)
794 args = property(
lambda self: self.
_args)
798 return '(' + self._op.join([str(arg)
for arg
in self.
_args]) +
')'
799 if (self._op.startswith(
'call_func_')
or
800 len(self.
_args) > 2
or
801 self._op
in [
'parity',
'segm']):
802 return self._op +
'(' +
', '.join([str(arg)
for arg
in self.
_args]) +
')'
803 if len(self.
_args) == 2:
804 return (
'(' + str(self.
_args[0]) +
805 ' ' + self.
op +
' ' + str(self.
_args[1]) +
')')
807 return reduce(
lambda x, y: x +
' ' + str(y),
809 '(' + str(self._op)) +
')'
811 def get_r(self, mem_read=False, cst_read=False):
812 return reduce(
lambda elements, arg:
813 elements.union(arg.get_r(mem_read, cst_read)), self.
_args, set())
816 raise ValueError(
'op cannot be written!', self)
819 h_hargs = [hash(arg)
for arg
in self.
_args]
820 return hash((EXPROP, self._op, tuple(h_hargs)))
823 return "%s(%r, %s)" % (self.__class__.__name__, self._op,
824 ', '.join(repr(arg)
for arg
in self.
_args))
829 for arg
in self.
_args:
830 if arg.__contains__(e):
835 return self._op.startswith(
'call')
838 "Return True iff current operation is associative"
839 return (self._op
in [
'+',
'*',
'^',
'&',
'|'])
842 "Return True iff current operation is commutative"
843 return (self._op
in [
'+',
'*',
'^',
'&',
'|'])
847 args = [arg.visit(cb, tv)
for arg
in self.
_args]
848 modified = any([arg[0] != arg[1]
for arg
in zip(self.
_args, args)])
850 return ExprOp(self._op, *args)
854 args = [arg.copy()
for arg
in self.
_args]
855 return ExprOp(self._op, *args)
858 depth = [arg.depth()
for arg
in self.
_args]
859 return max(depth) + 1
863 for arg
in self.
_args:
864 arg.graph_recursive(graph)
865 graph.add_uniq_edge(self, arg)
876 arg = property(
lambda self: self._arg)
877 start = property(
lambda self: self.
_start)
878 stop = property(
lambda self: self.
_stop)
881 return "%s[%d:%d]" % (str(self._arg), self.
_start, self.
_stop)
883 def get_r(self, mem_read=False, cst_read=False):
884 return self._arg.get_r(mem_read, cst_read)
887 return self._arg.get_w()
890 return hash((EXPRSLICE, hash(self._arg), self.
_start, self.
_stop))
893 return "%s(%r, %d, %d)" % (self.__class__.__name__, self._arg,
899 return self._arg.__contains__(e)
903 arg = self._arg.visit(cb, tv)
912 return self._arg.depth() + 1
915 "Return the completion of the current slice"
916 size = self._arg.size
918 raise ValueError(
'bad slice rest %s %s %s' %
926 rest.append((0, self.
_start))
927 if self.
_stop < size:
928 rest.append((self.
_stop, size))
934 self._arg.graph_recursive(graph)
935 graph.add_uniq_edge(self, self._arg)
941 Compose is like a hambuger.
942 It's arguments are tuple of: (Expression, start, stop)
943 start and stop are intergers, determining Expression position in the compose.
946 ExprCompose([(salad, 0, 3), (cheese, 3, 10), (beacon, 10, 16)])
947 In the example, salad.size == 3.
951 """Create an ExprCompose
952 The ExprCompose is contiguous and starts at 0
953 @args: tuple(Expr, int, int)
957 args = sorted(args, key=itemgetter(1))
958 for e, start, stop
in args:
959 if e.size != stop - start:
961 "sanitycheck: ExprCompose args must have correct size!" +
962 " %r %r %r" % (e, e.size, stop - start))
963 if last_stop != start:
965 "sanitycheck: ExprCompose args must be contiguous!" +
972 assert(a >= 0
and b >= 0)
973 o.append(tuple([e, a, b]))
978 args = property(
lambda self: self.
_args)
981 return '{' +
', '.join([
'%s,%d,%d' %
982 (str(arg[0]), arg[1], arg[2])
for arg
in self.
_args]) +
'}'
984 def get_r(self, mem_read=False, cst_read=False):
985 return reduce(
lambda elements, arg:
986 elements.union(arg[0].
get_r(mem_read, cst_read)), self.
_args, set())
989 return reduce(
lambda elements, arg:
990 elements.union(arg[0].
get_w()), self.
_args, set())
993 h_args = [EXPRCOMPOSE] + [(hash(arg[0]), arg[1], arg[2])
994 for arg
in self.
_args]
995 return hash(tuple(h_args))
998 return "%s(%r)" % (self.__class__.__name__, self.
_args)
1003 for arg
in self.
_args:
1012 args = [(arg[0].
visit(cb, tv), arg[1], arg[2])
for arg
in self.
_args]
1013 modified = any([arg[0] != arg[1]
for arg
in zip(self.
_args, args)])
1019 args = [(arg[0].
copy(), arg[1], arg[2])
for arg
in self.
_args]
1023 depth = [arg[0].
depth()
for arg
in self.
_args]
1024 return max(depth) + 1
1027 graph.add_node(self)
1028 for arg
in self.
args:
1030 graph.add_uniq_edge(self, arg[0])
1034 expr_order_dict = {ExprId: 1,
1046 x =
cmp(e1[1], e2[1])
1052 x =
cmp(e1[2], e2[2])
1058 for i
in xrange(min(len(l1_e), len(l2_e))):
1062 return cmp(len(l1_e), len(l2_e))
1067 for i
in xrange(min(len(l1_e), len(l2_e))):
1071 return cmp(len(l1_e), len(l2_e))
1075 """Compare 2 expressions for canonization
1085 return cmp(expr_order_dict[c1], expr_order_dict[c2])
1089 return cmp(e1.arg, e2.arg)
1091 x =
cmp(e1.name, e2.name)
1094 return cmp(e1.size, e2.size)
1096 raise NotImplementedError(
1097 "Comparaison from an ExprAff not yet implemented")
1098 elif c2 == ExprCond:
1111 return cmp(e1.size, e2.size)
1114 return cmp(e1.op, e2.op)
1116 elif c1 == ExprSlice:
1120 x =
cmp(e1.start, e2.start)
1123 x =
cmp(e1.stop, e2.stop)
1125 elif c1 == ExprCompose:
1127 raise NotImplementedError(
1128 "Comparaison between %r %r not implemented" % (e1, e2))
1133 l.sort(cmp=compare_exprs)
1139 l.sort(cmp=compare_exprs_compose)
1166 "Generate ExprInt with size equal to expression"
1167 return ExprInt(mod_size2uint[e.size](i))
1171 if isinstance(e, ExprId):
1183 """Test if v can correspond to e. If so, update the context in result.
1184 Otherwise, return False
1187 @tks : list of ExprId, available jokers
1188 @result : dictionnary of ExprId -> Expr, current context
1193 if v
in result
and result[v] != e:
1200 """Try to match m expression with e expression with tks jokers.
1201 Result is output dictionnary with matching joker values.
1204 @tks : list of ExprId, available jokers
1205 @result : dictionnary of ExprId -> Expr, output matching context
1215 if isinstance(e, ExprInt):
1218 elif isinstance(e, ExprId):
1221 elif isinstance(e, ExprOp):
1224 if not isinstance(m, ExprOp):
1228 if len(e.args) != len(m.args):
1232 if e.is_commutative():
1233 permutations = itertools.permutations(e.args)
1235 permutations = [e.args]
1238 for permut
in permutations:
1241 myresult = dict(result)
1242 for a1, a2
in zip(permut, m.args):
1250 for k, v
in myresult.items():
1258 elif isinstance(e, ExprMem):
1259 if not isinstance(m, ExprMem):
1261 if e.size != m.size:
1263 return MatchExpr(e.arg, m.arg, tks, result)
1265 elif isinstance(e, ExprSlice):
1266 if not isinstance(m, ExprSlice):
1268 if e.start != m.start
or e.stop != m.stop:
1270 return MatchExpr(e.arg, m.arg, tks, result)
1272 elif isinstance(e, ExprCond):
1273 if not isinstance(m, ExprCond):
1275 r =
MatchExpr(e.cond, m.cond, tks, result)
1278 r =
MatchExpr(e.src1, m.src1, tks, result)
1281 r =
MatchExpr(e.src2, m.src2, tks, result)
1286 elif isinstance(e, ExprCompose):
1287 if not isinstance(m, ExprCompose):
1289 for a1, a2
in zip(e.args, m.args):
1290 if a1[1] != a2[1]
or a1[2] != a2[2]:
1292 r =
MatchExpr(a1[0], a2[0], tks, result)
1298 raise NotImplementedError(
"MatchExpr: Unknown type: %s" %
type(e))
1306 def visit_search(e, m, tks, result):
1310 result.add(tuple(r.items()))
1312 e.visit(
lambda x: visit_search(x, m, tks, result))
1319 o_r.update(e.get_r(mem_read=
True))
1321 o_w.update(e.get_w())
1327 return list of read/write reg/cst/mem for each expressions
1335 o_r.update(e.get_r(mem_read=mem_read, cst_read=cst_read))
1336 if isinstance(e.dst, ExprMem):
1337 o_r.update(e.dst.arg.get_r(mem_read=mem_read, cst_read=cst_read))
1338 o_w.update(e.get_w())
1347 list_rw.append((o_r, o_w))
1353 def visit_getops(e, out=None):
1356 if isinstance(e, ExprOp):
1360 e.visit(
lambda x: visit_getops(x, ops))
1365 def visit_getmem(e, out=None):
1368 if isinstance(e, ExprMem):
1372 e.visit(
lambda x: visit_getmem(x, ops))
def compare_exprs_compose
def compare_expr_list_compose
def canonize_expr_list_compose