pyvex 9.2.189__cp312-cp312-win_amd64.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.
- 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/pyvex.dll +0 -0
- pyvex/lib/pyvex.lib +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 +1452 -0
- pyvex-9.2.189.dist-info/METADATA +181 -0
- pyvex-9.2.189.dist-info/RECORD +60 -0
- pyvex-9.2.189.dist-info/WHEEL +5 -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/const.py
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
# pylint:disable=missing-class-docstring,raise-missing-from,not-callable
|
|
2
|
+
import re
|
|
3
|
+
from abc import ABC
|
|
4
|
+
|
|
5
|
+
from .enums import VEXObject, get_enum_from_int
|
|
6
|
+
from .errors import PyVEXError
|
|
7
|
+
from .native import ffi, pvc
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# IRConst hierarchy
|
|
11
|
+
class IRConst(VEXObject, ABC):
|
|
12
|
+
__slots__ = ["_value"]
|
|
13
|
+
|
|
14
|
+
type: str
|
|
15
|
+
size: int
|
|
16
|
+
tag: str
|
|
17
|
+
c_constructor = None
|
|
18
|
+
_value: int
|
|
19
|
+
|
|
20
|
+
def pp(self):
|
|
21
|
+
print(str(self))
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def value(self) -> int:
|
|
25
|
+
return self._value
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def _from_c(c_const):
|
|
29
|
+
if c_const[0] == ffi.NULL:
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
tag = get_enum_from_int(c_const.tag)
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
return tag_to_const_class(tag)._from_c(c_const)
|
|
36
|
+
except KeyError:
|
|
37
|
+
raise PyVEXError("Unknown/unsupported IRConstTag %s\n" % tag)
|
|
38
|
+
|
|
39
|
+
_translate = _from_c
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def _to_c(cls, const):
|
|
43
|
+
# libvex throws an exception when constructing a U1 with a value other than 0 or 1
|
|
44
|
+
if const.tag == "Ico_U1" and const.value not in (0, 1):
|
|
45
|
+
raise PyVEXError("Invalid U1 value: %d" % const.value)
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
return cls.c_constructor(const.value)
|
|
49
|
+
except KeyError:
|
|
50
|
+
raise PyVEXError("Unknown/unsupported IRConstTag %s]n" % const.tag)
|
|
51
|
+
|
|
52
|
+
def __eq__(self, other):
|
|
53
|
+
if not isinstance(other, type(self)):
|
|
54
|
+
return False
|
|
55
|
+
return self._value == other._value
|
|
56
|
+
|
|
57
|
+
def __hash__(self):
|
|
58
|
+
return hash((type(self), self._value))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class U1(IRConst):
|
|
62
|
+
__slots__: list[str] = []
|
|
63
|
+
|
|
64
|
+
type = "Ity_I1"
|
|
65
|
+
size = 1
|
|
66
|
+
tag = "Ico_U1"
|
|
67
|
+
op_format = "1"
|
|
68
|
+
c_constructor = pvc.IRConst_U1
|
|
69
|
+
|
|
70
|
+
def __init__(self, value):
|
|
71
|
+
self._value = value
|
|
72
|
+
|
|
73
|
+
def __str__(self):
|
|
74
|
+
return "%d" % self.value
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def _from_c(c_const):
|
|
78
|
+
return U1(c_const.Ico.U1)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class U8(IRConst):
|
|
82
|
+
__slots__: list[str] = []
|
|
83
|
+
|
|
84
|
+
type = "Ity_I8"
|
|
85
|
+
size = 8
|
|
86
|
+
tag = "Ico_U8"
|
|
87
|
+
op_format = "8"
|
|
88
|
+
c_constructor = pvc.IRConst_U8
|
|
89
|
+
|
|
90
|
+
def __init__(self, value):
|
|
91
|
+
self._value = value
|
|
92
|
+
|
|
93
|
+
def __str__(self):
|
|
94
|
+
return "0x%02x" % self.value
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _from_c(c_const):
|
|
98
|
+
return _U8_POOL[c_const.Ico.U8]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
_U8_POOL = [U8(i) for i in range(256)]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class U16(IRConst):
|
|
105
|
+
__slots__: list[str] = []
|
|
106
|
+
|
|
107
|
+
type = "Ity_I16"
|
|
108
|
+
size = 16
|
|
109
|
+
tag = "Ico_U16"
|
|
110
|
+
op_format = "16"
|
|
111
|
+
c_constructor = pvc.IRConst_U16
|
|
112
|
+
|
|
113
|
+
def __init__(self, value):
|
|
114
|
+
self._value = value
|
|
115
|
+
|
|
116
|
+
def __str__(self):
|
|
117
|
+
return "0x%04x" % self.value
|
|
118
|
+
|
|
119
|
+
@staticmethod
|
|
120
|
+
def _from_c(c_const):
|
|
121
|
+
val = c_const.Ico.U16
|
|
122
|
+
if val < 1024:
|
|
123
|
+
return _U16_POOL[val]
|
|
124
|
+
if val >= 0xFC00:
|
|
125
|
+
return _U16_POOL[val - 0xFC00 + 1024]
|
|
126
|
+
return U16(val)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
_U16_POOL = [U16(i) for i in range(1024)] + [U16(i) for i in range(0xFC00, 0xFFFF + 1)]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class U32(IRConst):
|
|
133
|
+
__slots__: list[str] = []
|
|
134
|
+
|
|
135
|
+
type = "Ity_I32"
|
|
136
|
+
size = 32
|
|
137
|
+
tag = "Ico_U32"
|
|
138
|
+
op_format = "32"
|
|
139
|
+
c_constructor = pvc.IRConst_U32
|
|
140
|
+
|
|
141
|
+
def __init__(self, value: int):
|
|
142
|
+
self._value = value
|
|
143
|
+
|
|
144
|
+
def __str__(self):
|
|
145
|
+
return "0x%08x" % self.value
|
|
146
|
+
|
|
147
|
+
@staticmethod
|
|
148
|
+
def _from_c(c_const):
|
|
149
|
+
val = c_const.Ico.U32
|
|
150
|
+
if val < 1024:
|
|
151
|
+
return _U32_POOL[val]
|
|
152
|
+
if val >= 0xFFFFFC00:
|
|
153
|
+
return _U32_POOL[val - 0xFFFFFC00 + 1024]
|
|
154
|
+
return U32(val)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
_U32_POOL = [U32(i) for i in range(1024)] + [U32(i) for i in range(0xFFFFFC00, 0xFFFFFFFF + 1)]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class U64(IRConst):
|
|
161
|
+
__slots__: list[str] = []
|
|
162
|
+
|
|
163
|
+
type = "Ity_I64"
|
|
164
|
+
size = 64
|
|
165
|
+
tag = "Ico_U64"
|
|
166
|
+
op_format = "64"
|
|
167
|
+
c_constructor = pvc.IRConst_U64
|
|
168
|
+
|
|
169
|
+
def __init__(self, value):
|
|
170
|
+
self._value = value
|
|
171
|
+
|
|
172
|
+
def __str__(self):
|
|
173
|
+
return "0x%016x" % self.value
|
|
174
|
+
|
|
175
|
+
@staticmethod
|
|
176
|
+
def _from_c(c_const):
|
|
177
|
+
val = c_const.Ico.U64
|
|
178
|
+
if val < 1024:
|
|
179
|
+
return _U64_POOL[val]
|
|
180
|
+
if val >= 0xFFFFFFFFFFFFFC00:
|
|
181
|
+
return _U64_POOL[val - 0xFFFFFFFFFFFFFC00 + 1024]
|
|
182
|
+
return U64(val)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
_U64_POOL = [U64(i) for i in range(1024)] + [U64(i) for i in range(0xFFFFFFFFFFFFFC00, 0xFFFFFFFFFFFFFFFF + 1)]
|
|
186
|
+
|
|
187
|
+
# Integer Type Imagination
|
|
188
|
+
class_cache = {1: U1, 8: U8, 16: U16, 32: U32, 64: U64}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def vex_int_class(size):
|
|
192
|
+
try:
|
|
193
|
+
return class_cache[size]
|
|
194
|
+
except KeyError:
|
|
195
|
+
|
|
196
|
+
class VexInt(IRConst):
|
|
197
|
+
type = "Ity_I%d" % size
|
|
198
|
+
tag = "Ico_U%d" % size
|
|
199
|
+
op_format = str(size)
|
|
200
|
+
|
|
201
|
+
def __init__(self, value):
|
|
202
|
+
IRConst.__init__(self)
|
|
203
|
+
self._value = value
|
|
204
|
+
|
|
205
|
+
def __str__(self):
|
|
206
|
+
return f"(0x{self.value:x} :: {self.type})"
|
|
207
|
+
|
|
208
|
+
VexInt.__name__ = "U%d" % size
|
|
209
|
+
class_cache[size] = VexInt
|
|
210
|
+
return VexInt
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class F32(IRConst):
|
|
214
|
+
__slots__: list[str] = []
|
|
215
|
+
|
|
216
|
+
type = "Ity_F32"
|
|
217
|
+
tag = "Ico_F32"
|
|
218
|
+
op_format = "F32"
|
|
219
|
+
c_constructor = pvc.IRConst_F32
|
|
220
|
+
size = 32
|
|
221
|
+
|
|
222
|
+
def __init__(self, value):
|
|
223
|
+
self._value = value
|
|
224
|
+
|
|
225
|
+
def __str__(self):
|
|
226
|
+
return "%f" % self.value
|
|
227
|
+
|
|
228
|
+
@staticmethod
|
|
229
|
+
def _from_c(c_const):
|
|
230
|
+
return F32(c_const.Ico.F32)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class F32i(IRConst):
|
|
234
|
+
__slots__: list[str] = []
|
|
235
|
+
|
|
236
|
+
type = "Ity_F32"
|
|
237
|
+
tag = "Ico_F32i"
|
|
238
|
+
op_format = "F32"
|
|
239
|
+
c_constructor = pvc.IRConst_F32i
|
|
240
|
+
size = 32
|
|
241
|
+
|
|
242
|
+
def __init__(self, value):
|
|
243
|
+
self._value = value
|
|
244
|
+
|
|
245
|
+
def __str__(self):
|
|
246
|
+
return "%f" % self.value
|
|
247
|
+
|
|
248
|
+
@staticmethod
|
|
249
|
+
def _from_c(c_const):
|
|
250
|
+
return F32i(c_const.Ico.F32)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class F64(IRConst):
|
|
254
|
+
__slots__: list[str] = []
|
|
255
|
+
|
|
256
|
+
type = "Ity_F64"
|
|
257
|
+
tag = "Ico_F64"
|
|
258
|
+
op_format = "F64"
|
|
259
|
+
c_constructor = pvc.IRConst_F64
|
|
260
|
+
size = 64
|
|
261
|
+
|
|
262
|
+
def __init__(self, value):
|
|
263
|
+
self._value = value
|
|
264
|
+
|
|
265
|
+
def __str__(self):
|
|
266
|
+
return "%f" % self.value
|
|
267
|
+
|
|
268
|
+
@staticmethod
|
|
269
|
+
def _from_c(c_const):
|
|
270
|
+
return F64(c_const.Ico.F64)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class F64i(IRConst):
|
|
274
|
+
__slots__: list[str] = []
|
|
275
|
+
|
|
276
|
+
type = "Ity_F64"
|
|
277
|
+
tag = "Ico_F64i"
|
|
278
|
+
op_format = "F64"
|
|
279
|
+
c_constructor = pvc.IRConst_F64i
|
|
280
|
+
size = 64
|
|
281
|
+
|
|
282
|
+
def __init__(self, value):
|
|
283
|
+
self._value = value
|
|
284
|
+
|
|
285
|
+
def __str__(self):
|
|
286
|
+
return "%f" % self.value
|
|
287
|
+
|
|
288
|
+
@staticmethod
|
|
289
|
+
def _from_c(c_const):
|
|
290
|
+
return F64i(c_const.Ico.F64)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class V128(IRConst):
|
|
294
|
+
__slots__: list[str] = []
|
|
295
|
+
|
|
296
|
+
type = "Ity_V128"
|
|
297
|
+
tag = "Ico_V128"
|
|
298
|
+
op_format = "V128"
|
|
299
|
+
c_constructor = pvc.IRConst_V128
|
|
300
|
+
size = 128
|
|
301
|
+
|
|
302
|
+
def __init__(self, value):
|
|
303
|
+
self._value = value
|
|
304
|
+
|
|
305
|
+
def __str__(self):
|
|
306
|
+
return "%x" % self.value
|
|
307
|
+
|
|
308
|
+
# vex doesn't store a full 128 bit constant, instead it stores 1 bit per 8 bits of data
|
|
309
|
+
# and duplicates each bit 8 times
|
|
310
|
+
@staticmethod
|
|
311
|
+
def _from_c(c_const):
|
|
312
|
+
base_const = c_const.Ico.V128
|
|
313
|
+
real_const = 0
|
|
314
|
+
for i in range(16):
|
|
315
|
+
if (base_const >> i) & 1 == 1:
|
|
316
|
+
real_const |= 0xFF << (8 * i)
|
|
317
|
+
return V128(real_const)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class V256(IRConst):
|
|
321
|
+
__slots__: list[str] = []
|
|
322
|
+
|
|
323
|
+
type = "Ity_V256"
|
|
324
|
+
tag = "Ico_V256"
|
|
325
|
+
op_format = "V256"
|
|
326
|
+
c_constructor = pvc.IRConst_V256
|
|
327
|
+
size = 256
|
|
328
|
+
|
|
329
|
+
def __init__(self, value):
|
|
330
|
+
self._value = value
|
|
331
|
+
|
|
332
|
+
def __str__(self):
|
|
333
|
+
return "%x" % self.value
|
|
334
|
+
|
|
335
|
+
# see above
|
|
336
|
+
@staticmethod
|
|
337
|
+
def _from_c(c_const):
|
|
338
|
+
base_const = c_const.Ico.V256
|
|
339
|
+
real_const = 0
|
|
340
|
+
for i in range(32):
|
|
341
|
+
if (base_const >> i) & 1 == 1:
|
|
342
|
+
real_const |= 0xFF << (8 * i)
|
|
343
|
+
return V256(real_const)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
predefined_types = [U1, U8, U16, U32, U64, F32, F32i, F64, F64i, V128, V256]
|
|
347
|
+
predefined_types_map = {c.type: c for c in predefined_types}
|
|
348
|
+
predefined_classes_map = {c.tag: c for c in predefined_types}
|
|
349
|
+
|
|
350
|
+
# precompiled regexes
|
|
351
|
+
int_ty_re = re.compile(r"Ity_I\d+")
|
|
352
|
+
int_tag_re = re.compile(r"Ico_U\d+")
|
|
353
|
+
tag_size_re = re.compile(r"Ico_[UFV](?P<size>\d+)i?")
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def is_int_ty(ty):
|
|
357
|
+
m = int_ty_re.match(ty)
|
|
358
|
+
return m is not None
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def is_int_tag(tag):
|
|
362
|
+
m = int_tag_re.match(tag)
|
|
363
|
+
return m is not None
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def get_tag_size(tag):
|
|
367
|
+
m = tag_size_re.match(tag)
|
|
368
|
+
if m is None:
|
|
369
|
+
raise ValueError("Tag %s does not have size" % tag)
|
|
370
|
+
return int(m.group("size"))
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
type_str_re = re.compile(r"Ity_[IFDV](?P<size>\d+)")
|
|
374
|
+
type_tag_str_re = re.compile(r"[IFDV]?(?P<size>\d+)[SU]?")
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def get_type_size(ty):
|
|
378
|
+
"""
|
|
379
|
+
Returns the size, in BITS, of a VEX type specifier
|
|
380
|
+
e.g., Ity_I16 -> 16
|
|
381
|
+
|
|
382
|
+
:param ty:
|
|
383
|
+
:return:
|
|
384
|
+
"""
|
|
385
|
+
m = type_str_re.match(ty)
|
|
386
|
+
if m is None:
|
|
387
|
+
raise ValueError("Type %s does not have size" % ty)
|
|
388
|
+
return int(m.group("size"))
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def get_type_spec_size(ty):
|
|
392
|
+
"""
|
|
393
|
+
Get the width of a "type specifier"
|
|
394
|
+
like I16U
|
|
395
|
+
or F16
|
|
396
|
+
or just 16
|
|
397
|
+
(Yes, this really just takes the int out. If we must special-case, do it here.
|
|
398
|
+
:param tyspec:
|
|
399
|
+
:return:
|
|
400
|
+
"""
|
|
401
|
+
m = type_tag_str_re.match(ty)
|
|
402
|
+
if m is None:
|
|
403
|
+
raise ValueError("Type specifier %s does not have size" % ty)
|
|
404
|
+
return int(m.group("size"))
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def ty_to_const_class(ty):
|
|
408
|
+
try:
|
|
409
|
+
return predefined_types_map[ty]
|
|
410
|
+
except KeyError:
|
|
411
|
+
if is_int_ty(ty):
|
|
412
|
+
size = get_type_size(ty)
|
|
413
|
+
return vex_int_class(size)
|
|
414
|
+
else:
|
|
415
|
+
raise ValueError("Type %s does not exist" % ty)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def tag_to_const_class(tag):
|
|
419
|
+
try:
|
|
420
|
+
return predefined_classes_map[tag]
|
|
421
|
+
except KeyError:
|
|
422
|
+
if is_int_tag(tag):
|
|
423
|
+
size = get_tag_size(tag)
|
|
424
|
+
return vex_int_class(size)
|
|
425
|
+
else:
|
|
426
|
+
raise ValueError("Tag %s does not exist" % tag)
|
pyvex/const_val.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class ConstVal:
|
|
2
|
+
"""
|
|
3
|
+
A constant value object. Indicates a constant value assignment to a VEX tmp variable.
|
|
4
|
+
|
|
5
|
+
:ivar tmp: The tmp variable being assigned to.
|
|
6
|
+
:ivar value: The value of the tmp variable.
|
|
7
|
+
:ivar stmt_idx: The IRSB statement index containing the data access
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__slots__ = (
|
|
11
|
+
"tmp",
|
|
12
|
+
"value",
|
|
13
|
+
"stmt_idx",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
def __init__(self, tmp: int, value: int, stmt_idx: int):
|
|
17
|
+
self.tmp = tmp
|
|
18
|
+
self.value = value
|
|
19
|
+
self.stmt_idx = stmt_idx
|
|
20
|
+
|
|
21
|
+
def __repr__(self):
|
|
22
|
+
return f"<ConstVal {self.tmp} = {self.value:#x} @ {self.stmt_idx}>"
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def from_c(cls, r):
|
|
26
|
+
return cls(r.tmp, r.value, r.stmt_idx)
|
pyvex/data_ref.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
def data_ref_type_str(dref_enum):
|
|
2
|
+
"""
|
|
3
|
+
Translate an ``enum DataRefTypes`` value into a string representation.
|
|
4
|
+
"""
|
|
5
|
+
if dref_enum == 0x9000:
|
|
6
|
+
return "unknown"
|
|
7
|
+
elif dref_enum == 0x9001:
|
|
8
|
+
return "integer"
|
|
9
|
+
elif dref_enum == 0x9002:
|
|
10
|
+
return "fp"
|
|
11
|
+
elif dref_enum == 0x9003:
|
|
12
|
+
return "integer(store)"
|
|
13
|
+
else:
|
|
14
|
+
return "INVALID"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DataRef:
|
|
18
|
+
"""
|
|
19
|
+
A data reference object. Indicates a data access in an IRSB.
|
|
20
|
+
|
|
21
|
+
:ivar data_addr: The address of the data being accessed
|
|
22
|
+
:ivar data_size: The size of the data being accessed, in bytes
|
|
23
|
+
:ivar data_type: The type of the data, a DataRefTypes enum.
|
|
24
|
+
:ivar stmt_idx: The IRSB statement index containing the data access
|
|
25
|
+
:ivar ins_addr: The address of the instruction performing the data access
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
__slots__ = ("data_addr", "data_size", "data_type", "stmt_idx", "ins_addr")
|
|
29
|
+
|
|
30
|
+
def __init__(self, data_addr, data_size, data_type, stmt_idx, ins_addr):
|
|
31
|
+
self.data_addr = data_addr
|
|
32
|
+
self.data_size = data_size
|
|
33
|
+
self.data_type = data_type
|
|
34
|
+
self.stmt_idx = stmt_idx
|
|
35
|
+
self.ins_addr = ins_addr
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def data_type_str(self):
|
|
39
|
+
"""
|
|
40
|
+
The data ref type as a string, "unknown" "integer" "fp" or "INVALID"
|
|
41
|
+
"""
|
|
42
|
+
return data_ref_type_str(self.data_type)
|
|
43
|
+
|
|
44
|
+
def __repr__(self):
|
|
45
|
+
return "<DataRef accessing %#x %s:%d at %#x:%d>" % (
|
|
46
|
+
self.data_addr,
|
|
47
|
+
data_ref_type_str(self.data_type),
|
|
48
|
+
self.data_size,
|
|
49
|
+
self.ins_addr,
|
|
50
|
+
self.stmt_idx,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def from_c(cls, r):
|
|
55
|
+
return cls(r.data_addr, r.size, r.data_type, r.stmt_idx, r.ins_addr)
|
pyvex/enums.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from .native import ffi, pvc
|
|
4
|
+
from .utils import stable_hash
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class VEXObject:
|
|
8
|
+
"""
|
|
9
|
+
The base class for Vex types.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__slots__: list[str] = []
|
|
13
|
+
|
|
14
|
+
def __eq__(self, other):
|
|
15
|
+
if not isinstance(other, type(self)):
|
|
16
|
+
return False
|
|
17
|
+
# compare values in slots
|
|
18
|
+
for slot in self.__slots__:
|
|
19
|
+
if getattr(self, slot) != getattr(other, slot):
|
|
20
|
+
return False
|
|
21
|
+
return True
|
|
22
|
+
|
|
23
|
+
def __hash__(self):
|
|
24
|
+
values = [getattr(self, slot) for slot in self.__slots__]
|
|
25
|
+
for i, lst_val in enumerate(values):
|
|
26
|
+
if isinstance(lst_val, list):
|
|
27
|
+
values[i] = tuple(lst_val)
|
|
28
|
+
return stable_hash(tuple([type(self)] + values))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class IRCallee(VEXObject):
|
|
32
|
+
"""
|
|
33
|
+
Describes a helper function to call.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
__slots__ = ["regparms", "name", "mcx_mask"]
|
|
37
|
+
|
|
38
|
+
def __init__(self, regparms, name, mcx_mask):
|
|
39
|
+
VEXObject.__init__(self)
|
|
40
|
+
self.regparms = regparms
|
|
41
|
+
self.name = name
|
|
42
|
+
self.mcx_mask = mcx_mask
|
|
43
|
+
|
|
44
|
+
def __str__(self):
|
|
45
|
+
return str(self.name)
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def _from_c(c_callee):
|
|
49
|
+
return IRCallee(
|
|
50
|
+
c_callee.regparms,
|
|
51
|
+
ffi.string(c_callee.name).decode(),
|
|
52
|
+
# NO. #int(ffi.cast("unsigned long long", c_callee.addr)),
|
|
53
|
+
c_callee.mcx_mask,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def _to_c(callee): # pylint: disable=unused-argument
|
|
58
|
+
raise TypeError(
|
|
59
|
+
"This doesn't work! Please invent a way to get the correct address for the named function from pyvex_c."
|
|
60
|
+
)
|
|
61
|
+
# c_callee = pvc.mkIRCallee(callee.regparms,
|
|
62
|
+
# callee.name.encode(),
|
|
63
|
+
# ffi.cast("void *", callee.addr))
|
|
64
|
+
# c_callee.mcx_mask = callee.mcx_mask
|
|
65
|
+
# return c_callee
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class IRRegArray(VEXObject):
|
|
69
|
+
"""
|
|
70
|
+
A section of the guest state that we want te be able to index at run time, so as to be able to describe indexed or
|
|
71
|
+
rotating register files on the guest.
|
|
72
|
+
|
|
73
|
+
:ivar int base: The offset into the state that this array starts
|
|
74
|
+
:ivar str elemTy: The types of the elements in this array, as VEX enum strings
|
|
75
|
+
:ivar int nElems: The number of elements in this array
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
__slots__ = ["base", "elemTy", "nElems"]
|
|
79
|
+
|
|
80
|
+
def __init__(self, base, elemTy, nElems):
|
|
81
|
+
VEXObject.__init__(self)
|
|
82
|
+
self.base = base
|
|
83
|
+
self.elemTy = elemTy
|
|
84
|
+
self.nElems = nElems
|
|
85
|
+
|
|
86
|
+
def __str__(self):
|
|
87
|
+
return "%s:%sx%d" % (self.base, self.elemTy[4:], self.nElems)
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def _from_c(c_arr):
|
|
91
|
+
return IRRegArray(c_arr.base, ints_to_enums[c_arr.elemTy], c_arr.nElems)
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def _to_c(arr):
|
|
95
|
+
return pvc.mkIRRegArray(arr.base, get_int_from_enum(arr.elemTy), arr.nElems)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
ints_to_enums: dict[int, str] = {}
|
|
99
|
+
enums_to_ints: dict[str, int] = {}
|
|
100
|
+
irop_enums_to_ints: dict[str, int] = {}
|
|
101
|
+
will_be_overwritten = ["Ircr_GT", "Ircr_LT"]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def get_enum_from_int(i):
|
|
105
|
+
return ints_to_enums[i]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_int_from_enum(e):
|
|
109
|
+
return enums_to_ints[e]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
_add_enum_counter = 0
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _add_enum(s, i=None): # TODO get rid of this
|
|
116
|
+
global _add_enum_counter # pylint: disable=global-statement
|
|
117
|
+
if i is None:
|
|
118
|
+
while _add_enum_counter in ints_to_enums:
|
|
119
|
+
_add_enum_counter += 1
|
|
120
|
+
i = _add_enum_counter
|
|
121
|
+
_add_enum_counter += 1 # Update for the next iteration
|
|
122
|
+
if i in ints_to_enums:
|
|
123
|
+
if ints_to_enums[i] not in will_be_overwritten:
|
|
124
|
+
raise ValueError("Enum with intkey %d already present" % i)
|
|
125
|
+
enums_to_ints[s] = i
|
|
126
|
+
ints_to_enums[i] = s
|
|
127
|
+
if s.startswith("Iop_"):
|
|
128
|
+
irop_enums_to_ints[s] = i
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
for attr in dir(pvc):
|
|
132
|
+
if attr[0] in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" and hasattr(pvc, attr) and isinstance(getattr(pvc, attr), int):
|
|
133
|
+
_add_enum(attr, getattr(pvc, attr))
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def vex_endness_from_string(endness_str):
|
|
137
|
+
return getattr(pvc, endness_str)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def default_vex_archinfo() -> dict[str, Any]:
|
|
141
|
+
return {
|
|
142
|
+
"hwcaps": 0,
|
|
143
|
+
"endness": vex_endness_from_string("VexEndnessLE"),
|
|
144
|
+
"ppc_icache_line_szB": 0,
|
|
145
|
+
"ppc_dcbz_szB": 0,
|
|
146
|
+
"ppc_dcbzl_szB": 0,
|
|
147
|
+
"arm64_dMinLine_lg2_szB": 0,
|
|
148
|
+
"arm64_iMinLine_lg2_szB": 0,
|
|
149
|
+
"hwcache_info": {
|
|
150
|
+
"num_levels": 0,
|
|
151
|
+
"num_caches": 0,
|
|
152
|
+
"caches": None,
|
|
153
|
+
"icaches_maintain_coherence": True,
|
|
154
|
+
},
|
|
155
|
+
"x86_cr0": 0xFFFFFFFF,
|
|
156
|
+
}
|
pyvex/errors.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class PyVEXError(Exception):
|
|
2
|
+
pass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class SkipStatementsError(PyVEXError):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Exceptions and notifications that post-processors can raise
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LiftingException(Exception):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class NeedStatementsNotification(LiftingException):
|
|
19
|
+
"""
|
|
20
|
+
A post-processor may raise a NeedStatementsNotification if it needs to work with statements, but the current IRSB
|
|
21
|
+
is generated without any statement available (skip_stmts=True). The lifter will re-lift the current block with
|
|
22
|
+
skip_stmts=False upon catching a NeedStatementsNotification, and re-run the post-processors.
|
|
23
|
+
|
|
24
|
+
It's worth noting that if a post-processor always raises this notification for every basic block without statements,
|
|
25
|
+
it will essentially disable the skipping statement optimization, and it is bad for performance (especially for
|
|
26
|
+
CFGFast, which heavily relies on this optimization). Post-processor authors are encouraged to at least filter the
|
|
27
|
+
IRSBs based on available properties (jumpkind, next, etc.). If a post-processor must work with statements for the
|
|
28
|
+
majority of IRSBs, the author should implement it in PyVEX in C for the sake of a better performance.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
pass
|