Beispiel #1
0
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());
}
Beispiel #2
0
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());
}
Beispiel #3
0
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();
}
Beispiel #4
0
BaseSemantics::SValuePtr
RiscOperators::Cursor::operator()(const BaseSemantics::SValuePtr &a_) const
{
    ASSERT_require(!at_end());
    SValuePtr a = SValue::promote(a_);
    return a->get_subvalue(idx_);
}
Beispiel #5
0
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());
}
Beispiel #6
0
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);
}
Beispiel #7
0
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);
}
Beispiel #8
0
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);
}
Beispiel #9
0
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;
}
Beispiel #10
0
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;
}
Beispiel #12
0
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> &regs, 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));
    }
}
Beispiel #14
0
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;
}
Beispiel #15
0
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());
}
Beispiel #16
0
/** 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;
}
Beispiel #17
0
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());
}
Beispiel #18
0
/** 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;
}
Beispiel #20
0
BaseSemantics::SValuePtr
RiscOperators::mostSignificantSetBit(const BaseSemantics::SValuePtr &a_)
{
    SValuePtr a = SValue::promote(a_);
    return undefined_(a->get_width());
}
Beispiel #21
0
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;
}