Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pyvex/expr.py: 73%

606 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:15 +0000

1import logging 

2import re 

3from typing import List, Optional 

4 

5from archinfo import RegisterOffset, TmpVar 

6 

7from .const import U8, U16, U32, U64, IRConst, get_type_size 

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

9from .errors import PyVEXError 

10from .native import ffi, pvc 

11 

12log = logging.getLogger("pyvex.expr") 

13 

14 

15class IRExpr(VEXObject): 

16 """ 

17 IR expressions in VEX represent operations without side effects. 

18 """ 

19 

20 __slots__ = [] 

21 

22 tag: Optional[str] = None 

23 tag_int = 0 # set automatically at bottom of file 

24 

25 def pp(self): 

26 print(self.__str__()) 

27 

28 @property 

29 def child_expressions(self) -> List["IRExpr"]: 

30 """ 

31 A list of all of the expressions that this expression ends up evaluating. 

32 """ 

33 expressions = [] 

34 for k in self.__slots__: 

35 v = getattr(self, k) 

36 if isinstance(v, IRExpr): 

37 expressions.append(v) 

38 expressions.extend(v.child_expressions) 

39 return expressions 

40 

41 @property 

42 def constants(self): 

43 """ 

44 A list of all of the constants that this expression ends up using. 

45 """ 

46 constants = [] 

47 for k in self.__slots__: 

48 v = getattr(self, k) 

49 if isinstance(v, IRExpr): 

50 constants.extend(v.constants) 

51 elif isinstance(v, IRConst): 

52 constants.append(v) 

53 return constants 

54 

55 def result_size(self, tyenv): 

56 return get_type_size(self.result_type(tyenv)) 

57 

58 def result_type(self, tyenv): 

59 raise NotImplementedError() 

60 

61 def replace_expression(self, replacements): 

62 """ 

63 Replace child expressions in-place. 

64 

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

66 :return: None 

67 """ 

68 

69 for k in self.__slots__: 

70 v = getattr(self, k) 

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

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

73 elif isinstance(v, list): 

74 # Replace the instance in the list 

75 for i, expr_ in enumerate(v): 

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

77 v[i] = replacements.get(expr_) 

78 elif type(v) is tuple: 

79 # Rebuild the tuple 

80 _lst = [] 

81 replaced = False 

82 for i, expr_ in enumerate(v): 

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

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

85 replaced = True 

86 else: 

87 _lst.append(expr_) 

88 if replaced: 

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

90 elif isinstance(v, IRExpr): 

91 v.replace_expression(replacements) 

92 

93 @staticmethod 

94 def _from_c(c_expr) -> "IRExpr": 

95 if c_expr == ffi.NULL or c_expr[0] == ffi.NULL: 

96 return None 

97 

98 try: 

99 return enum_to_expr_class(c_expr.tag)._from_c(c_expr) 

100 except KeyError: 

101 raise PyVEXError("Unknown/unsupported IRExprTag %s\n" % get_enum_from_int(c_expr.tag)) 

102 

103 _translate = _from_c 

104 

105 @staticmethod 

106 def _to_c(expr): 

107 try: 

108 return tag_to_expr_class(expr.tag)._to_c(expr) 

109 except KeyError: 

110 raise PyVEXError("Unknown/unsupported IRExprTag %s\n" % expr.tag) 

111 

112 def typecheck(self, tyenv): 

113 return self.result_type(tyenv) 

114 

115 

116class Binder(IRExpr): 

117 """ 

118 Used only in pattern matching within Vex. Should not be seen outside of Vex. 

119 """ 

120 

121 __slots__ = ["binder"] 

122 

123 tag = "Iex_Binder" 

124 

125 def __init__(self, binder): 

126 self.binder = binder 

127 

128 def __str__(self): 

129 return "Binder" 

130 

131 @staticmethod 

132 def _from_c(c_expr): 

133 return Binder(c_expr.iex.Binder.binder) 

134 

135 @staticmethod 

