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

287 statements  

1# pylint:disable=missing-class-docstring,raise-missing-from,not-callable 

2import re 

3from abc import ABC 

4 

5from .enums import VEXObject, get_enum_from_int 

6from .errors import PyVEXError 

7from .native import ffi, pvc 

8 

9 

10# IRConst hierarchy 

11class IRConst(VEXObject, ABC): 

12 __slots__ = ["_value"] 

13 

14 type: str 

15 size: int 

16 tag: str 

17 c_constructor = None 

18 _value: int 

19 

20 def pp(self): 

21 print(str(self)) 

22 

23 @property 

24 def value(self) -> int: 

25 return self._value 

26 

27 @staticmethod 

28 def _from_c(c_const): 

29 if c_const[0] == ffi.NULL: 

30 return None 

31 

32 tag = get_enum_from_int(c_const.tag) 

33 

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) 

38 

39 _translate = _from_c 

40 

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) 

46 

47 try: 

48 return cls.c_constructor(const.value) 

49 except KeyError: 

50 raise PyVEXError("Unknown/unsupported IRConstTag %s]n" % const.tag) 

51 

52 def __eq__(self, other): 

53 if not isinstance(other, type(self)): 

54 return False 

55 return self._value == other._value 

56 

57 def __hash__(self): 

58 return hash((type(self), self._value)) 

59 

60 

61class U1(IRConst): 

62 __slots__: list[str] = [] 

63 

64 type = "Ity_I1" 

65 size = 1 

66 tag = "Ico_U1" 

67 op_format = "1" 

68 c_constructor = pvc.IRConst_U1 

69 

70 def __init__(self, value): 

71 self._value = value 

72 

73 def __str__(self): 

74 return "%d" % self.value 

75 

76 @staticmethod 

77 def _from_c(c_const): 

78 return U1(c_const.Ico.U1) 

79 

80 

81class U8(IRConst): 

82 __slots__: list[str] = [] 

83 

84 type = "Ity_I8" 

85 size = 8 

86 tag = "Ico_U8" 

87 op_format = "8" 

88 c_constructor = pvc.IRConst_U8 

89 

90 def __init__(self, value): 

91 self._value = value 

92 

93 def __str__(self): 

94 return "0x%02x" % self.value 

95 

96 @staticmethod 

97 def _from_c(c_const): 

98 return _U8_POOL[c_const.Ico.U8] 

99 

100 

101_U8_POOL = [U8(i) for i in range(256)] 

102 

103 

104class U16(IRConst): 

105 __slots__: list[str] = [] 

106 

107 type = "Ity_I16" 

108 size = 16 

109 tag = "Ico_U16" 

110 op_format = "16" 

111 c_constructor = pvc.IRConst_U16 

112 

113 def __init__(self, value): 

114 self._value = value 

115 

116 def __str__(self): 

117 return "0x%04x" % self.value 

118 

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) 

127 

128 

129_U16_POOL = [U16(i) for i in range(1024)] + [U16(i) for i in range(0xFC00, 0xFFFF + 1)] 

130 

131 

132class U32(IRConst): 

133 __slots__: list[str] = [] 

134 

135 type = "Ity_I32" 

136 size = 32 

137 tag = "Ico_U32" 

138 op_format = "32" 

139 c_constructor = pvc.IRConst_U32 

140 

141 def __init__(self, value: int): 

142 self._value = value 

143 

144 def __str__(self): 

145 return "0x%08x" % self.value 

146 

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) 

155 

156 

157_U32_POOL = [U32(i) for i in range(1024)] + [U32(i) for i in range(0xFFFFFC00, 0xFFFFFFFF + 1)] 

158 

159 

160class U64(IRConst): 

161 __slots__: list[str] = [] 

162 

163 type = "Ity_I64" 

164 size = 64 

165 tag = "Ico_U64" 

166 op_format = "64" 

167 c_constructor = pvc.IRConst_U64 

168 

169 def __init__(self, value): 

170 self._value = value 

171 

172 def __str__(self): 

173 return "0x%016x" % self.value 

174 

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) 

183 

184 

185_U64_POOL = [U64(i) for i in range(1024)] + [U64(i) for i in range(0xFFFFFFFFFFFFFC00, 0xFFFFFFFFFFFFFFFF + 1)] 

186 

187# Integer Type Imagination 

