Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pyvex/stmt.py: 66%

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

452 statements  

1from __future__ import annotations 

2 

3import logging 

4from collections.abc import Iterator 

5from typing import TYPE_CHECKING 

6 

7from . import expr 

8from .const import IRConst 

9from .enums import IRCallee, IRRegArray, VEXObject, get_enum_from_int, get_int_from_enum 

10from .errors import PyVEXError 

11from .expr import Const, Get, IRExpr 

12from .native import ffi, pvc 

13 

14if TYPE_CHECKING: 

15 from .block import IRTypeEnv 

16 

17log = logging.getLogger("pyvex.stmt") 

18 

19 

20class IRStmt(VEXObject): 

21 """ 

22 IR statements in VEX represents operations with side-effects. 

23 """ 

24 

25 tag: str 

26 tag_int = 0 # set automatically at bottom of file 

27 

28 __slots__ = [] 

29 

30 def pp(self): 

31 print(str(self)) 

32 

33 @property 

34 def child_expressions(self) -> Iterator[IRExpr]: 

35 for k in self.__slots__: 

36 v = getattr(self, k) 

37 if isinstance(v, IRExpr): 

38 # return itself 

39 yield v 

40 # return all the child expressions 

41 yield from v.child_expressions 

42 

43 # ??? 

44 @property 

45 def expressions(self): 

46 return self.child_expressions 

47 

48 @property 

49 def constants(self): 

50 return sum((e.constants for e in self.expressions), []) 

51 

52 @staticmethod 

53 def _from_c(c_stmt): 

54 if c_stmt[0] == ffi.NULL: 

55 return None 

56 

57 try: 

58 stmt_class = enum_to_stmt_class(c_stmt.tag) 

59 except KeyError: 

60 raise PyVEXError("Unknown/unsupported IRStmtTag %s.\n" % get_enum_from_int(c_stmt.tag)) 

61 return stmt_class._from_c(c_stmt) 

62 

63 def typecheck(self, tyenv: IRTypeEnv) -> bool: # pylint: disable=unused-argument,no-self-use 

64 return True 

65 

66 def replace_expression(self, replacements): 

67 """ 

68 Replace child expressions in-place. 

69 

70 :param Dict[IRExpr, IRExpr] replacements: A mapping from expression-to-find to expression-to-replace-with 

71 :return: None 

72 """ 

73 

74 for k in self.__slots__: 

75 v = getattr(self, k) 

76 if isinstance(v, IRExpr) and v in replacements: 

77 setattr(self, k, replacements.get(v)) 

78 elif isinstance(v, IRExpr): 

79 v.replace_expression(replacements) 

80 elif type(v) is tuple: 

81 # Rebuild the tuple 

82 _lst = [] 

83 replaced = False 

84 for expr_ in v: 

85 if isinstance(expr_, IRExpr) and expr_ in replacements: 

86 _lst.append(replacements.get(expr_)) 

87 replaced = True 

88 else: 

89 _lst.append(expr_) 

90 if replaced: 

91 setattr(self, k, tuple(_lst)) 

92 

93 def __str__(self): 

94 return self.pp_str(None, None, None) 

95 

96 def pp_str(self, reg_name=None, arch=None, tyenv=None) -> str: 

97 raise NotImplementedError() 

98 

99 

100class NoOp(IRStmt): 

101 """ 

102 A no-operation statement. It is usually the result of an IR optimization. 

103 """ 

104 

105 __slots__ = [] 

106 

107 tag = "Ist_NoOp" 

108 

109 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

110 return "IR-NoOp" 

111 

112 @staticmethod 

113 def _from_c(c_stmt): 

114 return NoOp() 

115 

116 

117class IMark(IRStmt): 

118 """ 

119 An instruction mark. It marks the start of the statements that represent a single machine instruction (the end of 

120 those statements is marked by the next IMark or the end of the IRSB). Contains the address and length of the 

121 instruction. 

122 """ 

123 

124 __slots__ = ["addr", "len", "delta"] 

125 

126 tag = "Ist_IMark" 

127 

128 def __init__(self, addr: int, length: int, delta: int): 

129 self.addr = addr 

130 self.len = length 

131 self.delta = delta 

132 

133 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

134 return "------ IMark(0x%x, %d, %d) ------" % (self.addr, self.len, self.delta) 

135 

136 @staticmethod 

137 def _from_c(c_stmt): 

138 return IMark(c_stmt.Ist.IMark.addr, c_stmt.Ist.IMark.len, c_stmt.Ist.IMark.delta) 

