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

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

609 statements  

1import logging 

2import re 

3from typing import Dict, List, Optional, Tuple 

4 

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

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

7from .errors import PyVEXError 

8from .native import ffi, pvc 

9 

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

11 

12 

13class IRExpr(VEXObject): 

14 """ 

15 IR expressions in VEX represent operations without side effects. 

16 """ 

17 

18 __slots__ = [] 

19 

20 tag: Optional[str] = None 

21 tag_int = 0 # set automatically at bottom of file 

22 

23 def pp(self): 

24 print(str(self)) 

25 

26 def __str__(self): 

27 return self._pp_str() 

28 

29 def _pp_str(self) -> str: 

30 raise NotImplementedError 

31 

32 @property 

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

34 """ 

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

36 """ 

37 expressions = [] 

38 for k in self.__slots__: 

39 v = getattr(self, k) 

40 if isinstance(v, IRExpr): 

41 expressions.append(v) 

42 expressions.extend(v.child_expressions) 

43 return expressions 

44 

45 @property 

46 def constants(self): 

47 """ 

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

49 """ 

50 constants = [] 

51 for k in self.__slots__: 

52 v = getattr(self, k) 

53 if isinstance(v, IRExpr): 

54 constants.extend(v.constants) 

55 elif isinstance(v, IRConst): 

56 constants.append(v) 

57 return constants 

58 

59 def result_size(self, tyenv): 

60 return get_type_size(self.result_type(tyenv)) 

61 

62 def result_type(self, tyenv): 

63 raise NotImplementedError() 

64 

65 def replace_expression(self, replacements): 

66 """ 

67 Replace child expressions in-place. 

68 

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

70 :return: None 

71 """ 

72 

73 for k in self.__slots__: 

74 v = getattr(self, k) 

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

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

77 elif isinstance(v, list): 

78 # Replace the instance in the list 

79 for i, expr_ in enumerate(v): 

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

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

82 elif type(v) is tuple: 

83 # Rebuild the tuple 

84 _lst = [] 

85 replaced = False 

86 for i, expr_ in enumerate(v): 

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

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

89 replaced = True 

90 else: 

91 _lst.append(expr_) 

92 if replaced: 

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

94 elif isinstance(v, IRExpr): 

95 v.replace_expression(replacements) 

96 

97 @staticmethod 

98 def _from_c(c_expr) -> Optional["IRExpr"]: 

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

100 return None 

101 

102 try: 

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

104 except KeyError: 

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

106 

107 _translate = _from_c 

108 

109 @staticmethod 

110 def _to_c(expr): 

111 try: 

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

113 except KeyError: 

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

115 

116 def typecheck(self, tyenv): 

117 return self.result_type(tyenv) 

118 

119 

120class Binder(IRExpr): 

121 """ 

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

123 """ 

124 

125 __slots__ = ["binder"] 

126 

127 tag = "Iex_Binder" 

128 

129 def __init__(self, binder): 

130 self.binder = binder 

131 

132 def _pp_str(self): 

133 return "Binder" 

134 

135 @staticmethod 

136 def _from_c(c_expr): 

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

138 

139 @staticmethod 

140 def _to_c(expr): 

141 return pvc.IRExpr_Binder(expr.binder) 

142 

143 def result_type(self, tyenv): 

144 return "Ity_INVALID" 

145 

146 

147class VECRET(IRExpr): 

148 tag = "Iex_VECRET" 

149 

150 __slots__ = [] 

151 

152 def _pp_str(self): 

153 return "VECRET" 

154 

155 @staticmethod 

156 def _from_c(c_expr): 

157 return VECRET() 

158 

159 @staticmethod 

160 def _to_c(expr): 

161 return pvc.IRExpr_VECRET() 

162 

163 def result_type(self, tyenv): 

164 return "Ity_INVALID" 

165 

166 

167class GSPTR(IRExpr): 

168 __slots__ = [] 

169 

170 tag = "Iex_GSPTR" 

171 

172 def _pp_str(self): 

173 return "GSPTR" 

174 

175 @staticmethod 

176 def _from_c(c_expr): 

177 return GSPTR() 

178 

179 @staticmethod 

180 def _to_c(expr): 

