def lhs_ast(self, astree: AbstractSyntaxTree, iaddr: str, xdata: InstrXData) -> Tuple[ASTLval, List[ASTInstruction]]: def indirect_lhs( rtype: Optional[BCTyp] ) -> Tuple[ASTLval, List[ASTInstruction]]: tmplval = astree.mk_returnval_variable_lval(iaddr, rtype) tmprhs = astree.mk_lval_expr(tmplval) reglval = astree.mk_register_variable_lval("R0") return (tmplval, [astree.mk_assign(reglval, tmprhs)]) calltarget = xdata.call_target(self.ixd) tgtname = calltarget.name models = ModelsAccess() if astree.has_symbol(tgtname): fnsymbol = astree.symbol(tgtname) if fnsymbol.returns_void: return (astree.mk_ignored_lval(), []) else: return indirect_lhs(fnsymbol.vtype) elif models.has_so_function_summary(tgtname): summary = models.so_function_summary(tgtname) returntype = summary.signature.returntype if returntype.is_named_type: returntype = cast(MNamedType, returntype) typename = returntype.typename if typename == "void" or typename == "VOID": return (astree.mk_ignored_lval(), []) else: return indirect_lhs(None) else: return indirect_lhs(None) else: return indirect_lhs(None)
def assembly_ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: regsop = self.operands[1] if not regsop.is_register_list: raise UF.CHBError("Argument to push is not a register list") (splval, _, _) = self.operands[0].ast_lvalue(astree) (sprval, _, _) = self.operands[0].ast_rvalue(astree) instrs: List[AST.ASTInstruction] = [] registers = regsop.registers sp_decr = 4 * len(registers) sp_offset = sp_decr for r in registers: sp_offset_c = astree.mk_integer_constant(sp_offset) addr = astree.mk_binary_op("minus", sprval, sp_offset_c) lhs = astree.mk_memref_lval(addr) rhs = astree.mk_register_variable_expr(r) instrs.append(astree.mk_assign(lhs, rhs)) sp_offset -= 4 sp_decr_c = astree.mk_integer_constant(sp_decr) sp_rhs = astree.mk_binary_op("minus", sprval, sp_decr_c) instrs.append(astree.mk_assign(splval, sp_rhs)) astree.add_instruction_span(instrs[0].id, iaddr, bytestring) return instrs
def field_at_offset(compinfo: "BCCompInfo", offsetvalue: int, astree: AbstractSyntaxTree) -> AST.ASTOffset: (finfo, r) = compinfo.field_at_offset(offsetvalue) if finfo.fieldtype.is_struct: fcompinfo = cast("BCTypComp", finfo.fieldtype).compinfo foffset = field_at_offset(fcompinfo, r, astree) return astree.mk_field_offset(finfo.fieldname, finfo.fieldtype, offset=foffset) elif r == 0: return astree.mk_field_offset(finfo.fieldname, finfo.fieldtype) elif finfo.fieldtype.is_array: ftype = cast("BCTypArray", finfo.fieldtype) elsize = ftype.tgttyp.byte_size() index = r // elsize ioffset = astree.mk_scalar_index_offset(index) return astree.mk_field_offset(finfo.fieldname, finfo.fieldtype, offset=ioffset) else: raise UF.CHBError("No field found at offset: " + str(offsetvalue) + " in struct " + compinfo.cname + " (Offsets found: " + ", ".join( (str(f[0]) + ":" + str(f[1].fieldtype) + " " + f[1].fieldname) for f in compinfo.fieldoffsets()) + ")")
def xvariable_to_ast_lval(xv: X.XVariable, astree: AbstractSyntaxTree) -> AST.ASTLval: """Convert a CHIF variable to an AST Lval node.""" if xv.is_tmp: return astree.mk_temp_lval() elif xv.is_register_variable: xvden = cast("VRegisterVariable", xv.denotation) reg = xvden.register if reg.is_mips_register: mipsreg = cast("MIPSRegister", reg) name = "mips_" + mipsreg.name else: name = str(xv) return astree.mk_register_variable_lval(name) elif xv.is_memory_variable: xvmem = cast("VMemoryVariable", xv.denotation) return vmemory_variable_to_ast_lval(xvmem, astree) elif xv.is_auxiliary_variable: xvaux = cast("VAuxiliaryVariable", xv.denotation) return vauxiliary_variable_to_ast_lval(xvaux, astree) else: print("other: " + str(xv)) return astree.mk_variable_lval(str(xv))
def assembly_ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[ASTInstruction]: msg = (iaddr + ": " + bytestring + " " + self.mnemonic + " " + self.operandstring + ": " + self.annotation(xdata)) astree.add_instruction_unsupported(self.mnemonic, msg) return []
def ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: rhs = XU.xxpr_to_ast_expr(xdata.xprs[1], astree) lhs = XU.xvariable_to_ast_lval(xdata.vars[0], astree) assign = astree.mk_assign(lhs, rhs) astree.add_instruction_span(assign.id, iaddr, bytestring) return [assign]
def xcompound_to_ast_expr(xc: X.XprCompound, astree: AbstractSyntaxTree) -> AST.ASTExpr: """Convert a compound expression to an AST Expr node.""" op = xc.operator operands = xc.operands if len(operands) == 1: op1 = xxpr_to_ast_expr(operands[0], astree) return astree.mk_unary_op(op, op1) elif len(operands) == 2: if xc.is_stack_address: stackoffset = xc.stack_address_offset() rhslval = astree.mk_stack_variable_lval(stackoffset) return astree.mk_address_of(rhslval) else: op1 = xxpr_to_ast_expr(operands[0], astree) op2 = xxpr_to_ast_expr(operands[1], astree) if op1.ctype is not None and op in ["plus", "minus"]: return xtyped_expr_to_ast_expr(op, op1, op2, astree) else: return astree.mk_binary_op(op, op1, op2) else: raise UF.CHBError("AST conversion of compound expression " + str(xc) + " not yet supported")
def ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: (rhs, _, _) = self.operands[0].ast_rvalue(astree) lhs = xdata.vars[0] lval = XU.xvariable_to_ast_lval(lhs, astree) assign = astree.mk_assign(lval, rhs) astree.add_instruction_span(assign.id, iaddr, bytestring) return [assign]
def assembly_ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: (rhs, preinstrs, postinstrs) = self.operands[1].ast_rvalue(astree) (lhs, _, _) = self.operands[0].ast_lvalue(astree) assign = astree.mk_assign(lhs, rhs) astree.add_instruction_span(assign.id, iaddr, bytestring) return preinstrs + [assign] + postinstrs
def stack_variable_to_ast_lval(offset: "VMemoryOffset", astree: AbstractSyntaxTree) -> AST.ASTLval: """TODO: split up.""" if offset.is_constant_value_offset: return astree.mk_stack_variable_lval(offset.offsetvalue()) print("stack variable: " + str(offset)) return astree.mk_variable_lval("stack: " + str(offset))
def assembly_ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[ASTInstruction]: (lhs, _, _) = self.operands[0].ast_lvalue(astree) (op1, _, _) = self.operands[1].ast_rvalue(astree) (op2, _, _) = self.operands[2].ast_rvalue(astree) binop = astree.mk_binary_op("minus", op1, op2) result = astree.mk_assign(lhs, binop) astree.add_instruction_span(result.id, iaddr, bytestring) return [result]
def assembly_ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: (rhs1, preinstrs1, postinstrs1) = self.operands[1].ast_rvalue(astree) (rhs2, preinstrs2, postinstrs2) = self.operands[2].ast_rvalue(astree) (lhs, _, _) = self.operands[0].ast_lvalue(astree) binop = astree.mk_binary_op("band", rhs1, rhs2) assign = astree.mk_assign(lhs, binop) astree.add_instruction_span(assign.id, iaddr, bytestring) return preinstrs1 + preinstrs2 + [assign] + postinstrs1 + postinstrs2
def assembly_ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: if len(xdata.vars) == 1 and len(xdata.xprs) == 1: lhs = astree.mk_variable_lval(str(xdata.vars[0])) rhs = XU.xxpr_to_ast_expr(xdata.xprs[0], astree) assign = astree.mk_assign(lhs, rhs) astree.add_instruction_span(assign.id, iaddr, bytestring) return [assign] else: return []
def target_expr_ast(self, astree: AbstractSyntaxTree, xdata: InstrXData) -> ASTExpr: calltarget = xdata.call_target(self.ixd) tgtname = calltarget.name if calltarget.is_app_target: apptgt = cast("AppTarget", calltarget) return astree.mk_global_variable_expr(tgtname, globaladdress=int( str(apptgt.address), 16)) else: return astree.mk_global_variable_expr(tgtname)
def assembly_ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: (lhs1, preinstrs1, postinstrs1) = self.operands[4].ast_lvalue(astree) (lhs2, preinstrs2, postinstrs2) = self.operands[5].ast_lvalue(astree) (rhs1, _, _) = self.operands[0].ast_rvalue(astree) (rhs2, _, _) = self.operands[1].ast_rvalue(astree) assign1 = astree.mk_assign(lhs1, rhs1) assign2 = astree.mk_assign(lhs2, rhs2) astree.add_instruction_span(assign1.id, iaddr, bytestring) return (preinstrs1 + preinstrs2 + [assign1, assign2] + postinstrs1 + postinstrs2)
def vfunctionreturn_value_to_ast_lval( vconstvar: "VFunctionReturnValue", astree: AbstractSyntaxTree) -> AST.ASTLval: vtype = None if vconstvar.has_call_target(): calltarget = str(vconstvar.call_target()) if astree.has_symbol(calltarget): vinfo = astree.symbol(calltarget) vtype = vinfo.vtype return astree.mk_returnval_variable_lval(vconstvar.callsite, vtype)
def global_variable_to_ast_lval(offset: "VMemoryOffset", astree: AbstractSyntaxTree) -> AST.ASTLval: if offset.is_constant_value_offset: gaddr = hex(offset.offsetvalue()) gvname = astree.global_variable_name(gaddr) if gvname is None: gvname = "gv_" + gaddr return astree.mk_global_variable_lval(gvname, globaladdress=int(gaddr, 16)) print("global-variable: " + "gv_" + str(offset)) return astree.mk_variable_lval("gv_" + str(offset))
def assembly_ast( self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: if xdata.instruction_is_subsumed(): return [] else: (lhs, _, _) = self.operands[0].ast_lvalue(astree) (rhs, _, _) = self.operands[1].ast_rvalue(astree) assign = astree.mk_assign(lhs, rhs) astree.add_instruction_span(assign.id, iaddr, bytestring) return [assign]
def assembly_ast_condition(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> Optional[ASTExpr]: ftconds = self.ft_conditions(xdata) if len(ftconds) == 2: tcond = ftconds[1] if tcond.is_constant: astcond = XU.xxpr_to_ast_expr(xdata.xprs[2], astree) else: astcond = XU.xxpr_to_ast_expr(tcond, astree) astree.add_instruction_span(astcond.id, iaddr, bytestring) return astcond else: return None
def ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: (rhs1, _, _) = self.operands[0].ast_rvalue(astree) (rhs2, _, _) = self.operands[1].ast_rvalue(astree) lhs1 = str(xdata.vars[0]) lhs2 = str(xdata.vars[1]) if lhs1.endswith("[0]"): lhs1 = "*" + lhs1[:-3] lval1 = astree.mk_variable_lval(lhs1) lval2 = astree.mk_variable_lval(lhs2) assign1 = astree.mk_assign(lval1, rhs1) assign2 = astree.mk_assign(lval2, rhs2) astree.add_instruction_span(assign1.id, iaddr, bytestring) astree.add_instruction_span(assign2.id, iaddr, bytestring) return [assign1, assign2]
def is_struct_field_address(xpr: X.XXpr, astree: AbstractSyntaxTree) -> bool: """Return true if the expression is the address of a known struct.""" if xpr.is_int_constant: return astree.is_struct_field_address(xpr.intvalue) return False
def ast_rvalue( self, astree: AbstractSyntaxTree ) -> Tuple[AST.ASTExpr, List[AST.ASTInstruction], List[AST.ASTInstruction]]: (lval, preinstrs, postinstrs) = self.ast_lvalue(astree) rval = astree.mk_lval_expr(lval) return (rval, preinstrs, postinstrs)
def ast( self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: if xdata.instruction_is_subsumed(): return [] else: lhs = XU.xvariable_to_ast_lval(xdata.vars[0], astree) rhs = XU.xxpr_to_ast_expr(xdata.xprs[0], astree) # (lhs, _, _) = self.operands[0].ast_lvalue(astree) # (rhs, _, _) = self.operands[1].ast_rvalue(astree) assign = astree.mk_assign(lhs, rhs) astree.add_instruction_span(assign.id, iaddr, bytestring) return [assign]
def ast_rvalue( self, astree: AbstractSyntaxTree ) -> Tuple[AST.ASTExpr, List[AST.ASTInstruction], List[AST.ASTInstruction]]: gvname = "gv_" + self.address.get_hex() gv = astree.mk_global_variable_expr( gvname, globaladdress=self.address.get_int()) return (gv, [], [])
def xxpr_to_struct_field_address_expr( xpr: X.XXpr, astree: AbstractSyntaxTree) -> AST.ASTExpr: """Return a struct field as an address expression.""" if not is_struct_field_address(xpr, astree): raise UF.CHBError("Expression " + str(xpr) + " is not a struct field") return astree.get_struct_field_address(xpr.intvalue)
def xtyped_expr_to_ast_expr(op: str, op1: AST.ASTExpr, op2: AST.ASTExpr, astree: AbstractSyntaxTree) -> AST.ASTExpr: """Determine if expression needs different representation based on type.""" if op1.ctype is None: raise UF.CHBError("Expression is not typed: " + str(op1)) if op1.ctype.is_pointer and op2.is_integer_constant: op2 = cast(AST.ASTIntegerConstant, op2) tgttype = cast("BCTypPtr", op1.ctype).tgttyp if tgttype.is_struct: compinfo = cast("BCTypComp", tgttype).compinfo fieldoffset = field_at_offset(compinfo, op2.cvalue, astree) lval = astree.mk_memref_lval(op1, fieldoffset) return astree.mk_address_of(lval) return astree.mk_binary_op(op, op1, op2)
def vinitregister_value_to_ast_lval(vconstvar: "VInitialRegisterValue", astree: AbstractSyntaxTree) -> AST.ASTLval: if vconstvar.is_argument_value: argindex = vconstvar.argument_index() funarg = astree.function_argument(argindex) if funarg: return astree.mk_register_variable_lval(funarg.name, vtype=funarg.typ, parameter=argindex) else: return astree.mk_register_variable_lval(str(vconstvar.register)) elif vconstvar.register.is_stack_pointer: return astree.mk_register_variable_lval("base_sp") else: print("Initial Register Value: " + str(vconstvar.register)) return astree.mk_register_variable_lval(str(vconstvar.register))
def assembly_ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[ASTInstruction]: lhs = astree.mk_register_variable_lval("R0") tgt = self.operands[0] if tgt.is_absolute: tgtaddr = cast(ARMAbsoluteOp, tgt.opkind) if self.app.has_function_name(tgtaddr.address.get_hex()): faddr = tgtaddr.address.get_hex() fnsymbol = self.app.function_name(faddr) tgtxpr: ASTExpr = astree.mk_global_variable_expr( fnsymbol, globaladdress=int(str(tgtaddr.address), 16)) else: (tgtxpr, _, _) = self.operands[0].ast_rvalue(astree) else: (tgtxpr, _, _) = self.operands[0].ast_rvalue(astree) call = astree.mk_call(lhs, tgtxpr, []) astree.add_instruction_span(call.id, iaddr, bytestring) return [call]
def xconstant_to_ast_expr(xc: X.XprConstant, astree: AbstractSyntaxTree) -> AST.ASTExpr: """Convert a constant value to an AST Expr node.""" if xc.is_int_constant: return astree.mk_integer_constant(xc.intvalue) else: raise UF.CHBError("AST conversion of xconstant " + str(xc) + " not yet supported")
def ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[ASTInstruction]: lhs = xdata.vars[0] rhs1 = str(xdata.xprs[0]) rhs2 = xdata.xprs[1] rhs3 = xdata.xprs[3] if lhs == "SP" and rhs1 == "SP" and rhs2.is_constant: return [] lhsast = XU.xvariable_to_ast_lval(lhs, astree) if rhs1 == "SP" and rhs3.is_stack_address: rhs3 = cast("XprCompound", rhs3) stackoffset = rhs3.stack_address_offset() rhslval = astree.mk_stack_variable_lval(stackoffset) rhsast: ASTExpr = astree.mk_address_of(rhslval) elif rhs1 == "PC" or str(rhs2) == "PC": if rhs3.is_int_constant: rhsval = cast("XprConstant", rhs3).intvalue rhsast = astree.mk_integer_constant(rhsval) else: rhsast = XU.xxpr_to_ast_expr(rhs3, astree) else: rhsast = XU.xxpr_to_ast_expr(rhs3, astree) result = astree.mk_assign(lhsast, rhsast) astree.add_instruction_span(result.id, iaddr, bytestring) return [result]