BaseSemantics::SValuePtr RiscOperators::rotateRight(const BaseSemantics::SValuePtr &a_, const BaseSemantics::SValuePtr &sa_) { SValuePtr a = SValue::promote(a_); SValuePtr sa = SValue::promote(sa_); return undefined_(a->get_width()); }
BaseSemantics::SValuePtr RiscOperators::concat(const BaseSemantics::SValuePtr &a_, const BaseSemantics::SValuePtr &b_) { SValuePtr a = SValue::promote(a_); SValuePtr b = SValue::promote(b_); return undefined_(a->get_width() + b->get_width()); }
Sawyer::Optional<BaseSemantics::SValuePtr> SValue::createOptionalMerge(const BaseSemantics::SValuePtr &other_, const BaseSemantics::MergerPtr &merger, const SmtSolverPtr &solver) const { SValuePtr other = SValue::promote(other_); SValuePtr retval = create_empty(other->get_width()); bool changed = false; for (size_t i=0; i<subvalues.size(); ++i) { BaseSemantics::SValuePtr thisValue = subvalues[i]; BaseSemantics::SValuePtr otherValue = other->subvalues[i]; if (otherValue) { if (thisValue==NULL) { retval->subvalues.push_back(otherValue); changed = true; } else if (BaseSemantics::SValuePtr mergedValue = thisValue->createOptionalMerge(otherValue, merger, solver).orDefault()) { changed = true; retval->subvalues.push_back(mergedValue); } else { retval->subvalues.push_back(thisValue); } } else { retval->subvalues.push_back(thisValue); } } return changed ? Sawyer::Optional<BaseSemantics::SValuePtr>(retval) : Sawyer::Nothing(); }
BaseSemantics::SValuePtr RiscOperators::Cursor::operator()(const BaseSemantics::SValuePtr &a_) const { ASSERT_require(!at_end()); SValuePtr a = SValue::promote(a_); return a->get_subvalue(idx_); }
BaseSemantics::SValuePtr RiscOperators::unsignedModulo(const BaseSemantics::SValuePtr &a_, const BaseSemantics::SValuePtr &b_) { SValuePtr a = SValue::promote(a_); SValuePtr b = SValue::promote(b_); return undefined_(b->get_width()); }
BaseSemantics::SValuePtr RiscOperators::extract(const BaseSemantics::SValuePtr &a_, size_t begin_bit, size_t end_bit) { SValuePtr a = SValue::promote(a_); assert(end_bit<=a->get_width()); assert(begin_bit<end_bit); return undefined_(end_bit-begin_bit); }
BaseSemantics::SValuePtr RiscOperators::signExtend(const BaseSemantics::SValuePtr &a_, size_t new_width) { SValuePtr a = SValue::promote(a_); if (new_width==a->get_width()) return a; return undefined_(new_width); }
BaseSemantics::SValuePtr RiscOperators::unsignedMultiply(const BaseSemantics::SValuePtr &a_, const BaseSemantics::SValuePtr &b_) { SValuePtr a = SValue::promote(a_); SValuePtr b = SValue::promote(b_); size_t retwidth = a->get_width() + b->get_width(); return undefined_(retwidth); }
BaseSemantics::SValuePtr RiscOperators::readRegister(RegisterDescriptor reg, const BaseSemantics::SValuePtr &dflt) { SValuePtr retval = SValue::promote(Super::readRegister(reg, dflt)); SymbolicExpr::Ptr expr = retval->get_expression(); if (expr->isLeafNode()) { std::string comment = commentForVariable(reg, "read"); State::promote(currentState())->varComment(expr->isLeafNode()->toString(), comment); } return retval; }
bool SValue::may_equal(const BaseSemantics::SValuePtr &other_, const SmtSolverPtr &solver) const { SValuePtr other = SValue::promote(other_); for (size_t i=0; i<subvalues.size(); ++i) { if (is_valid(i) && other->is_valid(i) && get_subvalue(i)->may_equal(other->get_subvalue(i), solver)) return true; } return false; }
BinaryAnalysis::Disassembler::AddressSet SgAsmM68kInstruction::getSuccessors(const std::vector<SgAsmInstruction*>& insns, bool *complete, const BinaryAnalysis::MemoryMap::Ptr &initial_memory) { using namespace Rose::BinaryAnalysis::InstructionSemantics2; Stream debug(mlog[DEBUG]); if (debug) { debug <<"SgAsmM68kInstruction::getSuccessors(" <<StringUtility::addrToString(insns.front()->get_address()) <<" for " <<insns.size() <<" instruction" <<(1==insns.size()?"":"s") <<"):" <<"\n"; } BinaryAnalysis::Disassembler::AddressSet successors = SgAsmInstruction::getSuccessors(insns, complete); // If we couldn't determine all the successors, or a cursory analysis couldn't narrow it down to a single successor then // we'll do a more thorough analysis now. In the case where the cursory analysis returned a complete set containing two // successors, a thorough analysis might be able to narrow it down to a single successor. We should not make special // assumptions about function call instructions -- their only successor is the specified address operand. */ if (!*complete || successors.size()>1) { using namespace Rose::BinaryAnalysis::InstructionSemantics2::PartialSymbolicSemantics; const RegisterDictionary *regdict = RegisterDictionary::dictionary_coldfire_emac(); RiscOperatorsPtr ops = RiscOperators::instance(regdict); ops->set_memory_map(initial_memory); DispatcherM68kPtr dispatcher = DispatcherM68k::instance(ops, 32); try { for (size_t i=0; i<insns.size(); ++i) { dispatcher->processInstruction(insns[i]); if (debug) debug << " state after " <<insns[i]->toString() <<"\n" <<*ops; } SValuePtr ip = SValue::promote(ops->readRegister(dispatcher->REG_PC)); if (ip->is_number()) { successors.clear(); successors.insert(ip->get_number()); *complete = true; /*this is the complete set of successors*/ } } catch(const BaseSemantics::Exception& e) { /* Abandon entire basic block if we hit an instruction that's not implemented. */ debug <<e <<"\n"; } } if (debug) { debug <<" successors:"; BOOST_FOREACH (rose_addr_t va, successors) debug <<" " <<StringUtility::addrToString(va); debug <<(*complete?"":"...") <<"\n"; } return successors; }
bool SValue::must_equal(const BaseSemantics::SValuePtr &other_, const SmtSolverPtr &solver) const { SValuePtr other = SValue::promote(other_); size_t nconsidered = 0; for (size_t i=0; i<subvalues.size(); ++i) { if (is_valid(i) && other->is_valid(i)) { if (!get_subvalue(i)->must_equal(other->get_subvalue(i), solver)) return false; ++nconsidered; } } return nconsidered>0; }
void RegisterStateGeneric::initialize_nonoverlapping(const std::vector<RegisterDescriptor> ®s, bool initialize_to_zero) { clear(); for (size_t i=0; i<regs.size(); ++i) { std::string name = regdict->lookup(regs[i]); SValuePtr val; if (initialize_to_zero) { val = get_protoval()->number_(regs[i].get_nbits(), 0); } else { val = get_protoval()->undefined_(regs[i].get_nbits()); if (!name.empty()) val->set_comment(name+"_0"); } registers_.insertMaybeDefault(regs[i]).push_back(RegPair(regs[i], val)); } }
SValuePtr SymbolicMemory::readMemory(const SValuePtr &address_, const SValuePtr &dflt, RiscOperators *addrOps, RiscOperators *valOps) { using namespace InsnSemanticsExpr; SymbolicSemantics::SValuePtr address = SymbolicSemantics::SValue::promote(address_); if (address->get_width() != mem_->domainWidth() || dflt->get_width() != mem_->get_nbits()) { ASSERT_require2(mem_->isLeafNode() && mem_->isLeafNode()->is_memory(), "invalid address and/or value size for memory; expecting " + StringUtility::numberToString(mem_->domainWidth()) + "-bit addresses and " + StringUtility::numberToString(mem_->get_nbits()) + "-bit values"); // We can finalize the domain and range widths for the memory now that they've been given. mem_ = LeafNode::create_memory(address->get_width(), dflt->get_width()); } TreeNodePtr resultExpr = InternalNode::create(8, OP_READ, mem_, address->get_expression()); SymbolicSemantics::SValuePtr retval = SymbolicSemantics::SValue::promote(dflt->copy()); retval->set_expression(resultExpr); return retval; }
BaseSemantics::SValuePtr RiscOperators::addWithCarries(const BaseSemantics::SValuePtr &a_, const BaseSemantics::SValuePtr &b_, const BaseSemantics::SValuePtr &c_, BaseSemantics::SValuePtr &carry_out/*out*/) { SValuePtr a = SValue::promote(a_); SValuePtr b = SValue::promote(b_); SValuePtr c = SValue::promote(c_); assert(a->get_width()==b->get_width() && c->get_width()==1); carry_out = undefined_(a->get_width()); return undefined_(a->get_width()); }
/** Read memory. * * If multi-path is enabled, then return a new memory expression that describes the process of reading a value from the * specified address; otherwise, actually read the value and return it. In any case, record some information about the * address that's being read if we've never seen it before. */ BaseSemantics::SValuePtr RiscOperators::readMemory(RegisterDescriptor segreg, const BaseSemantics::SValuePtr &addr, const BaseSemantics::SValuePtr &dflt_, const BaseSemantics::SValuePtr &cond) { BaseSemantics::SValuePtr dflt = dflt_; const size_t nBytes = dflt->get_width() / 8; if (cond->is_number() && !cond->get_number()) return dflt_; // If we know the address and that memory exists, then read the memory to obtain the default value. uint8_t buf[8]; if (addr->is_number() && nBytes < sizeof(buf) && nBytes == partitioner_->memoryMap()->at(addr->get_number()).limit(nBytes).read(buf).size()) { // FIXME[Robb P. Matzke 2015-05-25]: assuming little endian uint64_t value = 0; for (size_t i=0; i<nBytes; ++i) value |= (uint64_t)buf[i] << (8*i); dflt = number_(dflt->get_width(), value); } // Read from the symbolic state, and update the state with the default from real memory if known. BaseSemantics::SValuePtr retval = Super::readMemory(segreg, addr, dflt, cond); if (!currentInstruction()) return retval; // not called from dispatcher on behalf of an instruction // Save a description of the variable SymbolicExpr::Ptr valExpr = SValue::promote(retval)->get_expression(); if (valExpr->isLeafNode() && valExpr->isLeafNode()->isVariable()) { std::string comment = commentForVariable(addr, "read"); State::promote(currentState())->varComment(valExpr->isLeafNode()->toString(), comment); } // Save a description for its addresses for (size_t i=0; i<nBytes; ++i) { SValuePtr va = SValue::promote(add(addr, number_(addr->get_width(), i))); if (va->get_expression()->isLeafNode()) { std::string comment = commentForVariable(addr, "read", i, nBytes); State::promote(currentState())->varComment(va->get_expression()->isLeafNode()->toString(), comment); } } return retval; }
BaseSemantics::SValuePtr RiscOperators::ite(const BaseSemantics::SValuePtr &sel_, const BaseSemantics::SValuePtr &a_, const BaseSemantics::SValuePtr &b_) { SValuePtr sel = SValue::promote(sel_); SValuePtr a = SValue::promote(a_); SValuePtr b = SValue::promote(b_); assert(1==sel->get_width()); assert(a->get_width()==b->get_width()); return undefined_(a->get_width()); }
/** Write value to memory. * * If multi-path is enabled, then return a new memory expression that updates memory with a new address/value pair; * otherwise update the memory directly. In any case, record some information about the address that was written if we've * never seen it before. */ void RiscOperators::writeMemory(RegisterDescriptor segreg, const BaseSemantics::SValuePtr &addr, const BaseSemantics::SValuePtr &value, const BaseSemantics::SValuePtr &cond) { if (cond->is_number() && !cond->get_number()) return; Super::writeMemory(segreg, addr, value, cond); // Save a description of the variable SymbolicExpr::Ptr valExpr = SValue::promote(value)->get_expression(); if (valExpr->isLeafNode() && valExpr->isLeafNode()->isVariable()) { std::string comment = commentForVariable(addr, "write"); State::promote(currentState())->varComment(valExpr->isLeafNode()->toString(), comment); } // Save a description for its addresses size_t nBytes = value->get_width() / 8; for (size_t i=0; i<nBytes; ++i) { SValuePtr va = SValue::promote(add(addr, number_(addr->get_width(), i))); if (va->get_expression()->isLeafNode()) { std::string comment = commentForVariable(addr, "read", i, nBytes); State::promote(currentState())->varComment(va->get_expression()->isLeafNode()->toString(), comment); } } }
// 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; }
BaseSemantics::SValuePtr RiscOperators::mostSignificantSetBit(const BaseSemantics::SValuePtr &a_) { SValuePtr a = SValue::promote(a_); return undefined_(a->get_width()); }
BaseSemantics::SValuePtr RiscOperators::invert(const BaseSemantics::SValuePtr &a_) { SValuePtr a = SValue::promote(a_); return undefined_(a->get_width()); }
// 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; }