136 def _to_c(expr): 

137 return pvc.IRExpr_Binder(expr.binder) 

138 

139 def result_type(self, tyenv): 

140 return "Ity_INVALID" 

141 

142 

143class VECRET(IRExpr): 

144 tag = "Iex_VECRET" 

145 

146 __slots__ = [] 

147 

148 def __str__(self): 

149 return "VECRET" 

150 

151 @staticmethod 

152 def _from_c(c_expr): 

153 return VECRET() 

154 

155 @staticmethod 

156 def _to_c(expr): 

157 return pvc.IRExpr_VECRET() 

158 

159 def result_type(self, tyenv): 

160 return "Ity_INVALID" 

161 

162 

163class GSPTR(IRExpr): 

164 __slots__ = [] 

165 

166 tag = "Iex_GSPTR" 

167 

168 def __str__(self): 

169 return "GSPTR" 

170 

171 @staticmethod 

172 def _from_c(c_expr): 

173 return GSPTR() 

174 

175 @staticmethod 

176 def _to_c(expr): 

177 return pvc.IRExpr_GSPTR() 

178 

179 def result_type(self, tyenv): 

180 return "Ity_INVALID" 

181 

182 

183class GetI(IRExpr): 

184 """ 

185 Read a guest register at a non-fixed offset in the guest state. 

186 """ 

187 

188 __slots__ = ["descr", "ix", "bias"] 

189 

190 tag = "Iex_GetI" 

191 

192 def __init__(self, descr, ix, bias): 

193 self.descr = descr 

194 self.ix = ix 

195 self.bias = bias 

196 

197 @property 

198 def description(self): 

199 return self.descr 

200 

201 @property 

202 def index(self): 

203 return self.ix 

204 

205 def __str__(self): 

206 return f"GetI({self.descr})[{self.ix},{self.bias}]" 

207 

208 @staticmethod 

209 def _from_c(c_expr): 

210 descr = IRRegArray._from_c(c_expr.Iex.GetI.descr) 

211 ix = IRExpr._from_c(c_expr.Iex.GetI.ix) 

212 bias = c_expr.Iex.GetI.bias 

213 return GetI(descr, ix, bias) 

214 

215 @staticmethod 

216 def _to_c(expr): 

217 return pvc.IRExpr_GetI(IRRegArray._to_c(expr.descr), IRExpr._to_c(expr.ix), expr.bias) 

218 

219 def result_type(self, tyenv): 

220 return self.descr.elemTy 

221 

222 

223class RdTmp(IRExpr): 

224 """ 

225 Read the value held by a temporary. 

226 """ 

227 

228 __slots__ = ["_tmp"] 

229 

230 tag = "Iex_RdTmp" 

231 

232 def __init__(self, tmp: TmpVar): 

233 self._tmp = tmp 

234 

235 def __str__(self): 

236 return "t%d" % self.tmp 

237 

238 @property 

239 def tmp(self) -> TmpVar: 

240 return self._tmp 

241 

242 @staticmethod 

243 def _from_c(c_expr): 

244 tmp = c_expr.Iex.RdTmp.tmp 

245 return RdTmp.get_instance(tmp) 

246 

247 @staticmethod 

248 def _to_c(expr): 

249 return pvc.IRExpr_RdTmp(expr.tmp) 

250 

251 @staticmethod 

252 def get_instance(tmp): 

253 if tmp < 1024: 

254 # for small tmp reads, they are cached and are only created once globally 

255 return _RDTMP_POOL[tmp] 

256 return RdTmp(tmp) 

257 

258 def replace_expression(self, replacements): 

259 # RdTmp is one of the terminal IRExprs, which cannot be replaced. 

260 pass 

261 

262 def result_type(self, tyenv): 

263 return tyenv.lookup(self.tmp) 

264 

265 def __hash__(self): 

266 return 133700 + self._tmp 

267 

268 

269_RDTMP_POOL = list(RdTmp(i) for i in range(0, 1024)) 

