//! [basicReadTest] static void basicReadTest(const P2::Partitioner &partitioner) { std::cout <<"\n" <<std::string(40, '=') <<"\nbasicReadTest\n" <<std::string(40, '=') <<"\n"; SymbolicSemantics::Formatter fmt; fmt.set_line_prefix(" "); // Create the RiscOperators and the initial state. const RegisterDictionary *regdict = partitioner.instructionProvider().registerDictionary(); const RegisterDescriptor REG = partitioner.instructionProvider().stackPointerRegister(); const std::string REG_NAME = RegisterNames(regdict)(REG); BaseSemantics::RiscOperatorsPtr ops = SymbolicSemantics::RiscOperators::instance(regdict); ops->currentState()->memoryState()->set_byteOrder(partitioner.instructionProvider().defaultByteOrder()); BaseSemantics::StatePtr initialState = ops->currentState()->clone(); ops->initialState(initialState); // lazily evaluated initial state std::cout <<"Initial state before reading:\n" <<(*initialState+fmt); // Read some memory and a register, which should cause them to spring into existence in both the current state and the // initial state. BaseSemantics::SValuePtr addr1 = ops->number_(32, 0); BaseSemantics::SValuePtr dflt1m = ops->number_(32, 0x11223344); BaseSemantics::SValuePtr read1m = ops->readMemory(RegisterDescriptor(), addr1, dflt1m, ops->boolean_(true)); BaseSemantics::SValuePtr dflt1r = ops->undefined_(REG.get_nbits()); BaseSemantics::SValuePtr read1r = ops->readRegister(REG, dflt1r); std::cout <<"Initial state after reading " <<*read1m <<" from address " <<*addr1 <<"\n" <<"and " <<*read1r <<" from " <<REG_NAME <<"\n" <<(*initialState+fmt); ASSERT_always_require(read1m->must_equal(dflt1m)); ASSERT_always_require(read1r->must_equal(dflt1r)); // Create a new current state and read again. We should get the same value even though the current state is empty. BaseSemantics::StatePtr curState = ops->currentState()->clone(); curState->clear(); ops->currentState(curState); BaseSemantics::SValuePtr dflt2m = ops->number_(32, 0x55667788); BaseSemantics::SValuePtr read2m = ops->readMemory(RegisterDescriptor(), addr1, dflt2m, ops->boolean_(true)); BaseSemantics::SValuePtr dflt2r = ops->undefined_(REG.get_nbits()); BaseSemantics::SValuePtr read2r = ops->readRegister(REG, dflt2r); std::cout <<"Initial state after reading " <<*read2m <<" from address " <<*addr1 <<"\n" <<"and " <<*read2r <<" from " <<REG_NAME <<"\n" <<(*initialState+fmt); ASSERT_always_require(read1m->must_equal(read2m)); ASSERT_always_require(read1r->must_equal(read2r)); // Disable the initial state. If we re-read the same address we'll still get the same result because it's now present in // the current state also. ops->initialState(BaseSemantics::StatePtr()); BaseSemantics::SValuePtr dflt3m = ops->number_(32, 0x99aabbcc); BaseSemantics::SValuePtr read3m = ops->readMemory(RegisterDescriptor(), addr1, dflt3m, ops->boolean_(true)); BaseSemantics::SValuePtr dflt3r = ops->undefined_(REG.get_nbits()); BaseSemantics::SValuePtr read3r = ops->readRegister(REG, dflt3r); ASSERT_always_require(read1m->must_equal(read3m)); ASSERT_always_require(read1r->must_equal(read3r)); }
// see base class bool SgAsmX86Instruction::isFunctionCallSlow(const std::vector<SgAsmInstruction*>& insns, rose_addr_t *target, rose_addr_t *return_va) { if (isFunctionCallFast(insns, target, return_va)) return true; // The following stuff works only if we have a relatively complete AST. static const size_t EXECUTION_LIMIT = 10; // max size of basic blocks for expensive analyses if (insns.empty()) return false; SgAsmX86Instruction *last = isSgAsmX86Instruction(insns.back()); if (!last) return false; SgAsmFunction *func = SageInterface::getEnclosingNode<SgAsmFunction>(last); SgAsmInterpretation *interp = SageInterface::getEnclosingNode<SgAsmInterpretation>(func); // Slow method: Emulate the instructions and then look at the EIP and stack. If the EIP points outside the current // function and the top of the stack holds an address of an instruction within the current function, then this must be a // function call. if (interp && insns.size()<=EXECUTION_LIMIT) { using namespace Rose::BinaryAnalysis; using namespace Rose::BinaryAnalysis::InstructionSemantics2; using namespace Rose::BinaryAnalysis::InstructionSemantics2::SymbolicSemantics; const InstructionMap &imap = interp->get_instruction_map(); const RegisterDictionary *regdict = RegisterDictionary::dictionary_for_isa(interp); SmtSolverPtr solver = SmtSolver::instance(Rose::CommandLine::genericSwitchArgs.smtSolver); BaseSemantics::RiscOperatorsPtr ops = RiscOperators::instance(regdict, solver); ASSERT_not_null(ops); const RegisterDescriptor SP = regdict->findLargestRegister(x86_regclass_gpr, x86_gpr_sp); DispatcherX86Ptr dispatcher = DispatcherX86::instance(ops, SP.get_nbits()); SValuePtr orig_esp = SValue::promote(ops->readRegister(dispatcher->REG_anySP)); try { for (size_t i=0; i<insns.size(); ++i) dispatcher->processInstruction(insns[i]); } catch (const BaseSemantics::Exception &e) { return false; } // If the next instruction address is concrete but does not point to a function entry point, then this is not a call. SValuePtr eip = SValue::promote(ops->readRegister(dispatcher->REG_anyIP)); if (eip->is_number()) { rose_addr_t target_va = eip->get_number(); SgAsmFunction *target_func = SageInterface::getEnclosingNode<SgAsmFunction>(imap.get_value_or(target_va, NULL)); if (!target_func || target_va!=target_func->get_entry_va()) return false; } // If nothing was pushed onto the stack, then this isn't a function call. const size_t spWidth = dispatcher->REG_anySP.get_nbits(); SValuePtr esp = SValue::promote(ops->readRegister(dispatcher->REG_anySP)); SValuePtr stack_delta = SValue::promote(ops->add(esp, ops->negate(orig_esp))); SValuePtr stack_delta_sign = SValue::promote(ops->extract(stack_delta, spWidth-1, spWidth)); if (stack_delta_sign->is_number() && 0==stack_delta_sign->get_number()) return false; // If the top of the stack does not contain a concrete value or the top of the stack does not point to an instruction // in this basic block's function, then this is not a function call. const size_t ipWidth = dispatcher->REG_anyIP.get_nbits(); SValuePtr top = SValue::promote(ops->readMemory(dispatcher->REG_SS, esp, esp->undefined_(ipWidth), esp->boolean_(true))); if (top->is_number()) { rose_addr_t va = top->get_number(); SgAsmFunction *return_func = SageInterface::getEnclosingNode<SgAsmFunction>(imap.get_value_or(va, NULL)); if (!return_func || return_func!=func) { return false; } } else { return false; } // Since EIP might point to a function entry address and since the top of the stack contains a pointer to an // instruction in this function, we assume that this is a function call. if (target && eip->is_number()) *target = eip->get_number(); if (return_va && top->is_number()) *return_va = top->get_number(); return true; } // Similar to the above method, but works when all we have is the basic block (e.g., this case gets hit quite a bit from // the Partitioner). Returns true if, after executing the basic block, the top of the stack contains the fall-through // address of the basic block. We depend on our caller to figure out if EIP is reasonably a function entry address. if (!interp && insns.size()<=EXECUTION_LIMIT) { using namespace Rose::BinaryAnalysis; using namespace Rose::BinaryAnalysis::InstructionSemantics2; using namespace Rose::BinaryAnalysis::InstructionSemantics2::SymbolicSemantics; SmtSolverPtr solver = SmtSolver::instance(Rose::CommandLine::genericSwitchArgs.smtSolver); SgAsmX86Instruction *x86insn = isSgAsmX86Instruction(insns.front()); ASSERT_not_null(x86insn); #if 1 // [Robb P. Matzke 2015-03-03]: FIXME[Robb P. Matzke 2015-03-03]: not ready yet; x86-64 semantics still under construction if (x86insn->get_addressSize() != x86_insnsize_32) return false; #endif const RegisterDictionary *regdict = registersForInstructionSize(x86insn->get_addressSize()); const RegisterDescriptor SP = regdict->findLargestRegister(x86_regclass_gpr, x86_gpr_sp); BaseSemantics::RiscOperatorsPtr ops = RiscOperators::instance(regdict, solver); DispatcherX86Ptr dispatcher = DispatcherX86::instance(ops, SP.get_nbits()); try { for (size_t i=0; i<insns.size(); ++i) dispatcher->processInstruction(insns[i]); } catch (const BaseSemantics::Exception &e) { return false; } // Look at the top of the stack const size_t ipWidth = dispatcher->REG_anyIP.get_nbits(); SValuePtr top = SValue::promote(ops->readMemory(dispatcher->REG_SS, ops->readRegister(SP), ops->protoval()->undefined_(ipWidth), ops->protoval()->boolean_(true))); if (top->is_number() && top->get_number() == last->get_address()+last->get_size()) { if (target) { SValuePtr eip = SValue::promote(ops->readRegister(dispatcher->REG_anyIP)); if (eip->is_number()) *target = eip->get_number(); } if (return_va) *return_va = top->get_number(); return true; } } return false; }
// see base class; don't modify target_va or return_va if they are not known bool SgAsmM68kInstruction::isFunctionCallSlow(const std::vector<SgAsmInstruction*>& insns, rose_addr_t *target_va, rose_addr_t *return_va) { if (isFunctionCallFast(insns, target_va, return_va)) return true; static const size_t EXECUTION_LIMIT = 25; // max size of basic blocks for expensive analyses if (insns.empty()) return false; SgAsmM68kInstruction *last = isSgAsmM68kInstruction(insns.back()); if (!last) return false; SgAsmFunction *func = SageInterface::getEnclosingNode<SgAsmFunction>(last); SgAsmInterpretation *interp = SageInterface::getEnclosingNode<SgAsmInterpretation>(func); // Slow method: Emulate the instructions and then look at the program counter (PC) and stack (A7). If the PC points // outside the current function and the top of the stack holds an address of an instruction within the current function, // then this must be a function call. if (interp && insns.size()<=EXECUTION_LIMIT) { using namespace Rose::BinaryAnalysis; using namespace Rose::BinaryAnalysis::InstructionSemantics2; using namespace Rose::BinaryAnalysis::InstructionSemantics2::SymbolicSemantics; const InstructionMap &imap = interp->get_instruction_map(); const RegisterDictionary *regdict = RegisterDictionary::dictionary_for_isa(interp); SmtSolverPtr solver = SmtSolver::instance(Rose::CommandLine::genericSwitchArgs.smtSolver); BaseSemantics::RiscOperatorsPtr ops = RiscOperators::instance(regdict, solver); DispatcherM68kPtr dispatcher = DispatcherM68k::instance(ops, 32); SValuePtr orig_sp = SValue::promote(ops->readRegister(dispatcher->REG_A[7])); try { for (size_t i=0; i<insns.size(); ++i) dispatcher->processInstruction(insns[i]); } catch (const BaseSemantics::Exception &e) { return false; } // If the next instruction address is concrete but does not point to a function entry point, then this is not a call. SValuePtr ip = SValue::promote(ops->readRegister(dispatcher->REG_PC)); if (ip->is_number()) { rose_addr_t target_va = ip->get_number(); SgAsmFunction *target_func = SageInterface::getEnclosingNode<SgAsmFunction>(imap.get_value_or(target_va, NULL)); if (!target_func || target_va!=target_func->get_entry_va()) return false; } // If nothing was pushed onto the stack, then this isn't a function call. SValuePtr sp = SValue::promote(ops->readRegister(dispatcher->REG_A[7])); SValuePtr stack_delta = SValue::promote(ops->add(sp, ops->negate(orig_sp))); SValuePtr stack_delta_sign = SValue::promote(ops->extract(stack_delta, 31, 32)); if (stack_delta_sign->is_number() && 0==stack_delta_sign->get_number()) return false; // If the top of the stack does not contain a concrete value or the top of the stack does not point to an instruction // in this basic block's function, then this is not a function call. SValuePtr top = SValue::promote(ops->readMemory(RegisterDescriptor(), sp, sp->undefined_(32), sp->boolean_(true))); if (top->is_number()) { rose_addr_t va = top->get_number(); SgAsmFunction *return_func = SageInterface::getEnclosingNode<SgAsmFunction>(imap.get_value_or(va, NULL)); if (!return_func || return_func!=func) { return false; } } else { return false; } // Since the instruction pointer might point to a function entry address and since the top of the stack contains a // pointer to an instruction in this function, we assume that this is a function call. if (target_va && ip->is_number()) *target_va = ip->get_number(); if (return_va && top->is_number()) *return_va = top->get_number(); return true; } // Similar to the above method, but works when all we have is the basic block (e.g., this case gets hit quite a bit from // the Partitioner). Returns true if, after executing the basic block, the top of the stack contains the fall-through // address of the basic block. We depend on our caller to figure out if the instruction pointer is reasonably a function // entry address. if (!interp && insns.size()<=EXECUTION_LIMIT) { using namespace Rose::BinaryAnalysis; using namespace Rose::BinaryAnalysis::InstructionSemantics2; using namespace Rose::BinaryAnalysis::InstructionSemantics2::SymbolicSemantics; const RegisterDictionary *regdict = RegisterDictionary::dictionary_coldfire_emac(); SmtSolverPtr solver = SmtSolver::instance(Rose::CommandLine::genericSwitchArgs.smtSolver); BaseSemantics::RiscOperatorsPtr ops = RiscOperators::instance(regdict, solver); DispatcherM68kPtr dispatcher = DispatcherM68k::instance(ops, 32); try { for (size_t i=0; i<insns.size(); ++i) dispatcher->processInstruction(insns[i]); } catch (const BaseSemantics::Exception &e) { return false; } // Look at the top of the stack SValuePtr top = SValue::promote(ops->readMemory(RegisterDescriptor(), ops->readRegister(dispatcher->REG_A[7]), ops->protoval()->undefined_(32), ops->protoval()->boolean_(true))); if (top->is_number() && top->get_number() == last->get_address()+last->get_size()) { if (target_va) { SValuePtr ip = SValue::promote(ops->readRegister(dispatcher->REG_PC)); if (ip->is_number()) *target_va = ip->get_number(); } if (return_va) *return_va = top->get_number(); return true; } } return false; }