Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pyvex/const.py: 81%
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
1# pylint:disable=missing-class-docstring,raise-missing-from,not-callable
2import re
3from abc import ABC
5from .enums import VEXObject, get_enum_from_int
6from .errors import PyVEXError
7from .native import ffi, pvc
10# IRConst hierarchy
11class IRConst(VEXObject, ABC):
12 __slots__ = ["_value"]
14 type: str
15 size: int
16 tag: str
17 c_constructor = None
18 _value: int
20 def pp(self):
21 print(str(self))
23 @property
24 def value(self) -> int:
25 return self._value
27 @staticmethod
28 def _from_c(c_const):
29 if c_const[0] == ffi.NULL:
30 return None
32 tag = get_enum_from_int(c_const.tag)
34 try:
35 return tag_to_const_class(tag)._from_c(c_const)
36 except KeyError:
37 raise PyVEXError("Unknown/unsupported IRConstTag %s\n" % tag)
39 _translate = _from_c
41 @classmethod
42 def _to_c(cls, const):
43 # libvex throws an exception when constructing a U1 with a value other than 0 or 1
44 if const.tag == "Ico_U1" and const.value not in (0, 1):
45 raise PyVEXError("Invalid U1 value: %d" % const.value)
47 try:
48 return cls.c_constructor(const.value)
49 except KeyError:
50 raise PyVEXError("Unknown/unsupported IRConstTag %s]n" % const.tag)
52 def __eq__(self, other):
53 if not isinstance(other, type(self)):
54 return False
55 return self._value == other._value
57 def __hash__(self):
58 return hash((type(self), self._value))
61class U1(IRConst):
62 __slots__: list[str] = []
64 type = "Ity_I1"
65 size = 1
66 tag = "Ico_U1"
67 op_format = "1"
68 c_constructor = pvc.IRConst_U1
70 def __init__(self, value):
71 self._value = value
73 def __str__(self):
74 return "%d" % self.value
76 @staticmethod
77 def _from_c(c_const):
78 return U1(c_const.Ico.U1)
81class U8(IRConst):
82 __slots__: list[str] = []
84 type = "Ity_I8"
85 size = 8
86 tag = "Ico_U8"
87 op_format = "8"
88 c_constructor = pvc.IRConst_U8
90 def __init__(self, value):
91 self._value = value
93 def __str__(self):
94 return "0x%02x" % self.value
96 @staticmethod
97 def _from_c(c_const):
98 return _U8_POOL[c_const.Ico.U8]
101_U8_POOL = [U8(i) for i in range(256)]
104class U16(IRConst):
105 __slots__: list[str] = []
107 type = "Ity_I16"
108 size = 16
109 tag = "Ico_U16"
110 op_format = "16"
111 c_constructor = pvc.IRConst_U16
113 def __init__(self, value):
114 self._value = value
116 def __str__(self):
117 return "0x%04x" % self.value
119 @staticmethod
120 def _from_c(c_const):
121 val = c_const.Ico.U16
122 if val < 1024:
123 return _U16_POOL[val]
124 if val >= 0xFC00:
125 return _U16_POOL[val - 0xFC00 + 1024]
126 return U16(val)
129_U16_POOL = [U16(i) for i in range(1024)] + [U16(i) for i in range(0xFC00, 0xFFFF + 1)]
132class U32(IRConst):
133 __slots__: list[str] = []
135 type = "Ity_I32"
136 size = 32
137 tag = "Ico_U32"
138 op_format = "32"
139 c_constructor = pvc.IRConst_U32
141 def __init__(self, value: int):
142 self._value = value
144 def __str__(self):
145 return "0x%08x" % self.value
147 @staticmethod
148 def _from_c(c_const):
149 val = c_const.Ico.U32
150 if val < 1024:
151 return _U32_POOL[val]
152 if val >= 0xFFFFFC00:
153 return _U32_POOL[val - 0xFFFFFC00 + 1024]
154 return U32(val)
157_U32_POOL = [U32(i) for i in range(1024)] + [U32(i) for i in range(0xFFFFFC00, 0xFFFFFFFF + 1)]
160class U64(IRConst):
161 __slots__: list[str] = []
163 type = "Ity_I64"
164 size = 64
165 tag = "Ico_U64"
166 op_format = "64"
167 c_constructor = pvc.IRConst_U64
169 def __init__(self, value):
170 self._value = value
172 def __str__(self):
173 return "0x%016x" % self.value
175 @staticmethod
176 def _from_c(c_const):
177 val = c_const.Ico.U64
178 if val < 1024:
179 return _U64_POOL[val]
180 if val >= 0xFFFFFFFFFFFFFC00:
181 return _U64_POOL[val - 0xFFFFFFFFFFFFFC00 + 1024]
182 return U64(val)
185_U64_POOL = [U64(i) for i in range(1024)] + [U64(i) for i in range(0xFFFFFFFFFFFFFC00, 0xFFFFFFFFFFFFFFFF + 1)]
187# Integer Type Imagination
188class_cache = {1: U1, 8: U8, 16: U16, 32: U32, 64: U64}
191def vex_int_class(size):
192 try:
193 return class_cache[size]
194 except KeyError:
196 class VexInt(IRConst):
197 type = "Ity_I%d" % size
198 tag = "Ico_U%d" % size
199 op_format = str(size)
201 def __init__(self, value):
202 IRConst.__init__(self)
203 self._value = value
205 def __str__(self):
206 return f"(0x{self.value:x} :: {self.type})"
208 VexInt.__name__ = "U%d" % size
209 class_cache[size] = VexInt
210 return VexInt
213class F32(IRConst):
214 __slots__: list[str] = []
216 type = "Ity_F32"
217 tag = "Ico_F32"
218 op_format = "F32"
219 c_constructor = pvc.IRConst_F32
220 size = 32
222 def __init__(self, value):
223 self._value = value
225 def __str__(self):
226 return "%f" % self.value
228 @staticmethod
229 def _from_c(c_const):
230 return F32(c_const.Ico.F32)
233class F32i(IRConst):
234 __slots__: list[str] = []
236 type = "Ity_F32"
237 tag = "Ico_F32i"
238 op_format = "F32"
239 c_constructor = pvc.IRConst_F32i
240 size = 32
242 def __init__(self, value):
243 self._value = value
245 def __str__(self):
246 return "%f" % self.value
248 @staticmethod
249 def _from_c(c_const):
250 return F32i(c_const.Ico.F32)
253class F64(IRConst):
254 __slots__: list[str] = []
256 type = "Ity_F64"
257 tag = "Ico_F64"
258 op_format = "F64"
259 c_constructor = pvc.IRConst_F64
260 size = 64
262 def __init__(self, value):
263 self._value = value
265 def __str__(self):
266 return "%f" % self.value
268 @staticmethod
269 def _from_c(c_const):
270 return F64(c_const.Ico.F64)
273class F64i(IRConst):
274 __slots__: list[str] = []
276 type = "Ity_F64"
277 tag = "Ico_F64i"
278 op_format = "F64"
279 c_constructor = pvc.IRConst_F64i
280 size = 64
282 def __init__(self, value):
283 self._value = value
285 def __str__(self):
286 return "%f" % self.value
288 @staticmethod
289 def _from_c(c_const):
290 return F64i(c_const.Ico.F64)
293class V128(IRConst):
294 __slots__: list[str] = []
296 type = "Ity_V128"
297 tag = "Ico_V128"
298 op_format = "V128"
299 c_constructor = pvc.IRConst_V128
300 size = 128
302 def __init__(self, value):
303 self._value = value
305 def __str__(self):
306 return "%x" % self.value
308 # vex doesn't store a full 128 bit constant, instead it stores 1 bit per 8 bits of data
309 # and duplicates each bit 8 times
310 @staticmethod
311 def _from_c(c_const):
312 base_const = c_const.Ico.V128
313 real_const = 0
314 for i in range(16):
315 if (base_const >> i) & 1 == 1:
316 real_const |= 0xFF << (8 * i)
317 return V128(real_const)
320class V256(IRConst):
321 __slots__: list[str] = []
323 type = "Ity_V256"
324 tag = "Ico_V256"
325 op_format = "V256"
326 c_constructor = pvc.IRConst_V256
327 size = 256
329 def __init__(self, value):
330 self._value = value
332 def __str__(self):
333 return "%x" % self.value
335 # see above
336 @staticmethod
337 def _from_c(c_const):
338 base_const = c_const.Ico.V256
339 real_const = 0
340 for i in range(32):
341 if (base_const >> i) & 1 == 1:
342 real_const |= 0xFF << (8 * i)
343 return V256(real_const)
346predefined_types = [U1, U8, U16, U32, U64, F32, F32i, F64, F64i, V128, V256]
347predefined_types_map = {c.type: c for c in predefined_types}
348predefined_classes_map = {c.tag: c for c in predefined_types}
350# precompiled regexes
351int_ty_re = re.compile(r"Ity_I\d+")
352int_tag_re = re.compile(r"Ico_U\d+")
353tag_size_re = re.compile(r"Ico_[UFV](?P<size>\d+)i?")
356def is_int_ty(ty):
357 m = int_ty_re.match(ty)
358 return m is not None
361def is_int_tag(tag):
362 m = int_tag_re.match(tag)
363 return m is not None
366def get_tag_size(tag):
367 m = tag_size_re.match(tag)
368 if m is None:
369 raise ValueError("Tag %s does not have size" % tag)
370 return int(m.group("size"))
373type_str_re = re.compile(r"Ity_[IFDV](?P<size>\d+)")
374type_tag_str_re = re.compile(r"[IFDV]?(?P<size>\d+)[SU]?")
377def get_type_size(ty):
378 """
379 Returns the size, in BITS, of a VEX type specifier
380 e.g., Ity_I16 -> 16
382 :param ty:
383 :return:
384 """
385 m = type_str_re.match(ty)
386 if m is None:
387 raise ValueError("Type %s does not have size" % ty)
388 return int(m.group("size"))
391def get_type_spec_size(ty):
392 """
393 Get the width of a "type specifier"
394 like I16U
395 or F16
396 or just 16
397 (Yes, this really just takes the int out. If we must special-case, do it here.
398 :param tyspec:
399 :return:
400 """
401 m = type_tag_str_re.match(ty)
402 if m is None:
403 raise ValueError("Type specifier %s does not have size" % ty)
404 return int(m.group("size"))
407def ty_to_const_class(ty):
408 try:
409 return predefined_types_map[ty]
410 except KeyError:
411 if is_int_ty(ty):
412 size = get_type_size(ty)
413 return vex_int_class(size)
414 else:
415 raise ValueError("Type %s does not exist" % ty)
418def tag_to_const_class(tag):
419 try:
420 return predefined_classes_map[tag]
421 except KeyError:
422 if is_int_tag(tag):
423 size = get_tag_size(tag)
424 return vex_int_class(size)
425 else:
426 raise ValueError("Tag %s does not exist" % tag)