pyvex 9.2.193__cp310-cp310-macosx_10_12_x86_64.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/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.193.dist-info/METADATA +181 -0
- pyvex-9.2.193.dist-info/RECORD +59 -0
- pyvex-9.2.193.dist-info/WHEEL +6 -0
- pyvex-9.2.193.dist-info/licenses/LICENSE +24 -0
- pyvex-9.2.193.dist-info/licenses/pyvex_c/LICENSE +339 -0
- pyvex-9.2.193.dist-info/licenses/vex/LICENSE.GPL +340 -0
- pyvex-9.2.193.dist-info/licenses/vex/LICENSE.README +23 -0
pyvex/stmt.py
ADDED
|
@@ -0,0 +1,740 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Iterator
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from . import expr
|
|
8
|
+
from .const import IRConst
|
|
9
|
+
from .enums import IRCallee, IRRegArray, VEXObject, get_enum_from_int, get_int_from_enum
|
|
10
|
+
from .errors import PyVEXError
|
|
11
|
+
from .expr import Const, Get, IRExpr
|
|
12
|
+
from .native import ffi, pvc
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from .block import IRTypeEnv
|
|
16
|
+
|
|
17
|
+
log = logging.getLogger("pyvex.stmt")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class IRStmt(VEXObject):
|
|
21
|
+
"""
|
|
22
|
+
IR statements in VEX represents operations with side-effects.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
tag: str
|
|
26
|
+
tag_int = 0 # set automatically at bottom of file
|
|
27
|
+
|
|
28
|
+
__slots__ = []
|
|
29
|
+
|
|
30
|
+
def pp(self):
|
|
31
|
+
print(str(self))
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def child_expressions(self) -> Iterator[IRExpr]:
|
|
35
|
+
for k in self.__slots__:
|
|
36
|
+
v = getattr(self, k)
|
|
37
|
+
if isinstance(v, IRExpr):
|
|
38
|
+
# return itself
|
|
39
|
+
yield v
|
|
40
|
+
# return all the child expressions
|
|
41
|
+
yield from v.child_expressions
|
|
42
|
+
|
|
43
|
+
# ???
|
|
44
|
+
@property
|
|
45
|
+
def expressions(self):
|
|
46
|
+
return self.child_expressions
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def constants(self):
|
|
50
|
+
return sum((e.constants for e in self.expressions), [])
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def _from_c(c_stmt):
|
|
54
|
+
if c_stmt[0] == ffi.NULL:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
stmt_class = enum_to_stmt_class(c_stmt.tag)
|
|
59
|
+
except KeyError:
|
|
60
|
+
raise PyVEXError("Unknown/unsupported IRStmtTag %s.\n" % get_enum_from_int(c_stmt.tag))
|
|
61
|
+
return stmt_class._from_c(c_stmt)
|
|
62
|
+
|
|
63
|
+
def typecheck(self, tyenv: IRTypeEnv) -> bool: # pylint: disable=unused-argument,no-self-use
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
def replace_expression(self, replacements):
|
|
67
|
+
"""
|
|
68
|
+
Replace child expressions in-place.
|
|
69
|
+
|
|
70
|
+
:param Dict[IRExpr, IRExpr] replacements: A mapping from expression-to-find to expression-to-replace-with
|
|
71
|
+
:return: None
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
for k in self.__slots__:
|
|
75
|
+
v = getattr(self, k)
|
|
76
|
+
if isinstance(v, IRExpr) and v in replacements:
|
|
77
|
+
setattr(self, k, replacements.get(v))
|
|
78
|
+
elif isinstance(v, IRExpr):
|
|
79
|
+
v.replace_expression(replacements)
|
|
80
|
+
elif type(v) is tuple:
|
|
81
|
+
# Rebuild the tuple
|
|
82
|
+
_lst = []
|
|
83
|
+
replaced = False
|
|
84
|
+
for expr_ in v:
|
|
85
|
+
if isinstance(expr_, IRExpr) and expr_ in replacements:
|
|
86
|
+
_lst.append(replacements.get(expr_))
|
|
87
|
+
replaced = True
|
|
88
|
+
else:
|
|
89
|
+
_lst.append(expr_)
|
|
90
|
+
if replaced:
|
|
91
|
+
setattr(self, k, tuple(_lst))
|
|
92
|
+
|
|
93
|
+
def __str__(self):
|
|
94
|
+
return self.pp_str(None, None, None)
|
|
95
|
+
|
|
96
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None) -> str:
|
|
97
|
+
raise NotImplementedError()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class NoOp(IRStmt):
|
|
101
|
+
"""
|
|
102
|
+
A no-operation statement. It is usually the result of an IR optimization.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
__slots__ = []
|
|
106
|
+
|
|
107
|
+
tag = "Ist_NoOp"
|
|
108
|
+
|
|
109
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
110
|
+
return "IR-NoOp"
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def _from_c(c_stmt):
|
|
114
|
+
return NoOp()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class IMark(IRStmt):
|
|
118
|
+
"""
|
|
119
|
+
An instruction mark. It marks the start of the statements that represent a single machine instruction (the end of
|
|
120
|
+
those statements is marked by the next IMark or the end of the IRSB). Contains the address and length of the
|
|
121
|
+
instruction.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
__slots__ = ["addr", "len", "delta"]
|
|
125
|
+
|
|
126
|
+
tag = "Ist_IMark"
|
|
127
|
+
|
|
128
|
+
def __init__(self, addr: int, length: int, delta: int):
|
|
129
|
+
self.addr = addr
|
|
130
|
+
self.len = length
|
|
131
|
+
self.delta = delta
|
|
132
|
+
|
|
133
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
134
|
+
return "------ IMark(0x%x, %d, %d) ------" % (self.addr, self.len, self.delta)
|
|
135
|
+
|
|
136
|
+
@staticmethod
|
|
137
|
+
def _from_c(c_stmt):
|
|
138
|
+
return IMark(c_stmt.Ist.IMark.addr, c_stmt.Ist.IMark.len, c_stmt.Ist.IMark.delta)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class AbiHint(IRStmt):
|
|
142
|
+
"""
|
|
143
|
+
An ABI hint, provides specific information about this platform's ABI.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
__slots__ = ["base", "len", "nia"]
|
|
147
|
+
|
|
148
|
+
tag = "Ist_AbiHint"
|
|
149
|
+
|
|
150
|
+
def __init__(self, base, length, nia):
|
|
151
|
+
self.base = base
|
|
152
|
+
self.len = length
|
|
153
|
+
self.nia = nia
|
|
154
|
+
|
|
155
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
156
|
+
return "====== AbiHint(0x%s, %d, %s) ======" % (self.base, self.len, self.nia)
|
|
157
|
+
|
|
158
|
+
@staticmethod
|
|
159
|
+
def _from_c(c_stmt):
|
|
160
|
+
return AbiHint(
|
|
161
|
+
IRExpr._from_c(c_stmt.Ist.AbiHint.base), c_stmt.Ist.AbiHint.len, IRExpr._from_c(c_stmt.Ist.AbiHint.nia)
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class Put(IRStmt):
|
|
166
|
+
"""
|
|
167
|
+
Write to a guest register, at a fixed offset in the guest state.
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
__slots__ = ["data", "offset"]
|
|
171
|
+
|
|
172
|
+
tag = "Ist_Put"
|
|
173
|
+
|
|
174
|
+
def __init__(self, data: IRExpr, offset: int):
|
|
175
|
+
self.data = data
|
|
176
|
+
self.offset = offset
|
|
177
|
+
|
|
178
|
+
## TODO: Check if result_size and arch are available before looking of arch register name
|
|
179
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
180
|
+
if arch is not None and tyenv is not None:
|
|
181
|
+
reg_name = arch.translate_register_name(self.offset, self.data.result_size(tyenv) // 8)
|
|
182
|
+
|
|
183
|
+
if reg_name is not None:
|
|
184
|
+
return f"PUT({reg_name}) = {self.data}"
|
|
185
|
+
else:
|
|
186
|
+
return f"PUT(offset={self.offset}) = {self.data}"
|
|
187
|
+
|
|
188
|
+
@staticmethod
|
|
189
|
+
def _from_c(c_stmt):
|
|
190
|
+
return Put(IRExpr._from_c(c_stmt.Ist.Put.data), c_stmt.Ist.Put.offset)
|
|
191
|
+
|
|
192
|
+
def typecheck(self, tyenv):
|
|
193
|
+
return self.data.typecheck(tyenv)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class PutI(IRStmt):
|
|
197
|
+
"""
|
|
198
|
+
Write to a guest register, at a non-fixed offset in the guest state.
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
__slots__ = ["descr", "ix", "data", "bias"]
|
|
202
|
+
|
|
203
|
+
tag = "Ist_PutI"
|
|
204
|
+
|
|
205
|
+
def __init__(self, descr, ix, data, bias):
|
|
206
|
+
self.descr = descr
|
|
207
|
+
self.ix = ix
|
|
208
|
+
self.data = data
|
|
209
|
+
self.bias = bias
|
|
210
|
+
|
|
211
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
212
|
+
return "PutI(%s)[%s,%d] = %s" % (self.descr, self.ix, self.bias, self.data)
|
|
213
|
+
|
|
214
|
+
@staticmethod
|
|
215
|
+
def _from_c(c_stmt):
|
|
216
|
+
return PutI(
|
|
217
|
+
IRRegArray._from_c(c_stmt.Ist.PutI.details.descr),
|
|
218
|
+
IRExpr._from_c(c_stmt.Ist.PutI.details.ix),
|
|
219
|
+
IRExpr._from_c(c_stmt.Ist.PutI.details.data),
|
|
220
|
+
c_stmt.Ist.PutI.details.bias,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
def typecheck(self, tyenv):
|
|
224
|
+
dataty = self.data.typecheck(tyenv)
|
|
225
|
+
if dataty is None:
|
|
226
|
+
return False
|
|
227
|
+
if dataty != self.descr.elemTy:
|
|
228
|
+
log.debug("Expression doesn't match RegArray type")
|
|
229
|
+
return False
|
|
230
|
+
return True
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class WrTmp(IRStmt):
|
|
234
|
+
"""
|
|
235
|
+
Assign a value to a temporary. Note that SSA rules require each tmp is only assigned to once. IR sanity checking
|
|
236
|
+
will reject any block containing a temporary which is not assigned to exactly once.
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
__slots__ = ["data", "tmp"]
|
|
240
|
+
|
|
241
|
+
tag = "Ist_WrTmp"
|
|
242
|
+
|
|
243
|
+
def __init__(self, tmp, data: IRExpr):
|
|
244
|
+
self.tmp = tmp
|
|
245
|
+
self.data = data
|
|
246
|
+
|
|
247
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
248
|
+
# Support for named register in string representation of expr.Get
|
|
249
|
+
|
|
250
|
+
if arch is not None and tyenv is not None and isinstance(self.data, Get):
|
|
251
|
+
reg_name = arch.translate_register_name(self.data.offset, self.data.result_size(tyenv) // 8)
|
|
252
|
+
|
|
253
|
+
if reg_name is not None and isinstance(self.data, expr.Get):
|
|
254
|
+
return "t%d = %s" % (self.tmp, self.data.pp_str_with_name(reg_name))
|
|
255
|
+
else:
|
|
256
|
+
return "t%d = %s" % (self.tmp, self.data)
|
|
257
|
+
|
|
258
|
+
@staticmethod
|
|
259
|
+
def _from_c(c_stmt):
|
|
260
|
+
return WrTmp(c_stmt.Ist.WrTmp.tmp, IRExpr._from_c(c_stmt.Ist.WrTmp.data))
|
|
261
|
+
|
|
262
|
+
def typecheck(self, tyenv):
|
|
263
|
+
dataty = self.data.typecheck(tyenv)
|
|
264
|
+
if dataty is None:
|
|
265
|
+
return False
|
|
266
|
+
if dataty != tyenv.lookup(self.tmp):
|
|
267
|
+
log.debug("Expression doesn't match tmp type")
|
|
268
|
+
return False
|
|
269
|
+
return True
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class Store(IRStmt):
|
|
273
|
+
"""
|
|
274
|
+
Write a value to memory..
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
__slots__ = ["addr", "data", "end"]
|
|
278
|
+
|
|
279
|
+
tag = "Ist_Store"
|
|
280
|
+
|
|
281
|
+
def __init__(self, addr: IRExpr, data: IRExpr, end: str):
|
|
282
|
+
self.addr = addr
|
|
283
|
+
self.data = data
|
|
284
|
+
self.end = end
|
|
285
|
+
|
|
286
|
+
@property
|
|
287
|
+
def endness(self):
|
|
288
|
+
return self.end
|
|
289
|
+
|
|
290
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
291
|
+
return f"ST{self.endness[-2:].lower()}({self.addr}) = {self.data}"
|
|
292
|
+
|
|
293
|
+
@staticmethod
|
|
294
|
+
def _from_c(c_stmt):
|
|
295
|
+
return Store(
|
|
296
|
+
IRExpr._from_c(c_stmt.Ist.Store.addr),
|
|
297
|
+
IRExpr._from_c(c_stmt.Ist.Store.data),
|
|
298
|
+
get_enum_from_int(c_stmt.Ist.Store.end),
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
def typecheck(self, tyenv):
|
|
302
|
+
dataty = self.data.typecheck(tyenv)
|
|
303
|
+
if dataty is None:
|
|
304
|
+
return False
|
|
305
|
+
addrty = self.addr.typecheck(tyenv)
|
|
306
|
+
if addrty is None:
|
|
307
|
+
return False
|
|
308
|
+
if addrty != tyenv.wordty:
|
|
309
|
+
log.debug("addr must be full word for arch")
|
|
310
|
+
return False
|
|
311
|
+
if self.end not in ("Iend_LE", "Iend_BE"):
|
|
312
|
+
log.debug("invalid endness enum")
|
|
313
|
+
return False
|
|
314
|
+
return True
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class CAS(IRStmt):
|
|
318
|
+
"""
|
|
319
|
+
an atomic compare-and-swap operation.
|
|
320
|
+
"""
|
|
321
|
+
|
|
322
|
+
__slots__ = ["addr", "dataLo", "dataHi", "expdLo", "expdHi", "oldLo", "oldHi", "end"]
|
|
323
|
+
|
|
324
|
+
tag = "Ist_CAS"
|
|
325
|
+
|
|
326
|
+
def __init__(self, addr, dataLo, dataHi, expdLo, expdHi, oldLo, oldHi, end):
|
|
327
|
+
self.addr = addr
|
|
328
|
+
self.dataLo = dataLo
|
|
329
|
+
self.dataHi = dataHi
|
|
330
|
+
self.expdLo = expdLo
|
|
331
|
+
self.expdHi = expdHi
|
|
332
|
+
self.oldLo = oldLo
|
|
333
|
+
self.oldHi = oldHi
|
|
334
|
+
self.end = end
|
|
335
|
+
|
|
336
|
+
@property
|
|
337
|
+
def endness(self):
|
|
338
|
+
return self.end
|
|
339
|
+
|
|
340
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
341
|
+
return "t({},{}) = CAS{}({} :: ({},{})->({},{}))".format(
|
|
342
|
+
self.oldLo, self.oldHi, self.end[-2:].lower(), self.addr, self.expdLo, self.expdHi, self.dataLo, self.dataHi
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
@staticmethod
|
|
346
|
+
def _from_c(c_stmt):
|
|
347
|
+
return CAS(
|
|
348
|
+
IRExpr._from_c(c_stmt.Ist.CAS.details.addr),
|
|
349
|
+
IRExpr._from_c(c_stmt.Ist.CAS.details.dataLo),
|
|
350
|
+
IRExpr._from_c(c_stmt.Ist.CAS.details.dataHi),
|
|
351
|
+
IRExpr._from_c(c_stmt.Ist.CAS.details.expdLo),
|
|
352
|
+
IRExpr._from_c(c_stmt.Ist.CAS.details.expdHi),
|
|
353
|
+
c_stmt.Ist.CAS.details.oldLo,
|
|
354
|
+
c_stmt.Ist.CAS.details.oldHi,
|
|
355
|
+
get_enum_from_int(c_stmt.Ist.CAS.details.end),
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
def typecheck(self, tyenv):
|
|
359
|
+
addrty = self.addr.typecheck(tyenv)
|
|
360
|
+
if addrty is None:
|
|
361
|
+
return False
|
|
362
|
+
if addrty != tyenv.wordty:
|
|
363
|
+
log.debug("addr must be full word for arch")
|
|
364
|
+
return False
|
|
365
|
+
if self.end not in ("Iend_LE", "Iend_BE"):
|
|
366
|
+
log.debug("invalid endness enum")
|
|
367
|
+
return False
|
|
368
|
+
|
|
369
|
+
if self.oldHi == 0xFFFFFFFF:
|
|
370
|
+
# single-element case
|
|
371
|
+
if self.expdHi is not None or self.dataHi is not None:
|
|
372
|
+
log.debug("expdHi and dataHi must be None")
|
|
373
|
+
return False
|
|
374
|
+
expdLoTy = self.expdLo.typecheck(tyenv)
|
|
375
|
+
dataLoTy = self.dataLo.typecheck(tyenv)
|
|
376
|
+
if expdLoTy is None or dataLoTy is None:
|
|
377
|
+
return False
|
|
378
|
+
if tyenv.lookup(self.oldLo) != expdLoTy or expdLoTy != dataLoTy:
|
|
379
|
+
log.debug("oldLo, expdL, dataLo must all have the same type")
|
|
380
|
+
return False
|
|
381
|
+
else:
|
|
382
|
+
# double-element case
|
|
383
|
+
expdLoTy = self.expdLo.typecheck(tyenv)
|
|
384
|
+
dataLoTy = self.dataLo.typecheck(tyenv)
|
|
385
|
+
expdHiTy = self.expdHi.typecheck(tyenv)
|
|
386
|
+
dataHiTy = self.dataHi.typecheck(tyenv)
|
|
387
|
+
if expdLoTy is None or dataLoTy is None or expdHiTy is None or dataHiTy is None:
|
|
388
|
+
return False
|
|
389
|
+
if (
|
|
390
|
+
tyenv.lookup(self.oldLo) != expdLoTy
|
|
391
|
+
or expdLoTy != dataLoTy
|
|
392
|
+
or tyenv.lookup(self.oldHi) != expdHiTy
|
|
393
|
+
or expdHiTy != dataHiTy
|
|
394
|
+
or expdLoTy != expdHiTy
|
|
395
|
+
):
|
|
396
|
+
log.debug("oldLo, expdLo, dataLo, oldHi, expdHi, dataHi must all have the same type")
|
|
397
|
+
return False
|
|
398
|
+
|
|
399
|
+
return True
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
class LLSC(IRStmt):
|
|
403
|
+
"""
|
|
404
|
+
Either Load-Linked or Store-Conditional, depending on STOREDATA. If STOREDATA is NULL then this is a Load-Linked,
|
|
405
|
+
else it is a Store-Conditional.
|
|
406
|
+
"""
|
|
407
|
+
|
|
408
|
+
__slots__ = ["addr", "storedata", "result", "end"]
|
|
409
|
+
|
|
410
|
+
tag = "Ist_LLSC"
|
|
411
|
+
|
|
412
|
+
def __init__(self, addr: IRExpr, storedata: IRExpr, result: int, end: str):
|
|
413
|
+
self.addr = addr
|
|
414
|
+
self.storedata = storedata
|
|
415
|
+
self.result = result
|
|
416
|
+
self.end = end
|
|
417
|
+
|
|
418
|
+
@property
|
|
419
|
+
def endness(self):
|
|
420
|
+
return self.end
|
|
421
|
+
|
|
422
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
423
|
+
if self.storedata is None:
|
|
424
|
+
return "t%d = LD%s-Linked(%s)" % (self.result, self.end[-2:].lower(), self.addr)
|
|
425
|
+
else:
|
|
426
|
+
return "t%d = ( ST%s-Cond(%s) = %s )" % (self.result, self.end[-2:].lower(), self.addr, self.storedata)
|
|
427
|
+
|
|
428
|
+
@staticmethod
|
|
429
|
+
def _from_c(c_stmt):
|
|
430
|
+
return LLSC(
|
|
431
|
+
IRExpr._from_c(c_stmt.Ist.LLSC.addr),
|
|
432
|
+
IRExpr._from_c(c_stmt.Ist.LLSC.storedata),
|
|
433
|
+
c_stmt.Ist.LLSC.result,
|
|
434
|
+
get_enum_from_int(c_stmt.Ist.LLSC.end),
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
def typecheck(self, tyenv):
|
|
438
|
+
addrty = self.addr.typecheck(tyenv)
|
|
439
|
+
if addrty is None:
|
|
440
|
+
return False
|
|
441
|
+
if addrty != tyenv.wordty:
|
|
442
|
+
log.debug("addr must be full word for arch")
|
|
443
|
+
return False
|
|
444
|
+
if self.end not in ("Iend_LE", "Iend_BE"):
|
|
445
|
+
log.debug("invalid endness enum")
|
|
446
|
+
return False
|
|
447
|
+
|
|
448
|
+
if self.storedata is not None:
|
|
449
|
+
# load-linked
|
|
450
|
+
storety = self.storedata.typecheck(tyenv)
|
|
451
|
+
if storety is None:
|
|
452
|
+
return False
|
|
453
|
+
|
|
454
|
+
if tyenv.lookup(self.result) != "Ity_I1":
|
|
455
|
+
log.debug("result tmp must be Ity_I1")
|
|
456
|
+
return False
|
|
457
|
+
|
|
458
|
+
return True
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
class MBE(IRStmt):
|
|
462
|
+
__slots__ = ["event"]
|
|
463
|
+
|
|
464
|
+
tag = "Ist_MBE"
|
|
465
|
+
|
|
466
|
+
def __init__(self, event):
|
|
467
|
+
self.event = event
|
|
468
|
+
|
|
469
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
470
|
+
return "MBusEvent-" + self.event
|
|
471
|
+
|
|
472
|
+
@staticmethod
|
|
473
|
+
def _from_c(c_stmt):
|
|
474
|
+
return MBE(get_enum_from_int(c_stmt.Ist.MBE.event))
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
class Dirty(IRStmt):
|
|
478
|
+
__slots__ = ["cee", "guard", "args", "tmp", "mFx", "mAddr", "mSize", "nFxState"]
|
|
479
|
+
|
|
480
|
+
tag = "Ist_Dirty"
|
|
481
|
+
|
|
482
|
+
def __init__(self, cee, guard, args, tmp, mFx, mAddr, mSize, nFxState):
|
|
483
|
+
self.cee = cee
|
|
484
|
+
self.guard = guard
|
|
485
|
+
self.args = tuple(args)
|
|
486
|
+
self.tmp = tmp
|
|
487
|
+
self.mFx = mFx
|
|
488
|
+
self.mAddr = mAddr
|
|
489
|
+
self.mSize = mSize
|
|
490
|
+
self.nFxState = nFxState
|
|
491
|
+
|
|
492
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
493
|
+
return "t{} = DIRTY {} {} ::: {}({})".format(
|
|
494
|
+
self.tmp, self.guard, "TODO(effects)", self.cee, ",".join(str(a) for a in self.args)
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
@property
|
|
498
|
+
def child_expressions(self):
|
|
499
|
+
expressions = sum((a.child_expressions for a in self.args), [])
|
|
500
|
+
expressions.extend(self.args)
|
|
501
|
+
expressions.append(self.guard)
|
|
502
|
+
expressions.extend(self.guard.child_expressions)
|
|
503
|
+
return expressions
|
|
504
|
+
|
|
505
|
+
@staticmethod
|
|
506
|
+
def _from_c(c_stmt):
|
|
507
|
+
args = []
|
|
508
|
+
for i in range(20):
|
|
509
|
+
a = c_stmt.Ist.Dirty.details.args[i]
|
|
510
|
+
if a == ffi.NULL:
|
|
511
|
+
break
|
|
512
|
+
|
|
513
|
+
args.append(IRExpr._from_c(a))
|
|
514
|
+
|
|
515
|
+
return Dirty(
|
|
516
|
+
IRCallee._from_c(c_stmt.Ist.Dirty.details.cee),
|
|
517
|
+
IRExpr._from_c(c_stmt.Ist.Dirty.details.guard),
|
|
518
|
+
tuple(args),
|
|
519
|
+
c_stmt.Ist.Dirty.details.tmp,
|
|
520
|
+
get_enum_from_int(c_stmt.Ist.Dirty.details.mFx),
|
|
521
|
+
IRExpr._from_c(c_stmt.Ist.Dirty.details.mAddr),
|
|
522
|
+
c_stmt.Ist.Dirty.details.mSize,
|
|
523
|
+
c_stmt.Ist.Dirty.details.nFxState,
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
class Exit(IRStmt):
|
|
528
|
+
"""
|
|
529
|
+
A conditional exit from the middle of an IRSB.
|
|
530
|
+
"""
|
|
531
|
+
|
|
532
|
+
__slots__ = ["guard", "dst", "offsIP", "jk"]
|
|
533
|
+
|
|
534
|
+
tag = "Ist_Exit"
|
|
535
|
+
|
|
536
|
+
def __init__(self, guard: IRExpr, dst: IRConst, jk: str, offsIP: int):
|
|
537
|
+
self.guard = guard
|
|
538
|
+
self.dst = dst
|
|
539
|
+
self.offsIP = offsIP
|
|
540
|
+
self.jk = jk
|
|
541
|
+
|
|
542
|
+
@property
|
|
543
|
+
def jumpkind(self):
|
|
544
|
+
return self.jk
|
|
545
|
+
|
|
546
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
547
|
+
if arch is not None and tyenv is not None:
|
|
548
|
+
reg_name = arch.translate_register_name(self.offsIP, arch.bits // 8)
|
|
549
|
+
|
|
550
|
+
if reg_name is None:
|
|
551
|
+
return "if (%s) { PUT(offset=%d) = %#x; %s }" % (self.guard, self.offsIP, self.dst.value, self.jumpkind)
|
|
552
|
+
else:
|
|
553
|
+
return f"if ({self.guard}) {{ PUT({reg_name}) = {self.dst.value:#x}; {self.jumpkind} }}"
|
|
554
|
+
|
|
555
|
+
@property
|
|
556
|
+
def child_expressions(self):
|
|
557
|
+
return [self.guard] + self.guard.child_expressions + [Const(self.dst)]
|
|
558
|
+
|
|
559
|
+
@staticmethod
|
|
560
|
+
def _from_c(c_stmt):
|
|
561
|
+
return Exit(
|
|
562
|
+
IRExpr._from_c(c_stmt.Ist.Exit.guard),
|
|
563
|
+
IRConst._from_c(c_stmt.Ist.Exit.dst),
|
|
564
|
+
get_enum_from_int(c_stmt.Ist.Exit.jk),
|
|
565
|
+
c_stmt.Ist.Exit.offsIP,
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
def typecheck(self, tyenv):
|
|
569
|
+
if not self.jk.startswith("Ijk_"):
|
|
570
|
+
log.debug("Jumpkind is not a jumpkind enum")
|
|
571
|
+
return False
|
|
572
|
+
guardty = self.guard.typecheck(tyenv)
|
|
573
|
+
if guardty is None:
|
|
574
|
+
return False
|
|
575
|
+
if guardty != "Ity_I1":
|
|
576
|
+
log.debug("guard must be Ity_I1")
|
|
577
|
+
return False
|
|
578
|
+
return True
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
class LoadG(IRStmt):
|
|
582
|
+
"""
|
|
583
|
+
A guarded load.
|
|
584
|
+
"""
|
|
585
|
+
|
|
586
|
+
__slots__ = ["addr", "alt", "guard", "dst", "cvt", "end", "cvt_types"]
|
|
587
|
+
|
|
588
|
+
tag = "Ist_LoadG"
|
|
589
|
+
|
|
590
|
+
def __init__(self, end: str, cvt: str, dst: int, addr: IRExpr, alt: IRExpr, guard: IRExpr):
|
|
591
|
+
self.addr = addr
|
|
592
|
+
self.alt = alt
|
|
593
|
+
self.guard = guard
|
|
594
|
+
self.dst = dst
|
|
595
|
+
self.cvt = cvt
|
|
596
|
+
self.end = end
|
|
597
|
+
|
|
598
|
+
type_in = ffi.new("IRType *") # TODO separate this from the pyvex C implementation
|
|
599
|
+
type_out = ffi.new("IRType *")
|
|
600
|
+
pvc.typeOfIRLoadGOp(get_int_from_enum(self.cvt), type_out, type_in)
|
|
601
|
+
type_in = ffi.cast("int *", type_in)[0]
|
|
602
|
+
type_out = ffi.cast("int *", type_out)[0]
|
|
603
|
+
self.cvt_types = (get_enum_from_int(type_in), get_enum_from_int(type_out))
|
|
604
|
+
|
|
605
|
+
@property
|
|
606
|
+
def endness(self):
|
|
607
|
+
return self.end
|
|
608
|
+
|
|
609
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
610
|
+
return "t%d = if (%s) %s(LD%s(%s)) else %s" % (
|
|
611
|
+
self.dst,
|
|
612
|
+
self.guard,
|
|
613
|
+
self.cvt,
|
|
614
|
+
self.end[-2:].lower(),
|
|
615
|
+
self.addr,
|
|
616
|
+
self.alt,
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
@staticmethod
|
|
620
|
+
def _from_c(c_stmt):
|
|
621
|
+
return LoadG(
|
|
622
|
+
get_enum_from_int(c_stmt.Ist.LoadG.details.end),
|
|
623
|
+
get_enum_from_int(c_stmt.Ist.LoadG.details.cvt),
|
|
624
|
+
c_stmt.Ist.LoadG.details.dst,
|
|
625
|
+
IRExpr._from_c(c_stmt.Ist.LoadG.details.addr),
|
|
626
|
+
IRExpr._from_c(c_stmt.Ist.LoadG.details.alt),
|
|
627
|
+
IRExpr._from_c(c_stmt.Ist.LoadG.details.guard),
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
def typecheck(self, tyenv):
|
|
631
|
+
addrty = self.addr.typecheck(tyenv)
|
|
632
|
+
if addrty is None:
|
|
633
|
+
return False
|
|
634
|
+
if addrty != tyenv.wordty:
|
|
635
|
+
log.debug("addr must be full word for arch")
|
|
636
|
+
return False
|
|
637
|
+
if self.end not in ("Iend_LE", "Iend_BE"):
|
|
638
|
+
log.debug("invalid endness enum")
|
|
639
|
+
return False
|
|
640
|
+
|
|
641
|
+
dstty = tyenv.lookup(self.dst)
|
|
642
|
+
guardty = self.guard.typecheck(tyenv)
|
|
643
|
+
altty = self.alt.typecheck(tyenv)
|
|
644
|
+
|
|
645
|
+
if guardty is None or altty is None:
|
|
646
|
+
return False
|
|
647
|
+
if dstty != "Ity_I32" or altty != "Ity_I32":
|
|
648
|
+
log.debug("dst and alt must be Ity_I32")
|
|
649
|
+
return False
|
|
650
|
+
if guardty != "Ity_I1":
|
|
651
|
+
log.debug("guard must be Ity_I1")
|
|
652
|
+
return False
|
|
653
|
+
if not self.cvt.startswith("ILGop_"):
|
|
654
|
+
log.debug("Invalid cvt enum")
|
|
655
|
+
return False
|
|
656
|
+
return True
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
class StoreG(IRStmt):
|
|
660
|
+
"""
|
|
661
|
+
A guarded store.
|
|
662
|
+
"""
|
|
663
|
+
|
|
664
|
+
__slots__ = ["addr", "data", "guard", "end"]
|
|
665
|
+
|
|
666
|
+
tag = "Ist_StoreG"
|
|
667
|
+
|
|
668
|
+
def __init__(self, end, addr, data, guard):
|
|
669
|
+
self.addr = addr
|
|
670
|
+
self.data = data
|
|
671
|
+
self.guard = guard
|
|
672
|
+
self.end = end
|
|
673
|
+
|
|
674
|
+
@property
|
|
675
|
+
def endness(self):
|
|
676
|
+
return self.end
|
|
677
|
+
|
|
678
|
+
def pp_str(self, reg_name=None, arch=None, tyenv=None):
|
|
679
|
+
return f"if ({self.guard}) ST{self.end[-2:].lower()}({self.addr}) = {self.data}"
|
|
680
|
+
|
|
681
|
+
@staticmethod
|
|
682
|
+
def _from_c(c_stmt):
|
|
683
|
+
return StoreG(
|
|
684
|
+
get_enum_from_int(c_stmt.Ist.StoreG.details.end),
|
|
685
|
+
IRExpr._from_c(c_stmt.Ist.StoreG.details.addr),
|
|
686
|
+
IRExpr._from_c(c_stmt.Ist.StoreG.details.data),
|
|
687
|
+
IRExpr._from_c(c_stmt.Ist.StoreG.details.guard),
|
|
688
|
+
)
|
|
689
|
+
|
|
690
|
+
def typecheck(self, tyenv):
|
|
691
|
+
addrty = self.addr.typecheck(tyenv)
|
|
692
|
+
if addrty is None:
|
|
693
|
+
return False
|
|
694
|
+
if addrty != tyenv.wordty:
|
|
695
|
+
log.debug("addr must be full word for arch")
|
|
696
|
+
return False
|
|
697
|
+
if self.end not in ("Iend_LE", "Iend_BE"):
|
|
698
|
+
log.debug("invalid endness enum")
|
|
699
|
+
return False
|
|
700
|
+
|
|
701
|
+
guardty = self.guard.typecheck(tyenv)
|
|
702
|
+
dataty = self.data.typecheck(tyenv)
|
|
703
|
+
|
|
704
|
+
if guardty is None or dataty is None:
|
|
705
|
+
return False
|
|
706
|
+
if guardty != "Ity_I1":
|
|
707
|
+
log.debug("guard must be Ity_I1")
|
|
708
|
+
return False
|
|
709
|
+
return True
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
_globals = globals().copy()
|
|
713
|
+
#
|
|
714
|
+
# Mapping from tag strings/enums to IRStmt classes
|
|
715
|
+
#
|
|
716
|
+
tag_to_stmt_mapping = {}
|
|
717
|
+
enum_to_stmt_mapping = {}
|
|
718
|
+
tag_count = 0
|
|
719
|
+
cls = None
|
|
720
|
+
for cls in _globals.values():
|
|
721
|
+
if type(cls) is type and issubclass(cls, IRStmt) and cls is not IRStmt:
|
|
722
|
+
tag_to_stmt_mapping[cls.tag] = cls
|
|
723
|
+
enum_to_stmt_mapping[get_int_from_enum(cls.tag)] = cls
|
|
724
|
+
cls.tag_int = tag_count
|
|
725
|
+
tag_count += 1
|
|
726
|
+
del cls
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
def tag_to_stmt_class(tag):
|
|
730
|
+
try:
|
|
731
|
+
return tag_to_stmt_mapping[tag]
|
|
732
|
+
except KeyError:
|
|
733
|
+
raise KeyError("No statement class for tag %s." % tag)
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
def enum_to_stmt_class(tag_enum):
|
|
737
|
+
try:
|
|
738
|
+
return enum_to_stmt_mapping[tag_enum]
|
|
739
|
+
except KeyError:
|
|
740
|
+
raise KeyError("No statement class for tag %s." % get_enum_from_int(tag_enum))
|