181 return pvc.IRExpr_GSPTR() 

182 

183 def result_type(self, tyenv): 

184 return "Ity_INVALID" 

185 

186 

187class GetI(IRExpr): 

188 """ 

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

190 """ 

191 

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

193 

194 tag = "Iex_GetI" 

195 

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

197 self.descr = descr 

198 self.ix = ix 

199 self.bias = bias 

200 

201 @property 

202 def description(self): 

203 return self.descr 

204 

205 @property 

206 def index(self): 

207 return self.ix 

208 

209 def _pp_str(self): 

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

211 

212 @staticmethod 

213 def _from_c(c_expr): 

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

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

216 bias = c_expr.Iex.GetI.bias 

217 return GetI(descr, ix, bias) 

218 

219 @staticmethod 

220 def _to_c(expr): 

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

222 

223 def result_type(self, tyenv): 

224 return self.descr.elemTy 

225 

226 

227class RdTmp(IRExpr): 

228 """ 

229 Read the value held by a temporary. 

230 """ 

231 

232 __slots__ = ["_tmp"] 

233 

234 tag = "Iex_RdTmp" 

235 

236 def __init__(self, tmp): 

237 self._tmp = tmp 

238 

239 def _pp_str(self): 

240 return "t%d" % self.tmp 

241 

242 @property 

243 def tmp(self): 

244 return self._tmp 

245 

246 @staticmethod 

247 def _from_c(c_expr): 

248 tmp = c_expr.Iex.RdTmp.tmp 

249 return RdTmp.get_instance(tmp) 

250 

251 @staticmethod 

252 def _to_c(expr): 

253 return pvc.IRExpr_RdTmp(expr.tmp) 

254 

255 @staticmethod 

256 def get_instance(tmp): 

257 if tmp < 1024: 

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

259 return _RDTMP_POOL[tmp] 

260 return RdTmp(tmp) 

261 

262 def replace_expression(self, replacements): 

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

264 pass 

265 

266 def result_type(self, tyenv): 

267 return tyenv.lookup(self.tmp) 

268 

269 def __hash__(self): 

270 return 133700 + self._tmp 

271 

272 

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

274 

275 

276class Get(IRExpr): 

277 """ 

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

279 """ 

280 

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

282 

283 tag = "Iex_Get" 

284 

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

286 self.offset = offset 

287 if ty_int is None: 

288 self.ty_int = get_int_from_enum(ty) 

289 else: 

290 self.ty_int = ty_int 

291 

292 @property 

293 def ty(self): 

294 return get_enum_from_int(self.ty_int) 

295 

296 @property 

297 def type(self): 

298 return get_enum_from_int(self.ty_int) 

299 

300 def _pp_str(self): 

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

302 

303 def pp_str_with_name(self, reg_name: str): 

304 """pp_str_with_name is used to print the expression with the name of the 

305 register instead of the offset""" 

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

307 

308 @staticmethod 

309 def _from_c(c_expr): 

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

311 

312 @staticmethod 

313 def _to_c(expr): 

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

315 

316 def result_type(self, tyenv): 

317 return self.ty 

318 

319 def __hash__(self): 

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

321 

322 

323class Qop(IRExpr): 

324 """ 

325 A quaternary operation (4 arguments). 

326 """ 

327 

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

329 

330 tag = "Iex_Qop" 

331 

332 def __init__(self, op, args): 

333 self.op = op 

334 self.args = args 

335 

336 def _pp_str(self): 

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

338 

339 @property 

340 def child_expressions(self): 

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

342 expressions.extend(self.args) 

343 return expressions 

344 

345 @staticmethod 

346 def _from_c(c_expr): 

347 return Qop( 

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

349 [ 

350 IRExpr._from_c(arg) 

351 for arg in [ 

352 c_expr.Iex.Qop.details.arg1, 

353 c_expr.Iex.Qop.details.arg2, 

354 c_expr.Iex.Qop.details.arg3, 

355 c_expr.Iex.Qop.details.arg4, 

356 ] 

357 ], 

358 ) 

359 

360 @staticmethod 

361 def _to_c(expr): 

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

363 

364 def result_type(self, tyenv): 

