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

280 statements  

1import re 

2from typing import List, Optional 

3 

4from .enums import VEXObject, get_enum_from_int 

5from .errors import PyVEXError 

6from .native import ffi, pvc 

7 

8 

9# IRConst hierarchy 

10class IRConst(VEXObject): 

11 __slots__ = ["_value"] 

12 

13 type: str 

14 size: Optional[int] = None 

15 tag: str 

16 c_constructor = None 

17 _value: int 

18 

19 def pp(self): 

20 print(self.__str__()) 

21 

22 @property 

23 def value(self) -> int: 

24 return self._value 

25 

26 @staticmethod 

27 def _from_c(c_const): 

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

29 return None 

30 

31 tag = get_enum_from_int(c_const.tag) 

32 

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) 

37 

38 _translate = _from_c 

39 

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) 

45 

46 try: 

47 return cls.c_constructor(const.value) 

48 except KeyError: 

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

50 

51 def __eq__(self, other): 

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

53 return False 

54 return self._value == other._value 

55 

56 def __hash__(self): 

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

58 

59 

60class U1(IRConst): 

61 __slots__: List[str] = [] 

62 

63 type = "Ity_I1" 

64 size = 1 

65 tag = "Ico_U1" 

66 op_format = "1" 

67 c_constructor = pvc.IRConst_U1 

68 

69 def __init__(self, value): 

70 self._value = value 

71 

72 def __str__(self): 

73 return "%d" % self.value 

74 

75 @staticmethod 

76 def _from_c(c_const): 

77 return U1(c_const.Ico.U1) 

78 

79 

80class U8(IRConst): 

81 __slots__: List[str] = [] 

82 

83 type = "Ity_I8" 

84 size = 8 

85 tag = "Ico_U8" 

86 op_format = "8" 

87 c_constructor = pvc.IRConst_U8 

88 

89 def __init__(self, value): 

90 self._value = value 

91 

92 def __str__(self): 

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

94 

95 @staticmethod 

96 def _from_c(c_const): 

97 return _U8_POOL[c_const.Ico.U8] 

98 

99 

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

101 

102 

103class U16(IRConst): 

104 __slots__: List[str] = [] 

105 

106 type = "Ity_I16" 

107 size = 16 

108 tag = "Ico_U16" 

109 op_format = "16" 

110 c_constructor = pvc.IRConst_U16 

111 

112 def __init__(self, value): 

113 self._value = value 

114 

115 def __str__(self): 

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

117 

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) 

126 

127 

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

129 

130 

131class U32(IRConst): 

132 __slots__: List[str] = [] 

133 

134 type = "Ity_I32" 

135 size = 32 

136 tag = "Ico_U32" 

137 op_format = "32" 

138 c_constructor = pvc.IRConst_U32 

139 

140 def __init__(self, value: int): 

141 self._value = value 

142 

143 def __str__(self): 

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

145 

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) 

154 

155 

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

157 

158 

159class U64(IRConst): 

160 __slots__: List[str] = [] 

161 

162 type = "Ity_I64" 

163 size = 64 

164 tag = "Ico_U64" 

165 op_format = "64" 

166 c_constructor = pvc.IRConst_U64 

167 

168 def __init__(self, value): 

169 self._value = value 

170 

171 def __str__(self): 

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

173 

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) 

182 

183 

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

185 

186# Integer Type Imagination 

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

188 

189 

190def vex_int_class(size): 

191 try: 

192 return class_cache[size] 

193 except KeyError: 

194 

195 class VexInt(IRConst): 

196 type = "Ity_I%d" % size 

197 tag = "Ico_U%d" % size 

198 op_format = str(size) 

199 

200 def __init__(self, value): 

201 IRConst.__init__(self) 

202 self._value = value 

203 

204 def __str__(self): 

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

206 

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

208 class_cache[size] = VexInt 

209 return VexInt 

210 

211 

212class F32(IRConst): 

213 __slots__: List[str] = [] 

214 

215 type = "Ity_F32" 

216 tag = "Ico_F32" 

217 op_format = "F32" 

218 c_constructor = pvc.IRConst_F32 

219 

220 def __init__(self, value): 

221 self._value = value 

222 

223 def __str__(self): 

224 return "%f" % self.value 

225 

226 @staticmethod 

227 def _from_c(c_const): 

228 return F32(c_const.Ico.F32) 

229 

230 

231class F32i(IRConst): 

232 __slots__: List[str] = [] 

233 

234 type = "Ity_F32" 

235 tag = "Ico_F32i" 

236 op_format = "F32" 

237 c_constructor = pvc.IRConst_F32i 

238 

239 def __init__(self, value): 

240 self._value = value 

241 

242 def __str__(self): 

243 return "%f" % self.value 

244 

245 @staticmethod 

246 def _from_c(c_const): 

247 return F32i(c_const.Ico.F32) 

248 

249 

250class F64(IRConst): 

251 __slots__: List[str] = [] 

252 

253 type = "Ity_F64" 

254 tag = "Ico_F64" 

255 op_format = "F64" 

256 c_constructor = pvc.IRConst_F64 

257 

258 def __init__(self, value): 

259 self._value = value 

260 

261 def __str__(self): 

262 return "%f" % self.value 

263 

264 @staticmethod 

265 def _from_c(c_const): 

266 return F64(c_const.Ico.F64) 

267 

268 

269class F64i(IRConst): 

270 __slots__: List[str] = [] 

271 

272 type = "Ity_F64" 

273 tag = "Ico_F64i" 

274 op_format = "F64" 

275 c_constructor = pvc.IRConst_F64i 

276 

277 def __init__(self, value): 

278 self._value = value 

279 

280 def __str__(self): 

281 return "%f" % self.value 

282 

283 @staticmethod 

284 def _from_c(c_const): 

285 return F64i(c_const.Ico.F64) 

286 

287 

288class V128(IRConst): 

289 __slots__: List[str] = [] 

290 

291 type = "Ity_V128" 

292 tag = "Ico_V128" 

293 op_format = "V128" 

294 c_constructor = pvc.IRConst_V128 

295 

296 def __init__(self, value): 

297 self._value = value 

298 

299 def __str__(self): 

300 return "%x" % self.value 

301 

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) 

312 

313 

314class V256(IRConst): 

315 __slots__: List[str] = [] 

316 

317 type = "Ity_V256" 

318 tag = "Ico_V256" 

319 op_format = "V256" 

320 c_constructor = pvc.IRConst_V256 

321 

322 def __init__(self, value): 

323 self._value = value 

324 

325 def __str__(self): 

326 return "%x" % self.value 

327 

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) 

337 

338 

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} 

342 

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

347 

348 

349def is_int_ty(ty): 

350 m = int_ty_re.match(ty) 

351 return m is not None 

352 

353 

354def is_int_tag(tag): 

355 m = int_tag_re.match(tag) 

356 return m is not None 

357 

358 

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

364 

365 

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

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

368 

369 

370def get_type_size(ty): 

371 """ 

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

373 e.g., Ity_I16 -> 16 

374 

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

382 

383 

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

398 

399 

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) 

409 

410 

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)