188class_cache = {1: U1, 8: U8, 16: U16, 32: U32, 64: U64} 

189 

190 

191def vex_int_class(size): 

192 try: 

193 return class_cache[size] 

194 except KeyError: 

195 

196 class VexInt(IRConst): 

197 type = "Ity_I%d" % size 

198 tag = "Ico_U%d" % size 

199 op_format = str(size) 

200 

201 def __init__(self, value): 

202 IRConst.__init__(self) 

203 self._value = value 

204 

205 def __str__(self): 

206 return f"(0x{self.value:x} :: {self.type})" 

207 

208 VexInt.__name__ = "U%d" % size 

209 class_cache[size] = VexInt 

210 return VexInt 

211 

212 

213class F32(IRConst): 

214 __slots__: list[str] = [] 

215 

216 type = "Ity_F32" 

217 tag = "Ico_F32" 

218 op_format = "F32" 

219 c_constructor = pvc.IRConst_F32 

220 size = 32 

221 

222 def __init__(self, value): 

223 self._value = value 

224 

225 def __str__(self): 

226 return "%f" % self.value 

227 

228 @staticmethod 

229 def _from_c(c_const): 

230 return F32(c_const.Ico.F32) 

231 

232 

233class F32i(IRConst): 

234 __slots__: list[str] = [] 

235 

236 type = "Ity_F32" 

237 tag = "Ico_F32i" 

238 op_format = "F32" 

239 c_constructor = pvc.IRConst_F32i 

240 size = 32 

241 

242 def __init__(self, value): 

243 self._value = value 

244 

245 def __str__(self): 

246 return "%f" % self.value 

247 

248 @staticmethod 

249 def _from_c(c_const): 

250 return F32i(c_const.Ico.F32) 

251 

252 

253class F64(IRConst): 

254 __slots__: list[str] = [] 

255 

256 type = "Ity_F64" 

257 tag = "Ico_F64" 

258 op_format = "F64" 

259 c_constructor = pvc.IRConst_F64 

260 size = 64 

261 

262 def __init__(self, value): 

263 self._value = value 

264 

265 def __str__(self): 

266 return "%f" % self.value 

267 

268 @staticmethod 

269 def _from_c(c_const): 

270 return F64(c_const.Ico.F64) 

271 

272 

273class F64i(IRConst): 

274 __slots__: list[str] = [] 

275 

276 type = "Ity_F64" 

277 tag = "Ico_F64i" 

278 op_format = "F64" 

279 c_constructor = pvc.IRConst_F64i 

280 size = 64 

281 

282 def __init__(self, value): 

283 self._value = value 

284 

285 def __str__(self): 

286 return "%f" % self.value 

287 

288 @staticmethod 

289 def _from_c(c_const): 

290 return F64i(c_const.Ico.F64) 

291 

292 

293class V128(IRConst): 

294 __slots__: list[str] = [] 

295 

296 type = "Ity_V128" 

297 tag = "Ico_V128" 

298 op_format = "V128" 

299 c_constructor = pvc.IRConst_V128 

300 size = 128 

301 

302 def __init__(self, value): 

303 self._value = value 

304 

305 def __str__(self): 

306 return "%x" % self.value 

307 

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) 

318 

319 

320class V256(IRConst): 

321 __slots__: list[str] = [] 

322 

323 type = "Ity_V256" 

324 tag = "Ico_V256" 

325 op_format = "V256" 

326 c_constructor = pvc.IRConst_V256 

327 size = 256 

328 

329 def __init__(self, value): 

330 self._value = value 

331 

332 def __str__(self): 

333 return "%x" % self.value 

334 

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) 

344 

345 

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} 

349 

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?") 

354 

355 

356def is_int_ty(ty): 

357 m = int_ty_re.match(ty) 

358 return m is not None 

359 

360 

361def is_int_tag(tag): 

362 m = int_tag_re.match(tag) 

363 return m is not None 

364 

365 

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

371 

372 

373type_str_re = re.compile(r"Ity_[IFDV](?P<size>\d+)") 

374type_tag_str_re = re.compile(r"[IFDV]?(?P<size>\d+)[SU]?") 

375 

376 

377def get_type_size(ty): 

378 """ 

379 Returns the size, in BITS, of a VEX type specifier 

380 e.g., Ity_I16 -> 16 

381 

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

389 

390 

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

405 

406 

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) 

416 

417 

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)