pyvex 9.2.189__cp311-cp311-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyvex might be problematic. Click here for more details.
- pyvex/__init__.py +92 -0
- pyvex/_register_info.py +1800 -0
- pyvex/arches.py +94 -0
- pyvex/block.py +697 -0
- pyvex/const.py +426 -0
- pyvex/const_val.py +26 -0
- pyvex/data_ref.py +55 -0
- pyvex/enums.py +156 -0
- pyvex/errors.py +31 -0
- pyvex/expr.py +974 -0
- pyvex/include/libvex.h +1029 -0
- pyvex/include/libvex_basictypes.h +236 -0
- pyvex/include/libvex_emnote.h +142 -0
- pyvex/include/libvex_guest_amd64.h +252 -0
- pyvex/include/libvex_guest_arm.h +224 -0
- pyvex/include/libvex_guest_arm64.h +203 -0
- pyvex/include/libvex_guest_mips32.h +175 -0
- pyvex/include/libvex_guest_mips64.h +173 -0
- pyvex/include/libvex_guest_offsets.h +941 -0
- pyvex/include/libvex_guest_ppc32.h +298 -0
- pyvex/include/libvex_guest_ppc64.h +343 -0
- pyvex/include/libvex_guest_riscv64.h +148 -0
- pyvex/include/libvex_guest_s390x.h +201 -0
- pyvex/include/libvex_guest_tilegx.h +149 -0
- pyvex/include/libvex_guest_x86.h +322 -0
- pyvex/include/libvex_ir.h +3113 -0
- pyvex/include/libvex_s390x_common.h +123 -0
- pyvex/include/libvex_trc_values.h +99 -0
- pyvex/include/pyvex.h +96 -0
- pyvex/lib/libpyvex.dylib +0 -0
- pyvex/lifting/__init__.py +18 -0
- pyvex/lifting/gym/README.md +7 -0
- pyvex/lifting/gym/__init__.py +5 -0
- pyvex/lifting/gym/aarch64_spotter.py +40 -0
- pyvex/lifting/gym/arm_spotter.py +427 -0
- pyvex/lifting/gym/x86_spotter.py +129 -0
- pyvex/lifting/libvex.py +117 -0
- pyvex/lifting/lift_function.py +304 -0
- pyvex/lifting/lifter.py +124 -0
- pyvex/lifting/post_processor.py +16 -0
- pyvex/lifting/util/__init__.py +14 -0
- pyvex/lifting/util/instr_helper.py +422 -0
- pyvex/lifting/util/lifter_helper.py +154 -0
- pyvex/lifting/util/syntax_wrapper.py +312 -0
- pyvex/lifting/util/vex_helper.py +301 -0
- pyvex/lifting/zerodivision.py +71 -0
- pyvex/native.py +63 -0
- pyvex/py.typed +1 -0
- pyvex/stmt.py +740 -0
- pyvex/types.py +48 -0
- pyvex/utils.py +63 -0
- pyvex/vex_ffi.py +1453 -0
- pyvex-9.2.189.dist-info/METADATA +181 -0
- pyvex-9.2.189.dist-info/RECORD +59 -0
- pyvex-9.2.189.dist-info/WHEEL +6 -0
- pyvex-9.2.189.dist-info/licenses/LICENSE +24 -0
- pyvex-9.2.189.dist-info/licenses/pyvex_c/LICENSE +339 -0
- pyvex-9.2.189.dist-info/licenses/vex/LICENSE.GPL +340 -0
- pyvex-9.2.189.dist-info/licenses/vex/LICENSE.README +23 -0
pyvex/expr.py
ADDED
|
@@ -0,0 +1,974 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import re
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from .const import U8, U16, U32, U64, IRConst, get_type_size
|
|
8
|
+
from .enums import IRCallee, IRRegArray, VEXObject, get_enum_from_int, get_int_from_enum
|
|
9
|
+
from .errors import PyVEXError
|
|
10
|
+
from .native import ffi, pvc
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from .block import IRTypeEnv
|
|
14
|
+
|
|
15
|
+
log = logging.getLogger("pyvex.expr")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class IRExpr(VEXObject):
|
|
19
|
+
"""
|
|
20
|
+
IR expressions in VEX represent operations without side effects.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
__slots__ = []
|
|
24
|
+
|
|
25
|
+
tag: str | None = None
|
|
26
|
+
tag_int = 0 # set automatically at bottom of file
|
|
27
|
+
|
|
28
|
+
def pp(self):
|
|
29
|
+
print(str(self))
|
|
30
|
+
|
|
31
|
+
def __str__(self):
|
|
32
|
+
return self._pp_str()
|
|
33
|
+
|
|
34
|
+
def _pp_str(self) -> str:
|
|
35
|
+
raise NotImplementedError
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def child_expressions(self) -> list[IRExpr]:
|
|
39
|
+
"""
|
|
40
|
+
A list of all of the expressions that this expression ends up evaluating.
|
|
41
|
+
"""
|
|
42
|
+
expressions = []
|
|
43
|
+
for k in self.__slots__:
|
|
44
|
+
v = getattr(self, k)
|
|
45
|
+
if isinstance(v, IRExpr):
|
|
46
|
+
expressions.append(v)
|
|
47
|
+
expressions.extend(v.child_expressions)
|
|
48
|
+
return expressions
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def constants(self):
|
|
52
|
+
"""
|
|
53
|
+
A list of all of the constants that this expression ends up using.
|
|
54
|
+
"""
|
|
55
|
+
constants = []
|
|
56
|
+
for k in self.__slots__:
|
|
57
|
+
v = getattr(self, k)
|
|
58
|
+
if isinstance(v, IRExpr):
|
|
59
|
+
constants.extend(v.constants)
|
|
60
|
+
elif isinstance(v, IRConst):
|
|
61
|
+
constants.append(v)
|
|
62
|
+
return constants
|
|
63
|
+
|
|
64
|
+
def result_size(self, tyenv: IRTypeEnv):
|
|
65
|
+
return get_type_size(self.result_type(tyenv))
|
|
66
|
+
|
|
67
|
+
def result_type(self, tyenv: IRTypeEnv):
|
|
68
|
+
raise NotImplementedError()
|
|
69
|
+
|
|
70
|
+
def replace_expression(self, replacements):
|
|
71
|
+
"""
|
|
72
|
+
Replace child expressions in-place.
|
|
73
|
+
|
|
74
|
+
:param Dict[IRExpr, IRExpr] replacements: A mapping from expression-to-find to expression-to-replace-with
|
|
75
|
+
:return: None
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
for k in self.__slots__:
|
|
79
|
+
v = getattr(self, k)
|
|
80
|
+
if isinstance(v, IRExpr) and v in replacements:
|
|
81
|
+
setattr(self, k, replacements.get(v))
|
|
82
|
+
elif isinstance(v, list):
|
|
83
|
+
# Replace the instance in the list
|
|
84
|
+
for i, expr_ in enumerate(v):
|
|
85
|
+
if isinstance(expr_, IRExpr) and expr_ in replacements:
|
|
86
|
+
v[i] = replacements.get(expr_)
|
|
87
|
+
elif type(v) is tuple:
|
|
88
|
+
# Rebuild the tuple
|
|
89
|
+
_lst = []
|
|
90
|
+
replaced = False
|
|
91
|
+
for i, expr_ in enumerate(v):
|
|
92
|
+
if isinstance(expr_, IRExpr) and expr_ in replacements:
|
|
93
|
+
_lst.append(replacements.get(expr_))
|
|
94
|
+
replaced = True
|
|
95
|
+
else:
|
|
96
|
+
_lst.append(expr_)
|
|
97
|
+
if replaced:
|
|
98
|
+
setattr(self, k, tuple(_lst))
|
|
99
|
+
elif isinstance(v, IRExpr):
|
|
100
|
+
v.replace_expression(replacements)
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def _from_c(c_expr) -> IRExpr | None:
|
|
104
|
+
if c_expr == ffi.NULL or c_expr[0] == ffi.NULL:
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
return enum_to_expr_class(c_expr.tag)._from_c(c_expr)
|
|
109
|
+
except KeyError:
|
|
110
|
+
raise PyVEXError("Unknown/unsupported IRExprTag %s\n" % get_enum_from_int(c_expr.tag))
|
|
111
|
+
|
|
112
|
+
_translate = _from_c
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def _to_c(expr):
|
|
116
|
+
try:
|
|
117
|
+
return tag_to_expr_class(expr.tag)._to_c(expr)
|
|
118
|
+
except KeyError:
|
|
119
|
+
raise PyVEXError("Unknown/unsupported IRExprTag %s\n" % expr.tag)
|
|
120
|
+
|
|
121
|
+
def typecheck(self, tyenv):
|
|
122
|
+
return self.result_type(tyenv)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class Binder(IRExpr):
|
|
126
|
+
"""
|
|
127
|
+
Used only in pattern matching within Vex. Should not be seen outside of Vex.
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
__slots__ = ["binder"]
|
|
131
|
+
|
|
132
|
+
tag = "Iex_Binder"
|
|
133
|
+
|
|
134
|
+
def __init__(self, binder):
|
|
135
|
+
self.binder = binder
|
|
136
|
+
|
|
137
|
+
def _pp_str(self):
|
|
138
|
+
return "Binder"
|
|
139
|
+
|
|
140
|
+
@staticmethod
|
|
141
|
+
def _from_c(c_expr):
|
|
142
|
+
return Binder(c_expr.iex.Binder.binder)
|
|
143
|
+
|
|
144
|
+
@staticmethod
|
|
145
|
+
def _to_c(expr):
|
|
146
|
+
return pvc.IRExpr_Binder(expr.binder)
|
|
147
|
+
|
|
148
|
+
def result_type(self, tyenv):
|
|
149
|
+
return "Ity_INVALID"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class VECRET(IRExpr):
|
|
153
|
+
tag = "Iex_VECRET"
|
|
154
|
+
|
|
155
|
+
__slots__ = []
|
|
156
|
+
|
|
157
|
+
def _pp_str(self):
|
|
158
|
+
return "VECRET"
|
|
159
|
+
|
|
160
|
+
@staticmethod
|
|
161
|
+
def _from_c(c_expr):
|
|
162
|
+
return VECRET()
|
|
163
|
+
|
|
164
|
+
@staticmethod
|
|
165
|
+
def _to_c(expr):
|
|
166
|
+
return pvc.IRExpr_VECRET()
|
|
167
|
+
|
|
168
|
+
def result_type(self, tyenv):
|
|
169
|
+
return "Ity_INVALID"
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class GSPTR(IRExpr):
|
|
173
|
+
__slots__ = []
|
|
174
|
+
|
|
175
|
+
tag = "Iex_GSPTR"
|
|
176
|
+
|
|
177
|
+
def _pp_str(self):
|
|
178
|
+
return "GSPTR"
|
|
179
|
+
|
|
180
|
+
@staticmethod
|
|
181
|
+
def _from_c(c_expr):
|
|
182
|
+
return GSPTR()
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def _to_c(expr):
|
|
186
|
+
return pvc.IRExpr_GSPTR()
|
|
187
|
+
|
|
188
|
+
def result_type(self, tyenv):
|
|
189
|
+
return "Ity_INVALID"
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class GetI(IRExpr):
|
|
193
|
+
"""
|
|
194
|
+
Read a guest register at a non-fixed offset in the guest state.
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
__slots__ = ["descr", "ix", "bias"]
|
|
198
|
+
|
|
199
|
+
tag = "Iex_GetI"
|
|
200
|
+
|
|
201
|
+
def __init__(self, descr, ix, bias):
|
|
202
|
+
self.descr = descr
|
|
203
|
+
self.ix = ix
|
|
204
|
+
self.bias = bias
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def description(self):
|
|
208
|
+
return self.descr
|
|
209
|
+
|
|
210
|
+
@property
|
|
211
|
+
def index(self):
|
|
212
|
+
return self.ix
|
|
213
|
+
|
|
214
|
+
def _pp_str(self):
|
|
215
|
+
return f"GetI({self.descr})[{self.ix},{self.bias}]"
|
|
216
|
+
|
|
217
|
+
@staticmethod
|
|
218
|
+
def _from_c(c_expr):
|
|
219
|
+
descr = IRRegArray._from_c(c_expr.Iex.GetI.descr)
|
|
220
|
+
ix = IRExpr._from_c(c_expr.Iex.GetI.ix)
|
|
221
|
+
bias = c_expr.Iex.GetI.bias
|
|
222
|
+
return GetI(descr, ix, bias)
|
|
223
|
+
|
|
224
|
+
@staticmethod
|
|
225
|
+
def _to_c(expr):
|
|
226
|
+
return pvc.IRExpr_GetI(IRRegArray._to_c(expr.descr), IRExpr._to_c(expr.ix), expr.bias)
|
|
227
|
+
|
|
228
|
+
def result_type(self, tyenv):
|
|
229
|
+
return self.descr.elemTy
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class RdTmp(IRExpr):
|
|
233
|
+
"""
|
|
234
|
+
Read the value held by a temporary.
|
|
235
|
+
"""
|
|
236
|
+
|
|
237
|
+
__slots__ = ["_tmp"]
|
|
238
|
+
|
|
239
|
+
tag = "Iex_RdTmp"
|
|
240
|
+
|
|
241
|
+
def __init__(self, tmp):
|
|
242
|
+
self._tmp = tmp
|
|
243
|
+
|
|
244
|
+
def _pp_str(self):
|
|
245
|
+
return "t%d" % self.tmp
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def tmp(self):
|
|
249
|
+
return self._tmp
|
|
250
|
+
|
|
251
|
+
@staticmethod
|
|
252
|
+
def _from_c(c_expr):
|
|
253
|
+
tmp = c_expr.Iex.RdTmp.tmp
|
|
254
|
+
return RdTmp.get_instance(tmp)
|
|
255
|
+
|
|
256
|
+
@staticmethod
|
|
257
|
+
def _to_c(expr):
|
|
258
|
+
return pvc.IRExpr_RdTmp(expr.tmp)
|
|
259
|
+
|
|
260
|
+
@staticmethod
|
|
261
|
+
def get_instance(tmp):
|
|
262
|
+
if tmp < 1024:
|
|
263
|
+
# for small tmp reads, they are cached and are only created once globally
|
|
264
|
+
return _RDTMP_POOL[tmp]
|
|
265
|
+
return RdTmp(tmp)
|
|
266
|
+
|
|
267
|
+
def replace_expression(self, replacements):
|
|
268
|
+
# RdTmp is one of the terminal IRExprs, which cannot be replaced.
|
|
269
|
+
pass
|
|
270
|
+
|
|
271
|
+
def result_type(self, tyenv):
|
|
272
|
+
return tyenv.lookup(self.tmp)
|
|
273
|
+
|
|
274
|
+
def __hash__(self):
|
|
275
|
+
return 133700 + self._tmp
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
_RDTMP_POOL = list(RdTmp(i) for i in range(0, 1024))
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class Get(IRExpr):
|
|
282
|
+
"""
|
|
283
|
+
Read a guest register, at a fixed offset in the guest state.
|
|
284
|
+
"""
|
|
285
|
+
|
|
286
|
+
__slots__ = ["offset", "ty_int"]
|
|
287
|
+
|
|
288
|
+
tag = "Iex_Get"
|
|
289
|
+
|
|
290
|
+
def __init__(self, offset: int, ty: str, ty_int: int | None = None):
|
|
291
|
+
self.offset = offset
|
|
292
|
+
if ty_int is None:
|
|
293
|
+
self.ty_int = get_int_from_enum(ty)
|
|
294
|
+
else:
|
|
295
|
+
self.ty_int = ty_int
|
|
296
|
+
|
|
297
|
+
@property
|
|
298
|
+
def ty(self):
|
|
299
|
+
return get_enum_from_int(self.ty_int)
|
|
300
|
+
|
|
301
|
+
@property
|
|
302
|
+
def type(self):
|
|
303
|
+
return get_enum_from_int(self.ty_int)
|
|
304
|
+
|
|
305
|
+
def _pp_str(self):
|
|
306
|
+
return f"GET:{self.ty[4:]}(offset={self.offset})"
|
|
307
|
+
|
|
308
|
+
def pp_str_with_name(self, reg_name: str):
|
|
309
|
+
"""pp_str_with_name is used to print the expression with the name of the
|
|
310
|
+
register instead of the offset"""
|
|
311
|
+
return f"GET:{self.ty[4:]}({reg_name})"
|
|
312
|
+
|
|
313
|
+
@staticmethod
|
|
314
|
+
def _from_c(c_expr):
|
|
315
|
+
return Get(c_expr.Iex.Get.offset, get_enum_from_int(c_expr.Iex.Get.ty))
|
|
316
|
+
|
|
317
|
+
@staticmethod
|
|
318
|
+
def _to_c(expr):
|
|
319
|
+
return pvc.IRExpr_Get(expr.offset, expr.ty_int)
|
|
320
|
+
|
|
321
|
+
def result_type(self, tyenv):
|
|
322
|
+
return self.ty
|
|
323
|
+
|
|
324
|
+
def __hash__(self):
|
|
325
|
+
return (self.offset << 8) | self.ty_int
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class Qop(IRExpr):
|
|
329
|
+
"""
|
|
330
|
+
A quaternary operation (4 arguments).
|
|
331
|
+
"""
|
|
332
|
+
|
|
333
|
+
__slots__ = ["op", "args"]
|
|
334
|
+
|
|
335
|
+
tag = "Iex_Qop"
|
|
336
|
+
|
|
337
|
+
def __init__(self, op, args):
|
|
338
|
+
self.op = op
|
|
339
|
+
self.args = args
|
|
340
|
+
|
|
341
|
+
def _pp_str(self):
|
|
342
|
+
return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
|
|
343
|
+
|
|
344
|
+
@property
|
|
345
|
+
def child_expressions(self):
|
|
346
|
+
expressions = sum((a.child_expressions for a in self.args), [])
|
|
347
|
+
expressions.extend(self.args)
|
|
348
|
+
return expressions
|
|
349
|
+
|
|
350
|
+
@staticmethod
|
|
351
|
+
def _from_c(c_expr):
|
|
352
|
+
return Qop(
|
|
353
|
+
get_enum_from_int(c_expr.Iex.Qop.details.op),
|
|
354
|
+
[
|
|
355
|
+
IRExpr._from_c(arg)
|
|
356
|
+
for arg in [
|
|
357
|
+
c_expr.Iex.Qop.details.arg1,
|
|
358
|
+
c_expr.Iex.Qop.details.arg2,
|
|
359
|
+
c_expr.Iex.Qop.details.arg3,
|
|
360
|
+
c_expr.Iex.Qop.details.arg4,
|
|
361
|
+
]
|
|
362
|
+
],
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
@staticmethod
|
|
366
|
+
def _to_c(expr):
|
|
367
|
+
return pvc.IRExpr_Qop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
|
|
368
|
+
|
|
369
|
+
def result_type(self, tyenv):
|
|
370
|
+
return get_op_retty(self.op)
|
|
371
|
+
|
|
372
|
+
def typecheck(self, tyenv): # TODO change all this to use PyvexTypeErrorException
|
|
373
|
+
resty, (arg1ty, arg2ty, arg3ty, arg4ty) = op_arg_types(self.op)
|
|
374
|
+
arg1ty_real = self.args[0].typecheck(tyenv)
|
|
375
|
+
arg2ty_real = self.args[1].typecheck(tyenv)
|
|
376
|
+
arg3ty_real = self.args[2].typecheck(tyenv)
|
|
377
|
+
arg4ty_real = self.args[3].typecheck(tyenv)
|
|
378
|
+
if arg1ty_real is None or arg2ty_real is None or arg3ty_real is None or arg4ty_real is None:
|
|
379
|
+
return None
|
|
380
|
+
|
|
381
|
+
if arg1ty_real != arg1ty:
|
|
382
|
+
log.debug("First arg of %s must be %s", self.op, arg1ty)
|
|
383
|
+
return None
|
|
384
|
+
if arg2ty_real != arg2ty:
|
|
385
|
+
log.debug("Second arg of %s must be %s", self.op, arg2ty)
|
|
386
|
+
return None
|
|
387
|
+
if arg3ty_real != arg3ty:
|
|
388
|
+
log.debug("Third arg of %s must be %s", self.op, arg3ty)
|
|
389
|
+
return None
|
|
390
|
+
if arg4ty_real != arg4ty:
|
|
391
|
+
log.debug("Fourth arg of %s must be %s", self.op, arg4ty)
|
|
392
|
+
return None
|
|
393
|
+
|
|
394
|
+
return resty
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
class Triop(IRExpr):
|
|
398
|
+
"""
|
|
399
|
+
A ternary operation (3 arguments)
|
|
400
|
+
"""
|
|
401
|
+
|
|
402
|
+
__slots__ = ["op", "args"]
|
|
403
|
+
|
|
404
|
+
tag = "Iex_Triop"
|
|
405
|
+
|
|
406
|
+
def __init__(self, op, args):
|
|
407
|
+
self.op = op
|
|
408
|
+
self.args = args
|
|
409
|
+
|
|
410
|
+
def _pp_str(self):
|
|
411
|
+
return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
|
|
412
|
+
|
|
413
|
+
@property
|
|
414
|
+
def child_expressions(self):
|
|
415
|
+
expressions = sum((a.child_expressions for a in self.args), [])
|
|
416
|
+
expressions.extend(self.args)
|
|
417
|
+
return expressions
|
|
418
|
+
|
|
419
|
+
@staticmethod
|
|
420
|
+
def _from_c(c_expr):
|
|
421
|
+
return Triop(
|
|
422
|
+
get_enum_from_int(c_expr.Iex.Triop.details.op),
|
|
423
|
+
[
|
|
424
|
+
IRExpr._from_c(arg)
|
|
425
|
+
for arg in [c_expr.Iex.Triop.details.arg1, c_expr.Iex.Triop.details.arg2, c_expr.Iex.Triop.details.arg3]
|
|
426
|
+
],
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
@staticmethod
|
|
430
|
+
def _to_c(expr):
|
|
431
|
+
return pvc.IRExpr_Triop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
|
|
432
|
+
|
|
433
|
+
def result_type(self, tyenv):
|
|
434
|
+
return get_op_retty(self.op)
|
|
435
|
+
|
|
436
|
+
def typecheck(self, tyenv):
|
|
437
|
+
resty, (arg1ty, arg2ty, arg3ty) = op_arg_types(self.op)
|
|
438
|
+
arg1ty_real = self.args[0].typecheck(tyenv)
|
|
439
|
+
arg2ty_real = self.args[1].typecheck(tyenv)
|
|
440
|
+
arg3ty_real = self.args[2].typecheck(tyenv)
|
|
441
|
+
if arg1ty_real is None or arg2ty_real is None or arg3ty_real is None:
|
|
442
|
+
return None
|
|
443
|
+
|
|
444
|
+
if arg1ty_real != arg1ty:
|
|
445
|
+
log.debug("First arg of %s must be %s", self.op, arg1ty)
|
|
446
|
+
return None
|
|
447
|
+
if arg2ty_real != arg2ty:
|
|
448
|
+
log.debug("Second arg of %s must be %s", self.op, arg2ty)
|
|
449
|
+
return None
|
|
450
|
+
if arg3ty_real != arg3ty:
|
|
451
|
+
log.debug("Third arg of %s must be %s", self.op, arg3ty)
|
|
452
|
+
return None
|
|
453
|
+
|
|
454
|
+
return resty
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
class Binop(IRExpr):
|
|
458
|
+
"""
|
|
459
|
+
A binary operation (2 arguments).
|
|
460
|
+
"""
|
|
461
|
+
|
|
462
|
+
__slots__ = ["_op", "op_int", "args"]
|
|
463
|
+
|
|
464
|
+
tag = "Iex_Binop"
|
|
465
|
+
|
|
466
|
+
def __init__(self, op, args, op_int=None):
|
|
467
|
+
self.op_int = op_int
|
|
468
|
+
self.args = args
|
|
469
|
+
self._op = op if op is not None else None
|
|
470
|
+
|
|
471
|
+
def _pp_str(self):
|
|
472
|
+
return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
|
|
473
|
+
|
|
474
|
+
@property
|
|
475
|
+
def op(self):
|
|
476
|
+
if self._op is None:
|
|
477
|
+
self._op = get_enum_from_int(self.op_int)
|
|
478
|
+
return self._op
|
|
479
|
+
|
|
480
|
+
@property
|
|
481
|
+
def child_expressions(self):
|
|
482
|
+
expressions = sum((a.child_expressions for a in self.args), [])
|
|
483
|
+
expressions.extend(self.args)
|
|
484
|
+
return expressions
|
|
485
|
+
|
|
486
|
+
@staticmethod
|
|
487
|
+
def _from_c(c_expr):
|
|
488
|
+
return Binop(
|
|
489
|
+
None,
|
|
490
|
+
[IRExpr._from_c(arg) for arg in [c_expr.Iex.Binop.arg1, c_expr.Iex.Binop.arg2]],
|
|
491
|
+
op_int=c_expr.Iex.Binop.op,
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
@staticmethod
|
|
495
|
+
def _to_c(expr):
|
|
496
|
+
return pvc.IRExpr_Binop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
|
|
497
|
+
|
|
498
|
+
def result_type(self, tyenv):
|
|
499
|
+
return get_op_retty(self.op)
|
|
500
|
+
|
|
501
|
+
def typecheck(self, tyenv):
|
|
502
|
+
arg1ty_real = self.args[0].typecheck(tyenv)
|
|
503
|
+
arg2ty_real = self.args[1].typecheck(tyenv)
|
|
504
|
+
|
|
505
|
+
resty, (arg1ty, arg2ty) = op_arg_types(self.op)
|
|
506
|
+
if arg1ty_real is None or arg2ty_real is None:
|
|
507
|
+
return None
|
|
508
|
+
|
|
509
|
+
if arg1ty_real != arg1ty:
|
|
510
|
+
log.debug("First arg of %s must be %s", self.op, arg1ty)
|
|
511
|
+
return None
|
|
512
|
+
if arg2ty_real != arg2ty:
|
|
513
|
+
log.debug("Second arg of %s must be %s", self.op, arg2ty)
|
|
514
|
+
return None
|
|
515
|
+
|
|
516
|
+
return resty
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
class Unop(IRExpr):
|
|
520
|
+
"""
|
|
521
|
+
A unary operation (1 argument).
|
|
522
|
+
"""
|
|
523
|
+
|
|
524
|
+
__slots__ = ["op", "args"]
|
|
525
|
+
|
|
526
|
+
tag = "Iex_Unop"
|
|
527
|
+
|
|
528
|
+
def __init__(self, op: str, args: list[IRExpr]):
|
|
529
|
+
self.op = op
|
|
530
|
+
self.args = args
|
|
531
|
+
|
|
532
|
+
def _pp_str(self):
|
|
533
|
+
return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
|
|
534
|
+
|
|
535
|
+
@property
|
|
536
|
+
def child_expressions(self):
|
|
537
|
+
expressions = sum((a.child_expressions for a in self.args), [])
|
|
538
|
+
expressions.extend(self.args)
|
|
539
|
+
return expressions
|
|
540
|
+
|
|
541
|
+
@staticmethod
|
|
542
|
+
def _from_c(c_expr):
|
|
543
|
+
return Unop(get_enum_from_int(c_expr.Iex.Unop.op), [IRExpr._from_c(c_expr.Iex.Unop.arg)])
|
|
544
|
+
|
|
545
|
+
@staticmethod
|
|
546
|
+
def _to_c(expr):
|
|
547
|
+
return pvc.IRExpr_Unop(get_int_from_enum(expr.op), IRExpr._to_c(expr.args[0]))
|
|
548
|
+
|
|
549
|
+
def result_type(self, tyenv):
|
|
550
|
+
return get_op_retty(self.op)
|
|
551
|
+
|
|
552
|
+
def typecheck(self, tyenv):
|
|
553
|
+
resty, (arg1ty,) = op_arg_types(self.op)
|
|
554
|
+
arg1ty_real = self.args[0].typecheck(tyenv)
|
|
555
|
+
if arg1ty_real is None:
|
|
556
|
+
return None
|
|
557
|
+
|
|
558
|
+
if arg1ty_real != arg1ty:
|
|
559
|
+
log.debug("First arg of %s must be %s", self.op, arg1ty)
|
|
560
|
+
return None
|
|
561
|
+
|
|
562
|
+
return resty
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
class Load(IRExpr):
|
|
566
|
+
"""
|
|
567
|
+
A load from memory.
|
|
568
|
+
"""
|
|
569
|
+
|
|
570
|
+
__slots__ = ["end", "ty", "addr"]
|
|
571
|
+
|
|
572
|
+
tag = "Iex_Load"
|
|
573
|
+
|
|
574
|
+
def __init__(self, end, ty, addr):
|
|
575
|
+
self.end = end
|
|
576
|
+
self.ty = ty
|
|
577
|
+
self.addr = addr
|
|
578
|
+
|
|
579
|
+
@property
|
|
580
|
+
def endness(self):
|
|
581
|
+
return self.end
|
|
582
|
+
|
|
583
|
+
@property
|
|
584
|
+
def type(self):
|
|
585
|
+
return self.ty
|
|
586
|
+
|
|
587
|
+
def _pp_str(self):
|
|
588
|
+
return f"LD{self.end[-2:].lower()}:{self.ty[4:]}({self.addr})"
|
|
589
|
+
|
|
590
|
+
@staticmethod
|
|
591
|
+
def _from_c(c_expr):
|
|
592
|
+
return Load(
|
|
593
|
+
get_enum_from_int(c_expr.Iex.Load.end),
|
|
594
|
+
get_enum_from_int(c_expr.Iex.Load.ty),
|
|
595
|
+
IRExpr._from_c(c_expr.Iex.Load.addr),
|
|
596
|
+
)
|
|
597
|
+
|
|
598
|
+
@staticmethod
|
|
599
|
+
def _to_c(expr):
|
|
600
|
+
return pvc.IRExpr_Load(get_int_from_enum(expr.end), get_int_from_enum(expr.ty), IRExpr._to_c(expr.addr))
|
|
601
|
+
|
|
602
|
+
def result_type(self, tyenv):
|
|
603
|
+
return self.ty
|
|
604
|
+
|
|
605
|
+
def typecheck(self, tyenv):
|
|
606
|
+
addrty = self.addr.typecheck(tyenv)
|
|
607
|
+
if addrty is None:
|
|
608
|
+
return None
|
|
609
|
+
if addrty != tyenv.wordty:
|
|
610
|
+
log.debug("Address must be word-sized")
|
|
611
|
+
return None
|
|
612
|
+
return self.ty
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
class Const(IRExpr):
|
|
616
|
+
"""
|
|
617
|
+
A constant expression.
|
|
618
|
+
"""
|
|
619
|
+
|
|
620
|
+
__slots__ = ["_con"]
|
|
621
|
+
|
|
622
|
+
tag = "Iex_Const"
|
|
623
|
+
|
|
624
|
+
def __init__(self, con: IRConst):
|
|
625
|
+
self._con = con
|
|
626
|
+
|
|
627
|
+
def _pp_str(self):
|
|
628
|
+
return str(self.con)
|
|
629
|
+
|
|
630
|
+
@property
|
|
631
|
+
def con(self) -> IRConst:
|
|
632
|
+
return self._con
|
|
633
|
+
|
|
634
|
+
@staticmethod
|
|
635
|
+
def _from_c(c_expr):
|
|
636
|
+
con = IRConst._from_c(c_expr.Iex.Const.con)
|
|
637
|
+
return Const.get_instance(con)
|
|
638
|
+
|
|
639
|
+
@staticmethod
|
|
640
|
+
def _to_c(expr):
|
|
641
|
+
return pvc.IRExpr_Const(IRConst._to_c(expr.con))
|
|
642
|
+
|
|
643
|
+
@staticmethod
|
|
644
|
+
def get_instance(con):
|
|
645
|
+
if con.value < 1024 and con.__class__ in _CONST_POOL:
|
|
646
|
+
return _CONST_POOL[con.__class__][con.value]
|
|
647
|
+
return Const(con)
|
|
648
|
+
|
|
649
|
+
def result_type(self, tyenv):
|
|
650
|
+
return self.con.type
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
_CONST_POOL = {
|
|
654
|
+
U8: [Const(U8(i)) for i in range(0, 1024)],
|
|
655
|
+
U16: [Const(U16(i)) for i in range(0, 1024)],
|
|
656
|
+
U32: [Const(U32(i)) for i in range(0, 1024)],
|
|
657
|
+
U64: [Const(U64(i)) for i in range(0, 1024)],
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
class ITE(IRExpr):
|
|
662
|
+
"""
|
|
663
|
+
An if-then-else expression.
|
|
664
|
+
"""
|
|
665
|
+
|
|
666
|
+
__slots__ = ["cond", "iffalse", "iftrue"]
|
|
667
|
+
|
|
668
|
+
tag = "Iex_ITE"
|
|
669
|
+
|
|
670
|
+
def __init__(self, cond, iffalse, iftrue):
|
|
671
|
+
self.cond = cond
|
|
672
|
+
self.iffalse = iffalse
|
|
673
|
+
self.iftrue = iftrue
|
|
674
|
+
|
|
675
|
+
def _pp_str(self):
|
|
676
|
+
return f"ITE({self.cond},{self.iftrue},{self.iffalse})"
|
|
677
|
+
|
|
678
|
+
@staticmethod
|
|
679
|
+
def _from_c(c_expr):
|
|
680
|
+
return ITE(
|
|
681
|
+
IRExpr._from_c(c_expr.Iex.ITE.cond),
|
|
682
|
+
IRExpr._from_c(c_expr.Iex.ITE.iffalse),
|
|
683
|
+
IRExpr._from_c(c_expr.Iex.ITE.iftrue),
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
@staticmethod
|
|
687
|
+
def _to_c(expr):
|
|
688
|
+
return pvc.IRExpr_ITE(IRExpr._to_c(expr.cond), IRExpr._to_c(expr.iftrue), IRExpr._to_c(expr.iffalse))
|
|
689
|
+
|
|
690
|
+
def result_type(self, tyenv):
|
|
691
|
+
return self.iftrue.result_type(tyenv)
|
|
692
|
+
|
|
693
|
+
def typecheck(self, tyenv):
|
|
694
|
+
condty = self.cond.typecheck(tyenv)
|
|
695
|
+
falsety = self.iffalse.typecheck(tyenv)
|
|
696
|
+
truety = self.iftrue.typecheck(tyenv)
|
|
697
|
+
|
|
698
|
+
if condty is None or falsety is None or truety is None:
|
|
699
|
+
return None
|
|
700
|
+
|
|
701
|
+
if condty != "Ity_I1":
|
|
702
|
+
log.debug("guard must be Ity_I1")
|
|
703
|
+
return None
|
|
704
|
+
|
|
705
|
+
if falsety != truety:
|
|
706
|
+
log.debug("false condition must be same type as true condition")
|
|
707
|
+
return None
|
|
708
|
+
|
|
709
|
+
return falsety
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
class CCall(IRExpr):
|
|
713
|
+
"""
|
|
714
|
+
A call to a pure (no side-effects) helper C function.
|
|
715
|
+
"""
|
|
716
|
+
|
|
717
|
+
__slots__ = ["retty", "cee", "args"]
|
|
718
|
+
|
|
719
|
+
tag = "Iex_CCall"
|
|
720
|
+
|
|
721
|
+
def __init__(self, retty, cee, args):
|
|
722
|
+
self.retty = retty
|
|
723
|
+
self.cee = cee
|
|
724
|
+
self.args = tuple(args)
|
|
725
|
+
|
|
726
|
+
@property
|
|
727
|
+
def ret_type(self):
|
|
728
|
+
return self.retty
|
|
729
|
+
|
|
730
|
+
@property
|
|
731
|
+
def callee(self):
|
|
732
|
+
return self.cee
|
|
733
|
+
|
|
734
|
+
def _pp_str(self):
|
|
735
|
+
return "{}({}):{}".format(self.cee, ",".join(str(a) for a in self.args), self.retty)
|
|
736
|
+
|
|
737
|
+
@property
|
|
738
|
+
def child_expressions(self):
|
|
739
|
+
expressions = sum((a.child_expressions for a in self.args), [])
|
|
740
|
+
expressions.extend(self.args)
|
|
741
|
+
return expressions
|
|
742
|
+
|
|
743
|
+
@staticmethod
|
|
744
|
+
def _from_c(c_expr):
|
|
745
|
+
i = 0
|
|
746
|
+
args = []
|
|
747
|
+
while True:
|
|
748
|
+
arg = c_expr.Iex.CCall.args[i]
|
|
749
|
+
if arg == ffi.NULL:
|
|
750
|
+
break
|
|
751
|
+
args.append(IRExpr._from_c(arg))
|
|
752
|
+
i += 1
|
|
753
|
+
|
|
754
|
+
return CCall(get_enum_from_int(c_expr.Iex.CCall.retty), IRCallee._from_c(c_expr.Iex.CCall.cee), tuple(args))
|
|
755
|
+
|
|
756
|
+
@staticmethod
|
|
757
|
+
def _to_c(expr):
|
|
758
|
+
args = [IRExpr._to_c(arg) for arg in expr.args]
|
|
759
|
+
mkIRExprVec = getattr(pvc, "mkIRExprVec_%d" % len(args))
|
|
760
|
+
return pvc.IRExpr_CCall(IRCallee._to_c(expr.cee), get_int_from_enum(expr.retty), mkIRExprVec(*args))
|
|
761
|
+
|
|
762
|
+
def result_type(self, tyenv):
|
|
763
|
+
return self.retty
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
def get_op_retty(op):
|
|
767
|
+
return op_arg_types(op)[0]
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
op_signatures: dict[str, tuple[str, tuple[str, ...]]] = {}
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
def _request_op_type_from_cache(op):
|
|
774
|
+
return op_signatures[op]
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
def _request_op_type_from_libvex(op):
|
|
778
|
+
Ity_INVALID = 0x1100 # as defined in enum IRType in VEX
|
|
779
|
+
|
|
780
|
+
res_ty = ffi.new("IRType *")
|
|
781
|
+
arg_tys = [ffi.new("IRType *") for _ in range(4)]
|
|
782
|
+
# initialize all IRTypes to Ity_INVALID
|
|
783
|
+
for arg in arg_tys:
|
|
784
|
+
arg[0] = Ity_INVALID
|
|
785
|
+
pvc.typeOfPrimop(get_int_from_enum(op), res_ty, *arg_tys)
|
|
786
|
+
arg_ty_vals = [a[0] for a in arg_tys]
|
|
787
|
+
|
|
788
|
+
try:
|
|
789
|
+
numargs = arg_ty_vals.index(Ity_INVALID)
|
|
790
|
+
except ValueError:
|
|
791
|
+
numargs = 4
|
|
792
|
+
args_tys_list = [get_enum_from_int(arg_ty_vals[i]) for i in range(numargs)]
|
|
793
|
+
|
|
794
|
+
op_ty_sig = (get_enum_from_int(res_ty[0]), tuple(args_tys_list))
|
|
795
|
+
op_signatures[op] = op_ty_sig
|
|
796
|
+
return op_ty_sig
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
class PyvexOpMatchException(Exception):
|
|
800
|
+
pass
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
class PyvexTypeErrorException(Exception):
|
|
804
|
+
pass
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
def int_type_for_size(size):
|
|
808
|
+
return "Ity_I%d" % size
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
# precompiled regexes
|
|
812
|
+
unop_signature_re = re.compile(r"Iop_(Not|Ctz|Clz)(?P<size>\d+)$")
|
|
813
|
+
binop_signature_re = re.compile(r"Iop_(Add|Sub|Mul|Xor|Or|And|Div[SU]|Mod)(?P<size>\d+)$")
|
|
814
|
+
shift_signature_re = re.compile(r"Iop_(Shl|Shr|Sar)(?P<size>\d+)$")
|
|
815
|
+
cmp_signature_re_1 = re.compile(r"Iop_Cmp(EQ|NE)(?P<size>\d+)$")
|
|
816
|
+
cmp_signature_re_2 = re.compile(r"Iop_Cmp(GT|GE|LT|LE)(?P<size>\d+)[SU]$")
|
|
817
|
+
mull_signature_re = re.compile(r"Iop_Mull[SU](?P<size>\d+)$")
|
|
818
|
+
half_signature_re = re.compile(r"Iop_DivMod[SU](?P<fullsize>\d+)to(?P<halfsize>\d+)$")
|
|
819
|
+
cast_signature_re = re.compile(r"Iop_(?P<srcsize>\d+)(U|S|HI|HL)?to(?P<dstsize>\d+)")
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def unop_signature(op):
|
|
823
|
+
m = unop_signature_re.match(op)
|
|
824
|
+
if m is None:
|
|
825
|
+
raise PyvexOpMatchException()
|
|
826
|
+
size = int(m.group("size"))
|
|
827
|
+
size_type = int_type_for_size(size)
|
|
828
|
+
return size_type, (size_type,)
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
def binop_signature(op):
|
|
832
|
+
m = binop_signature_re.match(op)
|
|
833
|
+
if m is None:
|
|
834
|
+
raise PyvexOpMatchException()
|
|
835
|
+
size = int(m.group("size"))
|
|
836
|
+
size_type = int_type_for_size(size)
|
|
837
|
+
return (size_type, (size_type, size_type))
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
def shift_signature(op):
|
|
841
|
+
m = shift_signature_re.match(op)
|
|
842
|
+
if m is None:
|
|
843
|
+
raise PyvexOpMatchException()
|
|
844
|
+
size = int(m.group("size"))
|
|
845
|
+
if size > 255:
|
|
846
|
+
raise PyvexTypeErrorException("Cannot apply shift operation to %d size int because shift index is 8-bit" % size)
|
|
847
|
+
size_type = int_type_for_size(size)
|
|
848
|
+
return (size_type, (size_type, int_type_for_size(8)))
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
def cmp_signature(op):
|
|
852
|
+
m = cmp_signature_re_1.match(op)
|
|
853
|
+
m2 = cmp_signature_re_2.match(op)
|
|
854
|
+
if (m is None) == (m2 is None):
|
|
855
|
+
raise PyvexOpMatchException()
|
|
856
|
+
mfound = m if m is not None else m2
|
|
857
|
+
assert mfound is not None
|
|
858
|
+
size = int(mfound.group("size"))
|
|
859
|
+
size_type = int_type_for_size(size)
|
|
860
|
+
return (int_type_for_size(1), (size_type, size_type))
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
def mull_signature(op):
|
|
864
|
+
m = mull_signature_re.match(op)
|
|
865
|
+
if m is None:
|
|
866
|
+
raise PyvexOpMatchException()
|
|
867
|
+
size = int(m.group("size"))
|
|
868
|
+
size_type = int_type_for_size(size)
|
|
869
|
+
doubled_size_type = int_type_for_size(2 * size)
|
|
870
|
+
return (doubled_size_type, (size_type, size_type))
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
def half_signature(op):
|
|
874
|
+
m = half_signature_re.match(op)
|
|
875
|
+
if m is None:
|
|
876
|
+
raise PyvexOpMatchException()
|
|
877
|
+
fullsize = int(m.group("fullsize"))
|
|
878
|
+
halfsize = int(m.group("halfsize"))
|
|
879
|
+
if halfsize * 2 != fullsize:
|
|
880
|
+
raise PyvexTypeErrorException("Invalid Instruction %s: Type 1 must be twice the size of type 2" % op)
|
|
881
|
+
fullsize_type = int_type_for_size(fullsize)
|
|
882
|
+
halfsize_type = int_type_for_size(halfsize)
|
|
883
|
+
return (fullsize_type, (fullsize_type, halfsize_type))
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
def cast_signature(op):
|
|
887
|
+
m = cast_signature_re.match(op)
|
|
888
|
+
if m is None:
|
|
889
|
+
raise PyvexOpMatchException()
|
|
890
|
+
src_type = int_type_for_size(int(m.group("srcsize")))
|
|
891
|
+
dst_type = int_type_for_size(int(m.group("dstsize")))
|
|
892
|
+
return (dst_type, (src_type,))
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
polymorphic_op_processors = [
|
|
896
|
+
unop_signature,
|
|
897
|
+
binop_signature,
|
|
898
|
+
shift_signature,
|
|
899
|
+
cmp_signature,
|
|
900
|
+
mull_signature,
|
|
901
|
+
half_signature,
|
|
902
|
+
cast_signature,
|
|
903
|
+
]
|
|
904
|
+
|
|
905
|
+
|
|
906
|
+
def _request_polymorphic_op_type(op):
|
|
907
|
+
for polymorphic_signature in polymorphic_op_processors:
|
|
908
|
+
try:
|
|
909
|
+
op_ty_sig = polymorphic_signature(op)
|
|
910
|
+
break
|
|
911
|
+
except PyvexOpMatchException:
|
|
912
|
+
continue
|
|
913
|
+
else:
|
|
914
|
+
raise PyvexOpMatchException("Op %s not recognized" % op)
|
|
915
|
+
return op_ty_sig
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
_request_funcs = [_request_op_type_from_cache, _request_op_type_from_libvex, _request_polymorphic_op_type]
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
def op_arg_types(op):
|
|
922
|
+
for _request_func in _request_funcs:
|
|
923
|
+
try:
|
|
924
|
+
return _request_func(op)
|
|
925
|
+
except KeyError:
|
|
926
|
+
continue
|
|
927
|
+
raise ValueError("Cannot find type of op %s" % op)
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
_globals = globals().copy()
|
|
931
|
+
#
|
|
932
|
+
# Mapping from tag strings/enums to IRExpr classes
|
|
933
|
+
#
|
|
934
|
+
tag_to_expr_mapping = {}
|
|
935
|
+
enum_to_expr_mapping = {}
|
|
936
|
+
tag_count = 0
|
|
937
|
+
cls = None
|
|
938
|
+
for cls in _globals.values():
|
|
939
|
+
if type(cls) is type and issubclass(cls, IRExpr) and cls is not IRExpr:
|
|
940
|
+
tag_to_expr_mapping[cls.tag] = cls
|
|
941
|
+
enum_to_expr_mapping[get_int_from_enum(cls.tag)] = cls
|
|
942
|
+
cls.tag_int = tag_count
|
|
943
|
+
tag_count += 1
|
|
944
|
+
del cls
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
def tag_to_expr_class(tag):
|
|
948
|
+
"""
|
|
949
|
+
Convert a tag string to the corresponding IRExpr class type.
|
|
950
|
+
|
|
951
|
+
:param str tag: The tag string.
|
|
952
|
+
:return: A class.
|
|
953
|
+
:rtype: type
|
|
954
|
+
"""
|
|
955
|
+
|
|
956
|
+
try:
|
|
957
|
+
return tag_to_expr_mapping[tag]
|
|
958
|
+
except KeyError:
|
|
959
|
+
raise KeyError("Cannot find expression class for type %s." % tag)
|
|
960
|
+
|
|
961
|
+
|
|
962
|
+
def enum_to_expr_class(tag_enum):
|
|
963
|
+
"""
|
|
964
|
+
Convert a tag enum to the corresponding IRExpr class.
|
|
965
|
+
|
|
966
|
+
:param int tag_enum: The tag enum.
|
|
967
|
+
:return: A class.
|
|
968
|
+
:rtype: type
|
|
969
|
+
"""
|
|
970
|
+
|
|
971
|
+
try:
|
|
972
|
+
return enum_to_expr_mapping[tag_enum]
|
|
973
|
+
except KeyError:
|
|
974
|
+
raise KeyError("Cannot find expression class for type %s." % get_enum_from_int(tag_enum))
|