void StatsTracker::recordSolverQuery(uint64_t time_stamp, uint64_t solving_time, data::QueryReason reason, data::QueryOperation operation, bool shadow, const ExecutionState &state) { data::SolverQuery *query = currentQuerySet.add_solver_query(); query->set_time_stamp(time_stamp); query->set_solving_time(solving_time); query->set_reason(reason); query->set_operation(operation); KInstruction *ki = state.prevPC(); executor.kmodule->fillInstructionDebugInfo( ki->inst, *query->mutable_debug_info()); query->set_shadow(shadow); data::ExecutionState *es_data = query->mutable_execution_state(); recordStateUpdate(state, false, false, es_data); }
void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, std::vector< ref<Expr> > &arguments) { fireControlFlowEvent(&state, ::cloud9::worker::CALL); if (f && DebugCallHistory) { unsigned depth = state.stack().size(); LOG(INFO) << "Call[" << &state << "]: " << std::string(depth, ' ') << f->getName().str(); } Instruction *i = NULL; if (ki) i = ki->inst; if (ki && f && f->isDeclaration()) { switch(f->getIntrinsicID()) { case Intrinsic::not_intrinsic: // state may be destroyed by this call, cannot touch callExternalFunction(state, ki, f, arguments); break; // va_arg is handled by caller and intrinsic lowering, see comment for // ExecutionState::varargs case Intrinsic::vastart: { StackFrame &sf = state.stack().back(); assert(sf.varargs && "vastart called in function with no vararg object"); // FIXME: This is really specific to the architecture, not the pointer // size. This happens to work fir x86-32 and x86-64, however. Expr::Width WordSize = Context::get().getPointerWidth(); if (WordSize == Expr::Int32) { executeMemoryOperation(state, true, arguments[0], sf.varargs->getBaseExpr(), 0); } else { assert(WordSize == Expr::Int64 && "Unknown word size!"); // X86-64 has quite complicated calling convention. However, // instead of implementing it, we can do a simple hack: just // make a function believe that all varargs are on stack. executeMemoryOperation(state, true, arguments[0], ConstantExpr::create(48, 32), 0); // gp_offset executeMemoryOperation(state, true, AddExpr::create(arguments[0], ConstantExpr::create(4, 64)), ConstantExpr::create(304, 32), 0); // fp_offset executeMemoryOperation(state, true, AddExpr::create(arguments[0], ConstantExpr::create(8, 64)), sf.varargs->getBaseExpr(), 0); // overflow_arg_area executeMemoryOperation(state, true, AddExpr::create(arguments[0], ConstantExpr::create(16, 64)), ConstantExpr::create(0, 64), 0); // reg_save_area } break; } case Intrinsic::vaend: // va_end is a noop for the interpreter. // // FIXME: We should validate that the target didn't do something bad // with vaeend, however (like call it twice). break; case Intrinsic::vacopy: // va_copy should have been lowered. // // FIXME: It would be nice to check for errors in the usage of this as // well. default: LOG(FATAL) << "Unknown intrinsic: " << f->getName().data(); } if (InvokeInst *ii = dyn_cast<InvokeInst>(i)) transferToBasicBlock(ii->getNormalDest(), i->getParent(), state); } else { // FIXME: I'm not really happy about this reliance on prevPC but it is ok, I // guess. This just done to avoid having to pass KInstIterator everywhere // instead of the actual instruction, since we can't make a KInstIterator // from just an instruction (unlike LLVM). KFunction *kf = kmodule->functionMap[f]; state.pushFrame(state.prevPC(), kf); state.pc() = kf->instructions; if (statsTracker) statsTracker->framePushed(state, &state.stack()[state.stack().size()-2]); //XXX TODO fix this ugly stuff // TODO: support "byval" parameter attribute // TODO: support zeroext, signext, sret attributes unsigned callingArgs = arguments.size(); unsigned funcArgs = f->arg_size(); if (!f->isVarArg()) { if (callingArgs > funcArgs) { LOG(WARNING) << "Calling " << f->getName().data() << " with extra arguments."; } else if (callingArgs < funcArgs) { terminateStateOnError(state, "calling function with too few arguments", "user.err"); return; } } else { if (callingArgs < funcArgs) { terminateStateOnError(state, "calling function with too few arguments", "user.err"); return; } StackFrame &sf = state.stack().back(); unsigned size = 0; for (unsigned i = funcArgs; i < callingArgs; i++) { // FIXME: This is really specific to the architecture, not the pointer // size. This happens to work fir x86-32 and x86-64, however. Expr::Width WordSize = Context::get().getPointerWidth(); if (WordSize == Expr::Int32) { size += Expr::getMinBytesForWidth(arguments[i]->getWidth()); } else { size += llvm::RoundUpToAlignment(arguments[i]->getWidth(), WordSize) / 8; } } MemoryObject *mo = sf.varargs = memory->allocate(&state, size, true, false, state.prevPC()->inst); if (!mo) { terminateStateOnExecError(state, "out of memory (varargs)"); return; } ObjectState *os = bindObjectInState(state, mo, true); unsigned offset = 0; for (unsigned i = funcArgs; i < callingArgs; i++) { // FIXME: This is really specific to the architecture, not the pointer // size. This happens to work fir x86-32 and x86-64, however. Expr::Width WordSize = Context::get().getPointerWidth(); if (WordSize == Expr::Int32) { os->write(offset, arguments[i]); offset += Expr::getMinBytesForWidth(arguments[i]->getWidth()); } else { assert(WordSize == Expr::Int64 && "Unknown word size!"); os->write(offset, arguments[i]); offset += llvm::RoundUpToAlignment(arguments[i]->getWidth(), WordSize) / 8; } } } unsigned numFormals = f->arg_size(); for (unsigned i=0; i<numFormals; ++i) bindArgument(kf, i, state, arguments[i]); } }