365 return get_op_retty(self.op) 

366 

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

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

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

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

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

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

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

374 return None 

375 

376 if arg1ty_real != arg1ty: 

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

378 return None 

379 if arg2ty_real != arg2ty: 

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

381 return None 

382 if arg3ty_real != arg3ty: 

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

384 return None 

385 if arg4ty_real != arg4ty: 

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

387 return None 

388 

389 return resty 

390 

391 

392class Triop(IRExpr): 

393 """ 

394 A ternary operation (3 arguments) 

395 """ 

396 

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

398 

399 tag = "Iex_Triop" 

400 

401 def __init__(self, op, args): 

402 self.op = op 

403 self.args = args 

404 

405 def _pp_str(self): 

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

407 

408 @property 

409 def child_expressions(self): 

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

411 expressions.extend(self.args) 

412 return expressions 

413 

414 @staticmethod 

415 def _from_c(c_expr): 

416 return Triop( 

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

418 [ 

419 IRExpr._from_c(arg) 

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

421 ], 

422 ) 

423 

424 @staticmethod 

425 def _to_c(expr): 

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

427 

428 def result_type(self, tyenv): 

429 return get_op_retty(self.op) 

430 

431 def typecheck(self, tyenv): 

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

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

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

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

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

437 return None 

438 

439 if arg1ty_real != arg1ty: 

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

441 return None 

442 if arg2ty_real != arg2ty: 

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

444 return None 

445 if arg3ty_real != arg3ty: 

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

447 return None 

448 

449 return resty 

450 

451 

452class Binop(IRExpr): 

453 """ 

454 A binary operation (2 arguments). 

455 """ 

456 

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

458 

459 tag = "Iex_Binop" 

460 

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

462 self.op_int = op_int 

463 self.args = args 

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

465 

466 def _pp_str(self): 

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

468 

469 @property 

470 def op(self): 

471 if self._op is None: 

472 self._op = get_enum_from_int(self.op_int) 

473 return self._op 

474 

475 @property 

476 def child_expressions(self): 

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

478 expressions.extend(self.args) 

479 return expressions 

480 

481 @staticmethod 

482 def _from_c(c_expr): 

483 return Binop( 

484 None, 

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

486 op_int=c_expr.Iex.Binop.op, 

487 ) 

488 

489 @staticmethod 

490 def _to_c(expr): 

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

492 

493 def result_type(self, tyenv): 

494 return get_op_retty(self.op) 

495 

496 def typecheck(self, tyenv): 

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

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

499 

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

501 if arg1ty_real is None or arg2ty_real is None: 

502 return None 

503 

504 if arg1ty_real != arg1ty: 

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

506 return None 

507 if arg2ty_real != arg2ty: 

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

509 return None 

510 

511 return resty 

512 

513 

514class Unop(IRExpr): 

515 """ 

516 A unary operation (1 argument). 

517 """ 

518 

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

520 

521 tag = "Iex_Unop" 

522 

523 def __init__(self, op, args): 

524 self.op = op 

525 self.args = args 

526 

527 def _pp_str(self): 

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

529 

530 @property 

531 def child_expressions(self): 

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

533 expressions.extend(self.args) 

534 return expressions 

535 

536 @staticmethod 

537 def _from_c(c_expr): 

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

539 

540 @staticmethod 

541 def _to_c(expr): 

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

543 

544 def result_type(self, tyenv): 

545 return get_op_retty(self.op) 

546 

547 def typecheck(self, tyenv): 

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

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

550 if arg1ty_real is None: 

551 return None 

552 

553 if arg1ty_real != arg1ty: 

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

555 return None 

556 

557 return resty 

558 

559 

560class Load(IRExpr): 

561 """ 

562 A load from memory. 

563 """ 

564 

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

566 

567 tag = "Iex_Load" 

568 

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

570 self.end = end 

571 self.ty = ty 

572 self.addr = addr 

573 

574 @property 

575 def endness(self): 

576 return self.end 

577 

578 @property 

579 def type(self): 

580 return self.ty 

581 

582 def _pp_str(self): 

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

584 

585 @staticmethod 

586 def _from_c(c_expr): 

587 return Load( 

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

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

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

591 ) 

