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.
Files changed (59) hide show
  1. pyvex/__init__.py +92 -0
  2. pyvex/_register_info.py +1800 -0
  3. pyvex/arches.py +94 -0
  4. pyvex/block.py +697 -0
  5. pyvex/const.py +426 -0
  6. pyvex/const_val.py +26 -0
  7. pyvex/data_ref.py +55 -0
  8. pyvex/enums.py +156 -0
  9. pyvex/errors.py +31 -0
  10. pyvex/expr.py +974 -0
  11. pyvex/include/libvex.h +1029 -0
  12. pyvex/include/libvex_basictypes.h +236 -0
  13. pyvex/include/libvex_emnote.h +142 -0
  14. pyvex/include/libvex_guest_amd64.h +252 -0
  15. pyvex/include/libvex_guest_arm.h +224 -0
  16. pyvex/include/libvex_guest_arm64.h +203 -0
  17. pyvex/include/libvex_guest_mips32.h +175 -0
  18. pyvex/include/libvex_guest_mips64.h +173 -0
  19. pyvex/include/libvex_guest_offsets.h +941 -0
  20. pyvex/include/libvex_guest_ppc32.h +298 -0
  21. pyvex/include/libvex_guest_ppc64.h +343 -0
  22. pyvex/include/libvex_guest_riscv64.h +148 -0
  23. pyvex/include/libvex_guest_s390x.h +201 -0
  24. pyvex/include/libvex_guest_tilegx.h +149 -0
  25. pyvex/include/libvex_guest_x86.h +322 -0
  26. pyvex/include/libvex_ir.h +3113 -0
  27. pyvex/include/libvex_s390x_common.h +123 -0
  28. pyvex/include/libvex_trc_values.h +99 -0
  29. pyvex/include/pyvex.h +96 -0
  30. pyvex/lib/libpyvex.dylib +0 -0
  31. pyvex/lifting/__init__.py +18 -0
  32. pyvex/lifting/gym/README.md +7 -0
  33. pyvex/lifting/gym/__init__.py +5 -0
  34. pyvex/lifting/gym/aarch64_spotter.py +40 -0
  35. pyvex/lifting/gym/arm_spotter.py +427 -0
  36. pyvex/lifting/gym/x86_spotter.py +129 -0
  37. pyvex/lifting/libvex.py +117 -0
  38. pyvex/lifting/lift_function.py +304 -0
  39. pyvex/lifting/lifter.py +124 -0
  40. pyvex/lifting/post_processor.py +16 -0
  41. pyvex/lifting/util/__init__.py +14 -0
  42. pyvex/lifting/util/instr_helper.py +422 -0
  43. pyvex/lifting/util/lifter_helper.py +154 -0
  44. pyvex/lifting/util/syntax_wrapper.py +312 -0
  45. pyvex/lifting/util/vex_helper.py +301 -0
  46. pyvex/lifting/zerodivision.py +71 -0
  47. pyvex/native.py +63 -0
  48. pyvex/py.typed +1 -0
  49. pyvex/stmt.py +740 -0
  50. pyvex/types.py +48 -0
  51. pyvex/utils.py +63 -0
  52. pyvex/vex_ffi.py +1453 -0
  53. pyvex-9.2.193.dist-info/METADATA +181 -0
  54. pyvex-9.2.193.dist-info/RECORD +59 -0
  55. pyvex-9.2.193.dist-info/WHEEL +6 -0
  56. pyvex-9.2.193.dist-info/licenses/LICENSE +24 -0
  57. pyvex-9.2.193.dist-info/licenses/pyvex_c/LICENSE +339 -0
  58. pyvex-9.2.193.dist-info/licenses/vex/LICENSE.GPL +340 -0
  59. 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))