Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/pyvex/const.py: 80%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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: str
14 size: Optional[int] = None
15 tag: str
16 c_constructor = None
17 _value: int
19 def pp(self):
20 print(self.__str__())
22 @property
23 def value(self) -> int:
24 return self._value
26 @staticmethod
27 def _from_c(c_const):
28 if c_const[0] == ffi.NULL:
29 return None
31 tag = get_enum_from_int(c_const.tag)
33 try:
34 return tag_to_const_class(tag)._from_c(c_const)
35 except KeyError:
36 raise PyVEXError("Unknown/unsupported IRConstTag %s\n" % tag)
38 _translate = _from_c
40 @classmethod
41 def _to_c(cls, const):
42 # libvex throws an exception when constructing a U1 with a value other than 0 or 1
43 if const.tag == "Ico_U1" and const.value not in (0, 1):
44 raise PyVEXError("Invalid U1 value: %d" % const.value)
46 try:
47 return cls.c_constructor(const.value)
48 except KeyError:
49 raise PyVEXError("Unknown/unsupported IRConstTag %s]n" % const.tag)
51 def __eq__(self, other):
52 if not isinstance(other, type(self)):
53 return False
54 return self._value == other._value
56 def __hash__(self):
57 return hash((type(self), self._value))
60class U1(IRConst):
61 __slots__: List[str] = []
63 type = "Ity_I1"
64 size = 1
65 tag = "Ico_U1"
66 op_format = "1"
67 c_constructor = pvc.IRConst_U1
69 def __init__(self, value):
70 self._value = value
72 def __str__(self):
73 return "%d" % self.value
75 @staticmethod
76 def _from_c(c_const):
77 return U1(c_const.Ico.U1)
80class U8(IRConst):
81 __slots__: List[str] = []
83 type = "Ity_I8"
84 size = 8
85 tag = "Ico_U8"
86 op_format = "8"
87 c_constructor = pvc.IRConst_U8
89 def __init__(self, value):
90 self._value = value
92 def __str__(self):
93 return "0x%02x" % self.value
95 @staticmethod
96 def _from_c(c_const):
97 return _U8_POOL[c_const.Ico.U8]
100_U8_POOL = [U8(i) for i in range(256)]
103class U16(IRConst):
104 __slots__: List[str] = []
106 type = "Ity_I16"
107 size = 16
108 tag = "Ico_U16"
109 op_format = "16"
110 c_constructor = pvc.IRConst_U16
112 def __init__(self, value):
113 self._value = value
115 def __str__(self):
116 return "0x%04x" % self.value
118 @staticmethod
119 def _from_c(c_const):
120 val = c_const.Ico.U16
121 if val < 1024:
122 return _U16_POOL[val]
123 if val >= 0xFC00:
124 return _U16_POOL[val - 0xFC00 + 1024]
125 return U16(val)
128_U16_POOL = [U16(i) for i in range(1024)] + [U16(i) for i in range(0xFC00, 0xFFFF + 1)]
131class U32(IRConst):
132 __slots__: List[str] = []
134 type = "Ity_I32"
135 size = 32
136 tag = "Ico_U32"
137 op_format = "32"
138 c_constructor = pvc.IRConst_U32
140 def __init__(self, value: int):
141 self._value = value
143 def __str__(self):
144 return "0x%08x" % self.value
146 @staticmethod
147 def _from_c(c_const):
148 val = c_const.Ico.U32
149 if val < 1024:
150 return _U32_POOL[val]
151 if val >= 0xFFFFFC00:
152 return _U32_POOL[val - 0xFFFFFC00 + 1024]
153 return U32(val)
156_U32_POOL = [U32(i) for i in range(1024)] + [U32(i) for i in range(0xFFFFFC00, 0xFFFFFFFF + 1)]
159class U64(IRConst):
160 __slots__: List[str] = []
162 type = "Ity_I64"
163 size = 64
164 tag = "Ico_U64"
165 op_format = "64"
166 c_constructor = pvc.IRConst_U64
168 def __init__(self, value):
169 self._value = value
171 def __str__(self):
172 return "0x%016x" % self.value
174 @staticmethod
175 def _from_c(c_const):
176 val = c_const.Ico.U64
177 if val < 1024:
178 return _U64_POOL[val]
179 if val >= 0xFFFFFFFFFFFFFC00:
180 return _U64_POOL[val - 0xFFFFFFFFFFFFFC00 + 1024]
181 return U64(val)
184_U64_POOL = [U64(i) for i in range(1024)] + [U64(i) for i in range(0xFFFFFFFFFFFFFC00, 0xFFFFFFFFFFFFFFFF + 1)]
186# Integer Type Imagination
187class_cache = {1: U1, 8: U8, 16: U16, 32: U32, 64: U64}
190def vex_int_class(size):
191 try:
192 return class_cache[size]
193 except KeyError:
195 class VexInt(IRConst):
196 type = "Ity_I%d" % size
197 tag = "Ico_U%d" % size
198 op_format = str(size)
200 def __init__(self, value):
201 IRConst.__init__(self)
202 self._value = value
204 def __str__(self):
205 return f"(0x{self.value:x} :: {self.type})"
207 VexInt.__name__ = "U%d" % size
208 class_cache[size] = VexInt
209 return VexInt
212class F32(IRConst):
213 __slots__: List[str] = []
215 type = "Ity_F32"
216 tag = "Ico_F32"
217 op_format = "F32"
218 c_constructor = pvc.IRConst_F32
220 def __init__(self, value):
221 self._value = value
223 def __str__(self):
224 return "%f" % self.value
226 @staticmethod
227 def _from_c(c_const):
228 return F32(c_const.Ico.F32)
231class F32i(IRConst):
232 __slots__: List[str] = []
234 type = "Ity_F32"
235 tag = "Ico_F32i"
236 op_format = "F32"
237 c_constructor = pvc.IRConst_F32i
239 def __init__(self, value):
240 self._value = value
242 def __str__(self):
243 return "%f" % self.value
245 @staticmethod
246 def _from_c(c_const):
247 return F32i(c_const.Ico.F32)
250class F64(IRConst):
251 __slots__: List[str] = []
253 type = "Ity_F64"
254 tag = "Ico_F64"
255 op_format = "F64"
256 c_constructor = pvc.IRConst_F64
258 def __init__(self, value):
259 self._value = value
261 def __str__(self):
262 return "%f" % self.value
264 @staticmethod
265 def _from_c(c_const):
266 return F64(c_const.Ico.F64)
269class F64i(IRConst):
270 __slots__: List[str] = []
272 type = "Ity_F64"
273 tag = "Ico_F64i"
274 op_format = "F64"
275 c_constructor = pvc.IRConst_F64i
277 def __init__(self, value):
278 self._value = value
280 def __str__(self):
281 return "%f" % self.value
283 @staticmethod
284 def _from_c(c_const):
285 return F64i(c_const.Ico.F64)
288class V128(IRConst):
289 __slots__: List[str] = []
291 type = "Ity_V128"
292 tag = "Ico_V128"
293 op_format = "V128"
294 c_constructor = pvc.IRConst_V128
296 def __init__(self, value):
297 self._value = value
299 def __str__(self):
300 return "%x" % self.value
302 # vex doesn't store a full 128 bit constant, instead it stores 1 bit per 8 bits of data
303 # and duplicates each bit 8 times
304 @staticmethod
305 def _from_c(c_const):
306 base_const = c_const.Ico.V128
307 real_const = 0
308 for i in range(16):
309 if (base_const >> i) & 1 == 1:
310 real_const |= 0xFF << (8 * i)
311 return V128(real_const)
314class V256(IRConst):
315 __slots__: List[str] = []
317 type = "Ity_V256"
318 tag = "Ico_V256"
319 op_format = "V256"
320 c_constructor = pvc.IRConst_V256
322 def __init__(self, value):
323 self._value = value
325 def __str__(self):
326 return "%x" % self.value
328 # see above
329 @staticmethod
330 def _from_c(c_const):
331 base_const = c_const.Ico.V256
332 real_const = 0
333 for i in range(32):
334 if (base_const >> i) & 1 == 1:
335 real_const |= 0xFF << (8 * i)
336 return V256(real_const)
339predefined_types = [U1, U8, U16, U32, U64, F32, F32i, F64, F64i, V128, V256]
340predefined_types_map = {c.type: c for c in predefined_types}
341predefined_classes_map = {c.tag: c for c in predefined_types}
343# precompiled regexes
344int_ty_re = re.compile(r"Ity_I\d+")
345int_tag_re = re.compile(r"Ico_U\d+")
346tag_size_re = re.compile(r"Ico_[UFV](?P<size>\d+)i?")
349def is_int_ty(ty):
350 m = int_ty_re.match(ty)
351 return m is not None
354def is_int_tag(tag):
355 m = int_tag_re.match(tag)
356 return m is not None
359def get_tag_size(tag):
360 m = tag_size_re.match(tag)
361 if m is None:
362 raise ValueError("Tag %s does not have size" % tag)
363 return int(m.group("size"))
366type_str_re = re.compile(r"Ity_[IFDV](?P<size>\d+)")
367type_tag_str_re = re.compile(r"[IFDV]?(?P<size>\d+)[SU]?")
370def get_type_size(ty):
371 """
372 Returns the size, in BITS, of a VEX type specifier
373 e.g., Ity_I16 -> 16
375 :param ty:
376 :return:
377 """
378 m = type_str_re.match(ty)
379 if m is None:
380 raise ValueError("Type %s does not have size" % ty)
381 return int(m.group("size"))
384def get_type_spec_size(ty):
385 """
386 Get the width of a "type specifier"
387 like I16U
388 or F16
389 or just 16
390 (Yes, this really just takes the int out. If we must special-case, do it here.
391 :param tyspec:
392 :return:
393 """
394 m = type_tag_str_re.match(ty)
395 if m is None:
396 raise ValueError("Type specifier %s does not have size" % ty)
397 return int(m.group("size"))
400def ty_to_const_class(ty):
401 try:
402 return predefined_types_map[ty]
403 except KeyError:
404 if is_int_ty(ty):
405 size = get_type_size(ty)
406 return vex_int_class(size)
407 else:
408 raise ValueError("Type %s does not exist" % ty)
411def tag_to_const_class(tag):
412 try:
413 return predefined_classes_map[tag]
414 except KeyError:
415 if is_int_tag(tag):
416 size = get_tag_size(tag)
417 return vex_int_class(size)
418 else:
419 raise ValueError("Tag %s does not exist" % tag)