592 

593 @staticmethod 

594 def _to_c(expr): 

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

596 

597 def result_type(self, tyenv): 

598 return self.ty 

599 

600 def typecheck(self, tyenv): 

601 addrty = self.addr.typecheck(tyenv) 

602 if addrty is None: 

603 return None 

604 if addrty != tyenv.wordty: 

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

606 return None 

607 return self.ty 

608 

609 

610class Const(IRExpr): 

611 """ 

612 A constant expression. 

613 """ 

614 

615 __slots__ = ["_con"] 

616 

617 tag = "Iex_Const" 

618 

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

620 self._con = con 

621 

622 def _pp_str(self): 

623 return str(self.con) 

624 

625 @property 

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

627 return self._con 

628 

629 @staticmethod 

630 def _from_c(c_expr): 

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

632 return Const.get_instance(con) 

633 

634 @staticmethod 

635 def _to_c(expr): 

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

637 

638 @staticmethod 

639 def get_instance(con): 

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

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

642 return Const(con) 

643 

644 def result_type(self, tyenv): 

645 return self.con.type 

646 

647 

648_CONST_POOL = { 

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

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

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

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

653} 

654 

655 

656class ITE(IRExpr): 

657 """ 

658 An if-then-else expression. 

659 """ 

660 

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

662 

663 tag = "Iex_ITE" 

664 

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

666 self.cond = cond 

667 self.iffalse = iffalse 

668 self.iftrue = iftrue 

669 

670 def _pp_str(self): 

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

672 

673 @staticmethod 

674 def _from_c(c_expr): 

675 return ITE( 

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

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

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

679 ) 

680 

681 @staticmethod 

682 def _to_c(expr): 

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

684 

685 def result_type(self, tyenv): 

686 return self.iftrue.result_type(tyenv) 

687 

688 def typecheck(self, tyenv): 

689 condty = self.cond.typecheck(tyenv) 

690 falsety = self.iffalse.typecheck(tyenv) 

691 truety = self.iftrue.typecheck(tyenv) 

692 

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

694 return None 

695 

696 if condty != "Ity_I1": 

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

698 return None 

699 

700 if falsety != truety: 

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

702 return None 

703 

704 return falsety 

705 

706 

707class CCall(IRExpr): 

708 """ 

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

710 """ 

711 

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

713 

714 tag = "Iex_CCall" 

715 

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

717 self.retty = retty 

718 self.cee = cee 

719 self.args = tuple(args) 

720 

721 @property 

722 def ret_type(self): 

723 return self.retty 

724 

725 @property 

726 def callee(self): 

727 return self.cee 

728 

729 def _pp_str(self): 

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

731 

732 @property 

733 def child_expressions(self): 

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

735 expressions.extend(self.args) 

736 return expressions 

737 

738 @staticmethod 

739 def _from_c(c_expr): 

740 i = 0 

741 args = [] 

742 while True: 

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

744 if arg == ffi.NULL: 

745 break 

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

747 i += 1 

748 

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

750 

751 @staticmethod 

752 def _to_c(expr): 

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

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

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

756 

757 def result_type(self, tyenv): 

758 return self.retty 

759 

760 

761def get_op_retty(op): 

762 return op_arg_types(op)[0] 

763 

764 

765op_signatures: Dict[str, Tuple[str, Tuple[str, ...]]] = {} 

766 

767 

768def _request_op_type_from_cache(op): 

769 return op_signatures[op] 

770 

771 

772def _request_op_type_from_libvex(op): 

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

774 

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

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

777 # initialize all IRTypes to Ity_INVALID 

778 for arg in arg_tys: 

779 arg[0] = Ity_INVALID 

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

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

782 

783 try: 

784 numargs = arg_ty_vals.index(Ity_INVALID) 

785 except ValueError: 

786 numargs = 4 

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

788 

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

790 op_signatures[op] = op_ty_sig 

791 return op_ty_sig 

792 

793 

794class PyvexOpMatchException(Exception): 

795 pass 

796 

797 

798class PyvexTypeErrorException(Exception): 

799 pass 

800 

801 

802def int_type_for_size(size): 

803 return "Ity_I%d" % size 

804 

805 