270 

271 

272class Get(IRExpr): 

273 """ 

274 Read a guest register, at a fixed offset in the guest state. 

275 """ 

276 

277 __slots__ = ["offset", "ty_int"] 

278 

279 tag = "Iex_Get" 

280 

281 def __init__(self, offset: RegisterOffset, ty: str, ty_int: Optional[int] = None): 

282 self.offset = offset 

283 if ty_int is None: 

284 self.ty_int = get_int_from_enum(ty) 

285 else: 

286 self.ty_int = ty_int 

287 

288 @property 

289 def ty(self): 

290 return get_enum_from_int(self.ty_int) 

291 

292 @property 

293 def type(self): 

294 return get_enum_from_int(self.ty_int) 

295 

296 def __str__(self, reg_name=None): 

297 if reg_name: 

298 return f"GET:{self.ty[4:]}({reg_name})" 

299 else: 

300 return f"GET:{self.ty[4:]}(offset={self.offset})" 

301 

302 @staticmethod 

303 def _from_c(c_expr): 

304 return Get(c_expr.Iex.Get.offset, get_enum_from_int(c_expr.Iex.Get.ty)) 

305 

306 @staticmethod 

307 def _to_c(expr): 

308 return pvc.IRExpr_Get(expr.offset, expr.ty_int) 

309 

310 def result_type(self, tyenv): 

311 return self.ty 

312 

313 def __hash__(self): 

314 return (self.offset << 8) | self.ty_int 

315 

316 

317class Qop(IRExpr): 

318 """ 

319 A quaternary operation (4 arguments). 

320 """ 

321 

322 __slots__ = ["op", "args"] 

323 

324 tag = "Iex_Qop" 

325 

326 def __init__(self, op, args): 

327 self.op = op 

328 self.args = args 

329 

330 def __str__(self): 

331 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args)) 

332 

333 @property 

334 def child_expressions(self): 

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

336 expressions.extend(self.args) 

337 return expressions 

338 

339 @staticmethod 

340 def _from_c(c_expr): 

341 return Qop( 

342 get_enum_from_int(c_expr.Iex.Qop.details.op), 

343 [ 

344 IRExpr._from_c(arg) 

345 for arg in [ 

346 c_expr.Iex.Qop.details.arg1, 

347 c_expr.Iex.Qop.details.arg2, 

348 c_expr.Iex.Qop.details.arg3, 

349 c_expr.Iex.Qop.details.arg4, 

350 ] 

351 ], 

352 ) 

353 

354 @staticmethod 

355 def _to_c(expr): 

356 return pvc.IRExpr_Qop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args]) 

357 

358 def result_type(self, tyenv): 

359 return get_op_retty(self.op) 

360 

361 def typecheck(self, tyenv): # TODO change all this to use PyvexTypeErrorException 

362 resty, (arg1ty, arg2ty, arg3ty, arg4ty) = op_arg_types(self.op) 

363 arg1ty_real = self.args[0].typecheck(tyenv) 

364 arg2ty_real = self.args[1].typecheck(tyenv) 

365 arg3ty_real = self.args[2].typecheck(tyenv) 

366 arg4ty_real = self.args[3].typecheck(tyenv) 

367 if arg1ty_real is None or arg2ty_real is None or arg3ty_real is None or arg4ty_real is None: 

368 return None 

369 

370 if arg1ty_real != arg1ty: 

371 log.debug("First arg of %s must be %s", self.op, arg1ty) 

372 return None 

373 if arg2ty_real != arg2ty: 

374 log.debug("Second arg of %s must be %s", self.op, arg2ty) 

375 return None 

376 if arg3ty_real != arg3ty: 

377 log.debug("Third arg of %s must be %s", self.op, arg3ty) 

378 return None 

379 if arg4ty_real != arg4ty: 

380 log.debug("Fourth arg of %s must be %s", self.op, arg4ty) 

381 return None 

382 

383 return resty 

384 

