void BaseInstructions::killState(S2EExecutionState *state) { std::string message; uint32_t messagePtr; bool ok = true; klee::ref<klee::Expr> status = state->readCpuRegister(CPU_OFFSET(regs[R_EAX]), klee::Expr::Int32); ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EBX]), &messagePtr, 4); if (!ok) { s2e()->getWarningsStream(state) << "ERROR: symbolic argument was passed to s2e_kill_state \n"; } else { message="<NO MESSAGE>"; if(messagePtr && !state->readString(messagePtr, message)) { s2e()->getWarningsStream(state) << "Error reading message string from the guest\n"; } } //Kill the current state s2e()->getMessagesStream(state) << "Killing state " << state->getID() << '\n'; std::ostringstream os; os << "State was terminated by opcode\n" << " message: \"" << message << "\"\n" << " status: " << status; s2e()->getExecutor()->terminateStateEarly(*state, os.str()); }
void BaseInstructions::concretize(S2EExecutionState *state, bool addConstraint) { uint32_t address, size; bool ok = true; ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &address, 4); ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EBX]), &size, 4); if(!ok) { s2e()->getWarningsStream(state) << "ERROR: symbolic argument was passed to s2e_op " " get_example opcode\n"; return; } for(unsigned i = 0; i < size; ++i) { if (!state->readMemoryConcrete8(address + i, NULL, S2EExecutionState::VirtualAddress, addConstraint)) { s2e()->getWarningsStream(state) << "Can not concretize memory" << " at " << hexval(address + i) << '\n'; } } }
/** * A call handler can invoke this function to register a return handler. * XXX: We assume that the passed execution state corresponds to the state in which * this instance of FunctionMonitorState is used. */ void FunctionMonitorState::registerReturnSignal(S2EExecutionState *state, FunctionMonitor::ReturnSignal &sig) { if(sig.empty()) { return; } uint32_t sp; #ifdef TARGET_ARM bool ok = state->readCpuRegisterConcrete(CPU_OFFSET(regs[13]), &sp, sizeof(target_ulong)); #elif defined(TARGET_I386) bool ok = state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_ESP]), &sp, sizeof(target_ulong)); #else assert(false); #endif uint64_t pid = state->getPid(); if (m_plugin->m_monitor) { pid = m_plugin->m_monitor->getPid(state, state->getPc()); } if(!ok) { m_plugin->s2e()->getWarningsStream(state) << "Function call with symbolic SP!" << std::endl << " PC=" << hexval(state->getPc()) << " PID=" << hexval(pid) << std::endl; return; } ReturnDescriptor descriptor = {pid, sig }; m_returnDescriptors.insert(std::make_pair(sp, descriptor)); }
void BaseInstructions::isSymbolic(S2EExecutionState *state) { uint32_t address; uint32_t result; char buf; bool ok = true; ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_ECX]), &address, 4); if(!ok) { s2e()->getWarningsStream(state) << "ERROR: symbolic argument was passed to s2e_op is_symbolic\n"; return; } s2e()->getMessagesStream(state) << "Testing whether data at " << hexval(address) << " is symbolic:"; // readMemoryConcrete fails if the value is symbolic result = !state->readMemoryConcrete(address, &buf, 1); s2e()->getMessagesStream(state) << (result ? " true" : " false") << '\n'; state->writeCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &result, 4); }
void DasosPreproc::fuzzFork1 (S2EExecutionState* state, unsigned int value) { /** Emulate fork via WindowsApi forkRange Code */ klee::ref<klee::Expr> symb = state->createSymbolicValue (klee::Expr::Int32, "fuzz_symb"); klee::ref<klee::Expr> cond = klee::NeExpr::create (symb, klee::ConstantExpr::create (value, klee::Expr::Int32) ); klee::Executor::StatePair sp = s2e()->getExecutor()->fork (*state, cond, false); S2EExecutionState *fs = static_cast<S2EExecutionState *>(sp.second); // set the return value for state 1 to given value fs->writeCpuRegisterConcrete (CPU_OFFSET(regs[R_EAX]), &(value), 4); // set the return value for state 0 to a canary value = 0xffffffff; state->writeCpuRegisterConcrete (CPU_OFFSET(regs[R_EAX]), &(value), 4); return; } // end fn fuzzFork1
void BaseInstructions::printExpression(S2EExecutionState *state) { //Print the expression uint32_t name; //xxx bool ok = true; ref<Expr> val = state->readCpuRegister(offsetof(CPUX86State, regs[R_EAX]), klee::Expr::Int32); ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_ECX]), &name, 4); if(!ok) { s2e()->getWarningsStream(state) << "ERROR: symbolic argument was passed to s2e_op " "print_expression opcode\n"; return; } std::string nameStr = "<NO NAME>"; if(name && !state->readString(name, nameStr)) { s2e()->getWarningsStream(state) << "Error reading string from the guest\n"; } s2e()->getMessagesStream() << "SymbExpression " << nameStr << " - " <<val << '\n'; }
void BaseInstructions::printMessage(S2EExecutionState *state, bool isWarning) { uint32_t address = 0; //XXX bool ok = state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &address, 4); if(!ok) { s2e()->getWarningsStream(state) << "ERROR: symbolic argument was passed to s2e_op " " message opcode\n"; return; } std::string str=""; if(!address || !state->readString(address, str)) { s2e()->getWarningsStream(state) << "Error reading string message from the guest at address " << hexval(address) << '\n'; } else { llvm::raw_ostream *stream; if(isWarning) stream = &s2e()->getWarningsStream(state); else stream = &s2e()->getMessagesStream(state); (*stream) << "Message from guest (" << hexval(address) << "): " << str << '\n'; } }
/** * When emitSignal is false, this function simply removes all the return descriptors * for the current stack pointer. This can be used when a return handler manually changes the * program counter and/or wants to exit to the cpu loop and avoid being called again. * * Note: all the return handlers will be erased if emitSignal is false, not just the one * that issued the call. Also note that it not possible to return from the handler normally * whenever this function is called from within a return handler. */ void X86FunctionMonitorState::slotRet(S2EExecutionState *state, uint64_t pc, bool emitSignal) { target_ulong cr3 = state->readCpuState(CPU_OFFSET(cr[3]), 8*sizeof(target_ulong)); target_ulong esp; bool ok = state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_ESP]), &esp, sizeof(target_ulong)); if(!ok) { target_ulong eip = state->readCpuState(CPU_OFFSET(eip), 8*sizeof(target_ulong)); m_plugin->s2e()->getWarningsStream(state) << "Function return with symbolic ESP!" << '\n' << " EIP=" << hexval(eip) << " CR3=" << hexval(cr3) << '\n'; return; } if (m_returnDescriptors.empty()) { return; } //m_plugin->s2e()->getDebugStream() << "ESP AT RETURN 0x" << std::hex << esp << // " plgstate=0x" << this << " EmitSignal=" << emitSignal << std::endl; bool finished = true; do { finished = true; std::pair<ReturnDescriptorsMap::iterator, ReturnDescriptorsMap::iterator> range = m_returnDescriptors.equal_range(esp); for(ReturnDescriptorsMap::iterator it = range.first; it != range.second; ++it) { if (m_plugin->m_monitor) { cr3 = m_plugin->m_monitor->getPid(state, pc); } if(it->second.cr3 == cr3) { if (emitSignal) { it->second.signal.emit(state); } m_returnDescriptors.erase(it); finished = false; break; } } } while(!finished); }
void S2EEventLogger::extractCallStack(S2EExecutionState *state, int &stack_size) { #ifdef TARGET_I386 stack_size = 0; target_long frame_pointer; callstack_[stack_size++] = state->getPc(); if (!state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EBP]), &frame_pointer, sizeof(frame_pointer))) { return; } // XXX: Hack, hack, hack: Handle the case where EBP was pushed // on the stack by a concrete syscall. if (!frame_pointer) { ref<Expr> head = state->readMemory(state->getSp(), Expr::Int32, S2EExecutionState::VirtualAddress); if (ConstantExpr *ce = dyn_cast<ConstantExpr>(head)) { frame_pointer = ce->getZExtValue(); } else { return; } } while (frame_pointer && stack_size < CollectEventMaxStackDepth) { ref<Expr> next_expr = state->readMemory(frame_pointer, Expr::Int32, S2EExecutionState::VirtualAddress); ref<Expr> retaddr_expr = state->readMemory(frame_pointer + sizeof(target_ulong), Expr::Int32, S2EExecutionState::VirtualAddress); if (retaddr_expr.isNull()) return; if (ConstantExpr *ce = dyn_cast<ConstantExpr>(retaddr_expr)) { callstack_[stack_size++] = ce->getZExtValue(); } else { return; } if (next_expr.isNull()) return; if (ConstantExpr *ce = dyn_cast<ConstantExpr>(next_expr)) { frame_pointer = ce->getZExtValue(); } else { return; } } #else stack_size = 0; #endif }
void MemoryManager::onFunctionReturn(S2EExecutionState* state,bool test) { //s2e()->getMessagesStream() << "---onFunctionReturn" << '\n'; //get address state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]),&address , 4); //s2e()->getMessagesStream() << "分配的address (eax):" << hexval(address) << '\n'; //check? //因为s2e本身的机制,在此处得到的分配长度size会是具体化过的, //所以不能在此处检测分配的size,应当在调用的时候进行检测 //而return之后会再符号化 //grant();//如果保存所有的__kmalloc,vector会崩 TODO }
void BaseInstructions::concretize(S2EExecutionState *state, bool addConstraint) { uint32_t address, size; bool ok = true; ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &address, 4); ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EBX]), &size, 4); if(!ok) { s2e()->getWarningsStream(state) << "ERROR: symbolic argument was passed to s2e_op " " get_example opcode" << std::endl; return; } for(unsigned i = 0; i < size; ++i) { ref<Expr> expr = state->readMemory8(address + i); if(!expr.isNull()) { if(addConstraint) { /* concretize */ expr = s2e()->getExecutor()->toConstant(*state, expr, "request from guest"); } else { /* example */ expr = s2e()->getExecutor()->toConstantSilent(*state, expr); } if(!state->writeMemory(address + i, expr)) { s2e()->getWarningsStream(state) << "Can not write to memory" << " at " << hexval(address + i) << std::endl; } } else { s2e()->getWarningsStream(state) << "Can not read from memory" << " at " << hexval(address + i) << std::endl; } } }
void DasosPreproc::fuzzFork (S2EExecutionState* state, unsigned int start, unsigned int end) { /** Emulate fork via WindowsApi forkRange Code */ unsigned int i; //assert(m_functionMonitor); klee::ref<klee::Expr> symb = state->createSymbolicValue (klee::Expr::Int32, "fuzz_symb"); S2EExecutionState *curState = state; // by making this 1 shy of iterations you can leverage i value afterwards and the first input state so it doesn't go to waste for (i = start; i < end; i++) { //s2e()->getDebugStream () << "fuzzClone: 2 " << std::endl; klee::ref<klee::Expr> cond = klee::NeExpr::create (symb, klee::ConstantExpr::create (i, klee::Expr::Int32) ); //s2e()->getDebugStream () << "fuzzClone: 3 " << std::endl; klee::Executor::StatePair sp = s2e()->getExecutor()->fork (*curState, cond, false); //s2e()->getDebugStream () << "fuzzClone: 4 " << std::endl; S2EExecutionState *ts = static_cast<S2EExecutionState *>(sp.first); S2EExecutionState *fs = static_cast<S2EExecutionState *>(sp.second); fs->writeCpuRegisterConcrete (CPU_OFFSET(regs[R_EAX]), &(i), 4); // set the return value curState = ts; } state->writeCpuRegisterConcrete (CPU_OFFSET(regs[R_EAX]), &(i), 4); // set the return value return; } // end fn fuzzFork
void BaseInstructions::printMemory(S2EExecutionState *state) { uint32_t address, size, name; // XXX should account for 64 bits archs bool ok = true; ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &address, 4); ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EBX]), &size, 4); ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_ECX]), &name, 4); if(!ok) { s2e()->getWarningsStream(state) << "ERROR: symbolic argument was passed to s2e_op " "print_expression opcode\n"; return; } std::string nameStr = "<NO NAME>"; if(name && !state->readString(name, nameStr)) { s2e()->getWarningsStream(state) << "Error reading string from the guest\n"; } s2e()->getMessagesStream() << "Symbolic memory dump of " << nameStr << '\n'; for (uint32_t i=0; i<size; ++i) { s2e()->getMessagesStream() << hexval(address+i) << ": "; ref<Expr> res = state->readMemory8(address+i); if (res.isNull()) { s2e()->getMessagesStream() << "Invalid pointer\n"; }else { s2e()->getMessagesStream() << res << '\n'; } } }
void BaseInstructions::sleep(S2EExecutionState *state) { uint32_t duration = 0; state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &duration, sizeof(uint32_t)); s2e()->getDebugStream() << "Sleeping " << duration << " seconds\n"; llvm::sys::TimeValue startTime = llvm::sys::TimeValue::now(); while (llvm::sys::TimeValue::now().seconds() - startTime.seconds() < duration) { #ifdef _WIN32 Sleep(1000); #else ::sleep(1); #endif } }
/** * A call handler can invoke this function to register a return handler. * XXX: We assume that the passed execution state corresponds to the state in which * this instance of FunctionMonitorState is used. */ void X86FunctionMonitorState::registerReturnSignal(S2EExecutionState *state, X86FunctionMonitor::ReturnSignal &sig) { if(sig.empty()) { return; } target_ulong esp; bool ok = state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_ESP]), &esp, sizeof esp); if(!ok) { m_plugin->s2e()->getWarningsStream(state) << "Function call with symbolic ESP!\n" << " EIP=" << hexval(state->getPc()) << " CR3=" << hexval(state->getPid()) << '\n'; return; } uint64_t pid = state->getPid(); if (m_plugin->m_monitor) { pid = m_plugin->m_monitor->getPid(state, state->getPc()); } ReturnDescriptor descriptor = {pid, sig }; m_returnDescriptors.insert(std::make_pair(esp, descriptor)); }
/* Uses a custom instruction within the binary * must #include s2e.h in guest code source * (our custom insns start around line 350 in s2e.h * Also must #define DASOS_PREPROC_OPCODE 0xFA line 49 in Opcodes.h */ void DasosPreproc::onCustomInstruction (S2EExecutionState* state, uint64_t opcode) { if (!OPCODE_CHECK(opcode, DASOS_PREPROC_OPCODE)) { return; } bool ok = true; opcode >>= 16; uint8_t op = opcode & 0xFF; opcode >>= 8; switch (op) { case 1: //static inline void s2e_dasospreproc_init (unsigned base, unsigned size, unsigned eip, unsigned sysc) // Module load // eax = runtime load base // ebx = length of memory // ecx = goal eip ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &(cfg.base_addr), 4); cfg.base_addr = cfg.base_addr & 0xffffffff; ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EBX]), &(cfg.byte_len), 4); cfg.byte_len = cfg.byte_len & 0xffffffff; ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_ECX]), &(cfg.eip_addr), 4); cfg.eip_addr = cfg.eip_addr & 0xffffffff; ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EDX]), &(cfg.sysc), 4); cfg.sysc = cfg.sysc & 0xffffffff; cfg.end_addr = cfg.base_addr + cfg.byte_len; if (!ok) { s2e()->getWarningsStream (state) << "ERROR: symbolic argument was passed to s2e_op in DasosPreproc loadmodule" << std::endl; return; } onActivateModule (state); break; case 2: // static inline unsigned int s2e_dasospreproc_fuzz (unsigned int start, unsigned int end) // time to start fuzzing a particular variable // eax = return value // ebx = start of range value // ecx = end of range value uint64_t start; uint64_t end; ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EBX]), &(start), 4); start = start & 0xffffffff; if (!ok) s2e()->getWarningsStream (state) << "ERROR: bad argument was passed to s2e_op: start " << start << " in DasosPreproc start fuzzing" << std::endl; ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_ECX]), &(end), 4); end = end & 0xffffffff; if (!ok) s2e()->getWarningsStream (state) << "ERROR: bad argument was passed to s2e_op: end " << end << " in DasosPreproc start fuzzing" << std::endl; if (!ok) return; if (start > end) { s2e()->getWarningsStream (state) << "ERROR: start (" << start << ") > end (" << end << ") is invalid range in DasosPreproc start fuzzing" << std::endl; return; } s2e()->getDebugStream () << ">> fuzzInit: datum to be iterated from " << start << " to " << end << std::endl; // if there is no need to fork if (start == end) { state->writeCpuRegisterConcrete (CPU_OFFSET(regs[R_EAX]), &(start), 4); break; } // the following functions found in S2EExecutionState if (state->needToJumpToSymbolic () ) { // the state must be symbolic in order to fork state->jumpToSymbolic (); } // in case forking isn't enabled, enable it here if (!(state->isForkingEnabled () ) ) { state->enableForking (); } fuzzFork (state, start, end); break; case 4: // static inline unsigned int s2e_dasospreproc_createFork (unsigned int value) // return 2 states, 0 set to 0xffffffff and 1 set to value // eax = return value // ebx = value uint64_t value; ok &= state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_EBX]), &(value), 4); value = value & 0xffffffff; if (!ok) { s2e()->getWarningsStream (state) << "ERROR: bad argument was passed to s2e_op: start " << value << " in DasosPreproc start fuzzing" << std::endl; return; } s2e()->getDebugStream () << ">> fuzzInit: datum forking for value " << value << std::endl; // the following functions found in S2EExecutionState if (state->needToJumpToSymbolic () ) { // the state must be symbolic in order to fork state->jumpToSymbolic (); } // in case forking isn't enabled, enable it here if (!(state->isForkingEnabled () ) ) { state->enableForking (); } fuzzFork1 (state, value); break; case 6 : onFini (state); break; default : s2e()->getWarningsStream (state) << "ERROR: invalid opcode" << std::endl; } return; } // end fn DasosPreproc::onCustomInstruction
/** * When emitSignal is false, this function simply removes all the return descriptors * for the current stack pointer. This can be used when a return handler manually changes the * program counter and/or wants to exit to the cpu loop and avoid being called again. * * Note: all the return handlers will be erased if emitSignal is false, not just the one * that issued the call. Also note that it is not possible to return from the handler normally * whenever this function is called from within a return handler. */ void FunctionMonitorState::slotRet(S2EExecutionState *state, uint64_t pc, bool emitSignal) { target_ulong pid; target_ulong sp; #ifdef TARGET_ARM assert(m_plugin->m_monitor); pid = m_plugin->m_monitor->getPid(state, pc); bool ok = state->readCpuRegisterConcrete(CPU_OFFSET(regs[13]), &sp, sizeof(target_ulong)); if(!ok) { target_ulong pc = state->readCpuState(CPU_OFFSET(regs[15]), 8*sizeof(target_ulong)); m_plugin->s2e()->getWarningsStream(state) << "Function return with symbolic ESP!" << std::endl << " PC=" << hexval(pc) << /*" PID=" << hexval(pid) <<*/ std::endl; return; } #elif defined(TARGET_I386) pid = state->readCpuState(CPU_OFFSET(cr[3]), 8*sizeof(target_ulong)); bool ok = state->readCpuRegisterConcrete(CPU_OFFSET(regs[R_ESP]), &sp, sizeof(target_ulong)); if(!ok) { target_ulong pc = state->readCpuState(CPU_OFFSET(eip), 8*sizeof(target_ulong)); m_plugin->s2e()->getWarningsStream(state) << "Function return with symbolic ESP!" << std::endl << " PC=" << hexval(pc) << /*" PID=" << hexval(pid) <<*/ std::endl; return; } #else assert(false); #endif if (m_returnDescriptors.empty()) { return; } //m_plugin->s2e()->getDebugStream() << "ESP AT RETURN 0x" << std::hex << esp << // " plgstate=0x" << this << " EmitSignal=" << emitSignal << std::endl; bool finished = true; do { finished = true; std::pair<ReturnDescriptorsMap::iterator, ReturnDescriptorsMap::iterator> range = m_returnDescriptors.equal_range(sp); for(ReturnDescriptorsMap::iterator it = range.first; it != range.second; ++it) { if (m_plugin->m_monitor) { pid = m_plugin->m_monitor->getPid(state, pc); } if(it->second.pid == pid) { if (emitSignal) { it->second.signal.emit(state); } m_returnDescriptors.erase(it); finished = false; break; } } } while(!finished); }
void CooperativeSearcher::onCustomInstruction(S2EExecutionState* state, uint64_t opcode) { //XXX: find a better way of allocating custom opcodes if (!OPCODE_CHECK(opcode, COOPSEARCHER_OPCODE)) { return; } uint8_t op = OPCODE_GETSUBFUNCTION(opcode); bool ok = true; target_ulong nextState = 0; CoopSchedulerOpcodes opc = (CoopSchedulerOpcodes)op; switch(opc) { //Pick the next state specified as input ergument case ScheduleNext: { ok &= state->readCpuRegisterConcrete(CPU_OFFSET(COOPSEARCHER_NEXTSTATE), &nextState, sizeof nextState); if(!ok) { s2e()->getWarningsStream(state) << "ERROR: symbolic argument was passed to s2e_op " "CooperativeSearcher ScheduleNext" << '\n'; break; } States::iterator it = m_states.find(nextState); if (it == m_states.end()) { s2e()->getWarningsStream(state) << "ERROR: Invalid state passed to " << "CooperativeSearcher ScheduleNext: " << nextState << '\n'; } m_currentState = (*it).second; s2e()->getMessagesStream(state) << "CooperativeSearcher picked the state " << nextState << '\n'; //Force rescheduling state->setPc(state->getPc() + S2E_OPCODE_SIZE); throw CpuExitException(); break; } //Deschedule the current state. Will pick the state with strictly lower id. case Yield: { if (m_states.size() == 1) { break; } States::iterator it = m_states.find(m_currentState->getID()); if (it == m_states.begin()) { m_currentState = (*m_states.rbegin()).second; }else { --it; m_currentState = (*it).second; } //Force rescheduling state->setPc(state->getPc() + S2E_OPCODE_SIZE); throw CpuExitException(); break; } } }
/** Handle s2e_op instruction. Instructions: 0f 3f XX XX XX XX XX XX XX XX XX: opcode */ void BaseInstructions::handleBuiltInOps(S2EExecutionState* state, uint64_t opcode) { switch((opcode>>8) & 0xFF) { case 0: { /* s2e_check */ uint32_t v = 1; state->writeCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &v, 4); } break; case 1: state->enableSymbolicExecution(); break; case 2: state->disableSymbolicExecution(); break; case 3: { /* s2e_make_symbolic */ makeSymbolic(state, false); break; } case 4: { /* s2e_is_symbolic */ isSymbolic(state); break; } case 5: { /* s2e_get_path_id */ state->writeCpuRegister(offsetof(CPUX86State, regs[R_EAX]), klee::ConstantExpr::create(state->getID(), klee::Expr::Int32)); break; } case 6: { /* s2e_kill_state */ killState(state); break; } case 7: { /* s2e_print_expression */ printExpression(state); break; } case 8: { //Print memory contents printMemory(state); break; } case 9: state->enableForking(); break; case 10: state->disableForking(); break; case 0x10: { /* s2e_print_message */ printMessage(state, opcode >> 16); break; } case 0x11: { /* s2e_make_concolic */ makeSymbolic(state, true); break; } case 0x20: /* concretize */ concretize(state, true); break; case 0x21: { /* replace an expression by one concrete example */ concretize(state, false); break; } case 0x30: { /* Get number of active states */ uint32_t count = s2e()->getExecutor()->getStatesCount(); state->writeCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &count, sizeof(uint32_t)); break; } case 0x31: { /* Get number of active S2E instances */ uint32_t count = s2e()->getCurrentProcessCount(); state->writeCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &count, sizeof(uint32_t)); break; } case 0x32: { /* Sleep for a given number of seconds */ sleep(state); break; } case 0x50: { /* disable/enable timer interrupt */ uint64_t disabled = opcode >> 16; if(disabled) s2e()->getMessagesStream(state) << "Disabling timer interrupt\n"; else s2e()->getMessagesStream(state) << "Enabling timer interrupt\n"; state->writeCpuState(CPU_OFFSET(timer_interrupt_disabled), disabled, 8); break; } case 0x51: { /* disable/enable all apic interrupts */ uint64_t disabled = opcode >> 16; if(disabled) s2e()->getMessagesStream(state) << "Disabling all apic interrupt\n"; else s2e()->getMessagesStream(state) << "Enabling all apic interrupt\n"; state->writeCpuState(CPU_OFFSET(all_apic_interrupts_disabled), disabled, 8); break; } case 0x52: { /* Gets the current S2E memory object size (in power of 2) */ uint32_t size = S2E_RAM_OBJECT_BITS; state->writeCpuRegisterConcrete(CPU_OFFSET(regs[R_EAX]), &size, 4); break; } case 0x70: /* merge point */ state->jumpToSymbolicCpp(); s2e()->getExecutor()->queueStateForMerge(state); break; default: s2e()->getWarningsStream(state) << "BaseInstructions: Invalid built-in opcode " << hexval(opcode) << '\n'; break; } }