1import functools
2from typing import Union
3
4from pyvex.const import get_type_size
5from pyvex.expr import Const, IRExpr, RdTmp
6
7from .vex_helper import IRSBCustomizer, Type
8
9
10def checkparams(rhstype=None):
11 def decorator(fn):
12 @functools.wraps(fn)
13 def inner_decorator(self, *args, **kwargs):
14 irsb_cs = {a.irsb_c for a in list(args) + [self] if isinstance(a, VexValue)} # pylint: disable=no-member
15 assert len(irsb_cs) == 1, "All VexValues must belong to the same irsb_c"
16 args = list(args)
17 for idx, arg in enumerate(args):
18 if isinstance(arg, int):
19 thetype = rhstype if rhstype else self.ty
20 args[idx] = VexValue.Constant(self.irsb_c, arg, thetype)
21 elif not isinstance(arg, VexValue):
22 raise Exception("Cannot convert param %s" % str(arg))
23 args = tuple(args)
24 return fn(self, *args, **kwargs)
25
26 return inner_decorator
27
28 return decorator
29
30
31def vvifyresults(f):
32 @functools.wraps(f)
33 def decor(self, *args, **kwargs):
34 returned = f(self, *args, **kwargs)
35 assert isinstance(returned, RdTmp) or isinstance(returned, Const)
36 return VexValue(self.irsb_c, returned)
37
38 return decor
39
40
41class VexValue:
42 def __init__(self, irsb_c: "IRSBCustomizer", rdt: "Union[RdTmp, Const]", signed=False):
43 self.irsb_c = irsb_c
44 self.ty = self.irsb_c.get_type(rdt)
45 self.rdt = rdt
46 self.width = get_type_size(self.ty)
47 self._is_signed = signed
48
49 @property
50 def value(self):
51 if isinstance(self.rdt, Const):
52 return self.rdt.con.value
53 else:
54 raise ValueError("Non-constant VexValue has no value property")
55
56 @property
57 def signed(self):
58 return VexValue(self.irsb_c, self.rdt, True)
59
60 @vvifyresults
61 def widen_unsigned(self, ty):
62 return self.irsb_c.op_widen_int_unsigned(self.rdt, ty)
63
64 @vvifyresults
65 def cast_to(self, ty, signed=False, high=False):
66 return self.irsb_c.cast_to(self.rdt, ty, signed=signed, high=high)
67
68 @vvifyresults
69 def widen_signed(self, ty):
70 return self.irsb_c.op_widen_int_signed(self.rdt, ty)
71
72 @vvifyresults
73 def narrow_high(self, ty):
74 return self.irsb_c.op_narrow_int(self.rdt, ty, high_half=True)
75
76 @vvifyresults
77 def narrow_low(self, ty):
78 return self.irsb_c.op_narrow_int(self.rdt, ty, high_half=False)
79
80 # TODO at some point extend this to Vex nonconstants
81 def __getitem__(self, idx):
82 def getb(i):
83 return VexValue(self.irsb_c, self.irsb_c.get_bit(self.rdt, i))
84
85 def makeconstant(x):
86 return VexValue.Constant(self.irsb_c, x, Type.int_8).rdt
87
88 if not isinstance(idx, slice):
89 actualindex = slice(idx).indices(self.width)[1]
90 return getb(makeconstant(actualindex))
91 else:
92 return [getb(makeconstant(i)) for i in range(*idx.indices(self.width))]
93
94 def __setitem__(self, idx, bval):
95 setted = self.set_bit(idx, bval)
96 self.__init__(setted.irsb_c, setted.rdt)
97
98 @checkparams()
99 @vvifyresults
100 def set_bit(self, idx, bval):
101 return self.irsb_c.set_bit(self.rdt, idx.rdt, bval.rdt)
102
103 @checkparams()
104 @vvifyresults
105 def set_bits(self, idxsandvals):
106 return self.irsb_c.set_bits(self.rdt, [(i.cast_to(Type.int_8).rdt, b.rdt) for i, b in idxsandvals])
107
108 @checkparams()
109 @vvifyresults
110 def ite(self, iftrue, iffalse):
111 onebitcond = self.cast_to(Type.int_1)
112 return self.irsb_c.ite(onebitcond.rdt, iftrue.rdt, iffalse.rdt)
113
114 @checkparams()
115 @vvifyresults
116 def sar(self, right):
117 """
118 `v.sar(r)` should do arithmetic shift right of `v` by `r`
119
120 :param right:VexValue value to shift by
121 :return: VexValue - result of a shift
122 """
123 return self.irsb_c.op_sar(self.rdt, right.rdt)
124
125 @checkparams()
126 @vvifyresults
127 def __add__(self, right):
128 return self.irsb_c.op_add(self.rdt, right.rdt)
129
130 @checkparams()
131 def __radd__(self, left):
132 return self + left
133
134 @checkparams()
135 @vvifyresults
136 def __sub__(self, right):
137 return self.irsb_c.op_sub(self.rdt, right.rdt)
138
139 @checkparams()
140 def __rsub__(self, left):
141 return left - self
142
143 @checkparams()
144 @vvifyresults
145 def __div__(self, right):
146 if self._is_signed:
147 return self.irsb_c.op_sdiv(self.rdt, right.rdt)
148 else:
149 return self.irsb_c.op_udiv(self.rdt, right.rdt)
150
151 @checkparams()
152 def __rdiv__(self, left):
153 return left // self
154
155 @checkparams()
156 def __floordiv__(self, right): # Note: nonprimitive
157 return self.__div__(right)
158
159 @checkparams()
160 def __rfloordiv__(self, left):
161 return left // self
162
163 @checkparams()
164 def __truediv__(self, right): # Note: nonprimitive
165 return self / right
166
167 @checkparams()
168 def __rtruediv__(self, left):
169 return left.__truediv__(self)
170
171 @checkparams()
172 @vvifyresults
173 def __and__(self, right):
174 return self.irsb_c.op_and(self.rdt, right.rdt)
175
176 @checkparams()
177 def __rand__(self, left):
178 return left & self
179
180 @checkparams()
181 @vvifyresults
182 def __eq__(self, right):
183 return self.irsb_c.op_cmp_eq(self.rdt, right.rdt)
184
185 @checkparams()
186 @vvifyresults
187 def __ne__(self, other):
188 return self.irsb_c.op_cmp_ne(self.rdt, other.rdt)
189
190 @checkparams()
191 @vvifyresults
192 def __invert__(self):
193 return self.irsb_c.op_not(self.rdt)
194
195 @checkparams()
196 @vvifyresults
197 def __le__(self, right):
198 if self._is_signed:
199 return self.irsb_c.op_cmp_sle(self.rdt, right.rdt)
200 else:
201 return self.irsb_c.op_cmp_ule(self.rdt, right.rdt)
202
203 @checkparams()
204 @vvifyresults
205 def __gt__(self, other):
206 if self._is_signed:
207 return self.irsb_c.op_cmp_sgt(self.rdt, other.rdt)
208 else:
209 return self.irsb_c.op_cmp_ugt(self.rdt, other.rdt)
210
211 @checkparams()
212 @vvifyresults
213 def __ge__(self, right):
214 if self._is_signed:
215 return self.irsb_c.op_cmp_sge(self.rdt, right.rdt)
216 else:
217 return self.irsb_c.op_cmp_uge(self.rdt, right.rdt)
218
219 @checkparams(rhstype=Type.int_8)
220 @vvifyresults
221 def __lshift__(self, right): # TODO put better type inference in irsb_c so we can have rlshift
222 """
223 logical shift left
224 """
225 return self.irsb_c.op_shl(self.rdt, right.rdt)
226
227 @checkparams()
228 @vvifyresults
229 def __lt__(self, right):
230 if self._is_signed:
231 return self.irsb_c.op_cmp_slt(self.rdt, right.rdt)
232 else:
233 return self.irsb_c.op_cmp_ult(self.rdt, right.rdt)
234
235 @checkparams()
236 @vvifyresults
237 def __mod__(self, right): # Note: nonprimitive
238 return self.irsb_c.op_mod(self.rdt, right.rdt)
239
240 @checkparams()
241 def __rmod__(self, left):
242 return left % self
243
244 @checkparams()
245 @vvifyresults
246 def __mul__(self, right):
247 if self._is_signed:
248 return self.irsb_c.op_smul(self.rdt, right.rdt)
249 else:
250 return self.irsb_c.op_umul(self.rdt, right.rdt)
251
252 @checkparams()
253 def __rmul__(self, left):
254 return left * self
255
256 @checkparams()
257 @vvifyresults
258 def __neg__(self): # Note: nonprimitive
259 if not self._is_signed:
260 raise Exception("Number is unsigned, cannot change sign!")
261 else:
262 return self.rdt * -1
263
264 @checkparams()
265 @vvifyresults
266 def __or__(self, right):
267 return self.irsb_c.op_or(self.rdt, right.rdt)
268
269 def __ror__(self, left):
270 return self | left
271
272 @checkparams()
273 @vvifyresults
274 def __pos__(self):
275 return self
276
277 @checkparams(rhstype=Type.int_8)
278 @vvifyresults
279 def __rshift__(self, right):
280 """
281 logical shift right
282 """
283 return self.irsb_c.op_shr(self.rdt, right.rdt)
284
285 @checkparams()
286 def __rlshift__(self, left):
287 return left << self
288
289 @checkparams()
290 def __rrshift__(self, left):
291 return left >> self
292
293 @checkparams()
294 @vvifyresults
295 def __xor__(self, right):
296 return self.irsb_c.op_xor(self.rdt, right.rdt)
297
298 def __rxor__(self, left):
299 return self ^ left
300
301 @classmethod
302 def Constant(cls, irsb_c, val, ty):
303 """
304 Creates a constant as a VexValue
305 :param irsb_c: The IRSBCustomizer to use
306 :param val: The value, as an integer
307 :param ty: The type of the resulting VexValue
308 :return: a VexValue
309 """
310 assert not (isinstance(val, VexValue) or isinstance(val, IRExpr))
311 rdt = irsb_c.mkconst(val, ty)
312 return cls(irsb_c, rdt)