Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
expression.py
Go to the documentation of this file.
1 #
2 # Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along
15 # with this program; if not, write to the Free Software Foundation, Inc.,
16 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 #
18 # These module implements Miasm IR components and basic operations related.
19 # IR components are :
20 # - ExprInt
21 # - ExprId
22 # - ExprAff
23 # - ExprCond
24 # - ExprMem
25 # - ExprOp
26 # - ExprSlice
27 # - ExprCompose
28 #
29 
30 
31 import itertools
32 from operator import itemgetter
33 from miasm2.expression.modint import *
34 from miasm2.core.graph import DiGraph
35 
36 # Define tokens
37 TOK_INF = "<"
38 TOK_INF_SIGNED = TOK_INF + "s"
39 TOK_INF_UNSIGNED = TOK_INF + "u"
40 TOK_INF_EQUAL = "<="
41 TOK_INF_EQUAL_SIGNED = TOK_INF_EQUAL + "s"
42 TOK_INF_EQUAL_UNSIGNED = TOK_INF_EQUAL + "u"
43 TOK_EQUAL = "=="
44 TOK_POS = "pos"
45 TOK_POS_STRICT = "Spos"
46 
47 # Hashing constants
48 EXPRINT = 1
49 EXPRID = 2
50 EXPRAFF = 3
51 EXPRCOND = 4
52 EXPRMEM = 5
53 EXPROP = 6
54 EXPRSLICE = 5
55 EXPRCOMPOSE = 5
56 
57 
58 def visit_chk(visitor):
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)):
62  return e
63  e_new = visitor(e, cb, test_visit)
64  if e_new is None:
65  return None
66  e_new2 = cb(e_new)
67  return e_new2
68  return wrapped
69 
70 
71 # Expression display
72 
73 
75 
76  """Enhanced graph for Expression diplay
77  Expression are displayed as a tree with node and edge labeled
78  with only relevant information"""
79 
80  def node2str(self, node):
81  if isinstance(node, ExprOp):
82  return node.op
83  elif isinstance(node, ExprId):
84  return node.name
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)
93  return str(node)
94 
95  def edge2str(self, nfrom, nto):
96  if isinstance(nfrom, ExprCompose):
97  for i in nfrom.args:
98  if i[0] == nto:
99  return "[%s, %s]" % (i[1], i[2])
100  elif isinstance(nfrom, ExprCond):
101  if nfrom.cond == nto:
102  return "?"
103  elif nfrom.src1 == nto:
104  return "True"
105  elif nfrom.src2 == nto:
106  return "False"
107 
108  return ""
109 
110 
111 # IR definitions
112 
113 class Expr(object):
114 
115  "Parent class for Miasm Expressions"
116 
117  is_term = False # Terminal expression
118  is_simp = False # Expression already simplified
119  is_canon = False # Expression already canonised
120  is_eval = False # Expression already evalued
121 
122  _hash = None
123  _repr = None
124 
125  def set_size(self, value):
126  raise ValueError('size is not mutable')
127 
128  def __init__(self, arg):
129  self.arg = arg
130 
131  size = property(lambda self: self._size)
132 
133  # Common operations
134 
135  def __str__(self):
136  return str(self.arg)
137 
138  def __getitem__(self, i):
139  if not isinstance(i, slice):
140  raise TypeError("Expression: Bad slice: %s" % i)
141  start, stop, step = i.indices(self.size)
142  if step != 1:
143  raise ValueError("Expression: Bad slice: %s" % i)
144  return ExprSlice(self, start, stop)
145 
146  def get_size(self):
147  raise DeprecationWarning("use X.size instead of X.get_size()")
148 
149  def get_r(self, mem_read=False, cst_read=False):
150  return self.arg.get_r(mem_read, cst_read)
151 
152  def get_w(self):
153  return self.arg.get_w()
154 
155  def is_function_call(self):
156  """Returns true if the considered Expr is a function call
157  """
158  return False
159 
160  def __repr__(self):
161  if self._repr is None:
162  self._repr = self._exprrepr()
163  return self._repr
164 
165  def __hash__(self):
166  if self._hash is None:
167  self._hash = self._exprhash()
168  return self._hash
169 
170  def pre_eq(self, other):
171  """Return True if ids are equal;
172  False if instances are obviously not equal
173  None if we cannot simply decide"""
174 
175  if id(self) == id(other):
176  return True
177  if self.__class__ is not other.__class__:
178  return False
179  if hash(self) != hash(other):
180  return False
181  return None
182 
183  def __eq__(self, other):
184  res = self.pre_eq(other)
185  if res is not None:
186  return res
187  return repr(self) == repr(other)
188 
189  def __ne__(self, a):
190  return not self.__eq__(a)
191 
192  def __add__(self, a):
193  return ExprOp('+', self, a)
194 
195  def __sub__(self, a):
196  return ExprOp('+', self, ExprOp('-', a))
197 
198  def __div__(self, a):
199  return ExprOp('/', self, a)
200 
201  def __mod__(self, a):
202  return ExprOp('%', self, a)
203 
204  def __mul__(self, a):
205  return ExprOp('*', self, a)
206 
207  def __lshift__(self, a):
208  return ExprOp('<<', self, a)
209 
210  def __rshift__(self, a):
211  return ExprOp('>>', self, a)
212 
213  def __xor__(self, a):
214  return ExprOp('^', self, a)
215 
216  def __or__(self, a):
217  return ExprOp('|', self, a)
218 
219  def __and__(self, a):
220  return ExprOp('&', self, a)
221 
222  def __neg__(self):
223  return ExprOp('-', self)
224 
225  def __invert__(self):
226  s = self.size
227  return ExprOp('^', self, ExprInt(mod_size2uint[s](size2mask(s))))
228 
229  def copy(self):
230  "Deep copy of the expression"
231  return self.visit(lambda x: x)
232 
233  def replace_expr(self, dct=None):
234  """Find and replace sub expression using dct
235  @dct: dictionnary of Expr -> *
236  """
237  if dct is None:
238  dct = {}
239 
240  def my_replace(e, dct):
241  if e in dct:
242  return dct[e]
243  return e
244 
245  return self.visit(lambda e: my_replace(e, dct))
246 
247  def canonize(self):
248  "Canonize the Expression"
249 
250  def must_canon(e):
251  return not e.is_canon
252 
253  def canonize_visitor(e):
254  if e.is_canon:
255  return e
256  if isinstance(e, ExprOp):
257  if e.is_associative():
258  # ((a+b) + c) => (a + b + c)
259  args = []
260  for arg in e.args:
261  if isinstance(arg, ExprOp) and e.op == arg.op:
262  args += arg.args
263  else:
264  args.append(arg)
265  args = canonize_expr_list(args)
266  new_e = ExprOp(e.op, *args)
267  else:
268  new_e = e
269  elif isinstance(e, ExprCompose):
270  new_e = ExprCompose(canonize_expr_list_compose(e.args))
271  else:
272  new_e = e
273  new_e.is_canon = True
274  return new_e
275 
276  return self.visit(canonize_visitor, must_canon)
277 
278  def msb(self):
279  "Return the Most Significant Bit"
280  s = self.size
281  return self[s - 1:s]
282 
283  def zeroExtend(self, size):
284  """Zero extend to size
285  @size: int
286  """
287  assert(self.size <= size)
288  if self.size == size:
289  return self
290  ad_size = size - self.size
291  n = ExprInt(0, ad_size)
292  return ExprCompose([(self, 0, self.size),
293  (n, self.size, size)])
294 
295  def signExtend(self, size):
296  """Sign extend to size
297  @size: int
298  """
299  assert(self.size <= size)
300  if self.size == size:
301  return self
302  ad_size = size - self.size
303  c = ExprCompose([(self, 0, self.size),
304  (ExprCond(self.msb(),
305  ExprInt(size2mask(ad_size), ad_size),
306  ExprInt(0, ad_size)),
307  self.size, size)
308  ])
309  return c
310 
311  def graph_recursive(self, graph):
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"""
316 
317  raise ValueError("Abstract method")
318 
319  def graph(self):
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"""
323 
324  # Create recursively the graph
325  graph = DiGraphExpr()
326  self.graph_recursive(graph)
327 
328  return graph
329 
330  def set_mask(self, value):
331  raise ValueError('mask is not mutable')
332 
333  mask = property(lambda self: ExprInt(-1, self.size))
334 
335 
336 class ExprInt(Expr):
337 
338  """An ExprInt represent a constant in Miasm IR.
339 
340  Some use cases:
341  - Constant 0x42
342  - Constant -0x30
343  - Constant 0x12345678 on 32bits
344  """
345 
346  def __init__(self, num, size=None):
347  """Create an ExprInt from a modint or num/size
348  @arg: modint or num
349  @size: (optionnal) int size"""
350 
351  if is_modint(num):
352  self._arg = num
353  self._size = self.arg.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
359  else:
360  raise ValueError('arg must by modint or (int,size)! %s' % num)
361 
362  arg = property(lambda self: self._arg)
363 
364  def __eq__(self, other):
365  res = self.pre_eq(other)
366  if res is not None:
367  return res
368  return (self._arg == other._arg and
369  self._size == other._size)
370 
371  def __get_int(self):
372  "Return self integer representation"
373  return int(self._arg & size2mask(self._size))
374 
375  def __str__(self):
376  if self._arg < 0:
377  return str("-0x%X" % (- self.__get_int()))
378  else:
379  return str("0x%X" % self.__get_int())
380 
381  def get_r(self, mem_read=False, cst_read=False):
382  if cst_read:
383  return set([self])
384  else:
385  return set()
386 
387  def get_w(self):
388  return set()
389 
390  def _exprhash(self):
391  return hash((EXPRINT, self._arg, self._size))
392 
393  def _exprrepr(self):
394  return "%s(%r)" % (self.__class__.__name__, self._arg)
395 
396  def __contains__(self, e):
397  return self == e
398 
399  @visit_chk
400  def visit(self, cb, tv=None):
401  return self
402 
403  def copy(self):
404  return ExprInt(self._arg)
405 
406  def depth(self):
407  return 1
408 
409  def graph_recursive(self, graph):
410  graph.add_node(self)
411 
412 
413 class ExprId(Expr):
414 
415  """An ExprId represent an identifier in Miasm IR.
416 
417  Some use cases:
418  - EAX register
419  - 'start' offset
420  - variable v1
421  """
422 
423  def __init__(self, name, size=32):
424  """Create an identifier
425  @name: str, identifier's name
426  @size: int, identifier's size
427  """
428 
429  self._name, self._size = name, size
430 
431  name = property(lambda self: self._name)
432 
433  def __eq__(self, other):
434  res = self.pre_eq(other)
435  if res is not None:
436  return res
437  return (self._name == other._name and
438  self._size == other._size)
439 
440  def __str__(self):
441  return str(self._name)
442 
443  def get_r(self, mem_read=False, cst_read=False):
444  return set([self])
445 
446  def get_w(self):
447  return set([self])
448 
449  def _exprhash(self):
450  # TODO XXX: hash size ??
451  return hash((EXPRID, self._name, self._size))
452 
453  def _exprrepr(self):
454  return "%s(%r, %d)" % (self.__class__.__name__, self._name, self._size)
455 
456  def __contains__(self, e):
457  return self == e
458 
459  @visit_chk
460  def visit(self, cb, tv=None):
461  return self
462 
463  def copy(self):
464  return ExprId(self._name, self._size)
465 
466  def depth(self):
467  return 1
468 
469  def graph_recursive(self, graph):
470  graph.add_node(self)
471 
472 
473 class ExprAff(Expr):
474 
475  """An ExprAff represent an affection from an Expression to another one.
476 
477  Some use cases:
478  - var1 <- 2
479  """
480 
481  def __init__(self, dst, src):
482  """Create an ExprAff for dst <- src
483  @dst: Expr, affectation destination
484  @src: Expr, affectation source
485  """
486  if dst.size != src.size:
487  raise ValueError(
488  "sanitycheck: ExprAff args must have same size! %s" %
489  ([(str(arg), arg.size) for arg in [dst, src]]))
490 
491  if isinstance(dst, ExprSlice):
492  # Complete the source with missing slice parts
493  self._dst = dst.arg
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])
498  self._src = ExprCompose(all_a)
499 
500  else:
501  self._dst, self._src = dst, src
502 
503  self._size = self.dst.size
504 
505  dst = property(lambda self: self._dst)
506  src = property(lambda self: self._src)
507 
508  def __str__(self):
509  return "%s = %s" % (str(self._dst), str(self._src))
510 
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))
515  return elements
516 
517  def get_w(self):
518  if isinstance(self._dst, ExprMem):
519  return set([self._dst]) # [memreg]
520  else:
521  return self._dst.get_w()
522 
523  def _exprhash(self):
524  return hash((EXPRAFF, hash(self._dst), hash(self._src)))
525 
526  def _exprrepr(self):
527  return "%s(%r, %r)" % (self.__class__.__name__, self._dst, self._src)
528 
529  def __contains__(self, e):
530  return self == e or self._src.__contains__(e) or self._dst.__contains__(e)
531 
532  # XXX /!\ for hackish expraff to slice
534  """Return an Expr list of extra expressions needed during the
535  object instanciation"""
536 
537  dst = self._dst
538  if not isinstance(self._src, ExprCompose):
539  raise ValueError("Get mod slice not on expraff slice", str(self))
540  modified_s = []
541  for arg in self._src.args:
542  if (not isinstance(arg[0], ExprSlice) or
543  arg[0].arg != dst or
544  arg[1] != arg[0].start or
545  arg[2] != arg[0].stop):
546  # If x is not the initial expression
547  modified_s.append(arg)
548  return modified_s
549 
550  @visit_chk
551  def visit(self, cb, tv=None):
552  dst, src = self._dst.visit(cb, tv), self._src.visit(cb, tv)
553  if dst == self._dst and src == self._src:
554  return self
555  else:
556  return ExprAff(dst, src)
557 
558  def copy(self):
559  return ExprAff(self._dst.copy(), self._src.copy())
560 
561  def depth(self):
562  return max(self._src.depth(), self._dst.depth()) + 1
563 
564  def graph_recursive(self, graph):
565  graph.add_node(self)
566  for arg in [self._src, self._dst]:
567  arg.graph_recursive(graph)
568  graph.add_uniq_edge(self, arg)
569 
570 
571 class ExprCond(Expr):
572 
573  """An ExprCond stand for a condition on an Expr
574 
575  Use cases:
576  - var1 < var2
577  - min(var1, var2)
578  - if (cond) then ... else ...
579  """
580 
581  def __init__(self, cond, src1, src2):
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
586  """
587 
588  assert(src1.size == src2.size)
589 
590  self._cond, self._src1, self._src2 = cond, src1, src2
591  self._size = self.src1.size
592 
593  cond = property(lambda self: self._cond)
594  src1 = property(lambda self: self._src1)
595  src2 = property(lambda self: self._src2)
596 
597  def __str__(self):
598  return "(%s?(%s,%s))" % (str(self._cond), str(self._src1), str(self._src2))
599 
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)
605 
606  def get_w(self):
607  return set()
608 
609  def _exprhash(self):
610  return hash((EXPRCOND, hash(self.cond),
611  hash(self._src1), hash(self._src2)))
612 
613  def _exprrepr(self):
614  return "%s(%r, %r, %r)" % (self.__class__.__name__,
615  self._cond, self._src1, self._src2)
616 
617  def __contains__(self, e):
618  return (self == e or
619  self._cond.__contains__(e) or
620  self._src1.__contains__(e) or
621  self._src2.__contains__(e))
622 
623  @visit_chk
624  def visit(self, cb, tv=None):
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
630  src2 == self._src2):
631  return self
632  return ExprCond(cond, src1, src2)
633 
634  def copy(self):
635  return ExprCond(self._cond.copy(),
636  self._src1.copy(),
637  self._src2.copy())
638 
639  def depth(self):
640  return max(self._cond.depth(),
641  self._src1.depth(),
642  self._src2.depth()) + 1
643 
644  def graph_recursive(self, graph):
645  graph.add_node(self)
646  for arg in [self._cond, self._src1, self._src2]:
647  arg.graph_recursive(graph)
648  graph.add_uniq_edge(self, arg)
649 
650 
651 class ExprMem(Expr):
652 
653  """An ExprMem stand for a memory access
654 
655  Use cases:
656  - Memory read
657  - Memory write
658  """
659 
660  def __init__(self, arg, size=32):
661  """Create an ExprMem
662  @arg: Expr, memory access address
663  @size: int, memory access size
664  """
665  if not isinstance(arg, Expr):
666  raise ValueError(
667  'ExprMem: arg must be an Expr (not %s)' % type(arg))
668 
669  self._arg, self._size = arg, size
670 
671  arg = property(lambda self: self._arg)
672 
673  def __str__(self):
674  return "@%d[%s]" % (self._size, str(self._arg))
675 
676  def get_r(self, mem_read=False, cst_read=False):
677  if mem_read:
678  return set(self._arg.get_r(mem_read, cst_read).union(set([self])))
679  else:
680  return set([self])
681 
682  def get_w(self):
683  return set([self]) # [memreg]
684 
685  def _exprhash(self):
686  return hash((EXPRMEM, hash(self._arg), self._size))
687 
688  def _exprrepr(self):
689  return "%s(%r, %r)" % (self.__class__.__name__,
690  self._arg, self._size)
691 
692  def __contains__(self, e):
693  return self == e or self._arg.__contains__(e)
694 
695  @visit_chk
696  def visit(self, cb, tv=None):
697  arg = self._arg.visit(cb, tv)
698  if arg == self._arg:
699  return self
700  return ExprMem(arg, self._size)
701 
702  def copy(self):
703  arg = self._arg.copy()
704  return ExprMem(arg, size=self._size)
705 
706  def is_op_segm(self):
707  return isinstance(self._arg, ExprOp) and self._arg.op == 'segm'
708 
709  def depth(self):
710  return self._arg.depth() + 1
711 
712  def graph_recursive(self, graph):
713  graph.add_node(self)
714  self._arg.graph_recursive(graph)
715  graph.add_uniq_edge(self, self._arg)
716 
717 
718 class ExprOp(Expr):
719 
720  """An ExprOp stand for an operation between Expr
721 
722  Use cases:
723  - var1 XOR var2
724  - var1 + var2 + var3
725  - parity bit(var1)
726  """
727 
728  def __init__(self, op, *args):
729  """Create an ExprOp
730  @op: str, operation
731  @*args: Expr, operand list
732  """
733 
734  sizes = set([arg.size for arg in args])
735 
736  if len(sizes) != 1:
737  # Special cases : operande sizes can differ
738  if op not in ["segm"]:
739  raise ValueError(
740  "sanitycheck: ExprOp args must have same size! %s" %
741  ([(str(arg), arg.size) for arg in args]))
742 
743  if not isinstance(op, str):
744  raise ValueError("ExprOp: 'op' argument must be a string")
745 
746  self._op, self._args = op, tuple(args)
747 
748  # Set size for special cases
749  if self._op in [
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"]:
754  sz = 1
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,
758  TOK_EQUAL, TOK_POS,
759  TOK_POS_STRICT,
760  ]:
761  sz = 1
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']:
766  sz = 64
767  elif self._op in ['double_to_mem_16', 'double_to_int_16',
768  'float_trunc_to_int_16', 'double_trunc_to_int_16']:
769  sz = 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',
772  'double_to_float']:
773  sz = 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',
776  'float_to_double']:
777  sz = 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']:
781  sz = 80
782  elif self._op in ['segm']:
783  sz = self._args[1].size
784  else:
785  if None in sizes:
786  sz = None
787  else:
788  # All arguments have the same size
789  sz = list(sizes)[0]
790 
791  self._size = sz
792 
793  op = property(lambda self: self._op)
794  args = property(lambda self: self._args)
795 
796  def __str__(self):
797  if self.is_associative():
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]) + ')')
806  else:
807  return reduce(lambda x, y: x + ' ' + str(y),
808  self._args,
809  '(' + str(self._op)) + ')'
810 
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())
814 
815  def get_w(self):
816  raise ValueError('op cannot be written!', self)
817 
818  def _exprhash(self):
819  h_hargs = [hash(arg) for arg in self._args]
820  return hash((EXPROP, self._op, tuple(h_hargs)))
821 
822  def _exprrepr(self):
823  return "%s(%r, %s)" % (self.__class__.__name__, self._op,
824  ', '.join(repr(arg) for arg in self._args))
825 
826  def __contains__(self, e):
827  if self == e:
828  return True
829  for arg in self._args:
830  if arg.__contains__(e):
831  return True
832  return False
833 
834  def is_function_call(self):
835  return self._op.startswith('call')
836 
837  def is_associative(self):
838  "Return True iff current operation is associative"
839  return (self._op in ['+', '*', '^', '&', '|'])
840 
841  def is_commutative(self):
842  "Return True iff current operation is commutative"
843  return (self._op in ['+', '*', '^', '&', '|'])
844 
845  @visit_chk
846  def visit(self, cb, tv=None):
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)])
849  if modified:
850  return ExprOp(self._op, *args)
851  return self
852 
853  def copy(self):
854  args = [arg.copy() for arg in self._args]
855  return ExprOp(self._op, *args)
856 
857  def depth(self):
858  depth = [arg.depth() for arg in self._args]
859  return max(depth) + 1
860 
861  def graph_recursive(self, graph):
862  graph.add_node(self)
863  for arg in self._args:
864  arg.graph_recursive(graph)
865  graph.add_uniq_edge(self, arg)
866 
867 
869 
870  def __init__(self, arg, start, stop):
871  assert(start < stop)
872 
873  self._arg, self._start, self._stop = arg, start, stop
874  self._size = self._stop - self._start
875 
876  arg = property(lambda self: self._arg)
877  start = property(lambda self: self._start)
878  stop = property(lambda self: self._stop)
879 
880  def __str__(self):
881  return "%s[%d:%d]" % (str(self._arg), self._start, self._stop)
882 
883  def get_r(self, mem_read=False, cst_read=False):
884  return self._arg.get_r(mem_read, cst_read)
885 
886  def get_w(self):
887  return self._arg.get_w()
888 
889  def _exprhash(self):
890  return hash((EXPRSLICE, hash(self._arg), self._start, self._stop))
891 
892  def _exprrepr(self):
893  return "%s(%r, %d, %d)" % (self.__class__.__name__, self._arg,
894  self._start, self._stop)
895 
896  def __contains__(self, e):
897  if self == e:
898  return True
899  return self._arg.__contains__(e)
900 
901  @visit_chk
902  def visit(self, cb, tv=None):
903  arg = self._arg.visit(cb, tv)
904  if arg == self._arg:
905  return self
906  return ExprSlice(arg, self._start, self._stop)
907 
908  def copy(self):
909  return ExprSlice(self._arg.copy(), self._start, self._stop)
910 
911  def depth(self):
912  return self._arg.depth() + 1
913 
914  def slice_rest(self):
915  "Return the completion of the current slice"
916  size = self._arg.size
917  if self._start >= size or self._stop > size:
918  raise ValueError('bad slice rest %s %s %s' %
919  (size, self._start, self._stop))
920 
921  if self._start == self._stop:
922  return [(0, size)]
923 
924  rest = []
925  if self._start != 0:
926  rest.append((0, self._start))
927  if self._stop < size:
928  rest.append((self._stop, size))
929 
930  return rest
931 
932  def graph_recursive(self, graph):
933  graph.add_node(self)
934  self._arg.graph_recursive(graph)
935  graph.add_uniq_edge(self, self._arg)
936 
937 
939 
940  """
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.
944 
945  Burger Example:
946  ExprCompose([(salad, 0, 3), (cheese, 3, 10), (beacon, 10, 16)])
947  In the example, salad.size == 3.
948  """
949 
950  def __init__(self, args):
951  """Create an ExprCompose
952  The ExprCompose is contiguous and starts at 0
953  @args: tuple(Expr, int, int)
954  """
955 
956  last_stop = 0
957  args = sorted(args, key=itemgetter(1))
958  for e, start, stop in args:
959  if e.size != stop - start:
960  raise ValueError(
961  "sanitycheck: ExprCompose args must have correct size!" +
962  " %r %r %r" % (e, e.size, stop - start))
963  if last_stop != start:
964  raise ValueError(
965  "sanitycheck: ExprCompose args must be contiguous!" +
966  " %r" % (args))
967  last_stop = stop
968 
969  # Transform args to lists
970  o = []
971  for e, a, b in args:
972  assert(a >= 0 and b >= 0)
973  o.append(tuple([e, a, b]))
974  self._args = tuple(o)
975 
976  self._size = self._args[-1][2]
977 
978  args = property(lambda self: self._args)
979 
980  def __str__(self):
981  return '{' + ', '.join(['%s,%d,%d' %
982  (str(arg[0]), arg[1], arg[2]) for arg in self._args]) + '}'
983 
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())
987 
988  def get_w(self):
989  return reduce(lambda elements, arg:
990  elements.union(arg[0].get_w()), self._args, set())
991 
992  def _exprhash(self):
993  h_args = [EXPRCOMPOSE] + [(hash(arg[0]), arg[1], arg[2])
994  for arg in self._args]
995  return hash(tuple(h_args))
996 
997  def _exprrepr(self):
998  return "%s(%r)" % (self.__class__.__name__, self._args)
999 
1000  def __contains__(self, e):
1001  if self == e:
1002  return True
1003  for arg in self._args:
1004  if arg == e:
1005  return True
1006  if arg[0].__contains__(e):
1007  return True
1008  return False
1009 
1010  @visit_chk
1011  def visit(self, cb, tv=None):
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)])
1014  if modified:
1015  return ExprCompose(args)
1016  return self
1017 
1018  def copy(self):
1019  args = [(arg[0].copy(), arg[1], arg[2]) for arg in self._args]
1020  return ExprCompose(args)
1021 
1022  def depth(self):
1023  depth = [arg[0].depth() for arg in self._args]
1024  return max(depth) + 1
1025 
1026  def graph_recursive(self, graph):
1027  graph.add_node(self)
1028  for arg in self.args:
1029  arg[0].graph_recursive(graph)
1030  graph.add_uniq_edge(self, arg[0])
1031 
1032 
1033 # Expression order for comparaison
1034 expr_order_dict = {ExprId: 1,
1035  ExprCond: 2,
1036  ExprMem: 3,
1037  ExprOp: 4,
1038  ExprSlice: 5,
1039  ExprCompose: 7,
1040  ExprInt: 8,
1041  }
1042 
1043 
1045  # Sort by start bit address, then expr, then stop but address
1046  x = cmp(e1[1], e2[1])
1047  if x:
1048  return x
1049  x = compare_exprs(e1[0], e2[0])
1050  if x:
1051  return x
1052  x = cmp(e1[2], e2[2])
1053  return x
1054 
1055 
1057  # Sort by list elements in incremental order, then by list size
1058  for i in xrange(min(len(l1_e), len(l2_e))):
1059  x = compare_exprs_compose(l1_e[i], l2_e[i])
1060  if x:
1061  return x
1062  return cmp(len(l1_e), len(l2_e))
1063 
1064 
1065 def compare_expr_list(l1_e, l2_e):
1066  # Sort by list elements in incremental order, then by list size
1067  for i in xrange(min(len(l1_e), len(l2_e))):
1068  x = compare_exprs(l1_e[i], l2_e[i])
1069  if x:
1070  return x
1071  return cmp(len(l1_e), len(l2_e))
1072 
1073 
1074 def compare_exprs(e1, e2):
1075  """Compare 2 expressions for canonization
1076  @e1: Expr
1077  @e2: Expr
1078  0 => ==
1079  1 => e1 > e2
1080  -1 => e1 < e2
1081  """
1082  c1 = e1.__class__
1083  c2 = e2.__class__
1084  if c1 != c2:
1085  return cmp(expr_order_dict[c1], expr_order_dict[c2])
1086  if e1 == e2:
1087  return 0
1088  if c1 == ExprInt:
1089  return cmp(e1.arg, e2.arg)
1090  elif c1 == ExprId:
1091  x = cmp(e1.name, e2.name)
1092  if x:
1093  return x
1094  return cmp(e1.size, e2.size)
1095  elif c1 == ExprAff:
1096  raise NotImplementedError(
1097  "Comparaison from an ExprAff not yet implemented")
1098  elif c2 == ExprCond:
1099  x = compare_exprs(e1.cond, e2.cond)
1100  if x:
1101  return x
1102  x = compare_exprs(e1.src1, e2.src1)
1103  if x:
1104  return x
1105  x = compare_exprs(e1.src2, e2.src2)
1106  return x
1107  elif c1 == ExprMem:
1108  x = compare_exprs(e1.arg, e2.arg)
1109  if x:
1110  return x
1111  return cmp(e1.size, e2.size)
1112  elif c1 == ExprOp:
1113  if e1.op != e2.op:
1114  return cmp(e1.op, e2.op)
1115  return compare_expr_list(e1.args, e2.args)
1116  elif c1 == ExprSlice:
1117  x = compare_exprs(e1.arg, e2.arg)
1118  if x:
1119  return x
1120  x = cmp(e1.start, e2.start)
1121  if x:
1122  return x
1123  x = cmp(e1.stop, e2.stop)
1124  return x
1125  elif c1 == ExprCompose:
1126  return compare_expr_list_compose(e1.args, e2.args)
1127  raise NotImplementedError(
1128  "Comparaison between %r %r not implemented" % (e1, e2))
1129 
1130 
1132  l = list(l)
1133  l.sort(cmp=compare_exprs)
1134  return l
1135 
1136 
1138  l = list(l)
1139  l.sort(cmp=compare_exprs_compose)
1140  return l
1141 
1142 # Generate ExprInt with common size
1143 
1144 
1145 def ExprInt1(i):
1146  return ExprInt(uint1(i))
1147 
1148 
1149 def ExprInt8(i):
1150  return ExprInt(uint8(i))
1151 
1152 
1153 def ExprInt16(i):
1154  return ExprInt(uint16(i))
1155 
1156 
1157 def ExprInt32(i):
1158  return ExprInt(uint32(i))
1159 
1160 
1161 def ExprInt64(i):
1162  return ExprInt(uint64(i))
1163 
1164 
1165 def ExprInt_from(e, i):
1166  "Generate ExprInt with size equal to expression"
1167  return ExprInt(mod_size2uint[e.size](i))
1168 
1169 
1171  if isinstance(e, ExprId):
1172  ids.add(e)
1173  return e
1174 
1175 
1177  ids = set()
1178  e.visit(lambda x: get_expr_ids_visit(x, ids))
1179  return ids
1180 
1181 
1182 def test_set(e, v, tks, result):
1183  """Test if v can correspond to e. If so, update the context in result.
1184  Otherwise, return False
1185  @e : Expr
1186  @v : Expr
1187  @tks : list of ExprId, available jokers
1188  @result : dictionnary of ExprId -> Expr, current context
1189  """
1190 
1191  if not v in tks:
1192  return e == v
1193  if v in result and result[v] != e:
1194  return False
1195  result[v] = e
1196  return result
1197 
1198 
1199 def MatchExpr(e, m, tks, result=None):
1200  """Try to match m expression with e expression with tks jokers.
1201  Result is output dictionnary with matching joker values.
1202  @e : Expr to test
1203  @m : Targetted Expr
1204  @tks : list of ExprId, available jokers
1205  @result : dictionnary of ExprId -> Expr, output matching context
1206  """
1207 
1208  if result is None:
1209  result = {}
1210 
1211  if m in tks:
1212  # m is a Joker
1213  return test_set(e, m, tks, result)
1214 
1215  if isinstance(e, ExprInt):
1216  return test_set(e, m, tks, result)
1217 
1218  elif isinstance(e, ExprId):
1219  return test_set(e, m, tks, result)
1220 
1221  elif isinstance(e, ExprOp):
1222 
1223  # e need to be the same operation than m
1224  if not isinstance(m, ExprOp):
1225  return False
1226  if e.op != m.op:
1227  return False
1228  if len(e.args) != len(m.args):
1229  return False
1230 
1231  # Perform permutation only if the current operation is commutative
1232  if e.is_commutative():
1233  permutations = itertools.permutations(e.args)
1234  else:
1235  permutations = [e.args]
1236 
1237  # For each permutations of arguments
1238  for permut in permutations:
1239  good = True
1240  # We need to use a copy of result to not override it
1241  myresult = dict(result)
1242  for a1, a2 in zip(permut, m.args):
1243  r = MatchExpr(a1, a2, tks, myresult)
1244  # If the current permutation do not match EVERY terms
1245  if r is False:
1246  good = False
1247  break
1248  if good is True:
1249  # We found a possibility
1250  for k, v in myresult.items():
1251  # Updating result in place (to keep pointer in recursion)
1252  result[k] = v
1253  return result
1254  return False
1255 
1256  # Recursive tests
1257 
1258  elif isinstance(e, ExprMem):
1259  if not isinstance(m, ExprMem):
1260  return False
1261  if e.size != m.size:
1262  return False
1263  return MatchExpr(e.arg, m.arg, tks, result)
1264 
1265  elif isinstance(e, ExprSlice):
1266  if not isinstance(m, ExprSlice):
1267  return False
1268  if e.start != m.start or e.stop != m.stop:
1269  return False
1270  return MatchExpr(e.arg, m.arg, tks, result)
1271 
1272  elif isinstance(e, ExprCond):
1273  if not isinstance(m, ExprCond):
1274  return False
1275  r = MatchExpr(e.cond, m.cond, tks, result)
1276  if r is False:
1277  return False
1278  r = MatchExpr(e.src1, m.src1, tks, result)
1279  if r is False:
1280  return False
1281  r = MatchExpr(e.src2, m.src2, tks, result)
1282  if r is False:
1283  return False
1284  return result
1285 
1286  elif isinstance(e, ExprCompose):
1287  if not isinstance(m, ExprCompose):
1288  return False
1289  for a1, a2 in zip(e.args, m.args):
1290  if a1[1] != a2[1] or a1[2] != a2[2]:
1291  return False
1292  r = MatchExpr(a1[0], a2[0], tks, result)
1293  if r is False:
1294  return False
1295  return result
1296 
1297  else:
1298  raise NotImplementedError("MatchExpr: Unknown type: %s" % type(e))
1299 
1300 
1301 def SearchExpr(e, m, tks, result=None):
1302  # TODO XXX: to test
1303  if result is None:
1304  result = set()
1305 
1306  def visit_search(e, m, tks, result):
1307  r = {}
1308  MatchExpr(e, m, tks, r)
1309  if r:
1310  result.add(tuple(r.items()))
1311  return e
1312  e.visit(lambda x: visit_search(x, m, tks, result))
1313 
1314 
1315 def get_rw(exprs):
1316  o_r = set()
1317  o_w = set()
1318  for e in exprs:
1319  o_r.update(e.get_r(mem_read=True))
1320  for e in exprs:
1321  o_w.update(e.get_w())
1322  return o_r, o_w
1323 
1324 
1325 def get_list_rw(exprs, mem_read=False, cst_read=True):
1326  """
1327  return list of read/write reg/cst/mem for each expressions
1328  """
1329  list_rw = []
1330  # cst_num = 0
1331  for e in exprs:
1332  o_r = set()
1333  o_w = set()
1334  # get r/w
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())
1339  # each cst is indexed
1340  o_r_rw = set()
1341  for r in o_r:
1342  # if isinstance(r, ExprInt):
1343  # r = ExprOp('cst_%d'%cst_num, r)
1344  # cst_num += 1
1345  o_r_rw.add(r)
1346  o_r = o_r_rw
1347  list_rw.append((o_r, o_w))
1348 
1349  return list_rw
1350 
1351 
1353  def visit_getops(e, out=None):
1354  if out is None:
1355  out = set()
1356  if isinstance(e, ExprOp):
1357  out.add(e.op)
1358  return e
1359  ops = set()
1360  e.visit(lambda x: visit_getops(x, ops))
1361  return ops
1362 
1363 
1365  def visit_getmem(e, out=None):
1366  if out is None:
1367  out = set()
1368  if isinstance(e, ExprMem):
1369  out.add(e)
1370  return e
1371  ops = set()
1372  e.visit(lambda x: visit_getmem(x, ops))
1373  return ops