385 

386class Triop(IRExpr): 

387 """ 

388 A ternary operation (3 arguments) 

389 """ 

390 

391 __slots__ = ["op", "args"] 

392 

393 tag = "Iex_Triop" 

394 

395 def __init__(self, op, args): 

396 self.op = op 

397 self.args = args 

398 

399 def __str__(self): 

400 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args)) 

401 

402 @property 

403 def child_expressions(self): 

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

405 expressions.extend(self.args) 

406 return expressions 

407 

408 @staticmethod 

409 def _from_c(c_expr): 

410 return Triop( 

411 get_enum_from_int(c_expr.Iex.Triop.details.op), 

412 [ 

413 IRExpr._from_c(arg) 

414 for arg in [c_expr.Iex.Triop.details.arg1, c_expr.Iex.Triop.details.arg2, c_expr.Iex.Triop.details.arg3] 

415 ], 

416 ) 

417 

418 @staticmethod 

419 def _to_c(expr): 

420 return pvc.IRExpr_Triop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args]) 

421 

422 def result_type(self, tyenv): 

423 return get_op_retty(self.op) 

424 

425 def typecheck(self, tyenv): 

426 resty, (arg1ty, arg2ty, arg3ty) = op_arg_types(self.op) 

427 arg1ty_real = self.args[0].typecheck(tyenv) 

428 arg2ty_real = self.args[1].typecheck(tyenv) 

429 arg3ty_real = self.args[2].typecheck(tyenv) 

430 if arg1ty_real is None or arg2ty_real is None or arg3ty_real is None: 

431 return None 

432 

433 if arg1ty_real != arg1ty: 

434 log.debug("First arg of %s must be %s", self.op, arg1ty) 

435 return None 

436 if arg2ty_real != arg2ty: 

437 log.debug("Second arg of %s must be %s", self.op, arg2ty) 

438 return None 

439 if arg3ty_real != arg3ty: 

440 log.debug("Third arg of %s must be %s", self.op, arg3ty) 

441 return None 

442 

443 return resty 

444 

445 

446class Binop(IRExpr): 

447 """ 

448 A binary operation (2 arguments). 

449 """ 

450 

451 __slots__ = ["_op", "op_int", "args"] 

452 

453 tag = "Iex_Binop" 

454 

455 def __init__(self, op, args, op_int=None): 

456 self.op_int = op_int 

457 self.args = args 

458 self._op = op if op is not None else None 

459 

460 def __str__(self): 

461 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args)) 

462 

463 @property 

464 def op(self): 

465 if self._op is None: 

466 self._op = get_enum_from_int(self.op_int) 

467 return self._op 

468 

469 @property 

470 def child_expressions(self): 

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

472 expressions.extend(self.args) 

473 return expressions 

474 

475 @staticmethod 

476 def _from_c(c_expr): 

477 return Binop( 

478 None, 

479 [IRExpr._from_c(arg) for arg in [c_expr.Iex.Binop.arg1, c_expr.Iex.Binop.arg2]], 

480 op_int=c_expr.Iex.Binop.op, 

481 ) 

482 

483 @staticmethod 

484 def _to_c(expr): 

485 return pvc.IRExpr_Binop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args]) 

486 

487 def result_type(self, tyenv): 

488 return get_op_retty(self.op) 

489 

490 def typecheck(self, tyenv): 

491 arg1ty_real = self.args[0].typecheck(tyenv) 

492 arg2ty_real = self.args[1].typecheck(tyenv) 

493 

494 resty, (arg1ty, arg2ty) = op_arg_types(self.op) 

495 if arg1ty_real is None or arg2ty_real is None: 

496 return None 

497 

498 if arg1ty_real != arg1ty: 

499 log.debug("First arg of %s must be %s", self.op, arg1ty) 

500 return None 

501 if arg2ty_real != arg2ty: 

502 log.debug("Second arg of %s must be %s", self.op, arg2ty) 

503 return None 

504 

