1import logging
2import threading
3from typing import TYPE_CHECKING
4
5from pyvex.errors import LiftingException
6from pyvex.native import ffi, pvc
7from pyvex.types import CLiftSource, LibvexArch
8
9from .lift_function import Lifter
10
11log = logging.getLogger("pyvex.lifting.libvex")
12
13_libvex_lock = threading.Lock()
14
15LIBVEX_SUPPORTED_ARCHES = {
16 "X86",
17 "AMD64",
18 "MIPS32",
19 "MIPS64",
20 "ARM",
21 "ARMEL",
22 "ARMHF",
23 "ARMCortexM",
24 "AARCH64",
25 "PPC32",
26 "PPC64",
27 "S390X",
28 "RISCV64",
29}
30
31VEX_MAX_INSTRUCTIONS = 99
32VEX_MAX_BYTES = 5000
33
34
35class VexRegisterUpdates:
36 VexRegUpd_INVALID = 0x700
37 VexRegUpdSpAtMemAccess = 0x701
38 VexRegUpdUnwindregsAtMemAccess = 0x702
39 VexRegUpdAllregsAtMemAccess = 0x703
40 VexRegUpdAllregsAtEachInsn = 0x704
41 VexRegUpdLdAllregsAtEachInsn = 0x705
42
43
44class LibVEXLifter(Lifter):
45 __slots__ = ()
46
47 REQUIRE_DATA_C = True
48
49 @staticmethod
50 def get_vex_log():
51 return bytes(ffi.buffer(pvc.msg_buffer, pvc.msg_current_size)).decode() if pvc.msg_buffer != ffi.NULL else None
52
53 def _lift(self):
54 if TYPE_CHECKING:
55 assert isinstance(self.irsb.arch, LibvexArch)
56 assert isinstance(self.data, CLiftSource)
57 try:
58 _libvex_lock.acquire()
59
60 pvc.log_level = log.getEffectiveLevel()
61 vex_arch = getattr(pvc, self.irsb.arch.vex_arch, None)
62 assert vex_arch is not None
63
64 if self.bytes_offset is None:
65 self.bytes_offset = 0
66
67 if self.max_bytes is None or self.max_bytes > VEX_MAX_BYTES:
68 max_bytes = VEX_MAX_BYTES
69 else:
70 max_bytes = self.max_bytes
71
72 if self.max_inst is None or self.max_inst > VEX_MAX_INSTRUCTIONS:
73 max_inst = VEX_MAX_INSTRUCTIONS
74 else:
75 max_inst = self.max_inst
76
77 strict_block_end = self.strict_block_end
78 if strict_block_end is None:
79 strict_block_end = True
80
81 collect_data_refs = 1 if self.collect_data_refs else 0
82 if collect_data_refs != 0 and self.load_from_ro_regions:
83 collect_data_refs |= 2 # the second bit stores load_from_ro_regions
84
85 if self.cross_insn_opt:
86 px_control = VexRegisterUpdates.VexRegUpdUnwindregsAtMemAccess
87 else:
88 px_control = VexRegisterUpdates.VexRegUpdLdAllregsAtEachInsn
89
90 self.irsb.arch.vex_archinfo["hwcache_info"]["caches"] = ffi.NULL
91 lift_r = pvc.vex_lift(
92 vex_arch,
93 self.irsb.arch.vex_archinfo,
94 self.data + self.bytes_offset,
95 self.irsb.addr,
96 max_inst,
97 max_bytes,
98 self.opt_level,
99 self.traceflags,
100 self.allow_arch_optimizations,
101 strict_block_end,
102 collect_data_refs,
103 px_control,
104 self.bytes_offset,
105 )
106 log_str = self.get_vex_log()
107 if lift_r == ffi.NULL:
108 raise LiftingException("libvex: unknown error" if log_str is None else log_str)
109 else:
110 if log_str is not None:
111 log.debug(log_str)
112
113 self.irsb._from_c(lift_r, skip_stmts=self.skip_stmts)
114 if self.irsb.size == 0:
115 log.debug("raising lifting exception")
116 raise LiftingException("libvex: could not decode any instructions @ 0x%x" % self.addr)
117 finally:
118 _libvex_lock.release()
119 self.irsb.arch.vex_archinfo["hwcache_info"]["caches"] = None