139 

140 

141class AbiHint(IRStmt): 

142 """ 

143 An ABI hint, provides specific information about this platform's ABI. 

144 """ 

145 

146 __slots__ = ["base", "len", "nia"] 

147 

148 tag = "Ist_AbiHint" 

149 

150 def __init__(self, base, length, nia): 

151 self.base = base 

152 self.len = length 

153 self.nia = nia 

154 

155 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

156 return "====== AbiHint(0x%s, %d, %s) ======" % (self.base, self.len, self.nia) 

157 

158 @staticmethod 

159 def _from_c(c_stmt): 

160 return AbiHint( 

161 IRExpr._from_c(c_stmt.Ist.AbiHint.base), c_stmt.Ist.AbiHint.len, IRExpr._from_c(c_stmt.Ist.AbiHint.nia) 

162 ) 

163 

164 

165class Put(IRStmt): 

166 """ 

167 Write to a guest register, at a fixed offset in the guest state. 

168 """ 

169 

170 __slots__ = ["data", "offset"] 

171 

172 tag = "Ist_Put" 

173 

174 def __init__(self, data: IRExpr, offset: int): 

175 self.data = data 

176 self.offset = offset 

177 

178 ## TODO: Check if result_size and arch are available before looking of arch register name 

179 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

180 if arch is not None and tyenv is not None: 