505 return resty 

506 

507 

508class Unop(IRExpr): 

509 """ 

510 A unary operation (1 argument). 

511 """ 

512 

513 __slots__ = ["op", "args"] 

514 

515 tag = "Iex_Unop" 

516 

517 def __init__(self, op, args): 

518 self.op = op 

519 self.args = args 

520 

521 def __str__(self): 

522 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args)) 

523 

524 @property 

525 def child_expressions(self): 

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

527 expressions.extend(self.args) 

528 return expressions 

529 

530 @staticmethod 

531 def _from_c(c_expr): 

532 return Unop(get_enum_from_int(c_expr.Iex.Unop.op), [IRExpr._from_c(c_expr.Iex.Unop.arg)]) 

533 

534 @staticmethod 

535 def _to_c(expr): 

536 return pvc.IRExpr_Unop(get_int_from_enum(expr.op), IRExpr._to_c(expr.args[0])) 

537 

538 def result_type(self, tyenv): 

539 return get_op_retty(self.op) 

540 

541 def typecheck(self, tyenv): 

542 resty, (arg1ty,) = op_arg_types(self.op) 

543 arg1ty_real = self.args[0].typecheck(tyenv) 

544 if arg1ty_real is None: 

545 return None 

546 

547 if arg1ty_real != arg1ty: 

548 log.debug("First arg of %s must be %s", self.op, arg1ty) 

549 return None 

550 

551 return resty 

552 

553 

554class Load(IRExpr): 

555 """ 

556 A load from memory. 

557 """ 

558 

559 __slots__ = ["end", "ty", "addr"] 

560 

561 tag = "Iex_Load" 

562 

563 def __init__(self, end, ty, addr): 

564 self.end = end 

565 self.ty = ty 

566 self.addr = addr 

567 

568 @property 

569 def endness(self): 

570 return self.end 

571 

572 @property 

573 def type(self): 

574 return self.ty 

575 

576 def __str__(self): 

577 return f"LD{self.end[-2:].lower()}:{self.ty[4:]}({self.addr})" 

578 

579 @staticmethod 

580 def _from_c(c_expr): 

581 return Load( 

582 get_enum_from_int(c_expr.Iex.Load.end), 

583 get_enum_from_int(c_expr.Iex.Load.ty), 

584 IRExpr._from_c(c_expr.Iex.Load.addr), 

585 ) 

586 

587 @staticmethod 

588 def _to_c(expr): 

589 return pvc.IRExpr_Load(get_int_from_enum(expr.end), get_int_from_enum(expr.ty), IRExpr._to_c(expr.addr)) 

590 

591 def result_type(self, tyenv): 

592 return self.ty 

593 

594 def typecheck(self, tyenv): 

595 addrty = self.addr.typecheck(tyenv) 

596 if addrty is None: 

597 return None 

598 if addrty != tyenv.wordty: 

599 log.debug("Address must be word-sized") 

600 return None 

601 return self.ty 

602 

603 

604class Const(IRExpr): 

605 """ 

606 A constant expression. 

607 """ 

608 

609 __slots__ = ["_con"] 

610 

611 tag = "Iex_Const" 

612 

613 def __init__(self, con: "IRConst"): 

614 self._con = con 

615 

616 def __str__(self): 

617 return str(self.con) 

618 

619 @property 

620 def con(self) -> "IRConst": 

621 return self._con 

622 

623 @staticmethod 

624 def _from_c(c_expr): 

625 con = IRConst._from_c(c_expr.Iex.Const.con) 

626 return Const.get_instance(con) 

627 

628 @staticmethod 

629 def _to_c(expr): 

630 return pvc.IRExpr_Const(IRConst._to_c(expr.con)) 

631 

632 @staticmethod 

633 def get_instance(con): 

634 if con.value < 1024 and con.__class__ in _CONST_POOL: 

635 return _CONST_POOL[con.__class__][con.value] 

636 return Const(con) 

637 

