// Run natively and return number of instructions executed and reason for termination. static std::pair<size_t, std::string> runNatively(const Settings &settings, const std::string &specimenName, Sawyer::Optional<rose_addr_t> initVa, const P2::Partitioner &partitioner, rose_addr_t randomAddress) { Stream debug(mlog[DEBUG]); BinaryDebugger debugger(specimenName); if (debugger.isTerminated()) { mlog[FATAL] <<"child " <<debugger.isAttached() <<" " <<debugger.howTerminated() <<" before we could gain control\n"; exit(1); } // Allow child to run until we hit the desired address. if (initVa) { debugger.setBreakpoint(*initVa); debugger.runToBreakpoint(); debugger.clearBreakpoint(*initVa); if (debugger.isTerminated()) { mlog[FATAL] <<"child " <<debugger.isAttached() <<" " <<debugger.howTerminated() <<" without reaching " <<addrToString(*initVa) <<"\n"; exit(1); } } // Show specimen address map so we can verify that the Linux loader used the same addresses we used. // We could have shown it earlier, but then we wouldn't have seen the results of dynamic linking. if (settings.showMaps) { std::cout <<"Linux loader specimen memory map:\n"; system(("cat /proc/" + numberToString(debugger.isAttached()) + "/maps").c_str()); } // Branch to the starting address debug <<"branching to " <<addrToString(randomAddress) <<"\n"; debugger.executionAddress(randomAddress); std::string terminationReason; size_t nExecuted = 0; // number of instructions executed while (1) { // Check for and avoid system calls if necessary if (!settings.allowSyscalls) { rose_addr_t eip = debugger.executionAddress(); SgAsmX86Instruction *insn = isSgAsmX86Instruction(partitioner.instructionProvider()[eip]); if (!insn || insn->isUnknown()) { if (settings.showInsnTrace) std::cout <<"at " <<addrToString(eip) <<": " <<(insn?"no":"unknown") <<" instruction\n"; terminationReason = "executed at " + addrToString(eip) +" which we don't know about"; break; } if (settings.showInsnTrace) std::cout <<"at " <<unparseInstructionWithAddress(insn) <<"\n"; if (insn->get_kind() == x86_int || insn->get_kind() == x86_sysenter) { terminationReason = "tried to execute a system call"; break; } } // Single-step if (debug) debug <<"single stepping at " <<addrToString(debugger.executionAddress()) <<"\n"; debugger.singleStep(); if (debugger.isTerminated()) { terminationReason = debugger.howTerminated(); break; } ++nExecuted; if (settings.maxInsns!=0 && nExecuted>=settings.maxInsns) { terminationReason = "reached instruction limit"; break; } } debugger.terminate(); return std::make_pair(nExecuted, terminationReason); }