def _ail_handle_Sub(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) x_0, c_0, x_1, c_1 = None, None, None, None if isinstance(operand_1, Expr.BinaryOp) \ and isinstance(operand_1.operands[1], Expr.Const) \ and operand_1.op == 'Mul': if isinstance(operand_1.operands[0], Expr.BinaryOp) \ and isinstance(operand_1.operands[0].operands[1], Expr.Const) \ and operand_1.operands[0].op in ['Div', 'DivMod']: x_0 = operand_1.operands[0].operands[0] x_1 = operand_0 c_0 = operand_1.operands[1] c_1 = operand_1.operands[0].operands[1] elif isinstance(operand_1.operands[0], Expr.Convert) \ and isinstance(operand_1.operands[0].operand, Expr.BinaryOp) \ and operand_1.operands[0].operand.op in ['Div', 'DivMod']: x_0 = operand_1.operands[0].operand.operands[0] x_1 = operand_0 c_0 = operand_1.operands[1] c_1 = operand_1.operands[0].operand.operands[1] if x_0 is not None and x_1 is not None and x_0 == x_1 and c_0.value == c_1.value: return Expr.BinaryOp(expr.idx, 'Mod', [x_0, c_0], expr.signed, **expr.tags) if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]): return Expr.BinaryOp(expr.idx, 'Sub', [operand_0, operand_1], expr.signed, **expr.tags) return expr
def _ail_handle_Convert(self, expr: Expr.Convert): operand_expr = self._expr(expr.operand) # import ipdb; ipdb.set_trace() if type(operand_expr) is Expr.Convert: if expr.from_bits == operand_expr.to_bits and expr.to_bits == operand_expr.from_bits: # eliminate the redundant Convert return operand_expr.operand else: return Expr.Convert(expr.idx, operand_expr.from_bits, expr.to_bits, expr.is_signed, operand_expr.operand, **expr.tags) elif type(operand_expr) is Expr.Const: # do the conversion right away value = operand_expr.value mask = (2**expr.to_bits) - 1 value &= mask return Expr.Const(expr.idx, operand_expr.variable, value, expr.to_bits, **expr.tags) elif type(operand_expr) is Expr.BinaryOp \ and operand_expr.op in {'Mul', 'Shl', 'Div', 'DivMod', 'Add', 'Sub'}: if isinstance(operand_expr.operands[1], Expr.Const): if isinstance(operand_expr.operands[0], Expr.Register) and \ expr.from_bits == operand_expr.operands[0].bits: converted = Expr.Convert(expr.idx, expr.from_bits, expr.to_bits, expr.is_signed, operand_expr.operands[0]) return Expr.BinaryOp(operand_expr.idx, operand_expr.op, [converted, operand_expr.operands[1]], operand_expr.signed, **expr.tags) # TODO: the below optimization was unsound # Conv(32->64, (Conv(64->32, r14<8>) + 0x1<32>)) became Add(r14<8>, 0x1<32>) # ideally it should become Conv(32->64, Conv(64->32, r14<8> + 0x1<64>)) # and then the double convert can be pretty-printed away #elif isinstance(operand_expr.operands[0], Expr.Convert) and \ # expr.from_bits == operand_expr.operands[0].to_bits and \ # expr.to_bits == operand_expr.operands[0].from_bits: # return Expr.BinaryOp(operand_expr.idx, operand_expr.op, # [operand_expr.operands[0].operand, operand_expr.operands[1]], # operand_expr.signed, # **operand_expr.tags) elif isinstance(operand_expr.operands[0], Expr.Convert) \ and isinstance(operand_expr.operands[1], Expr.Convert) \ and operand_expr.operands[0].from_bits == operand_expr.operands[1].from_bits: if operand_expr.operands[0].to_bits == operand_expr.operands[1].to_bits \ and expr.from_bits == operand_expr.operands[0].to_bits \ and expr.to_bits == operand_expr.operands[1].from_bits: return Expr.BinaryOp(operand_expr.idx, operand_expr.op, [ operand_expr.operands[0].operand, operand_expr.operands[1].operand ], expr.is_signed, **operand_expr.tags) converted = Expr.Convert(expr.idx, expr.from_bits, expr.to_bits, expr.is_signed, operand_expr, **expr.tags) return converted
def _ail_handle_Convert(self, expr): if expr.from_bits == 128 and expr.to_bits == 64: operand_expr = self._expr(expr.operand) if isinstance(operand_expr, Expr.BinaryOp) \ and operand_expr.op == 'Mul' \ and isinstance(operand_expr.operands[1], Expr.Const) \ and isinstance(operand_expr.operands[0], Expr.BinaryOp): if operand_expr.operands[0].op in {'Shr', 'DivMod'} \ and isinstance(operand_expr.operands[0].operands[1], Expr.Const): if operand_expr.operands[0].op == 'Shr': Y = operand_expr.operands[0].operands[1].value else: Y = int( math.log2( operand_expr.operands[0].operands[1].value)) C = operand_expr.operands[1].value divisor = self._check_divisor(pow(2, 64 + Y), C) if divisor: X = operand_expr.operands[0].operands[0] new_const = Expr.Const(expr.idx, None, divisor, 64) return Expr.BinaryOp(expr.idx, 'DivMod', [X, new_const], expr.signed, **expr.tags) if expr.from_bits == 64 and expr.to_bits == 32 \ and isinstance(expr.operand, Expr.BinaryOp) and expr.operand.op == "Shr" \ and isinstance(expr.operand.operands[1], Expr.Const) and expr.operand.operands[1].value == expr.to_bits: inner = expr.operand.operands[0] if isinstance(inner, Expr.BinaryOp) and inner.op == "Mull": operand_0, operand_1 = inner.operands if isinstance(operand_1, Expr.Const) and not isinstance( operand_0, Expr.Const): # swap them operand_0, operand_1 = operand_1, operand_0 if isinstance(operand_0, Expr.Const) and not isinstance( operand_1, Expr.Const) and operand_0.bits == 32: bits = operand_0.bits C = operand_0.value X = operand_1 V = bits ndigits = 5 if V == 32 else 6 divisor = self._check_divisor(pow(2, V), C, ndigits) if divisor is not None and X: new_const = Expr.Const(None, None, divisor, V) new_expr = Expr.BinaryOp(inner.idx, 'Div', [X, new_const], inner.signed, **inner.tags) return new_expr return super()._ail_handle_Convert(expr)
def _ail_handle_Convert(self, expr): operand_expr = self._expr(expr.operand) # import ipdb; ipdb.set_trace() if type(operand_expr) is Expr.Convert: if expr.from_bits == operand_expr.to_bits and expr.to_bits == operand_expr.from_bits: # eliminate the redundant Convert return operand_expr.operand else: return Expr.Convert(expr.idx, operand_expr.from_bits, expr.to_bits, expr.is_signed, operand_expr.operand, **expr.tags) elif type(operand_expr) is Expr.Const: # do the conversion right away value = operand_expr.value mask = (2**expr.to_bits) - 1 value &= mask return Expr.Const(expr.idx, operand_expr.variable, value, expr.to_bits, **expr.tags) elif type(operand_expr) is Expr.BinaryOp \ and operand_expr.op in {'Mul', 'Shl', 'Div', 'DivMod', 'Add', 'Sub'}: if isinstance(operand_expr.operands[1], Expr.Const): if isinstance(operand_expr.operands[0], Expr.Register) and \ expr.from_bits == operand_expr.operands[0].bits: converted = Expr.Convert(expr.idx, expr.from_bits, expr.to_bits, expr.is_signed, operand_expr.operands[0]) return Expr.BinaryOp(operand_expr.idx, operand_expr.op, [converted, operand_expr.operands[1]], **expr.tags) elif isinstance(operand_expr.operands[0], Expr.Convert) and \ expr.from_bits == operand_expr.operands[0].to_bits and \ expr.to_bits == operand_expr.operands[0].from_bits: return Expr.BinaryOp(operand_expr.idx, operand_expr.op, [ operand_expr.operands[0].operand, operand_expr.operands[1] ], **operand_expr.tags) elif isinstance(operand_expr.operands[0], Expr.Convert) \ and isinstance(operand_expr.operands[1], Expr.Convert) \ and operand_expr.operands[0].from_bits == operand_expr.operands[1].from_bits: if operand_expr.operands[0].to_bits == operand_expr.operands[1].to_bits \ and expr.from_bits == operand_expr.operands[0].to_bits \ and expr.to_bits == operand_expr.operands[1].from_bits: return Expr.BinaryOp(operand_expr.idx, operand_expr.op, [ operand_expr.operands[0].operand, operand_expr.operands[1].operand ], **operand_expr.tags) converted = Expr.Convert(expr.idx, expr.from_bits, expr.to_bits, expr.is_signed, operand_expr, **expr.tags) return converted
def _ail_handle_Shl(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if isinstance(operand_1, Expr.Const): new_operand = Expr.Const(operand_1.idx, None, 2**operand_1.value, operand_0.bits) return Expr.BinaryOp(expr.idx, 'Mul', [operand_0, new_operand], expr.signed, **expr.tags) if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]): return Expr.BinaryOp(expr.idx, 'Shl', [operand_0, operand_1], expr.signed, **expr.tags) return expr
def _test_concatenation(pv: PropValue): if pv.offset_and_details is not None and len(pv.offset_and_details) == 2 and 0 in pv.offset_and_details: lo_value = pv.offset_and_details[0] hi_offset = next(iter(k for k in pv.offset_and_details if k != 0)) hi_value = pv.offset_and_details[hi_offset] if lo_value.def_at == hi_value.def_at: # it's the same value! we can apply concatenation here if isinstance(hi_value.expr, Expr.Const) and hi_value.expr.value == 0: # it's probably an up-cast mappings = { # (lo_value.size, hi_value.size): (from_bits, to_bits) (1, 1): (8, 16), # char to short (1, 3): (8, 32), # char to int (1, 7): (8, 64), # char to int64 (2, 2): (16, 32), # short to int (2, 6): (16, 64), # short to int64 (4, 4): (32, 64), # int to int64 } key = (lo_value.size, hi_value.size) if key in mappings: from_bits, to_bits = mappings[key] result_expr = Expr.Convert(None, from_bits, to_bits, False, lo_value.expr) return True, result_expr result_expr = Expr.BinaryOp(None, "Concat", [hi_value.expr, lo_value.expr], False) return True, result_expr return False, None
def _ail_handle_And(self, expr: Expr.BinaryOp): o0_value = self._expr(expr.operands[0]) o1_value = self._expr(expr.operands[1]) value = self.state.top(expr.bits) if o0_value is None or o1_value is None: new_expr = expr else: o0_expr = o0_value.one_expr o1_expr = o1_value.one_expr # Special logic for stack pointer alignment sp_offset = self.extract_offset_to_sp(o0_value.value) if sp_offset is not None and type(o1_expr) is Expr.Const and is_alignment_mask(o1_expr.value): value = o0_value.value new_expr = o0_expr elif isinstance(o0_expr, Expr.StackBaseOffset) and type(o1_expr) is Expr.Const \ and is_alignment_mask(o1_expr.value): value = o0_value.value new_expr = o0_expr else: value = self.state.top(expr.bits) new_expr = Expr.BinaryOp(expr.idx, 'And', [o0_expr if o0_expr is not None else expr.operands[0], o1_expr if o1_expr is not None else expr.operands[1],], expr.signed, **expr.tags) return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
def _ail_handle_Convert(self, expr): if expr.from_bits == 128 and expr.to_bits == 64: operand_expr = self._expr(expr.operand) if isinstance(operand_expr, Expr.BinaryOp) \ and operand_expr.op == 'Mul' \ and isinstance(operand_expr.operands[1], Expr.Const) \ and isinstance(operand_expr.operands[0], Expr.BinaryOp): if operand_expr.operands[0].op in {'Shr', 'DivMod'} \ and isinstance(operand_expr.operands[0].operands[1], Expr.Const): if operand_expr.operands[0].op == 'Shr': Y = operand_expr.operands[0].operands[1].value else: Y = int( math.log2( operand_expr.operands[0].operands[1].value)) C = operand_expr.operands[1].value divisor = self._check_divisor(pow(2, 64 + Y), C) if divisor: X = operand_expr.operands[0].operands[0] new_const = Expr.Const(expr.idx, None, divisor, 64) return Expr.BinaryOp(expr.idx, 'DivMod', [X, new_const], expr.signed, **expr.tags) return super()._ail_handle_Convert(expr)
def _ail_handle_Sub(self, expr: Expr.BinaryOp) -> PropValue: o0_value = self._expr(expr.operands[0]) o1_value = self._expr(expr.operands[1]) if o0_value is None or o1_value is None: new_expr = expr value = self.state.top(expr.bits) else: if o0_value.value.concrete and o1_value.value.concrete: value = o0_value.value - o1_value.value else: value = self.state.top(expr.bits) o0_expr = o0_value.one_expr o1_expr = o1_value.one_expr if isinstance(o0_expr, Expr.BasePointerOffset) and isinstance(o1_expr, Expr.Const): new_expr = o0_value.one_expr.copy() new_expr.offset -= o1_expr.value else: new_expr = Expr.BinaryOp(expr.idx, 'Sub', [o0_expr if o0_expr is not None else expr.operands[0], o1_expr if o1_expr is not None else expr.operands[1],], expr.signed, **expr.tags) return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
def _ail_handle_Cmp(self, expr: Expr.BinaryOp) -> PropValue: operand_0_value = self._expr(expr.operands[0]) operand_1_value = self._expr(expr.operands[1]) if operand_0_value is not None and operand_1_value is not None: operand_0_oneexpr = operand_0_value.one_expr operand_1_oneexpr = operand_1_value.one_expr if operand_0_oneexpr is expr.operands[ 0] and operand_1_oneexpr is expr.operands[1]: # nothing changed return PropValue.from_value_and_details( self.state.top(expr.bits), expr.size, expr, self._codeloc()) else: operand_0 = operand_0_oneexpr if operand_0_oneexpr is not None else expr.operands[ 0] operand_1 = operand_1_oneexpr if operand_1_oneexpr is not None else expr.operands[ 1] new_expr = Expr.BinaryOp(expr.idx, expr.op, [operand_0, operand_1], expr.signed, **expr.tags) else: new_expr = expr return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, new_expr, self._codeloc())
def _ail_handle_Mul(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]): return Expr.BinaryOp(expr.idx, 'Mul', [operand_0, operand_1], **expr.tags) return expr
def _ail_handle_Xor(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if type(operand_0) is Top or type(operand_1) is Top: return Top(operand_0.size) return Expr.BinaryOp(expr.idx, 'Xor', [ operand_0, operand_1 ], expr.signed, **expr.tags)
def _ail_handle_Div(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if isinstance(operand_1, Expr.Const) \ and isinstance(operand_0, Expr.BinaryOp) \ and operand_0.op in {'Div', 'DivMod'} \ and isinstance(operand_0.operands[1], Expr.Const): new_const_value = operand_1.value * operand_0.operands[1].value new_const = Expr.Const(operand_1.idx, None, new_const_value, operand_1.bits) return Expr.BinaryOp(expr.idx, 'Div', [operand_0.operands[0], new_const], expr.signed, **expr.tags) if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]): return Expr.BinaryOp(expr.idx, 'Div', [operand_0, operand_1], expr.signed, **expr.tags) return expr
def _ail_handle_CmpNE(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if type(operand_0) is Top or type(operand_1) is Top: return Top(1) return Expr.BinaryOp(expr.idx, 'CmpNE', [operand_0, operand_1], expr.signed)
def _ail_handle_And(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) # Special logic for SP alignment if type(operand_0) is Expr.StackBaseOffset and \ type(operand_1) is Expr.Const and is_alignment_mask(operand_1.value): return operand_0 return Expr.BinaryOp(expr.idx, 'And', [operand_0, operand_1])
def _ail_handle_Mul(self, expr): operand_0, operand_1 = expr.operands if isinstance(operand_1, Expr.Const) \ and isinstance(operand_0, Expr.BinaryOp) \ and isinstance(operand_0.operands[1], Expr.Const) \ and operand_0.op in {'DivMod', 'Shr'}: if operand_0.op == 'DivMod': Y = int(math.log2(operand_0.operands[1].value)) else: Y = operand_0.operands[1].value C = operand_1.value X = operand_0.operands[0] # there is a convert outside this expr V = 64 if isinstance(X, Expr.Convert): V = X.from_bits - X.to_bits ndigits = 5 if V == 32 else 6 if self._check_divisor(pow(2, V + Y), C, ndigits) and X: divisor = self._check_divisor(pow(2, Y + V), C, ndigits) new_const = Expr.Const(expr.idx, None, divisor, 64) return Expr.BinaryOp(expr.idx, 'DivMod', [X, new_const], expr.signed, **expr.tags) if isinstance(operand_1, Expr.Const) \ and isinstance(operand_0, Expr.Convert) \ and isinstance(operand_0.operand, Expr.BinaryOp) \ and isinstance(operand_0.operand.operands[1], Expr.Const) \ and operand_0.operand.op in {'DivMod', 'Shr'}: if operand_0.operand.op == 'DivMod': Y = int(math.log2(operand_0.operand.operands[1].value)) else: Y = operand_0.operand.operands[1].value C = operand_1.value X = operand_0.operand.operands[0] V = operand_0.from_bits - operand_0.to_bits ndigits = 5 if V == 32 else 6 if self._check_divisor(pow(2, V + Y), C, ndigits) and X: divisor = self._check_divisor(pow(2, Y + V), C, ndigits) new_const = Expr.Const(expr.idx, None, divisor, 64) return Expr.BinaryOp(expr.idx, 'DivMod', [X, new_const], expr.signed, **expr.tags) return super()._ail_handle_Mul(expr)
def _ail_handle_Shr(self, expr: Expr.BinaryOp): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if self.state.is_top(operand_0): return self.state.top(expr.bits) elif self.state.is_top(operand_1): return self.state.top(expr.bits) return Expr.BinaryOp(expr.idx, 'Shr', [ operand_0, operand_1 ], expr.signed, **expr.tags)
def _ail_handle_Mul(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if Expr.Const in [type(operand_0), type(operand_1)]: if Expr.BinaryOp in [type(operand_0), type(operand_1)]: const_, x0 = (operand_0, operand_1) if isinstance( operand_0, Expr.Const) else (operand_1, operand_0) if x0.op == 'Mul' and Expr.Const in [ type(x0.operands[0]), type(x0.operands[1]) ]: const_x0, x = (x0.operands[0], x0.operands[1]) if isinstance( x0.operands[0], Expr.Const) else (x0.operands[1], x0.operands[0]) new_const = Expr.Const(const_.idx, None, const_.value * const_x0.value, const_.bits) new_expr = Expr.BinaryOp(expr.idx, 'Mul', [x, new_const], expr.signed, **expr.tags) return new_expr elif isinstance(operand_0, Expr.Convert) \ and isinstance(operand_0.operand, Expr.BinaryOp) \ and operand_0.operand.op == 'Mul' \ and isinstance(operand_0.operand.operands[1], Expr.Const): x = operand_0.operand.operands[0] new_const = Expr.Const( operand_1.idx, None, operand_1.value * operand_0.operand.operands[1].value, operand_1.bits) new_expr = Expr.BinaryOp(expr.idx, 'Mul', [x, new_const], expr.signed, **expr.tags) return new_expr if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]): return Expr.BinaryOp(expr.idx, 'Mul', [operand_0, operand_1], expr.signed, **expr.tags) return expr
def _ail_handle_Sub(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if isinstance(operand_0, Expr.Const) and isinstance(operand_1, Expr.Const): return Expr.Const(expr.idx, None, operand_0.value - operand_1.value, expr.bits) elif isinstance(operand_0, Expr.BasePointerOffset) and isinstance(operand_1, Expr.Const): r = operand_0.copy() r.offset -= operand_1.value return r return Expr.BinaryOp(expr.idx, 'Sub', [ operand_0 if operand_0 is not None else expr.operands[0], operand_1 if operand_1 is not None else expr.operands[1] ])
def _ail_handle_Cmp(self, expr: Expr.BinaryOp): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if self.state.is_top(operand_0): operand_0 = expr.operands[0] if self.state.is_top(operand_1): operand_1 = expr.operands[1] if operand_0 is expr.operands[0] and operand_1 is expr.operands[1]: # nothing changed return expr return Expr.BinaryOp(expr.idx, expr.op, [operand_0, operand_1], expr.signed, **expr.tags)
def _rewrite(self, ccall: Expr.VEXCCallExpression) -> Optional[Expr.Expression]: if ccall.cee_name == "amd64g_calculate_condition": cond = ccall.operands[0] op = ccall.operands[1] dep_1 = ccall.operands[2] dep_2 = ccall.operands[3] if isinstance(cond, Expr.Const) and isinstance(op, Expr.Const): cond_v = cond.value op_v = op.value if cond_v == AMD64_CondTypes['CondLE'] and op_v == AMD64_OpTypes['G_CC_OP_SUBL']: # dep_1 <=s dep_2 return Expr.BinaryOp(ccall.idx, "CmpLE", (dep_1, dep_2), True, **ccall.tags) if cond_v == AMD64_CondTypes['CondLE'] and op_v == AMD64_OpTypes['G_CC_OP_SUBB']: # dep_1 <=s dep_2 return Expr.BinaryOp(ccall.idx, "CmpLE", (dep_1, dep_2), True, **ccall.tags) return None
def _ail_handle_Concat(self, expr): o0_value = self._expr(expr.operands[0]) o1_value = self._expr(expr.operands[1]) value = self.state.top(expr.bits) if o0_value is None or o1_value is None: new_expr = expr else: o0_expr = o0_value.one_expr o1_expr = o1_value.one_expr new_expr = Expr.BinaryOp(expr.idx, 'Concat', [ o0_expr if o0_expr is not None else expr.operands[0], o1_expr if o1_expr is not None else expr.operands[1], ], expr.signed, **expr.tags) return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
def _ail_handle_Mull(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if self.state.is_top(operand_0): return self.state.top(expr.bits) elif self.state.is_top(operand_1): return self.state.top(expr.bits) return Expr.BinaryOp(expr.idx, 'Mull', [ operand_0, operand_1, ], expr.signed, bits=expr.bits, **expr.tags)
def _ail_handle_Add(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if type(operand_0) is Top or type(operand_1) is Top: return Top(operand_0.size) if isinstance(operand_0, Expr.Const) and isinstance(operand_1, Expr.Const): return Expr.Const(expr.idx, None, operand_0.value + operand_1.value, expr.bits) elif isinstance(operand_0, Expr.BasePointerOffset) and isinstance(operand_1, Expr.Const): r = operand_0.copy() r.offset += operand_1.value return r return Expr.BinaryOp(expr.idx, 'Add', [operand_0 if operand_0 is not None else expr.operands[0], operand_1 if operand_1 is not None else expr.operands[1] ], expr.signed)
def _ail_handle_And(self, expr: Expr.BinaryOp): self.state: 'PropagatorAILState' operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if self.state.is_top(operand_0): return self.state.top(expr.bits) elif self.state.is_top(operand_1): return self.state.top(expr.bits) # Special logic for stack pointer alignment sp_offset = self.extract_offset_to_sp(operand_0) if sp_offset is not None and type(operand_1) is Expr.Const and is_alignment_mask(operand_1.value): return operand_0 return Expr.BinaryOp(expr.idx, 'And', [ operand_0, operand_1 ], expr.signed, **expr.tags)
def _ail_handle_Add(self, expr: Expr.BinaryOp): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) if self.state.is_top(operand_0): return self.state.top(expr.bits) elif self.state.is_top(operand_1): return self.state.top(expr.bits) if isinstance(operand_0, Expr.Const) and isinstance(operand_1, Expr.Const): return Expr.Const(expr.idx, None, operand_0.value + operand_1.value, expr.bits) elif isinstance(operand_0, Expr.BasePointerOffset) and isinstance(operand_1, Expr.Const): r = operand_0.copy() r.offset += operand_1.value return r return Expr.BinaryOp(expr.idx, 'Add', [operand_0 if operand_0 is not None else expr.operands[0], operand_1 if operand_1 is not None else expr.operands[1] ], expr.signed, **expr.tags)
def _ail_handle_Shr(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) X = None divisor = None if isinstance(operand_1, Expr.Const) \ and isinstance(operand_0, Expr.BinaryOp) \ and operand_0.op == 'DivMod' \ and isinstance(operand_0.operands[1], Expr.Const): divisor = operand_0.operands[1].value * pow(2, operand_1.value) X = operand_0.operands[0] if isinstance(operand_1, Expr.Const) \ and isinstance(operand_0, Expr.Convert) \ and isinstance(operand_0.operand, Expr.BinaryOp) \ and operand_0.operand.op == 'DivMod' \ and isinstance(operand_0.operand.operands[1], Expr.Const): divisor = operand_0.operand.operands[1].value * pow( 2, operand_1.value) X = operand_0.operand.operands[0] if isinstance(operand_1, Expr.Const) \ and isinstance(operand_0, Expr.Convert) \ and operand_0.from_bits == 128 \ and operand_0.to_bits == 64: if isinstance(operand_0.operand, Expr.BinaryOp)\ and operand_0.operand.op == 'Mul': if isinstance(operand_0.operand.operands[1], Expr.Const): C = operand_0.operand.operands[1].value Y = operand_1.value divisor = self._check_divisor(pow(2, 64 + Y), C) X = operand_0.operand.operands[0] elif isinstance(operand_0.operand.operands[0], Expr.BinaryOp) \ and operand_0.operand.operands[0].op in {'Shr', 'DivMod'}: C = operand_0.operand.operands[1].value Z = operand_1.value if operand_0.operand.operands[0].op == 'Shr': Y = operand_0.operand.operands[0].operands[1].value else: Y = int( math.log2(operand_0.operand.operands[0]. operands[1].value)) divisor = self._check_divisor(pow(2, 64 + Z + Y), C) X = operand_0.operand.operands[0].operands[0] if isinstance(operand_1, Expr.Const) \ and isinstance(operand_0, Expr.BinaryOp) \ and operand_0.op == 'Add': add_0, add_1 = operand_0.operands Z = operand_1.value if add_0.has_atom(add_1) or add_1.has_atom(add_0): xC = add_1 if add_0.has_atom(add_1) else add_0 x_xC = add_0 if add_0.has_atom(add_1) else add_1 if isinstance(xC, Expr.Convert) and (xC.from_bits > xC.to_bits): Y = xC.from_bits - xC.to_bits if isinstance(xC.operand, Expr.BinaryOp) and xC.operand.op == 'Mul': xC_ = xC.operand if isinstance(xC_.operands[1], Expr.Const): C = xC_.operands[1].value X = xC_.operands[0] if isinstance(x_xC, Expr.BinaryOp) and x_xC.op == 'Shr': V_, V = x_xC.operands if isinstance(V, Expr.Const): V = V.value if isinstance( V_, Expr.BinaryOp) and V_.op == 'Sub': if V_.operands[0] == X and V_.operands[ 1] == xC: divisor = self._check_divisor( pow(2, Y + V + Z), C * (pow(2, V) - 1) + pow(2, Y)) # unsigned int here if isinstance(xC, Expr.BinaryOp) and xC.op == 'Mul': if isinstance(xC.operands[1], Expr.Const) \ and isinstance(xC.operands[0], Expr.Convert): C = xC.operands[1].value X = xC.operands[0] Y = X.from_bits - X.to_bits if isinstance(x_xC, Expr.BinaryOp) and x_xC.op == 'Shr': V_, V = x_xC.operands if isinstance(V, Expr.Const): V = V.value if isinstance( V_, Expr.BinaryOp) and V_.op == 'Sub': if V_.operands[1] == xC: divisor = self._check_divisor( pow(2, Y + V + Z), C * (pow(2, V) - 1) + pow(2, Y)) elif isinstance(xC, Expr.BinaryOp) and xC.op == 'Shr': if isinstance(xC.operands[1], Expr.Const) \ and isinstance(xC.operands[0], Expr.BinaryOp) \ and xC.operands[0].op == 'Mul' \ and isinstance(xC.operands[0].operands[1], Expr.Const): if isinstance(x_xC, Expr.BinaryOp) \ and isinstance(x_xC.operands[1], Expr.Const) \ and isinstance(x_xC.operands[0], Expr.BinaryOp) \ and x_xC.op == 'Shr' and x_xC.operands[0].op == 'Sub': X = xC.operands[0].operands[0] C = xC.operands[0].operands[1].value Y = xC.operands[1].value V = x_xC.operands[1].value if X == x_xC.operands[0].operands[0]: divisor = self._check_divisor( pow(2, Y + V + Z), C * (pow(2, V) - 1) + pow(2, Y)) # unsigned int if isinstance(operand_1, Expr.Const) \ and isinstance(operand_0, Expr.BinaryOp) \ and operand_0.op == 'Mul' \ and isinstance(operand_0.operands[1], Expr.Const): if isinstance(operand_0.operands[0], Expr.Convert): V = operand_0.operands[0].from_bits - operand_0.operands[ 0].to_bits C = operand_0.operands[1].value Z = operand_1.value X = operand_0.operands[0] divisor = self._check_divisor(pow(2, V + Z), C) elif isinstance(operand_0.operands[0], Expr.BinaryOp) \ and isinstance(operand_0.operands[0].operands[1], Expr.Const) \ and operand_0.operands[0].op in {'Shr', 'DivMod'}: X = operand_0.operands[0].operands[0] V = 0 ndigits = 6 if isinstance(X, Expr.Convert): V = X.from_bits - X.to_bits if V == 32: ndigits = 5 C = operand_0.operands[1].value Y = operand_0.operands[0].operands[1].value if operand_0.operands[0].op == 'DivMod': Y = int(math.log2(operand_0.operands[0].operands[1].value)) Z = operand_1.value divisor = self._check_divisor(pow(2, Y + Z + V), C, ndigits) else: X = operand_0.operands[0] Y = operand_1.value C = operand_0.operands[1].value divisor = self._check_divisor(pow(2, Y), C) if divisor and X: new_const = Expr.Const(expr.idx, None, divisor, 64) return Expr.BinaryOp(expr.idx, 'DivMod', [X, new_const], expr.signed, **expr.tags) if isinstance(operand_1, Expr.Const): if isinstance(operand_0, Expr.Register): new_operand = Expr.Const(operand_1.idx, None, 2**operand_1.value, operand_1.bits) return Expr.BinaryOp(expr.idx, 'DivMod', [operand_0, new_operand], expr.signed) elif isinstance(operand_0, Expr.BinaryOp) \ and operand_0.op == 'Shr' \ and isinstance(operand_0.operands[1], Expr.Const): new_const = Expr.Const( operand_1.idx, None, operand_0.operands[1].value + operand_1.value, operand_1.bits) return Expr.BinaryOp(expr.idx, 'Shr', [operand_0.operands[0], new_const], expr.signed, **expr.tags) if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]): return Expr.BinaryOp(expr.idx, 'Shr', [operand_0, operand_1], expr.signed) return expr
def _ail_handle_Xor(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) return Expr.BinaryOp(expr.idx, 'Xor', [operand_0, operand_1])
def _ail_handle_CmpNE(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) return Expr.BinaryOp(expr.idx, 'CmpNE', [operand_0, operand_1], expr.signed)
def _ail_handle_Sub(self, expr): operand_0 = self._expr(expr.operands[0]) operand_1 = self._expr(expr.operands[1]) # x + x = 2*x if type(operand_0) in [Expr.Convert, Expr.Register]: if isinstance(operand_1, (Expr.Convert, Expr.Register)): if operand_0 == operand_1: count = Expr.Const(expr.idx, None, 0, 8) new_expr = Expr.BinaryOp(expr.idx, 'Mul', [operand_1, count], expr.signed, **expr.tags) return new_expr # 2*x - x = x if Expr.BinaryOp in [type(operand_0), type(operand_1)]: if isinstance(operand_1, Expr.BinaryOp) and operand_1.op == 'Mul' and \ (not isinstance(operand_0, Expr.BinaryOp) or \ (isinstance(operand_0, Expr.BinaryOp) and operand_0.op != 'Mul')): x0 = operand_0 x1_index = 0 if isinstance(operand_1.operands[1], Expr.Const) else 1 x1 = operand_1.operands[x1_index] const_x1 = operand_1.operands[1 - x1_index] if x0 == x1: new_const = Expr.Const(const_x1.idx, None, const_x1.value - 1, const_x1.bits) new_expr = Expr.BinaryOp(expr.idx, 'Mul', [x0, new_const], expr.signed, **expr.tags) return new_expr elif isinstance(operand_0, Expr.BinaryOp) and operand_0.op == 'Mul' and \ (not isinstance(operand_1, Expr.BinaryOp) or \ (isinstance(operand_1, Expr.BinaryOp) and operand_1.op != 'Mul')): x1 = operand_1 x0_index = 0 if isinstance(operand_0.operands[1], Expr.Const) else 1 x0 = operand_0.operands[x0_index] const_x0 = operand_0.operands[1 - x0_index] if x0 == x1: new_const = Expr.Const(const_x0.idx, None, const_x0.value - 1, const_x0.bits) new_expr = Expr.BinaryOp(expr.idx, 'Mul', [x1, new_const], expr.signed, **expr.tags) return new_expr # 3*x - 2*x = x elif isinstance(operand_0, Expr.BinaryOp) and isinstance(operand_1, Expr.BinaryOp) and \ operand_0.op == 'Mul' and operand_1.op == 'Mul': if Expr.Const in [type(operand_0.operands[0]), type(operand_0.operands[1])] \ and Expr.Const in [type(operand_1.operands[0]), type(operand_1.operands[1])]: x0_index = 0 if isinstance(operand_0.operands[1], Expr.Const) else 1 x0 = operand_0.operands[x0_index] const_x0 = operand_0.operands[1 - x0_index] x1_index = 0 if isinstance(operand_1.operands[1], Expr.Const) else 1 x1 = operand_1.operands[x1_index] const_x1 = operand_1.operands[1 - x1_index] if x0 == x1: new_const = Expr.Const(const_x1.idx, None, const_x0.value - const_x1.value, const_x1.bits) new_expr = Expr.BinaryOp(expr.idx, 'Mul', [x0, new_const], expr.signed, **expr.tags) return new_expr if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]): return Expr.BinaryOp(expr.idx, 'Sub', [operand_0, operand_1], expr.signed, **expr.tags) return expr