638 def result_type(self, tyenv): 

639 return self.con.type 

640 

641 

642_CONST_POOL = { 

643 U8: [Const(U8(i)) for i in range(0, 1024)], 

644 U16: [Const(U16(i)) for i in range(0, 1024)], 

645 U32: [Const(U32(i)) for i in range(0, 1024)], 

646 U64: [Const(U64(i)) for i in range(0, 1024)], 

647} 

648 

649 

650class ITE(IRExpr): 

651 """ 

652 An if-then-else expression. 

653 """ 

654 

655 __slots__ = ["cond", "iffalse", "iftrue"] 

656 

657 tag = "Iex_ITE" 

658 

659 def __init__(self, cond, iffalse, iftrue): 

660 self.cond = cond 

661 self.iffalse = iffalse 

662 self.iftrue = iftrue 

663 

664 def __str__(self): 

665 return f"ITE({self.cond},{self.iftrue},{self.iffalse})" 

666 

667 @staticmethod 

668 def _from_c(c_expr): 

669 return ITE( 

670 IRExpr._from_c(c_expr.Iex.ITE.cond), 

671 IRExpr._from_c(c_expr.Iex.ITE.iffalse), 

672 IRExpr._from_c(c_expr.Iex.ITE.iftrue), 

673 ) 

674 

675 @staticmethod 

676 def _to_c(expr): 

677 return pvc.IRExpr_ITE(IRExpr._to_c(expr.cond), IRExpr._to_c(expr.iftrue), IRExpr._to_c(expr.iffalse)) 

678 

679 def result_type(self, tyenv): 

680 return self.iftrue.result_type(tyenv) 

681 

682 def typecheck(self, tyenv): 

683 condty = self.cond.typecheck(tyenv) 

684 falsety = self.iffalse.typecheck(tyenv) 

685 truety = self.iftrue.typecheck(tyenv) 

686 

687 if condty is None or falsety is None or truety is None: 

688 return None 

689 

690 if condty != "Ity_I1": 

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

692 return None 

693 

694 if falsety != truety: 

695 log.debug("false condition must be same type as true condition") 

696 return None 

697 

698 return falsety 

699 

700 

701class CCall(IRExpr): 

702 """ 

703 A call to a pure (no side-effects) helper C function. 

704 """ 

705 

706 __slots__ = ["retty", "cee", "args"] 

707 

708 tag = "Iex_CCall" 

709 

710 def __init__(self, retty, cee, args): 

711 self.retty = retty 

712 self.cee = cee 

713 self.args = tuple(args) 

714 

715 @property 

716 def ret_type(self): 

717 return self.retty 

718 

719 @property 

720 def callee(self): 

721 return self.cee 

722 

723 def __str__(self): 

724 return "{}({}):{}".format(self.cee, ",".join(str(a) for a in self.args), self.retty) 

725 

726 @property 

727 def child_expressions(self): 

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

729 expressions.extend(self.args) 

730 return expressions 

731 

732 @staticmethod 

733 def _from_c(c_expr): 

734 i = 0 

735 args = [] 

736 while True: 

737 arg = c_expr.Iex.CCall.args[i] 

738 if arg == ffi.NULL: 

739 break 

740 args.append(IRExpr._from_c(arg)) 

741 i += 1 

742 

743 return CCall(get_enum_from_int(c_expr.Iex.CCall.retty), IRCallee._from_c(c_expr.Iex.CCall.cee), tuple(args)) 

744 

745 @staticmethod 

746 def _to_c(expr): 

747 args = [IRExpr._to_c(arg) for arg in expr.args] 

748 mkIRExprVec = getattr(pvc, "mkIRExprVec_%d" % len(args)) 

749 return pvc.IRExpr_CCall(IRCallee._to_c(expr.cee), get_int_from_enum(expr.retty), mkIRExprVec(*args)) 

750 

751 def result_type(self, tyenv): 

752 return self.retty 

753 

754 

755def get_op_retty(op): 

