1# pylint:disable=no-self-use
2from typing import Tuple, Optional
3import logging
4
5import ailment
6import pyvex
7import archinfo
8
9from ...engines.vex.claripy.irop import UnsupportedIROpError, vexop_to_simop
10from ...code_location import CodeLocation
11from ...utils.constants import DEFAULT_STATEMENT
12from ..engine import SimEngine
13
14
15class SimEngineLight(SimEngine):
16    def __init__(self):
17        super(SimEngineLight, self).__init__()
18
19        self.l = logging.getLogger(self.__module__ + "." + self.__class__.__name__)
20
21        # local variables
22        self.state = None
23        self.arch = None
24        self.block = None
25        self._call_stack = None
26
27        self.stmt_idx = None
28        self.ins_addr = None
29        self.tmps = None
30
31        # for VEX blocks only
32        self.tyenv = None
33
34    def process(self, state, *args, **kwargs):
35        # we are using a completely different state. Therefore, we directly call our _process() method before
36        # SimEngine becomes flexible enough.
37        self._process(state, None, block=kwargs.pop('block', None), whitelist=kwargs.pop('whitelist', None))
38
39    def _process(self, new_state, successors, *args, **kwargs):
40        raise NotImplementedError()
41
42    def _check(self, state, *args, **kwargs):
43        return True
44
45    #
46    # Helper methods
47    #
48
49    @property
50    def _context(self) -> Optional[Tuple[int]]:
51        if self._call_stack is None:
52            # contextless mode
53            return None
54
55        if not self._call_stack:
56            # contextful but the callstack is empty
57            return tuple()
58
59        # Convert to Tuple to make `context` hashable if not None
60        call_stack_addresses = tuple(self._call_stack)
61        return call_stack_addresses
62
63    def _codeloc(self, block_only=False):
64        return CodeLocation(self.block.addr,
65                            None if block_only else self.stmt_idx,
66                            ins_addr=None if block_only else self.ins_addr,
67                            context=self._context
68                            )
69
70
71class SimEngineLightVEXMixin:
72
73    def _process(self, state, successors, *args, block, whitelist=None, **kwargs):  # pylint:disable=arguments-differ,unused-argument
74
75        # initialize local variables
76        self.tmps = {}
77        self.block = block
78        self.state = state
79
80        if state is not None:
81            self.arch: archinfo.Arch = state.arch
82
83        self.tyenv = block.vex.tyenv
84
85        self._process_Stmt(whitelist=whitelist)
86
87        self.stmt_idx = None
88        self.ins_addr = None
89
90    def _process_Stmt(self, whitelist=None):
91
92        if whitelist is not None:
93            # optimize whitelist lookups
94            whitelist = set(whitelist)
95
96        for stmt_idx, stmt in enumerate(self.block.vex.statements):
97            if whitelist is not None and stmt_idx not in whitelist:
98                continue
99            self.stmt_idx = stmt_idx
100
101            if type(stmt) is pyvex.IRStmt.IMark:
102                # Note that we cannot skip IMarks as they are used later to trigger observation events
103                # The bug caused by skipping IMarks is reported at https://github.com/angr/angr/pull/1150
104                self.ins_addr = stmt.addr + stmt.delta
105
106            self._handle_Stmt(stmt)
107
108        self._process_block_end()
109
110    def _process_block_end(self):
111        # handle calls to another function
112        # Note that without global information, we cannot handle cases where we *jump* to another function (jumpkind ==
113        # "Ijk_Boring"). Users are supposed to overwrite this method, detect these cases with the help of global
114        # information (such as CFG or symbol addresses), and handle them accordingly.
115        if self.block.vex.jumpkind == 'Ijk_Call':
116            self.stmt_idx = DEFAULT_STATEMENT
117            handler = '_handle_function'
118            if hasattr(self, handler):
119                func_addr = self._expr(self.block.vex.next)
120                if func_addr is not None:
121                    getattr(self, handler)(func_addr)
122                else:
123                    self.l.debug('Cannot determine the callee address at %#x.', self.block.addr)
124            else:
125                self.l.warning('Function handler not implemented.')
126
127    #
128    # Statement handlers
129    #
130
131    def _handle_Stmt(self, stmt):
132        handler = "_handle_%s" % type(stmt).__name__
133        if hasattr(self, handler):
134            getattr(self, handler)(stmt)
135        elif type(stmt).__name__ not in ('IMark', 'AbiHint'):
136            self.l.error('Unsupported statement type %s.', type(stmt).__name__)
137
138    # synchronize with function _handle_WrTmpData()
139    def _handle_WrTmp(self, stmt):
140        data = self._expr(stmt.data)
141        if data is None:
142            return
143
144        self.tmps[stmt.tmp] = data
145
146    # invoked by LoadG
147    def _handle_WrTmpData(self, tmp, data):
148        if data is None:
149            return
150        self.tmps[tmp] = data
151
152    def _handle_Put(self, stmt):
153        raise NotImplementedError('Please implement the Put handler with your own logic.')
154
155    def _handle_Store(self, stmt):
156        raise NotImplementedError('Please implement the Store handler with your own logic.')
157
158    def _handle_StoreG(self, stmt):
159        raise NotImplementedError('Please implement the StoreG handler with your own logic.')
160
161    def _handle_LLSC(self, stmt: pyvex.IRStmt.LLSC):
162        raise NotImplementedError('Please implement the LLSC handler with your own logic.')
163
164    #
165    # Expression handlers
166    #
167
168    def _expr(self, expr):
169
170        handler = "_handle_%s" % type(expr).__name__
171        if hasattr(self, handler):
172            return getattr(self, handler)(expr)
173        else:
174            self.l.error('Unsupported expression type %s.', type(expr).__name__)
175        return None
176
177    def _handle_RdTmp(self, expr):
178        tmp = expr.tmp
179
180        if tmp in self.tmps:
181            return self.tmps[tmp]
182        return None
183
184    def _handle_Get(self, expr):
185        raise NotImplementedError('Please implement the Get handler with your own logic.')
186
187    def _handle_Load(self, expr):
188        raise NotImplementedError('Please implement the Load handler with your own logic.')
189
190    def _handle_LoadG(self, stmt):
191        raise NotImplementedError('Please implement the LoadG handler with your own logic.')
192
193    def _handle_Exit(self, stmt):
194        self._expr(stmt.guard)
195        self._expr(stmt.dst)
196
197    def _handle_ITE(self, expr):
198        # EDG says: Not sure how generic this is.
199        cond = self._expr(expr.cond)
200        if cond is True:
201            return self._expr(expr.iftrue)
202        elif cond is False:
203            return self._expr(expr.iffalse)
204        else:
205            return None
206
207    def _handle_Unop(self, expr):
208        handler = None
209
210        # All conversions are handled by the Conversion handler
211        simop = None
212        try:
213            simop = vexop_to_simop(expr.op)
214        except UnsupportedIROpError:
215            pass
216
217        if simop is not None and simop.op_attrs.get('conversion', None):
218            handler = '_handle_Conversion'
219        # Notice order of "Not" comparisons
220        elif expr.op == 'Iop_Not1':
221            handler = '_handle_Not1'
222        elif expr.op.startswith('Iop_Not'):
223            handler = '_handle_Not'
224
225        if handler is not None and hasattr(self, handler):
226            return getattr(self, handler)(expr)
227        else:
228            self.l.error('Unsupported Unop %s.', expr.op)
229            return None
230
231    def _handle_Binop(self, expr):
232        handler = None
233        if expr.op.startswith('Iop_And'):
234            handler = '_handle_And'
235        elif expr.op.startswith('Iop_Mod'):
236            handler = '_handle_Mod'
237        elif expr.op.startswith('Iop_Or'):
238            handler = '_handle_Or'
239        elif expr.op.startswith('Iop_Add'):
240            handler = '_handle_Add'
241        elif expr.op.startswith('Iop_Sub'):
242            handler = '_handle_Sub'
243        elif expr.op.startswith('Iop_Mul'):
244            handler = "_handle_Mul"
245        elif expr.op.startswith('Iop_Div'):
246            handler = "_handle_Div"
247        elif expr.op.startswith('Iop_Xor'):
248            handler = '_handle_Xor'
249        elif expr.op.startswith('Iop_Shl'):
250            handler = '_handle_Shl'
251        elif expr.op.startswith('Iop_Shr'):
252            handler = '_handle_Shr'
253        elif expr.op.startswith('Iop_Sal'):
254            # intended use of SHL
255            handler = '_handle_Shl'
256        elif expr.op.startswith('Iop_Sar'):
257            handler = '_handle_Sar'
258        elif expr.op.startswith('Iop_CmpEQ'):
259            handler = '_handle_CmpEQ'
260        elif expr.op.startswith('Iop_CmpNE'):
261            handler = '_handle_CmpNE'
262        elif expr.op.startswith('Iop_CmpLT'):
263            handler = '_handle_CmpLT'
264        elif expr.op.startswith('Iop_CmpLE'):
265            handler = '_handle_CmpLE'
266        elif expr.op.startswith('Iop_CmpGE'):
267            handler = '_handle_CmpGE'
268        elif expr.op.startswith('Iop_CmpGT'):
269            handler = '_handle_CmpGT'
270        elif expr.op.startswith('Iop_CmpORD'):
271            handler = '_handle_CmpORD'
272        elif expr.op == 'Iop_32HLto64':
273            handler = '_handle_32HLto64'
274        elif expr.op.startswith('Const'):
275            handler = '_handle_Const'
276        if handler is not None and hasattr(self, handler):
277            return getattr(self, handler)(expr)
278        else:
279            self.l.error('Unsupported Binop %s.', expr.op)
280
281        return None
282
283    def _handle_CCall(self, expr):  # pylint:disable=useless-return
284        self.l.warning('Unsupported expression type CCall with callee %s.', str(expr.cee))
285        return None
286
287    #
288    # Unary operation handlers
289    #
290
291    def _handle_U32(self, expr):
292        return expr.value
293
294    def _handle_U64(self, expr):
295        return expr.value
296
297    def _handle_U16(self, expr):
298        return expr.value
299
300    def _handle_U8(self, expr):
301        return expr.value
302
303    def _handle_U1(self, expr):
304        return expr.value
305
306    def _handle_Const(self, expr):  # pylint:disable=no-self-use
307        return expr.con.value
308
309    def _handle_Conversion(self, expr):
310        expr = self._expr(expr.args[0])
311        if expr is None:
312            return None
313
314        # FIXME: implement real conversion
315        return expr
316
317    #
318    # Binary operation handlers
319    #
320
321    def _handle_And(self, expr):
322        arg0, arg1 = expr.args
323        expr_0 = self._expr(arg0)
324        if expr_0 is None:
325            return None
326        expr_1 = self._expr(arg1)
327        if expr_1 is None:
328            return None
329
330        try:
331            return expr_0 & expr_1
332        except TypeError as e:
333            self.l.warning(e)
334            return None
335
336    def _handle_Or(self, expr):
337        arg0, arg1 = expr.args
338        expr_0 = self._expr(arg0)
339        if expr_0 is None:
340            return None
341        expr_1 = self._expr(arg1)
342        if expr_1 is None:
343            return None
344
345        try:
346            return expr_0 | expr_1
347        except TypeError as e:
348            self.l.warning(e)
349            return None
350
351    def _handle_Not1(self, expr):
352        return self._handle_Not(expr)
353
354    def _handle_Not(self, expr):
355        arg0 = expr.args[0]
356        expr_0 = self._expr(arg0)
357        if expr_0 is None:
358            return None
359        try:
360            return ~expr_0  # pylint:disable=invalid-unary-operand-type
361        except TypeError as e:
362            self.l.exception(e)
363            return None
364
365    def _handle_Add(self, expr):
366        arg0, arg1 = expr.args
367        expr_0 = self._expr(arg0)
368        if expr_0 is None:
369            return None
370        expr_1 = self._expr(arg1)
371        if expr_1 is None:
372            return None
373
374        try:
375            if isinstance(expr_0, int) and isinstance(expr_1, int):
376                # self.tyenv is not used
377                mask = (1 << expr.result_size(self.tyenv)) - 1
378                return (expr_0 + expr_1) & mask
379            else:
380                return expr_0 + expr_1
381        except TypeError as e:
382            self.l.warning(e)
383            return None
384
385    def _handle_Sub(self, expr):
386        arg0, arg1 = expr.args
387        expr_0 = self._expr(arg0)
388        if expr_0 is None:
389            return None
390        expr_1 = self._expr(arg1)
391        if expr_1 is None:
392            return None
393
394        try:
395            if isinstance(expr_0, int) and isinstance(expr_1, int):
396                # self.tyenv is not used
397                mask = (1 << expr.result_size(self.tyenv)) - 1
398                return (expr_0 - expr_1) & mask
399            else:
400                return expr_0 - expr_1
401        except TypeError as e:
402            self.l.warning(e)
403            return None
404
405    def _handle_Mul(self, expr):
406        arg0, arg1 = expr.args
407        expr_0 = self._expr(arg0)
408        if expr_0 is None:
409            return None
410        expr_1 = self._expr(arg1)
411        if expr_1 is None:
412            return None
413
414        try:
415            if isinstance(expr_0, int) and isinstance(expr_1, int):
416                # self.tyenv is not used
417                mask = (1 << expr.result_size(self.tyenv)) - 1
418                return (expr_0 * expr_1) & mask
419            else:
420                return expr_0 * expr_1
421        except TypeError as e:
422            self.l.warning(e)
423            return None
424
425    def _handle_Div(self, expr):
426        arg0, arg1 = expr.args
427        expr_0 = self._expr(arg0)
428        if expr_0 is None:
429            return None
430        expr_1 = self._expr(arg1)
431        if expr_1 is None:
432            return None
433
434        try:
435            # TODO: Probably should take care of the sign
436            return expr_0 // expr_1
437        except TypeError as e:
438            self.l.warning(e)
439            return None
440        except ZeroDivisionError as e:
441            self.l.warning(e)
442            return None
443
444    def _handle_Mod(self, expr):
445        arg0, arg1 = expr.args
446        expr_0 = self._expr(arg0)
447        if expr_0 is None:
448            return None
449        expr_1 = self._expr(arg1)
450        if expr_1 is None:
451            return None
452
453        try:
454            # TODO: Probably should take care of the sign
455            return expr_0 - (expr_0 // expr_1)*expr_1
456        except TypeError as e:
457            self.l.warning(e)
458            return None
459
460    def _handle_Xor(self, expr):
461        arg0, arg1 = expr.args
462        expr_0 = self._expr(arg0)
463        if expr_0 is None:
464            return None
465        expr_1 = self._expr(arg1)
466        if expr_1 is None:
467            return None
468
469        try:
470            return expr_0 ^ expr_1
471        except TypeError as e:
472            self.l.warning(e)
473            return None
474
475    def _handle_Shl(self, expr):
476        arg0, arg1 = expr.args
477
478        expr_0 = self._expr(arg0)
479        if expr_0 is None:
480            return None
481        expr_1 = self._expr(arg1)
482        if expr_1 is None:
483            return None
484        #elif expr_1 < 0:
485        #    expr.args = [expr_0, -1*expr_1]
486         #   return self._handle_Shr(expr)
487        try:
488            if isinstance(expr_0, int) and isinstance(expr_1, int):
489                # self.tyenv is not used
490                mask = (1 << expr.result_size(self.tyenv)) - 1
491                if expr_1 < 0:
492                    return (expr_0 >> -expr_1) & mask
493                else:
494                    return (expr_0 << expr_1) & mask
495            else:
496                return expr_0 << expr_1
497        except TypeError as e:
498            self.l.warning(e)
499            return None
500
501    def _handle_Shr(self, expr):
502        arg0, arg1 = expr.args
503        expr_0 = self._expr(arg0)
504        if expr_0 is None:
505            return None
506        expr_1 = self._expr(arg1)
507        if expr_1 is None:
508            return None
509
510        try:
511            if expr_1 < 0:
512                return expr_0 << -expr_1
513            else:
514                return expr_0 >> expr_1
515        except TypeError as e:
516            self.l.warning(e)
517            return None
518
519    def _handle_Sar(self, expr):
520        # EDG asks: is this right?
521        arg0, arg1 = expr.args
522        expr_0 = self._expr(arg0)
523        if expr_0 is None:
524            return None
525        expr_1 = self._expr(arg1)
526        if expr_1 is None:
527            return None
528        try:
529            return expr_0 >> expr_1
530        except TypeError as e:
531            self.l.warning(e)
532            return None
533
534    def _handle_CmpEQ(self, expr):
535        arg0, arg1 = expr.args
536        expr_0 = self._expr(arg0)
537        if expr_0 is None:
538            return None
539        expr_1 = self._expr(arg1)
540        if expr_1 is None:
541            return None
542
543        try:
544            return expr_0 == expr_1
545        except TypeError as ex:
546            self.l.warning(ex)
547            return None
548
549    def _handle_CmpNE(self, expr):
550        arg0, arg1 = expr.args
551        expr_0 = self._expr(arg0)
552        if expr_0 is None:
553            return None
554        expr_1 = self._expr(arg1)
555        if expr_1 is None:
556            return None
557
558        try:
559            return expr_0 != expr_1
560        except TypeError as ex:
561            self.l.warning(ex)
562            return None
563
564    def _handle_CmpLE(self, expr):
565        arg0, arg1 = expr.args
566        expr_0 = self._expr(arg0)
567        if expr_0 is None:
568            return None
569        expr_1 = self._expr(arg1)
570        if expr_1 is None:
571            return None
572
573        try:
574            return expr_0 <= expr_1
575        except TypeError as ex:
576            self.l.warning(ex)
577            return None
578
579    def _handle_CmpGE(self, expr):
580        arg0, arg1 = expr.args
581        expr_0 = self._expr(arg0)
582        if expr_0 is None:
583            return None
584        expr_1 = self._expr(arg1)
585        if expr_1 is None:
586            return None
587
588        try:
589            return expr_0 >= expr_1
590        except TypeError as ex:
591            self.l.warning(ex)
592            return None
593
594    def _handle_CmpLT(self, expr):
595        arg0, arg1 = expr.args
596        expr_0 = self._expr(arg0)
597        if expr_0 is None:
598            return None
599        expr_1 = self._expr(arg1)
600        if expr_1 is None:
601            return None
602
603        try:
604            return expr_0 < expr_1
605        except TypeError as ex:
606            self.l.warning(ex)
607            return None
608
609    def _handle_CmpGT(self, expr):
610        arg0, arg1 = expr.args
611        expr_0 = self._expr(arg0)
612        if expr_0 is None:
613            return None
614        expr_1 = self._expr(arg1)
615        if expr_1 is None:
616            return None
617
618        try:
619            return expr_0 > expr_1
620        except TypeError as ex:
621            self.l.warning(ex)
622            return None
623
624    def _handle_MBE(self, expr):  # pylint:disable=unused-argument
625        # Yeah.... no.
626        return None
627
628    def _handle_32HLto64(self, expr):
629        arg0, arg1 = expr.args
630        expr_0 = self._expr(arg0)
631        if expr_0 is None:
632            return None
633        expr_1 = self._expr(arg1)
634        if expr_1 is None:
635            return None
636
637        return None
638
639
640class SimEngineLightAILMixin:
641
642    def _process(self, state, successors, *args, block=None, whitelist=None, **kwargs):  # pylint:disable=arguments-differ,unused-argument
643
644        self.tmps = {}
645        self.block = block
646        self.state = state
647        self.arch = state.arch
648
649        self._process_Stmt(whitelist=whitelist)
650
651        self.stmt_idx = None
652        self.ins_addr = None
653
654    def _process_Stmt(self, whitelist=None):
655
656        if whitelist is not None:
657            whitelist = set(whitelist)
658
659        for stmt_idx, stmt in enumerate(self.block.statements):
660            if whitelist is not None and stmt_idx not in whitelist:
661                continue
662
663            self.stmt_idx = stmt_idx
664            self.ins_addr = stmt.ins_addr
665
666            self._handle_Stmt(stmt)
667
668    def _expr(self, expr):
669
670        expr_type_name = type(expr).__name__
671        if isinstance(expr, ailment.Stmt.Call):
672            # Call can be both an expression and a statement. Add a suffix to make sure we are working on the expression
673            # variant.
674            expr_type_name += "Expr"
675
676        h = None
677        handler = "_handle_%s" % expr_type_name
678        if hasattr(self, handler):
679            h = getattr(self, handler)
680
681        if h is None:
682            handler = "_ail_handle_%s" % expr_type_name
683            if hasattr(self, handler):
684                h = getattr(self, handler)
685
686        if h is not None:
687            return h(expr)
688        self.l.warning('Unsupported expression type %s.', type(expr).__name__)
689        return None
690
691    #
692    # Helper methods
693    #
694
695    def _codeloc(self):
696        return CodeLocation(self.block.addr, self.stmt_idx, ins_addr=self.ins_addr, context=self._context)
697
698    #
699    # Statement handlers
700    #
701
702    def _handle_Stmt(self, stmt):
703        handler = "_handle_%s" % type(stmt).__name__
704        if hasattr(self, handler):
705            getattr(self, handler)(stmt)
706            return
707
708        # compatibility
709        old_handler = "_ail_handle_%s" % type(stmt).__name__
710        if hasattr(self, old_handler):
711            getattr(self, old_handler)(stmt)
712            return
713
714        self.l.warning('Unsupported statement type %s.', type(stmt).__name__)
715
716    def _ail_handle_Jump(self, stmt):
717        raise NotImplementedError('Please implement the Jump handler with your own logic.')
718
719    def _ail_handle_Call(self, stmt):
720        raise NotImplementedError('Please implement the Call handler with your own logic.')
721
722    def _ail_handle_Return(self, stmt):
723        raise NotImplementedError('Please implement the Return handler with your own logic.')
724
725    #
726    # Expression handlers
727    #
728
729    def _ail_handle_Const(self, expr):  # pylint:disable=no-self-use
730        return expr.value
731
732    def _ail_handle_Tmp(self, expr):
733        tmp_idx = expr.tmp_idx
734
735        try:
736            return self.tmps[tmp_idx]
737        except KeyError:
738            return None
739
740    def _ail_handle_Load(self, expr):
741        raise NotImplementedError('Please implement the Load handler with your own logic.')
742
743    def _ail_handle_CallExpr(self, expr):
744        raise NotImplementedError('Please implement the CallExpr handler with your own logic.')
745
746    def _ail_handle_UnaryOp(self, expr):
747        handler_name = '_ail_handle_%s' % expr.op
748        try:
749            handler = getattr(self, handler_name)
750        except AttributeError:
751            self.l.warning('Unsupported UnaryOp %s.', expr.op)
752            return None
753
754        return handler(expr)
755
756    def _ail_handle_BinaryOp(self, expr):
757        handler_name = '_ail_handle_%s' % expr.op
758        try:
759            handler = getattr(self, handler_name)
760        except AttributeError:
761            self.l.warning('Unsupported BinaryOp %s.', expr.op)
762            return None
763
764        return handler(expr)
765
766    #
767    # Binary operation handlers
768    #
769
770    def _ail_handle_CmpLT(self, expr):
771
772        arg0, arg1 = expr.operands
773
774        expr_0 = self._expr(arg0)
775        expr_1 = self._expr(arg1)
776        if expr_0 is None:
777            expr_0 = arg0
778        if expr_1 is None:
779            expr_1 = arg1
780
781        try:
782            return expr_0 <= expr_1
783        except TypeError:
784            return ailment.Expr.BinaryOp(expr.idx, 'CmpLT', [expr_0, expr_1], expr.signed, **expr.tags)
785
786    def _ail_handle_Add(self, expr):
787
788        arg0, arg1 = expr.operands
789
790        expr_0 = self._expr(arg0)
791        expr_1 = self._expr(arg1)
792        if expr_0 is None:
793            expr_0 = arg0
794        if expr_1 is None:
795            expr_1 = arg1
796
797        try:
798            return expr_0 + expr_1
799        except TypeError:
800            return ailment.Expr.BinaryOp(expr.idx, 'Add', [expr_0, expr_1], expr.signed, **expr.tags)
801
802    def _ail_handle_Sub(self, expr):
803
804        arg0, arg1 = expr.operands
805
806        expr_0 = self._expr(arg0)
807        expr_1 = self._expr(arg1)
808
809        if expr_0 is None:
810            expr_0 = arg0
811        if expr_1 is None:
812            expr_1 = arg1
813
814        try:
815            return expr_0 - expr_1
816        except TypeError:
817            return ailment.Expr.BinaryOp(expr.idx, 'Sub', [expr_0, expr_1], expr.signed, **expr.tags)
818
819    def _ail_handle_Div(self, expr):
820
821        arg0, arg1 = expr.operands
822
823        expr_0 = self._expr(arg0)
824        expr_1 = self._expr(arg1)
825
826        if expr_0 is None:
827            expr_0 = arg0
828        if expr_1 is None:
829            expr_1 = arg1
830
831        try:
832            return expr_0 // expr_1
833        except TypeError:
834            return ailment.Expr.BinaryOp(expr.idx, 'Div', [expr_0, expr_1], expr.signed, **expr.tags)
835
836    def _ail_handle_DivMod(self, expr):
837        return self._ail_handle_Div(expr)
838
839    def _ail_handle_Mul(self, expr):
840
841        arg0, arg1 = expr.operands
842
843        expr_0 = self._expr(arg0)
844        expr_1 = self._expr(arg1)
845
846        if expr_0 is None:
847            expr_0 = arg0
848        if expr_1 is None:
849            expr_1 = arg1
850
851        try:
852            return expr_0 * expr_1
853        except TypeError:
854            return ailment.Expr.BinaryOp(expr.idx, 'Mul', [expr_0, expr_1], expr.signed, **expr.tags)
855
856    def _ail_handle_Mull(self, expr):
857        return self._ail_handle_Mul(expr)
858
859    def _ail_handle_And(self, expr):
860
861        arg0, arg1 = expr.operands
862
863        expr_0 = self._expr(arg0)
864        expr_1 = self._expr(arg1)
865
866        if expr_0 is None:
867            expr_0 = arg0
868        if expr_1 is None:
869            expr_1 = arg1
870
871        try:
872            return expr_0 & expr_1
873        except TypeError:
874            return ailment.Expr.BinaryOp(expr.idx, 'And', [expr_0, expr_1], expr.signed, **expr.tags)
875
876    def _ail_handle_Or(self, expr):
877
878        arg0, arg1 = expr.operands
879
880        expr_0 = self._expr(arg0)
881        expr_1 = self._expr(arg1)
882
883        if expr_0 is None:
884            expr_0 = arg0
885        if expr_1 is None:
886            expr_1 = arg1
887
888        try:
889            return expr_0 | expr_1
890        except TypeError:
891            return ailment.Expr.BinaryOp(expr.idx, 'Or', [expr_0, expr_1], expr.signed, **expr.tags)
892
893    def _ail_handle_Xor(self, expr):
894
895        arg0, arg1 = expr.operands
896
897        expr_0 = self._expr(arg0)
898        expr_1 = self._expr(arg1)
899
900        if expr_0 is None:
901            expr_0 = arg0
902        if expr_1 is None:
903            expr_1 = arg1
904
905        try:
906            return expr_0 ^ expr_1
907        except TypeError:
908            return ailment.Expr.BinaryOp(expr.idx, 'Xor', [expr_0, expr_1], expr.signed, **expr.tags)
909
910    def _ail_handle_Shr(self, expr):
911
912        arg0, arg1 = expr.operands
913        expr_0 = self._expr(arg0)
914        expr_1 = self._expr(arg1)
915
916        if expr_0 is None:
917            expr_0 = arg0
918        if expr_1 is None:
919            expr_1 = arg1
920
921        try:
922            return expr_0 >> expr_1
923        except TypeError:
924            return ailment.Expr.BinaryOp(expr.idx, 'Shr', [expr_0, expr_1], expr.signed, **expr.tags)
925
926    def _ail_handle_Shl(self, expr):
927
928        arg0, arg1 = expr.operands
929        expr_0 = self._expr(arg0)
930        expr_1 = self._expr(arg1)
931
932        if expr_0 is None:
933            expr_0 = arg0
934        if expr_1 is None:
935            expr_1 = arg1
936
937        try:
938            return expr_0 << expr_1
939        except TypeError:
940            return ailment.Expr.BinaryOp(expr.idx, 'Shl', [expr_0, expr_1], expr.signed, **expr.tags)
941
942    def _ail_handle_Sal(self, expr):
943        return self._ail_handle_Shl(expr)
944
945    def _ail_handle_Sar(self, expr):
946
947        arg0, arg1 = expr.operands
948        expr_0 = self._expr(arg0)
949        expr_1 = self._expr(arg1)
950
951        if expr_0 is None:
952            expr_0 = arg0
953        if expr_1 is None:
954            expr_1 = arg1
955
956        try:
957            return expr_0 >> expr_1
958        except TypeError:
959            return ailment.Expr.BinaryOp(expr.idx, 'Sar', [expr_0, expr_1], expr.signed, **expr.tags)
960
961    def _ail_handle_Concat(self, expr):
962
963        arg0, arg1 = expr.operands
964        expr_0 = self._expr(arg0)
965        expr_1 = self._expr(arg1)
966
967        if expr_0 is None:
968            expr_0 = arg0
969        if expr_1 is None:
970            expr_1 = arg1
971
972        return ailment.Expr.BinaryOp(expr.idx, 'Concat', [expr_0, expr_1], expr.signed, **expr.tags)
973
974    #
975    # Unary operation handlers
976    #
977
978    def _ail_handle_Convert(self, expr):
979        data = self._expr(expr.operand)
980        if data is not None:
981            if type(data) is int:
982                return data
983        return None
984
985    def _ail_handle_Not(self, expr):
986
987        data = self._expr(expr.operand)
988        if data is None:
989            return None
990
991        try:
992            return ~data  # pylint:disable=invalid-unary-operand-type
993        except TypeError:
994            return ailment.Expr.UnaryOp(expr.idx, 'Not', data, **expr.tags)
995
996
997# Compatibility
998SimEngineLightVEX = SimEngineLightVEXMixin
999SimEngineLightAIL = SimEngineLightAILMixin
1000