181 reg_name = arch.translate_register_name(self.offset, self.data.result_size(tyenv) // 8) 

182 

183 if reg_name is not None: 

184 return f"PUT({reg_name}) = {self.data}" 

185 else: 

186 return f"PUT(offset={self.offset}) = {self.data}" 

187 

188 @staticmethod 

189 def _from_c(c_stmt): 

190 return Put(IRExpr._from_c(c_stmt.Ist.Put.data), c_stmt.Ist.Put.offset) 

191 

192 def typecheck(self, tyenv): 

193 return self.data.typecheck(tyenv) 

194 

195 

196class PutI(IRStmt): 

197 """ 

198 Write to a guest register, at a non-fixed offset in the guest state. 

199 """ 

200 

201 __slots__ = ["descr", "ix", "data", "bias"] 

202 

203 tag = "Ist_PutI" 

204 

205 def __init__(self, descr, ix, data, bias): 

206 self.descr = descr 

207 self.ix = ix 

208 self.data = data 

209 self.bias = bias 

210 

211 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

212 return "PutI(%s)[%s,%d] = %s" % (self.descr, self.ix, self.bias, self.data) 

213 

214 @staticmethod 

215 def _from_c(c_stmt): 

216 return PutI( 

217 IRRegArray._from_c(c_stmt.Ist.PutI.details.descr), 

218 IRExpr._from_c(c_stmt.Ist.PutI.details.ix), 

219 IRExpr._from_c(c_stmt.Ist.PutI.details.data), 

220 c_stmt.Ist.PutI.details.bias, 

221 ) 

222 

223 def typecheck(self, tyenv): 

224 dataty = self.data.typecheck(tyenv) 

225 if dataty is None: 

226 return False 

227 if dataty != self.descr.elemTy: 

228 log.debug("Expression doesn't match RegArray type") 

229 return False 

230 return True 

231 

232 

233class WrTmp(IRStmt): 

234 """ 

235 Assign a value to a temporary. Note that SSA rules require each tmp is only assigned to once. IR sanity checking 

236 will reject any block containing a temporary which is not assigned to exactly once. 

237 """ 

238 

239 __slots__ = ["data", "tmp"] 

240 

241 tag = "Ist_WrTmp" 

242 

243 def __init__(self, tmp, data: IRExpr): 

244 self.tmp = tmp 

245 self.data = data 

246 

247 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

248 # Support for named register in string representation of expr.Get 

249 

250 if arch is not None and tyenv is not None and isinstance(self.data, Get): 

251 reg_name = arch.translate_register_name(self.data.offset, self.data.result_size(tyenv) // 8) 

252 

253 if reg_name is not None and isinstance(self.data, expr.Get): 

254 return "t%d = %s" % (self.tmp, self.data.pp_str_with_name(reg_name)) 

255 else: 

256 return "t%d = %s" % (self.tmp, self.data) 

257 

258 @staticmethod 

259 def _from_c(c_stmt): 

260 return WrTmp(c_stmt.Ist.WrTmp.tmp, IRExpr._from_c(c_stmt.Ist.WrTmp.data)) 

261 

262 def typecheck(self, tyenv): 

263 dataty = self.data.typecheck(tyenv) 

264 if dataty is None: 

265 return False 

266 if dataty != tyenv.lookup(self.tmp): 

267 log.debug("Expression doesn't match tmp type") 

268 return False 

269 return True 

270 

271 

272class Store(IRStmt): 

273 """ 

274 Write a value to memory.. 

275 """ 

276 

277 __slots__ = ["addr", "data", "end"] 

278 

279 tag = "Ist_Store" 

280 

281 def __init__(self, addr: IRExpr, data: IRExpr, end: str): 

282 self.addr = addr 

283 self.data = data 

284 self.end = end 

285 

286 @property 

287 def endness(self): 

288 return self.end 

289 

290 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

291 return f"ST{self.endness[-2:].lower()}({self.addr}) = {self.data}" 

292 

293 @staticmethod 

294 def _from_c(c_stmt): 

295 return Store( 

296 IRExpr._from_c(c_stmt.Ist.Store.addr), 

297 IRExpr._from_c(c_stmt.Ist.Store.data), 

298 get_enum_from_int(c_stmt.Ist.Store.end), 

299 ) 

300 

301 def typecheck(self, tyenv): 

302 dataty = self.data.typecheck(tyenv) 

303 if dataty is None: 

304 return False 

305 addrty = self.addr.typecheck(tyenv) 

306 if addrty is None: 

307 return False 

308 if addrty != tyenv.wordty: 

309 log.debug("addr must be full word for arch") 

310 return False 

311 if self.end not in ("Iend_LE", "Iend_BE"): 

312 log.debug("invalid endness enum") 

313 return False 

314 return True 

315 

316 

317class CAS(IRStmt): 

318 """ 

319 an atomic compare-and-swap operation. 

320 """ 

321 

322 __slots__ = ["addr", "dataLo", "dataHi", "expdLo", "expdHi", "oldLo", "oldHi", "end"] 

323 

324 tag = "Ist_CAS" 

325 

326 def __init__(self, addr, dataLo, dataHi, expdLo, expdHi, oldLo, oldHi, end): 

327 self.addr = addr 

328 self.dataLo = dataLo 

329 self.dataHi = dataHi 

330 self.expdLo = expdLo 

331 self.expdHi = expdHi 

332 self.oldLo = oldLo 

333 self.oldHi = oldHi 

334 self.end = end 

335 

336 @property 

337 def endness(self): 

338 return self.end 

339 

340 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

341 return "t({},{}) = CAS{}({} :: ({},{})->({},{}))".format( 

342 self.oldLo, self.oldHi, self.end[-2:].lower(), self.addr, self.expdLo, self.expdHi, self.dataLo, self.dataHi 

343 ) 

344 

345 @staticmethod 

346 def _from_c(c_stmt): 

347 return CAS( 

348 IRExpr._from_c(c_stmt.Ist.CAS.details.addr), 

349 IRExpr._from_c(c_stmt.Ist.CAS.details.dataLo), 

350 IRExpr._from_c(c_stmt.Ist.CAS.details.dataHi), 

351 IRExpr._from_c(c_stmt.Ist.CAS.details.expdLo), 

352 IRExpr._from_c(c_stmt.Ist.CAS.details.expdHi), 

353 c_stmt.Ist.CAS.details.oldLo, 

354 c_stmt.Ist.CAS.details.oldHi, 

355 get_enum_from_int(c_stmt.Ist.CAS.details.end), 

356 ) 

357 

358 def typecheck(self, tyenv): 

359 addrty = self.addr.typecheck(tyenv) 

360 if addrty is None: 

361 return False 

362 if addrty != tyenv.wordty: 

363 log.debug("addr must be full word for arch") 

364 return False 

365 if self.end not in ("Iend_LE", "Iend_BE"): 

366 log.debug("invalid endness enum") 

367 return False 

368 

369 if self.oldHi == 0xFFFFFFFF: 

370 # single-element case 

371 if self.expdHi is not None or self.dataHi is not None: 

372 log.debug("expdHi and dataHi must be None") 

373 return False 

374 expdLoTy = self.expdLo.typecheck(tyenv) 

375 dataLoTy = self.dataLo.typecheck(tyenv) 

376 if expdLoTy is None or dataLoTy is None: 

377 return False 

378 if tyenv.lookup(self.oldLo) != expdLoTy or expdLoTy != dataLoTy: 

379 log.debug("oldLo, expdL, dataLo must all have the same type") 

380 return False 

381 else: 

382 # double-element case 

383 expdLoTy = self.expdLo.typecheck(tyenv) 

384 dataLoTy = self.dataLo.typecheck(tyenv) 

385 expdHiTy = self.expdHi.typecheck(tyenv) 

386 dataHiTy = self.dataHi.typecheck(tyenv) 

387 if expdLoTy is None or dataLoTy is None or expdHiTy is None or dataHiTy is None: 

388 return False 

389 if ( 

390 tyenv.lookup(self.oldLo) != expdLoTy 

391 or expdLoTy != dataLoTy 

392 or tyenv.lookup(self.oldHi) != expdHiTy 

393 or expdHiTy != dataHiTy 

394 or expdLoTy != expdHiTy 

395 ): 

396 log.debug("oldLo, expdLo, dataLo, oldHi, expdHi, dataHi must all have the same type") 

397 return False 

398 

399 return True 

400 

401 

402class LLSC(IRStmt): 

403 """ 

404 Either Load-Linked or Store-Conditional, depending on STOREDATA. If STOREDATA is NULL then this is a Load-Linked, 

405 else it is a Store-Conditional. 

406 """ 

407 

408 __slots__ = ["addr", "storedata", "result", "end"] 

409 

410 tag = "Ist_LLSC" 

411 

412 def __init__(self, addr: IRExpr, storedata: IRExpr, result: int, end: str): 

413 self.addr = addr 

414 self.storedata = storedata 

415 self.result = result 

416 self.end = end 

417 

418 @property 

419 def endness(self): 

420 return self.end 

421 

422 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

423 if self.storedata is None: 

424 return "t%d = LD%s-Linked(%s)" % (self.result, self.end[-2:].lower(), self.addr) 

425 else: 

426 return "t%d = ( ST%s-Cond(%s) = %s )" % (self.result, self.end[-2:].lower(), self.addr, self.storedata) 

427 

428 @staticmethod 

429 def _from_c(c_stmt): 

430 return LLSC( 

431 IRExpr._from_c(c_stmt.Ist.LLSC.addr), 

432 IRExpr._from_c(c_stmt.Ist.LLSC.storedata), 

433 c_stmt.Ist.LLSC.result, 

434 get_enum_from_int(c_stmt.Ist.LLSC.end), 

435 ) 

436 

437 def typecheck(self, tyenv): 

438 addrty = self.addr.typecheck(tyenv) 

439 if addrty is None: 

440 return False 

441 if addrty != tyenv.wordty: 

442 log.debug("addr must be full word for arch") 

443 return False 

444 if self.end not in ("Iend_LE", "Iend_BE"): 

445 log.debug("invalid endness enum") 

446 return False 

447 

448 if self.storedata is not None: 

449 # load-linked 

450 storety = self.storedata.typecheck(tyenv) 

451 if storety is None: 

452 return False 

453 

454 if tyenv.lookup(self.result) != "Ity_I1": 

455 log.debug("result tmp must be Ity_I1") 

456 return False 

457 

458 return True 

459 

460 

461class MBE(IRStmt): 

462 __slots__ = ["event"] 

463 

464 tag = "Ist_MBE" 

465 

466 def __init__(self, event): 

467 self.event = event 

468 

469 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

470 return "MBusEvent-" + self.event 

471 

472 @staticmethod 

473 def _from_c(c_stmt): 

474 return MBE(get_enum_from_int(c_stmt.Ist.MBE.event)) 

475 

476 

477class Dirty(IRStmt): 

478 __slots__ = ["cee", "guard", "args", "tmp", "mFx", "mAddr", "mSize", "nFxState"] 

479 

480 tag = "Ist_Dirty" 

481 

482 def __init__(self, cee, guard, args, tmp, mFx, mAddr, mSize, nFxState): 

483 self.cee = cee 

484 self.guard = guard 

485 self.args = tuple(args) 

486 self.tmp = tmp 

487 self.mFx = mFx 

488 self.mAddr = mAddr 

489 self.mSize = mSize 

490 self.nFxState = nFxState 

491 

492 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

493 return "t{} = DIRTY {} {} ::: {}({})".format( 

494 self.tmp, self.guard, "TODO(effects)", self.cee, ",".join(str(a) for a in self.args) 

495 ) 

496 

497 @property 

498 def child_expressions(self): 

499 expressions = sum((a.child_expressions for a in self.args), []) 

500 expressions.extend(self.args) 

501 expressions.append(self.guard) 

502 expressions.extend(self.guard.child_expressions) 

503 return expressions 

504 

505 @staticmethod 

506 def _from_c(c_stmt): 

507 args = [] 

508 for i in range(20): 

509 a = c_stmt.Ist.Dirty.details.args[i] 

510 if a == ffi.NULL: 

511 break 

512 

513 args.append(IRExpr._from_c(a)) 

514 

515 return Dirty( 

516 IRCallee._from_c(c_stmt.Ist.Dirty.details.cee), 

517 IRExpr._from_c(c_stmt.Ist.Dirty.details.guard), 

518 tuple(args), 

519 c_stmt.Ist.Dirty.details.tmp, 

520 get_enum_from_int(c_stmt.Ist.Dirty.details.mFx), 

521 IRExpr._from_c(c_stmt.Ist.Dirty.details.mAddr), 

522 c_stmt.Ist.Dirty.details.mSize, 

523 c_stmt.Ist.Dirty.details.nFxState, 

524 ) 

525 

526 

527class Exit(IRStmt): 

528 """ 

529 A conditional exit from the middle of an IRSB. 

530 """ 

531 

532 __slots__ = ["guard", "dst", "offsIP", "jk"] 

533 

534 tag = "Ist_Exit" 

535 

536 def __init__(self, guard: IRExpr, dst: IRConst, jk: str, offsIP: int): 

537 self.guard = guard 

538 self.dst = dst 

539 self.offsIP = offsIP 

540 self.jk = jk 

541 

542 @property 

543 def jumpkind(self): 

544 return self.jk 

545 

546 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

547 if arch is not None and tyenv is not None: 

548 reg_name = arch.translate_register_name(self.offsIP, arch.bits // 8) 

549 

550 if reg_name is None: 

551 return "if (%s) { PUT(offset=%d) = %#x; %s }" % (self.guard, self.offsIP, self.dst.value, self.jumpkind) 

552 else: 

553 return f"if ({self.guard}) {{ PUT({reg_name}) = {self.dst.value:#x}; {self.jumpkind} }}" 

554 

555 @property 

556 def child_expressions(self): 

557 return [self.guard] + self.guard.child_expressions + [Const(self.dst)] 

558 

559 @staticmethod 

560 def _from_c(c_stmt): 

561 return Exit( 

562 IRExpr._from_c(c_stmt.Ist.Exit.guard), 

563 IRConst._from_c(c_stmt.Ist.Exit.dst), 

564 get_enum_from_int(c_stmt.Ist.Exit.jk), 

565 c_stmt.Ist.Exit.offsIP, 

566 ) 

567 

568 def typecheck(self, tyenv): 

569 if not self.jk.startswith("Ijk_"): 

570 log.debug("Jumpkind is not a jumpkind enum") 

571 return False 

572 guardty = self.guard.typecheck(tyenv) 

573 if guardty is None: 

574 return False 

575 if guardty != "Ity_I1": 

576 log.debug("guard must be Ity_I1") 

577 return False 

578 return True 

579 

580 

581class LoadG(IRStmt): 

582 """ 

583 A guarded load. 

584 """ 

585 

586 __slots__ = ["addr", "alt", "guard", "dst", "cvt", "end", "cvt_types"] 

587 

588 tag = "Ist_LoadG" 

589 

590 def __init__(self, end: str, cvt: str, dst: int, addr: IRExpr, alt: IRExpr, guard: IRExpr): 

591 self.addr = addr 

592 self.alt = alt 

593 self.guard = guard 

594 self.dst = dst 

595 self.cvt = cvt 

596 self.end = end 

597 

598 type_in = ffi.new("IRType *") # TODO separate this from the pyvex C implementation 

599 type_out = ffi.new("IRType *") 

600 pvc.typeOfIRLoadGOp(get_int_from_enum(self.cvt), type_out, type_in) 

601 type_in = ffi.cast("int *", type_in)[0] 

602 type_out = ffi.cast("int *", type_out)[0] 

603 self.cvt_types = (get_enum_from_int(type_in), get_enum_from_int(type_out)) 

604 

605 @property 

606 def endness(self): 

607 return self.end 

608 

609 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

610 return "t%d = if (%s) %s(LD%s(%s)) else %s" % ( 

611 self.dst, 

612 self.guard, 

613 self.cvt, 

614 self.end[-2:].lower(), 

615 self.addr, 

616 self.alt, 

617 ) 

618 

619 @staticmethod 

620 def _from_c(c_stmt): 

621 return LoadG( 

622 get_enum_from_int(c_stmt.Ist.LoadG.details.end), 

623 get_enum_from_int(c_stmt.Ist.LoadG.details.cvt), 

624 c_stmt.Ist.LoadG.details.dst, 

625 IRExpr._from_c(c_stmt.Ist.LoadG.details.addr), 

626 IRExpr._from_c(c_stmt.Ist.LoadG.details.alt), 

627 IRExpr._from_c(c_stmt.Ist.LoadG.details.guard), 

628 ) 

629 

630 def typecheck(self, tyenv): 

631 addrty = self.addr.typecheck(tyenv) 

632 if addrty is None: 

633 return False 

634 if addrty != tyenv.wordty: 

635 log.debug("addr must be full word for arch") 

636 return False 

637 if self.end not in ("Iend_LE", "Iend_BE"): 

638 log.debug("invalid endness enum") 

639 return False 

640 

641 dstty = tyenv.lookup(self.dst) 

642 guardty = self.guard.typecheck(tyenv) 

643 altty = self.alt.typecheck(tyenv) 

644 

645 if guardty is None or altty is None: 

646 return False 

647 if dstty != "Ity_I32" or altty != "Ity_I32": 

648 log.debug("dst and alt must be Ity_I32") 

649 return False 

650 if guardty != "Ity_I1": 

651 log.debug("guard must be Ity_I1") 

652 return False 

653 if not self.cvt.startswith("ILGop_"): 

654 log.debug("Invalid cvt enum") 

655 return False 

656 return True 

657 

658 

659class StoreG(IRStmt): 

660 """ 

661 A guarded store. 

662 """ 

663 

664 __slots__ = ["addr", "data", "guard", "end"] 

665 

666 tag = "Ist_StoreG" 

667 

668 def __init__(self, end, addr, data, guard): 

669 self.addr = addr 

670 self.data = data 

671 self.guard = guard 

672 self.end = end 

673 

674 @property 

675 def endness(self): 

676 return self.end 

677 

678 def pp_str(self, reg_name=None, arch=None, tyenv=None): 

679 return f"if ({self.guard}) ST{self.end[-2:].lower()}({self.addr}) = {self.data}" 

680 

681 @staticmethod 

682 def _from_c(c_stmt): 

683 return StoreG( 

684 get_enum_from_int(c_stmt.Ist.StoreG.details.end), 

685 IRExpr._from_c(c_stmt.Ist.StoreG.details.addr), 

686 IRExpr._from_c(c_stmt.Ist.StoreG.details.data), 

687 IRExpr._from_c(c_stmt.Ist.StoreG.details.guard), 

688 ) 

689 

690 def typecheck(self, tyenv): 

691 addrty = self.addr.typecheck(tyenv) 

692 if addrty is None: 

693 return False 

694 if addrty != tyenv.wordty: 

695 log.debug("addr must be full word for arch") 

696 return False 

697 if self.end not in ("Iend_LE", "Iend_BE"): 

698 log.debug("invalid endness enum") 

699 return False 

700 

701 guardty = self.guard.typecheck(tyenv) 

702 dataty = self.data.typecheck(tyenv) 

703 

704 if guardty is None or dataty is None: 

705 return False 

706 if guardty != "Ity_I1": 

707 log.debug("guard must be Ity_I1") 

708 return False 

709 return True 

710 

711 

712_globals = globals().copy() 

713# 

714# Mapping from tag strings/enums to IRStmt classes 

715# 

716tag_to_stmt_mapping = {} 

717enum_to_stmt_mapping = {} 

718tag_count = 0 

719cls = None 

720for cls in _globals.values(): 

721 if type(cls) is type and issubclass(cls, IRStmt) and cls is not IRStmt: 

722 tag_to_stmt_mapping[cls.tag] = cls 

723 enum_to_stmt_mapping[get_int_from_enum(cls.tag)] = cls 

724 cls.tag_int = tag_count 

725 tag_count += 1 

726del cls 

727 

728 

729def tag_to_stmt_class(tag): 

730 try: 

731 return tag_to_stmt_mapping[tag] 

732 except KeyError: 

733 raise KeyError("No statement class for tag %s." % tag) 

734 

735 

736def enum_to_stmt_class(tag_enum): 

737 try: 

738 return enum_to_stmt_mapping[tag_enum] 

739 except KeyError: 

740 raise KeyError("No statement class for tag %s." % get_enum_from_int(tag_enum))