806# precompiled regexes 

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

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

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

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

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

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

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

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

815 

816 

817def unop_signature(op): 

818 m = unop_signature_re.match(op) 

819 if m is None: 

820 raise PyvexOpMatchException() 

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

822 size_type = int_type_for_size(size) 

823 return size_type, (size_type,) 

824 

825 

826def binop_signature(op): 

827 m = binop_signature_re.match(op) 

828 if m is None: 

829 raise PyvexOpMatchException() 

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

831 size_type = int_type_for_size(size) 

832 return (size_type, (size_type, size_type)) 

833 

834 

835def shift_signature(op): 

836 m = shift_signature_re.match(op) 

837 if m is None: 

838 raise PyvexOpMatchException() 

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

840 if size > 255: 

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

842 size_type = int_type_for_size(size) 

843 return (size_type, (size_type, int_type_for_size(8))) 

844 

845 

846def cmp_signature(op): 

847 m = cmp_signature_re_1.match(op) 

848 m2 = cmp_signature_re_2.match(op) 

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

850 raise PyvexOpMatchException() 

851 mfound = m if m is not None else m2 

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

853 size_type = int_type_for_size(size) 

854 return (int_type_for_size(1), (size_type, size_type)) 

855 

856 

857def mull_signature(op): 

858 m = mull_signature_re.match(op) 

859 if m is None: 

860 raise PyvexOpMatchException() 

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

862 size_type = int_type_for_size(size) 

863 doubled_size_type = int_type_for_size(2 * size) 

864 return (doubled_size_type, (size_type, size_type)) 

865 

866 

867def half_signature(op): 

868 m = half_signature_re.match(op) 

869 if m is None: 

870 raise PyvexOpMatchException() 

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

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

873 if halfsize * 2 != fullsize: 

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

875 fullsize_type = int_type_for_size(fullsize) 

876 halfsize_type = int_type_for_size(halfsize) 

877 return (fullsize_type, (fullsize_type, halfsize_type)) 

878 

879 

880def cast_signature(op): 

881 m = cast_signature_re.match(op) 

882 if m is None: 

883 raise PyvexOpMatchException() 

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

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

886 return (dst_type, (src_type,)) 

887 

888 

889polymorphic_op_processors = [ 

890 unop_signature, 

891 binop_signature, 

892 shift_signature, 

893 cmp_signature, 

894 mull_signature, 

895 half_signature, 

896 cast_signature, 

897] 

898 

899 

900def _request_polymorphic_op_type(op): 

901 for polymorphic_signature in polymorphic_op_processors: 

902 try: 

903 op_ty_sig = polymorphic_signature(op) 

904 break 

905 except PyvexOpMatchException: 

906 continue 

907 else: 

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

909 return op_ty_sig 

910 

911 

912_request_funcs = [_request_op_type_from_cache, _request_op_type_from_libvex, _request_polymorphic_op_type] 

913 

914 

915def op_arg_types(op): 

916 for _request_func in _request_funcs: 

917 try: 

918 return _request_func(op) 

919 except KeyError: 

920 continue 

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

922 

923 

924_globals = globals().copy() 

925# 

926# Mapping from tag strings/enums to IRExpr classes 

927# 

928tag_to_expr_mapping = {} 

929enum_to_expr_mapping = {} 

930tag_count = 0 

931cls = None 

932for cls in _globals.values(): 

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

934 tag_to_expr_mapping[cls.tag] = cls 

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

936 cls.tag_int = tag_count 

937 tag_count += 1 

938del cls 

939 

940 

941def tag_to_expr_class(tag): 

942 """ 

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

944 

945 :param str tag: The tag string. 

946 :return: A class. 

947 :rtype: type 

948 """ 

949 

950 try: 

951 return tag_to_expr_mapping[tag] 

952 except KeyError: 

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

954 

955 

956def enum_to_expr_class(tag_enum): 

957 """ 

958 Convert a tag enum to the corresponding IRExpr class. 

959 

960 :param int tag_enum: The tag enum. 

961 :return: A class. 

962 :rtype: type 

963 """ 

964 

965 try: 

966 return enum_to_expr_mapping[tag_enum] 

967 except KeyError: 

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