Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pyvex/const.py: 78%
279 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:15 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:15 +0000
1import re
2from typing import List, Optional
4from .enums import VEXObject, get_enum_from_int
5from .errors import PyVEXError
6from .native import ffi, pvc
9# IRConst hierarchy
10class IRConst(VEXObject):
11 __slots__ = ["_value"]
13 type: Optional[str] = None
14 size = None
15 tag: Optional[str] = None
16 c_constructor = None
18 def pp(self):
19 print(self.__str__())
21 @property
22 def value(self) -> int:
23 return self._value
25 @staticmethod
26 def _from_c(c_const):
27 if c_const[0] == ffi.NULL:
28 return None
30 tag = get_enum_from_int(c_const.tag)
32 try:
33 return tag_to_const_class(tag)._from_c(c_const)
34 except KeyError:
35 raise PyVEXError("Unknown/unsupported IRConstTag %s\n" % tag)
37 _translate = _from_c
39 @classmethod
40 def _to_c(cls, const):
41 # libvex throws an exception when constructing a U1 with a value other than 0 or 1
42 if const.tag == "Ico_U1" and const.value not in (0, 1):
43 raise PyVEXError("Invalid U1 value: %d" % const.value)
45 try:
46 return cls.c_constructor(const.value)
47 except KeyError:
48 raise PyVEXError("Unknown/unsupported IRConstTag %s]n" % const.tag)
50 def __eq__(self, other):
51 if not isinstance(other, type(self)):
52 return False
53 return self._value == other._value
55 def __hash__(self):
56 return hash((type(self), self._value))
59class U1(IRConst):
60 __slots__: List[str] = []
62 type = "Ity_I1"
63 size = 1
64 tag = "Ico_U1"
65 op_format = "1"
66 c_constructor = pvc.IRConst_U1
68 def __init__(self, value):
69 self._value = value
71 def __str__(self):
72 return "%d" % self.value
74 @staticmethod
75 def _from_c(c_const):
76 return U1(c_const.Ico.U1)
79class U8(IRConst):
80 __slots__: List[str] = []
82 type = "Ity_I8"
83 size = 8
84 tag = "Ico_U8"
85 op_format = "8"
86 c_constructor = pvc.IRConst_U8
88 def __init__(self, value):
89 self._value = value
91 def __str__(self):
92 return "0x%02x" % self.value
94 @staticmethod
95 def _from_c(c_const):
96 return _U8_POOL[c_const.Ico.U8]
99_U8_POOL = [U8(i) for i in range(256)]
102class U16(IRConst):
103 __slots__: List[str] = []
105 type = "Ity_I16"
106 size = 16
107 tag = "Ico_U16"
108 op_format = "16"
109 c_constructor = pvc.IRConst_U16
111 def __init__(self, value):
112 self._value = value
114 def __str__(self):
115 return "0x%04x" % self.value
117 @staticmethod
118 def _from_c(c_const):
119 val = c_const.Ico.U16
120 if val < 1024:
121 return _U16_POOL[val]
122 if val >= 0xFC00:
123 return _U16_POOL[val - 0xFC00 + 1024]
124 return U16(val)
127_U16_POOL = [U16(i) for i in range(1024)] + [U16(i) for i in range(0xFC00, 0xFFFF + 1)]
130class U32(IRConst):
131 __slots__: List[str] = []
133 type = "Ity_I32"
134 size = 32
135 tag = "Ico_U32"
136 op_format = "32"
137 c_constructor = pvc.IRConst_U32
139 def __init__(self, value: int):
140 self._value = value
142 def __str__(self):
143 return "0x%08x" % self.value
145 @staticmethod
146 def _from_c(c_const):
147 val = c_const.Ico.U32
148 if val < 1024:
149 return _U32_POOL[val]
150 if val >= 0xFFFFFC00:
151 return _U32_POOL[val - 0xFFFFFC00 + 1024]
152 return U32(val)
155_U32_POOL = [U32(i) for i in range(1024)] + [U32(i) for i in range(0xFFFFFC00, 0xFFFFFFFF + 1)]
158class U64(IRConst):
159 __slots__: List[str] = []
161 type = "Ity_I64"
162 size = 64
163 tag = "Ico_U64"
164 op_format = "64"
165 c_constructor = pvc.IRConst_U64
167 def __init__(self, value):
168 self._value = value
170 def __str__(self):
171 return "0x%016x" % self.value
173 @staticmethod
174 def _from_c(c_const):
175 val = c_const.Ico.U64
176 if val < 1024:
177 return _U64_POOL[val]
178 if val >= 0xFFFFFFFFFFFFFC00:
179 return _U64_POOL[val - 0xFFFFFFFFFFFFFC00 + 1024]
180 return U64(val)
183_U64_POOL = [U64(i) for i in range(1024)] + [U64(i) for i in range(0xFFFFFFFFFFFFFC00, 0xFFFFFFFFFFFFFFFF + 1)]
185# Integer Type Imagination
186class_cache = {1: U1, 8: U8, 16: U16, 32: U32, 64: U64}
189def vex_int_class(size):
190 try:
191 return class_cache[size]
192 except KeyError:
194 class VexInt(IRConst):
195 type = "Ity_I%d" % size
196 tag = "Ico_U%d" % size
197 op_format = str(size)
199 def __init__(self, value):
200 IRConst.__init__(self)
201 self._value = value
203 def __str__(self):
204 return f"(0x{self.value:x} :: {self.type})"
206 VexInt.__name__ = "U%d" % size
207 class_cache[size] = VexInt
208 return VexInt
211class F32(IRConst):
212 __slots__: List[str] = []
214 type = "Ity_F32"
215 tag = "Ico_F32"
216 op_format = "F32"
217 c_constructor = pvc.IRConst_F32
219 def __init__(self, value):
220 self._value = value
222 def __str__(self):
223 return "%f" % self.value
225 @staticmethod
226 def _from_c(c_const):
227 return F32(c_const.Ico.F32)
230class F32i(IRConst):
231 __slots__: List[str] = []
233 type = "Ity_F32"
234 tag = "Ico_F32i"
235 op_format = "F32"
236 c_constructor = pvc.IRConst_F32i
238 def __init__(self, value):
239 self._value = value
241 def __str__(self):
242 return "%f" % self.value
244 @staticmethod
245 def _from_c(c_const):
246 return F32i(c_const.Ico.F32)
249class F64(IRConst):
250 __slots__: List[str] = []
252 type = "Ity_F64"
253 tag = "Ico_F64"
254 op_format = "F64"
255 c_constructor = pvc.IRConst_F64
257 def __init__(self, value):
258 self._value = value
260 def __str__(self):
261 return "%f" % self.value
263 @staticmethod
264 def _from_c(c_const):
265 return F64(c_const.Ico.F64)
268class F64i(IRConst):
269 __slots__: List[str] = []
271 type = "Ity_F64"
272 tag = "Ico_F64i"
273 op_format = "F64"
274 c_constructor = pvc.IRConst_F64i
276 def __init__(self, value):
277 self._value = value
279 def __str__(self):
280 return "%f" % self.value
282 @staticmethod
283 def _from_c(c_const):
284 return F64i(c_const.Ico.F64)
287class V128(IRConst):
288 __slots__: List[str] = []
290 type = "Ity_V128"
291 tag = "Ico_V128"
292 op_format = "V128"
293 c_constructor = pvc.IRConst_V128
295 def __init__(self, value):
296 self._value = value
298 def __str__(self):
299 return "%x" % self.value
301 # vex doesn't store a full 128 bit constant, instead it stores 1 bit per 8 bits of data
302 # and duplicates each bit 8 times
303 @staticmethod
304 def _from_c(c_const):
305 base_const = c_const.Ico.V128
306 real_const = 0
307 for i in range(16):
308 if (base_const >> i) & 1 == 1:
309 real_const |= 0xFF << (8 * i)
310 return V128(real_const)
313class V256(IRConst):
314 __slots__: List[str] = []
316 type = "Ity_V256"
317 tag = "Ico_V256"
318 op_format = "V256"
319 c_constructor = pvc.IRConst_V256
321 def __init__(self, value):
322 self._value = value
324 def __str__(self):
325 return "%x" % self.value
327 # see above
328 @staticmethod
329 def _from_c(c_const):
330 base_const = c_const.Ico.V256
331 real_const = 0
332 for i in range(32):
333 if (base_const >> i) & 1 == 1:
334 real_const |= 0xFF << (8 * i)
335 return V256(real_const)
338predefined_types = [U1, U8, U16, U32, U64, F32, F32i, F64, F64i, V128, V256]
339predefined_types_map = {c.type: c for c in predefined_types}
340predefined_classes_map = {c.tag: c for c in predefined_types}
342# precompiled regexes
343int_ty_re = re.compile(r"Ity_I\d+")
344int_tag_re = re.compile(r"Ico_U\d+")
345tag_size_re = re.compile(r"Ico_[UFV](?P<size>\d+)i?")
348def is_int_ty(ty):
349 m = int_ty_re.match(ty)
350 return m is not None
353def is_int_tag(tag):
354 m = int_tag_re.match(tag)
355 return m is not None
358def get_tag_size(tag):
359 m = tag_size_re.match(tag)
360 if m is None:
361 raise ValueError("Tag %s does not have size" % tag)
362 return int(m.group("size"))
365type_str_re = re.compile(r"Ity_[IFDV](?P<size>\d+)")
366type_tag_str_re = re.compile(r"[IFDV]?(?P<size>\d+)[SU]?")
369def get_type_size(ty):
370 """
371 Returns the size, in BITS, of a VEX type specifier
372 e.g., Ity_I16 -> 16
374 :param ty:
375 :return:
376 """
377 m = type_str_re.match(ty)
378 if m is None:
379 raise ValueError("Type %s does not have size" % ty)
380 return int(m.group("size"))
383def get_type_spec_size(ty):
384 """
385 Get the width of a "type specifier"
386 like I16U
387 or F16
388 or just 16
389 (Yes, this really just takes the int out. If we must special-case, do it here.
390 :param tyspec:
391 :return:
392 """
393 m = type_tag_str_re.match(ty)
394 if m is None:
395 raise ValueError("Type specifier %s does not have size" % ty)
396 return int(m.group("size"))
399def ty_to_const_class(ty):
400 try:
401 return predefined_types_map[ty]
402 except KeyError:
403 if is_int_ty(ty):
404 size = get_type_size(ty)
405 return vex_int_class(size)
406 else:
407 raise ValueError("Type %s does not exist" % ty)
410def tag_to_const_class(tag):
411 try:
412 return predefined_classes_map[tag]
413 except KeyError:
414 if is_int_tag(tag):
415 size = get_tag_size(tag)
416 return vex_int_class(size)
417 else:
418 raise ValueError("Tag %s does not exist" % tag)