756 return op_arg_types(op)[0] 

757 

758 

759op_signatures = {} 

760 

761 

762def _request_op_type_from_cache(op): 

763 return op_signatures[op] 

764 

765 

766def _request_op_type_from_libvex(op): 

767 Ity_INVALID = 0x1100 # as defined in enum IRType in VEX 

768 

769 res_ty = ffi.new("IRType *") 

770 arg_tys = [ffi.new("IRType *") for _ in range(4)] 

771 # initialize all IRTypes to Ity_INVALID 

772 for arg in arg_tys: 

773 arg[0] = Ity_INVALID 

774 pvc.typeOfPrimop(get_int_from_enum(op), res_ty, *arg_tys) 

775 arg_ty_vals = [a[0] for a in arg_tys] 

776 

777 try: 

778 numargs = arg_ty_vals.index(Ity_INVALID) 

779 except ValueError: 

780 numargs = 4 

781 args_tys_list = [get_enum_from_int(arg_ty_vals[i]) for i in range(numargs)] 

782 

783 op_ty_sig = (get_enum_from_int(res_ty[0]), tuple(args_tys_list)) 

784 op_signatures[op] = op_ty_sig 

785 return op_ty_sig 

786 

787 

788class PyvexOpMatchException(Exception): 

789 pass 

790 

791 

792class PyvexTypeErrorException(Exception): 

793 pass 

794 

795 

796def int_type_for_size(size): 

797 return "Ity_I%d" % size 

798 

799 

800# precompiled regexes 

801unop_signature_re = re.compile(r"Iop_(Not|Ctz|Clz)(?P<size>\d+)$") 

802binop_signature_re = re.compile(r"Iop_(Add|Sub|Mul|Xor|Or|And|Div[SU]|Mod)(?P<size>\d+)$") 

803shift_signature_re = re.compile(r"Iop_(Shl|Shr|Sar)(?P<size>\d+)$") 

804cmp_signature_re_1 = re.compile(r"Iop_Cmp(EQ|NE)(?P<size>\d+)$") 

805cmp_signature_re_2 = re.compile(r"Iop_Cmp(GT|GE|LT|LE)(?P<size>\d+)[SU]$") 

806mull_signature_re = re.compile(r"Iop_Mull[SU](?P<size>\d+)$") 

807half_signature_re = re.compile(r"Iop_DivMod[SU](?P<fullsize>\d+)to(?P<halfsize>\d+)$") 

808cast_signature_re = re.compile(r"Iop_(?P<srcsize>\d+)(U|S|HI|HL)?to(?P<dstsize>\d+)") 

809 

810 

811def unop_signature(op): 

812 m = unop_signature_re.match(op) 

813 if m is None: 

814 raise PyvexOpMatchException() 

815 size = int(m.group("size")) 

816 size_type = int_type_for_size(size) 

817 return size_type, (size_type,) 

818 

819 

820def binop_signature(op): 

821 m = binop_signature_re.match(op) 

822 if m is None: 

823 raise PyvexOpMatchException() 

824 size = int(m.group("size")) 

825 size_type = int_type_for_size(size) 

826 return (size_type, (size_type, size_type)) 

827 

828 

829def shift_signature(op): 

830 m = shift_signature_re.match(op) 

831 if m is None: 

832 raise PyvexOpMatchException() 

833 size = int(m.group("size")) 

834 if size > 255: 

835 raise PyvexTypeErrorException("Cannot apply shift operation to %d size int because shift index is 8-bit" % size) 

836 size_type = int_type_for_size(size) 

837 return (size_type, (size_type, int_type_for_size(8))) 

838 

839 

840def cmp_signature(op): 

841 m = cmp_signature_re_1.match(op) 

842 m2 = cmp_signature_re_2.match(op) 

843 if (m is None) == (m2 is None): 

844 raise PyvexOpMatchException() 

845 mfound = m if m is not None else m2 

846 size = int(mfound.group("size")) 

