Files
cea-sec-miasm/miasm/expression/expression.py
T
2012-02-23 11:23:18 +01:00

823 lines
29 KiB
Python

#
# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
from numpy import uint8, uint16, uint32, uint64, int8, int16, int32, int64
tip = 'tip'
def slice_rest(size, start, stop):
if start >=size or stop > size: raise 'bad slice rest %s %s %s'%(str(size), str(start), str(stop))
if start == stop: return [(0,size)]
rest = []
if start !=0:
rest.append((0, start))
if stop < size:
rest.append((stop, size))
return rest
tab_int_size = {int8:8,
uint8:8,
int16:16,
uint16:16,
int32:32,
uint32:32,
int64:64,
uint64:64
}
my_size_mask = {1:1, 8:0xFF, 16:0xFFFF, 32:0xFFFFFFFF, 64:0xFFFFFFFFFFFFFFFFL}
def is_int(a):
t = [int8, int16, int32, int64,
uint8, uint16, uint32, uint64]
return any([isinstance(a, x) for x in t])
def get_missing_interval(all_intervals, i_min = 0, i_max = 32):
my_intervals = all_intervals[:]
my_intervals.sort()
my_intervals.append((i_max, i_max))
missing_i = []
last_pos = i_min
for start, stop in my_intervals:
if last_pos != start:
missing_i.append((last_pos, start))
last_pos = stop
return missing_i
class Expr:
is_term = False
is_simp = False
is_eval = False
def __init__(self, arg):
self.arg = arg
def __str__(self):
return str(self.arg)
def __getitem__(self, i):
if not isinstance(i, slice):
print i
raise "bad slice"
start, stop, step = i.indices(0x1337BEEF)
return ExprSlice(self, start, stop)
def get_r(self, mem_read=False):
return self.arg.get_r(mem_read)
def get_w(self):
return self.arg.get_w()
def get_size(self):
return arg.get_size()
def __repr__(self):
return "<%s 0x%x>"%(self.__class__.__name__, id(self))
def __ne__(self, a):
return not self.__eq__(a)
def toC(self):
print self
fdsfs
return self.arg.toC()
def __add__(self, a):
return ExprOp('+', self, a)
def __sub__(self, a):
return ExprOp('-', self, a)
def __div__(self, a):
return ExprOp('/', self, a)
def __mul__(self, a):
return ExprOp('*', self, a)
def __lshift__(self, a):
return ExprOp('<<', self, a)
def __rshift__(self, a):
return ExprOp('>>', self, a)
def __xor__(self, a):
return ExprOp('^', self, a)
def __or__(self, a):
return ExprOp('|', self, a)
def __and__(self, a):
return ExprOp('&', self, a)
class ExprTop(Expr):
def __init__(self, e=None):
fdqs
self.e = e
pass
def __str__(self):
return "top(%s)"%str(self.e)
def get_r(self, mem_read=False):
raise ValueError("get_r on TOP")
def get_w(self):
raise ValueError("get_r on TOP")
def get_size(self):
raise ValueError("get_size on TOP")
def reload_expr(self, g = {}):
return ExprTop(self.e)
def __eq__(self, a):
return isinstance(a, ExprTop)
def __hash__(self):
return 0x1337beef
def toC(self):
raise ValueError('cannot toC TOP')
class ExprInt(Expr):
def __init__(self, arg):
if not is_int(arg):
raise 'arg must by numpy int! %s'%str(arg)
self.arg = arg
def __str__(self):
if self.arg < 0:
return str("-0x%X"%-int(self.arg&0xffffffffffffffffL))
else:
return str("0x%X"%int(self.arg&0xffffffffffffffffL))
def get_r(self, mem_read=False):
return set()
def get_w(self):
return set()
def get_size(self):
return 8*self.arg.nbytes
def reload_expr(self, g = {}):
return ExprInt(self.arg)
def __contains__(self, e):
return self == e
def replace_expr(self, g = {}):
if self in g:
return g[self]
return self
def __eq__(self, a):
if not isinstance(a, ExprInt):
return False
return self.arg == a.arg
def __hash__(self):
return hash(self.arg)
def __repr__(self):
return Expr.__repr__(self)[:-1]+" 0x%X>"%int(self.arg&0xffffffffffffffffL)
def toC(self):
return str(self)
def canonize(self):
return self
class ExprId(Expr):
def __init__(self, name, size = 32, is_term = False):
self.name, self.size = name, size
self.is_term = is_term
def __str__(self):
return str(self.name)
def get_r(self, mem_read=False):
return set([self])
def get_w(self):
return set([self])
def get_size(self):
return self.size
def reload_expr(self, g = {}):
if self in g:
return g[self]
else:
return ExprId(self.name, self.size)
if self in g:
return g[self]
return self
def __contains__(self, e):
return self == e
def replace_expr(self, g = {}):
if self in g:
return g[self]
return self
def __eq__(self, a):
if not isinstance(a, ExprId):
return False
if self.name == a.name and self.size != a.size:
fdsfdsfdsdsf
return self.name == a.name and self.size == a.size
def __hash__(self):
return hash(self.name)
def __repr__(self):
return Expr.__repr__(self)[:-1]+" %s>"%self.name
def toC(self):
return str(self)
def canonize(self):
return self
memreg = ExprId('MEM')
class ExprAff(Expr):
def __init__(self, dst, src):
#if dst is slice=> replace with id make composed src
if isinstance(dst, ExprSlice):
self.dst = dst.arg
rest = [ExprSliceTo(ExprSlice(dst.arg, *r), *r) for r in slice_rest(dst.arg.size, dst.start, dst.stop)]
all_a = [(dst.start, ExprSliceTo(src, dst.start, dst.stop))]+ [(x.start, x) for x in rest]
all_a.sort()
self.src = ExprCompose([x[1] for x in all_a])
else:
self.dst, self.src = dst,src
def __str__(self):
return "%s = %s"%(str(self.dst), str(self.src))
def get_r(self, mem_read=False):
return self.src.get_r(mem_read)
def get_w(self):
if isinstance(self.dst, ExprMem):
return set([self.dst]) #[memreg]
else:
return self.dst.get_w()
#return dst size? XXX
def get_size(self):
return self.dst.get_size()
def reload_expr(self, g = {}):
if self in g:
return g[self]
dst = self.dst
if isinstance(dst, Expr):
dst = self.dst.reload_expr(g)
src = self.src
if isinstance(src, Expr):
src = self.src.reload_expr(g)
return ExprAff(dst, src )
def __contains__(self, e):
return self == e or self.src.__contains__(e) or self.dst.__contains__(e)
def replace_expr(self, g = {}):
if self in g:
return g[self]
dst = self.dst.replace_expr(g)
src = self.src.replace_expr(g)
return ExprAff(dst, src)
def __eq__(self, a):
if not isinstance(a, ExprAff):
return False
return self.src == a.src and self.dst == a.dst
def __hash__(self):
return hash(self.dst)^hash(self.src)
def toC(self):
return "%s = %s"%(self.dst.toC(), self.src.toC())
#XXX /!\ for hackish expraff to slice
def get_modified_slice(self):
dst = self.dst
if not isinstance(self.src, ExprCompose):
raise ValueError("get mod slice not on expraff slice", str(self))
modified_s = []
for x in self.src.args:
if not isinstance(x.arg, ExprSlice) or x.arg.arg != dst or x.start != x.arg.start or x.stop != x.arg.stop:
modified_s.append(x)
return modified_s
def canonize(self):
return ExprAff(self.src.canonize(), self.dst.canonize())
class ExprCond(Expr):
def __init__(self, cond, src1, src2):
self.cond, self.src1, self.src2 = cond, src1, src2
def __str__(self):
return "%s?(%s,%s)"%(str(self.cond), str(self.src1), str(self.src2))
def get_r(self, mem_read=False):
out=self.cond.get_r(mem_read).union(self.src1.get_r(mem_read)).union(self.src2.get_r(mem_read))
return out
def get_w(self):
return set()
#return src1 size? XXX
def get_size(self):
return self.src1.get_size()
def reload_expr(self, g = {}):
if self in g:
return g[self]
src1 = self.src1
if isinstance(src1, Expr):
src1 = self.src1.reload_expr(g)
src2 = self.src2
if isinstance(src2, Expr):
src2 = self.src2.reload_expr(g)
cond = self.cond
if isinstance(cond, Expr):
cond = self.cond.reload_expr(g)
return ExprCond(cond, src1, src2 )
def replace_expr(self, g = {}):
if self in g:
return g[self]
cond = self.cond.replace_expr(g)
src1 = self.src1.replace_expr(g)
src2 = self.src2.replace_expr(g)
return ExprCond(cond, src1, src2 )
def __contains__(self, e):
return self == e or self.cond.__contains__(e) or self.src1.__contains__(e) or self.src2.__contains__(e)
def __eq__(self, a):
if not isinstance(a, ExprCond):
return False
return self.cond == a.cond and self.src1 == a.src1 and self.src2 == a.src2
def __hash__(self):
return hash(self.cond)^hash(self.src1)^hash(self.src2)
def toC(self):
return "(%s?%s:%s)"%(self.cond.toC(), self.src1.toC(), self.src2.toC())
def canonize(self):
return ExprAff(self.cond.canonize(),
self.src1.canonize(),
self.src2.canonize())
class ExprMem(Expr):
def __init__(self, arg, size = 32, segm = None):
if not isinstance(arg, Expr): raise 'arg must be expr'
self.arg, self.size, self.segm = arg, size, segm
def __str__(self):
if self.segm:
return "%s:@%d[%s]"%(self.segm, self.size, str(self.arg))
else:
return "@%d[%s]"%(self.size, str(self.arg))
def get_r(self, mem_read=False):
if mem_read:
return set(self.arg.get_r(mem_read).union(set([self])))
else:
return set([self])
def get_w(self):
return set([self]) #[memreg]
def get_size(self):
return self.size
def reload_expr(self, g = {}):
if self in g:
return g[self]
arg = self.arg
segm = self.segm
if isinstance(arg, Expr):
arg = self.arg.reload_expr(g)
if isinstance(segm, Expr):
segm = self.segm.reload_expr(g)
return ExprMem(arg, self.size, segm)
def __contains__(self, e):
return self == e or self.arg.__contains__(e)
def replace_expr(self, g = {}):
if self in g:
return g[self]
arg = self.arg.replace_expr(g)
return ExprMem(arg, self.size, self.segm)
def __eq__(self, a):
if not isinstance(a, ExprMem):
return False
return self.arg == a.arg and self.size == a.size and self.segm == a.segm
def __hash__(self):
return hash(self.arg)^hash(self.size)^hash(self.segm)
def toC(self):
if self.segm:
return "MEM_LOOKUP_%.2d_SEGM(%s, %s)"%(self.size, self.segm.toC(), self.arg.toC())
else:
return "MEM_LOOKUP_%.2d(%s)"%(self.size, self.arg.toC())
def canonize(self):
return ExprMem(self.arg.canonize(), size = self.size)
class ExprOp(Expr):
def __init__(self, op, *args):
self.op, self.args = op, args
def __str__(self):
if len(self.args) == 2:
return '('+str(self.args[0]) + ' ' + self.op + ' ' + str(self.args[1]) + ')'
elif len(self.args)> 2:
return self.op + '(' + ', '.join([str(x) for x in self.args]) + ')'
else:
return reduce(lambda x,y:x+' '+str(y), self.args, '('+str(self.op))+')'
def get_r(self, mem_read=False):
return reduce(lambda x,y:x.union(y.get_r(mem_read)), self.args, set())
def get_w(self):
raise ValueError('op cannot be written!', self)
#return 1st arg size XXX
def get_size(self):
a = self.args[0].get_size()
if len(self.args)>1:
if not a:
a = self.args[1].get_size()
return a
def reload_expr(self, g = {}):
if self in g:
return g[self]
args = []
for a in self.args:
if isinstance(a, Expr):
args.append(a.reload_expr(g))
else:
args.append(a)
return ExprOp(self.op, *args )
def __contains__(self, e):
if self == e:
return True
for a in self.args:
if a.__contains__(e):
return True
return False
def replace_expr(self, g = {}):
if self in g:
return g[self]
args = []
for a in self.args:
args.append(a.replace_expr(g))
return ExprOp(self.op, *args )
def __eq__(self, a):
if not isinstance(a, ExprOp):
return False
if self.op !=a.op:
return False
if len(self.args) != len(a.args):
return False
for i, x in enumerate(self.args):
if not x == a.args[i]:
return False
return True
def __hash__(self):
h = hash(self.op)
for a in self.args:
h^=hash(a)
return h
def toC(self):
dct_shift= {'a>>':"right_arith",
'>>':"right_logic",
'<<':"left_logic",
'a<<':"left_logic"}
dct_rot = {'<<<':'rot_left',
'>>>':'rot_right'}
if len(self.args)==1:
if self.op == 'parity':
return "parity(%s&0x%x)"%(self.args[0].toC(), my_size_mask[self.args[0].get_size()])
elif self.op == '!':
return "(~ %s)&0x%x"%(self.args[0].toC(), my_size_mask[self.args[0].get_size()])
elif self.op in ['int_32_to_double', 'int_64_to_double']:
return "%s(%s)"%(self.op, self.args[0].toC())
elif self.op == 'double_to_int_32':
return "%s(%s)"%(self.op, self.args[0].toC())
elif self.op in ['mem_32_to_double', 'mem_64_to_double']:
return "%s(%s)"%(self.op, self.args[0].toC())
elif self.op.startswith("double_to_mem_"):
return "%s(%s)"%(self.op, self.args[0].toC())
elif self.op in ["ftan", "frndint", "f2xm1", "fsin", "fsqrt", "fabs", "fcos"]:
return "%s(%s)"%(self.op, self.args[0].toC())
else:
print self.op
raise ValueError('unknown op!!', str(self.op))
return '('+str(self.op)+self.args[0].toC()+')'
elif len(self.args)==2:
if self.op == "==":
return '(((%s&0x%x) == (%s&0x%x))?1:0)'%(self.args[0].toC(), my_size_mask[self.args[0].get_size()], self.args[1].toC(), my_size_mask[self.args[1].get_size()])
elif self.op in dct_shift:
return 'shift_%s_%.2d(%s , %s)'%(dct_shift[self.op],
self.args[0].get_size(),
self.args[0].toC(),
self.args[1].toC())
elif self.op in ['+', '-', '*', '^', '&', '|']:
return '(((%s&0x%x) %s (%s&0x%x))&0x%x)'%(self.args[0].toC(),
my_size_mask[self.args[0].get_size()],
str(self.op),
self.args[1].toC(),
my_size_mask[self.args[1].get_size()],
my_size_mask[self.args[0].get_size()])
elif self.op in dct_rot:
return '(%s(%s, %s, %s) &0x%x)'%(dct_rot[self.op],
self.args[0].get_size(),
self.args[0].toC(),
self.args[1].toC(),
my_size_mask[self.args[0].get_size()])
elif self.op == '*lo':
return 'mul_lo_op(%s, %s, %s)' %(
self.args[0].get_size(),
self.args[0].toC(),
self.args[1].toC())
elif self.op == 'umul32_lo':
return 'mul_lo_op(%s, %s, %s)' %(
self.args[0].get_size(),
self.args[0].toC(),
self.args[1].toC())
elif self.op in ['imul16_lo', 'imul32_lo']:
return 'imul_lo_op_%s(%s, %s)' %(
self.args[0].get_size(),
self.args[0].toC(),
self.args[1].toC())
elif self.op in ['imul16_hi', 'imul32_hi']:
return 'imul_hi_op_%s(%s, %s)' %(
self.args[0].get_size(),
self.args[0].toC(),
self.args[1].toC())
elif self.op == '*hi':
return 'mul_hi_op(%s, %s, %s)' %(
self.args[0].get_size(),
self.args[0].toC(),
self.args[1].toC())
elif self.op == 'umul32_hi':
return 'mul_hi_op(%s, %s, %s)' %(
self.args[0].get_size(),
self.args[0].toC(),
self.args[1].toC())
elif self.op == 'umul08':
return 'mul_hi_op(%s, %s, %s)' %(
self.args[0].get_size(),
self.args[0].toC(),
self.args[1].toC())
elif self.op in ['umul16_lo', 'umul16_hi']:
return '%s(%s, %s)' %(self.op,
self.args[0].toC(),
self.args[1].toC())
elif self.op in ['bsr', 'bsf']:
return 'my_%s(%s, %s)'%(self.op,
self.args[0].toC(),
self.args[1].toC())
elif self.op in ['imul08']:
return 'my_%s(%s, %s)'%(self.op,
self.args[0].toC(),
self.args[1].toC())
elif self.op.startswith('cpuid'):
return "%s(%s, %s)"%(self.op, self.args[0].toC(), self.args[1].toC())
elif self.op.startswith("fcom"):
return "%s(%s, %s)"%(self.op, self.args[0].toC(), self.args[1].toC())
elif self.op in ["fadd", "fsub", "fdiv", 'fmul', "fscale"]:
return "%s(%s, %s)"%(self.op, self.args[0].toC(), self.args[1].toC())
else:
print self.op
raise ValueError('unknown op!!', str(self.op))
elif len(self.args)==3:
dct_div= {'div8':"div_op",
'div16':"div_op",
'div32':"div_op",
'idiv32':"div_op", #XXX to test
'rem8':"rem_op",
'rem16':"rem_op",
'rem32':"rem_op",
'irem32':"rem_op", #XXX to test
'<<<c_rez':'rcl_rez_op',
'<<<c_cf':'rcl_cf_op',
'>>>c_rez':'rcr_rez_op',
'>>>c_cf':'rcr_cf_op',
}
if not self.op in dct_div:
fsdff
return '(%s(%s, %s, %s, %s) &0x%x)'%(dct_div[self.op],
self.args[0].get_size(),
self.args[0].toC(),
self.args[1].toC(),
self.args[2].toC(),
my_size_mask[self.args[0].get_size()])
else:
raise ValueError('not imple', str(self))
def canonize(self):
args = [x.canonize() for x in self.args]
if self.op in ['+', '^', '&', '|', '*']:
args = canonize_expr_list(args)
return ExprOp(self.op, *args)
class ExprSlice(Expr):
def __init__(self, arg, start, stop):
self.arg, self.start, self.stop = arg, start, stop
def __str__(self):
return "%s[%d:%d]"%(str(self.arg), self.start, self.stop)
def get_r(self, mem_read=False):
return self.arg.get_r(mem_read)
def get_w(self):
return self.arg.get_w()
def get_size(self):
return self.stop-self.start
def reload_expr(self, g = {}):
arg = self.arg.reload_expr(g)
return ExprSlice(arg, self.start, self.stop )
def __contains__(self, e):
if self == e:
return True
for a in self.args:
if a.__contains__(e):
return True
return False
def replace_expr(self, g = {}):
if self in g:
return g[self]
arg = self.arg.replace_expr(g)
return ExprSlice(arg, self.start, self.stop )
def __eq__(self, a):
if not isinstance(a, ExprSlice):
return False
return self.arg == a.arg and self.start == a.start and self.stop == a.stop
def __hash__(self):
return hash(self.arg)^hash(self.start)^hash(self.stop)
def toC(self):
# XXX gen mask in python for 64 bit & 32 bit compat
return "((%s>>%d) & ((0xFFFFFFFF>>(32-%d))))"%(self.arg.toC(), self.start, self.stop-self.start)
def canonize(self):
return ExprSlice(self.arg.canonize(),
self.start,
self.stop)
class ExprSliceTo(Expr):
def __init__(self, arg, start, stop):
self.arg, self.start, self.stop = arg, start, stop
def __str__(self):
return "%s_to[%d:%d]"%(str(self.arg), self.start, self.stop)
def get_r(self, mem_read=False):
return self.arg.get_r(mem_read)
def get_w(self):
return self.arg.get_w()
def get_size(self):
return self.stop-self.start
def reload_expr(self, g = {}):
if isinstance(self.arg, Expr):
arg = self.arg.reload_expr(g)
else:
arg = self.arg
return ExprSliceTo(arg, self.start, self.stop )
def __contains__(self, e):
return self == e or self.arg.__contains__(e)
def replace_expr(self, g = {}):
if self in g:
return g[self]
arg = self.arg.replace_expr(g)
return ExprSliceTo(arg, self.start, self.stop)
def __eq__(self, a):
if not isinstance(a, ExprSliceTo):
return False
return self.arg == a.arg and self.start == a.start and self.stop == a.stop
def __hash__(self):
return hash(self.arg)^hash(self.start)^hash(self.stop)
def toC(self):
# XXX gen mask in python for 64 bit & 32 bit compat
return "((%s & (0xFFFFFFFF>>(32-%d))) << %d)"%(self.arg.toC(), self.stop-self.start, self.start)
def canonize(self):
return ExprSliceTo(self.arg.canonize(),
self.start,
self.stop)
class ExprCompose(Expr):
def __init__(self, args):
self.args = args
def __str__(self):
return '('+', '.join([str(x) for x in self.args])+')'
def get_r(self, mem_read=False):
return reduce(lambda x,y:x.union(y.get_r(mem_read)), self.args, set())
def get_w(self):
return reduce(lambda x,y:x.union(y.get_r(mem_read)), self.args, set())
def get_size(self):
return max([x.stop for x in self.args]) - min([x.start for x in self.args])
def reload_expr(self, g = {}):
if self in g:
return g[self]
args = []
for a in self.args:
if isinstance(a, Expr):
args.append(a.reload_expr(g))
else:
args.append(a)
return ExprCompose(args )
def __contains__(self, e):
if self == e:
return True
for a in self.args:
if a.__contains__(e):
return True
return False
def replace_expr(self, g = {}):
if self in g:
return g[self]
args = []
for a in self.args:
args.append(a.replace_expr(g))
return ExprCompose(args )
def __eq__(self, a):
if not isinstance(a, ExprCompose):
return False
if not len(self.args) == len(a.args):
return False
for i, x in enumerate(self.args):
if not x == a.args[i]:
return False
return True
def __hash__(self):
h = 0
for a in self.args:
h^=hash(a)
return h
def toC(self):
out = ' | '.join([x.toC() for x in self.args])
return '('+out+')'
def canonize(self):
return ExprCompose(canonize_expr_list([x.canonize() for x in self.args]))
class set_expr:
def __init__(self, l = []):
self._list = []
for a in l:
self.add(a)
def add(self, a):
astr = str(a)
for x in self._list:
if str(x) == astr:
return
self._list.append(a)
def discard(self, a):
astr = str(a)
for x in self._list:
if str(x) == astr:
self._list.remove(x)
return True
return False
def remove(self ,a):
if not self.discard(a):
raise ValueError('value not found %s'%str(a))
def update(self, list_a):
if not isinstance(list_a, list) and not isinstance(list_a, set):
raise ValueError('arg must be list or set')
for a in list_a:
self.add(a)
def __contains__(self, a):
astr = str(a)
for x in self._list:
if astr == str(x):
return True
return False
def __str__(self):
o = []
o.append('[')
for x in self._list:
o.append(str(x))
o.append(']')
return " ".join(o)
def __repr__(self):
return "set_expr["+", ".join([str(x) for x in self._list])+"]"
def __iter__(self):
return self._list.__iter__()
expr_order_dict = {ExprId: 1,
ExprCond: 2,
ExprMem: 3,
ExprOp: 4,
ExprSlice: 5,
ExprSliceTo: 6,
ExprCompose: 7,
ExprInt: 8,
}
def compare_exprs_list(l1_e, l2_e):
for i in xrange(min(len(l1_e, l2_e))):
x = expr_compare(l1_e[i], l2_e[i])
if x: return x
return cmp(len(l1_e), len(l2_e))
# compare 2 expressions for canonization
# 0 => ==
# 1 => e1 > e2
# -1 => e1 < e2
def compare_exprs(e1, e2):
c1 = e1.__class__
c2 = e2.__class__
if c1 != c2:
return cmp(expr_order_dict[c1], expr_order_dict[c2])
if e1 == e2:
return 0
if c1 == ExprInt:
return cmp(e1.arg, e2.arg)
elif c1 == ExprId:
x = cmp(e1.name, e2.name)
if x: return x
return cmp(e1.size, e2.size)
elif c1 == ExprAff:
fds
elif c2 == ExprCond:
x = compare_exprs(e1.cond, e2.cond)
if x: return x
x = compare_exprs(e1.src1, e2.src1)
if x: return x
x = compare_exprs(e1.src2, e2.src2)
return x
elif c1 == ExprMem:
x = compare_exprs(e1.arg, e2.arg)
if x: return x
return cmp(e1.size, e2.size)
elif c1 == ExprOp:
if e1.op != e2.op:
return cmp(e1.op, e2.op)
return compare_exprs_list(e1.arg, e2.arg)
elif c1 == ExprSlice:
x = compare_exprs(e1.arg, e2.arg)
if x: return x
x = cmp(e1.start, e2.start)
if x: return x
x = cmp(e1.stop, e2.stop)
return x
elif c1 == ExprSliceTo:
x = compare_exprs(e1.arg, e2.arg)
if x: return x
x = cmp(e1.start, e2.start)
if x: return x
x = cmp(e1.stop, e2.stop)
return x
elif c1 == ExprCompose:
return compare_exprs_list(e1.arg, e2.arg)
raise ValueError("not imppl %r %r"%(e1, e2))
def canonize_expr_list(l):
l = l[:]
l.sort(cmp=compare_exprs)
return l