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/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))