847 size_type = int_type_for_size(size) 

848 return (int_type_for_size(1), (size_type, size_type)) 

849 

850 

851def mull_signature(op): 

852 m = mull_signature_re.match(op) 

853 if m is None: 

854 raise PyvexOpMatchException() 

855 size = int(m.group("size")) 

856 size_type = int_type_for_size(size) 

857 doubled_size_type = int_type_for_size(2 * size) 

858 return (doubled_size_type, (size_type, size_type)) 

859 

860 

861def half_signature(op): 

862 m = half_signature_re.match(op) 

863 if m is None: 

864 raise PyvexOpMatchException() 

865 fullsize = int(m.group("fullsize")) 

866 halfsize = int(m.group("halfsize")) 

867 if halfsize * 2 != fullsize: 

868 raise PyvexTypeErrorException("Invalid Instruction %s: Type 1 must be twice the size of type 2" % op) 

869 fullsize_type = int_type_for_size(fullsize) 

870 halfsize_type = int_type_for_size(halfsize) 

871 return (fullsize_type, (fullsize_type, halfsize_type)) 

872 

873 

874def cast_signature(op): 

875 m = cast_signature_re.match(op) 

876 if m is None: 

877 raise PyvexOpMatchException() 

878 src_type = int_type_for_size(int(m.group("srcsize"))) 

879 dst_type = int_type_for_size(int(m.group("dstsize"))) 

880 return (dst_type, (src_type,)) 

881 

882 

883polymorphic_op_processors = [ 

884 unop_signature, 

885 binop_signature, 

886 shift_signature, 

887 cmp_signature, 

888 mull_signature, 

889 half_signature, 

890 cast_signature, 

891] 

892 

893 

894def _request_polymorphic_op_type(op): 

895 for polymorphic_signature in polymorphic_op_processors: 

896 try: 

897 op_ty_sig = polymorphic_signature(op) 

898 break 

899 except PyvexOpMatchException: 

900 continue 

901 else: 

902 raise PyvexOpMatchException("Op %s not recognized" % op) 

903 return op_ty_sig 

904 

905 

906_request_funcs = [_request_op_type_from_cache, _request_op_type_from_libvex, _request_polymorphic_op_type] 

907 

908 

909def op_arg_types(op): 

910 for _request_func in _request_funcs: 

911 try: 

912 return _request_func(op) 

913 except KeyError: 

914 continue 

915 raise ValueError("Cannot find type of op %s" % op) 

916 

917 

918_globals = globals().copy() 

919# 

920# Mapping from tag strings/enums to IRExpr classes 

921# 

922tag_to_expr_mapping = {} 

923enum_to_expr_mapping = {} 

924tag_count = 0 

925cls = None 

926for cls in _globals.values(): 

927 if type(cls) is type and issubclass(cls, IRExpr) and cls is not IRExpr: 

928 tag_to_expr_mapping[cls.tag] = cls 

929 enum_to_expr_mapping[get_int_from_enum(cls.tag)] = cls 

930 cls.tag_int = tag_count 

931 tag_count += 1 

932del cls 

933 

934 

935def tag_to_expr_class(tag): 

936 """ 

937 Convert a tag string to the corresponding IRExpr class type. 

938 

939 :param str tag: The tag string. 

940 :return: A class. 

941 :rtype: type 

942 """ 

943 

944 try: 

945 return tag_to_expr_mapping[tag] 

946 except KeyError: 

947 raise KeyError("Cannot find expression class for type %s." % tag) 

948 

949 

950def enum_to_expr_class(tag_enum): 

951 """ 

952 Convert a tag enum to the corresponding IRExpr class. 

953 

954 :param int tag_enum: The tag enum. 

955 :return: A class. 

956 :rtype: type 

957 """ 

958 

959 try: 

960 return enum_to_expr_mapping[tag_enum] 

961 except KeyError: 

962 raise KeyError("Cannot find expression class for type %s." % get_enum_from_int(tag_enum))