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

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: Optional[str] = None 

14 size = None 

15 tag: Optional[str] = None 

16 c_constructor = None 

17 

18 def pp(self): 

19 print(self.__str__()) 

20 

21 @property 

22 def value(self) -> int: 

23 return self._value 

24 

25 @staticmethod 

26 def _from_c(c_const): 

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

28 return None 

29 

30 tag = get_enum_from_int(c_const.tag) 

31 

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) 

36 

37 _translate = _from_c 

38 

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) 

44 

45 try: 

46 return cls.c_constructor(const.value) 

47 except KeyError: 

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

49 

50 def __eq__(self, other): 

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

52 return False 

53 return self._value == other._value 

54 

55 def __hash__(self): 

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

57 

58 

59class U1(IRConst): 

60 __slots__: List[str] = [] 

61 

62 type = "Ity_I1" 

63 size = 1 

64 tag = "Ico_U1" 

65 op_format = "1" 

66 c_constructor = pvc.IRConst_U1 

67 

68 def __init__(self, value): 

69 self._value = value 

70 

71 def __str__(self): 

72 return "%d" % self.value 

73 

74 @staticmethod 

75 def _from_c(c_const): 

76 return U1(c_const.Ico.U1) 

77 

78 

79class U8(IRConst): 

80 __slots__: List[str] = [] 

81 

82 type = "Ity_I8" 

83 size = 8 

84 tag = "Ico_U8" 

85 op_format = "8" 

86 c_constructor = pvc.IRConst_U8 

87 

88 def __init__(self, value): 

89 self._value = value 

90 

91 def __str__(self): 

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

93 

94 @staticmethod 

95 def _from_c(c_const): 

96 return _U8_POOL[c_const.Ico.U8] 

97 

98 

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

100 

101 

102class U16(IRConst): 

103 __slots__: List[str] = [] 

104 

105 type = "Ity_I16" 

106 size = 16 

107 tag = "Ico_U16" 

108 op_format = "16" 

109 c_constructor = pvc.IRConst_U16 

110 

111 def __init__(self, value): 

112 self._value = value 

113 

114 def __str__(self): 

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

116 

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) 

125 

126 

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

128 

129 

130class U32(IRConst): 

131 __slots__: List[str] = [] 

132 

133 type = "Ity_I32" 

134 size = 32 

135 tag = "Ico_U32" 

136 op_format = "32" 

137 c_constructor = pvc.IRConst_U32 

138 

139 def __init__(self, value: int): 

140 self._value = value 

141 

142 def __str__(self): 

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

144 

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) 

153 

154 

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

156 

157 

158class U64(IRConst): 

159 __slots__: List[str] = [] 

160 

161 type = "Ity_I64" 

162 size = 64 

163 tag = "Ico_U64" 

164 op_format = "64" 

165 c_constructor = pvc.IRConst_U64 

166 

167 def __init__(self, value): 

168 self._value = value 

169 

170 def __str__(self): 

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

172 

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) 

181 

182 

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

184 

185# Integer Type Imagination 

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

187 

188 

189def vex_int_class(size): 

190 try: 

191 return class_cache[size] 

192 except KeyError: 

193 

194 class VexInt(IRConst): 

195 type = "Ity_I%d" % size 

196 tag = "Ico_U%d" % size 

197 op_format = str(size) 

198 

199 def __init__(self, value): 

200 IRConst.__init__(self) 

201 self._value = value 

202 

203 def __str__(self): 

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

205 

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

207 class_cache[size] = VexInt 

208 return VexInt 

209 

210 

211class F32(IRConst): 

212 __slots__: List[str] = [] 

213 

214 type = "Ity_F32" 

215 tag = "Ico_F32" 

216 op_format = "F32" 

217 c_constructor = pvc.IRConst_F32 

218 

219 def __init__(self, value): 

220 self._value = value 

221 

222 def __str__(self): 

223 return "%f" % self.value 

224 

225 @staticmethod 

226 def _from_c(c_const): 

227 return F32(c_const.Ico.F32) 

228 

229 

230class F32i(IRConst): 

231 __slots__: List[str] = [] 

232 

233 type = "Ity_F32" 

234 tag = "Ico_F32i" 

235 op_format = "F32" 

236 c_constructor = pvc.IRConst_F32i 

237 

238 def __init__(self, value): 

239 self._value = value 

240 

241 def __str__(self): 

242 return "%f" % self.value 

243 

244 @staticmethod 

245 def _from_c(c_const): 

246 return F32i(c_const.Ico.F32) 

247 

248 

249class F64(IRConst): 

250 __slots__: List[str] = [] 

251 

252 type = "Ity_F64" 

253 tag = "Ico_F64" 

254 op_format = "F64" 

255 c_constructor = pvc.IRConst_F64 

256 

257 def __init__(self, value): 

258 self._value = value 

259 

260 def __str__(self): 

261 return "%f" % self.value 

262 

263 @staticmethod 

264 def _from_c(c_const): 

265 return F64(c_const.Ico.F64) 

266 

267 

268class F64i(IRConst): 

269 __slots__: List[str] = [] 

270 

271 type = "Ity_F64" 

272 tag = "Ico_F64i" 

273 op_format = "F64" 

274 c_constructor = pvc.IRConst_F64i 

275 

276 def __init__(self, value): 

277 self._value = value 

278 

279 def __str__(self): 

280 return "%f" % self.value 

281 

282 @staticmethod 

283 def _from_c(c_const): 

284 return F64i(c_const.Ico.F64) 

285 

286 

287class V128(IRConst): 

288 __slots__: List[str] = [] 

289 

290 type = "Ity_V128" 

291 tag = "Ico_V128" 

292 op_format = "V128" 

293 c_constructor = pvc.IRConst_V128 

294 

295 def __init__(self, value): 

296 self._value = value 

297 

298 def __str__(self): 

299 return "%x" % self.value 

300 

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) 

311 

312 

313class V256(IRConst): 

314 __slots__: List[str] = [] 

315 

316 type = "Ity_V256" 

317 tag = "Ico_V256" 

318 op_format = "V256" 

319 c_constructor = pvc.IRConst_V256 

320 

321 def __init__(self, value): 

322 self._value = value 

323 

324 def __str__(self): 

325 return "%x" % self.value 

326 

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) 

336 

337 

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} 

341 

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

346 

347 

348def is_int_ty(ty): 

349 m = int_ty_re.match(ty) 

350 return m is not None 

351 

352 

353def is_int_tag(tag): 

354 m = int_tag_re.match(tag) 

355 return m is not None 

356 

357 

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

363 

364 

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

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

367 

368 

369def get_type_size(ty): 

370 """ 

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

372 e.g., Ity_I16 -> 16 

373 

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

381 

382 

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

397 

398 

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) 

408 

409 

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)