diff --git a/src/experiments/kesogc/CMakeLists.txt b/src/experiments/kesogc/CMakeLists.txt new file mode 100644 index 00000000..dfd5e336 --- /dev/null +++ b/src/experiments/kesogc/CMakeLists.txt @@ -0,0 +1,37 @@ +set(EXPERIMENT_NAME kesogc) +set(EXPERIMENT_TYPE KESOgc) +configure_file(../instantiate-experiment.ah.in + ${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY +) + +## Setup desired protobuf descriptions HERE ## +set(MY_PROTOS + kesogc.proto +) + +set(MY_CAMPAIGN_SRCS + experiment.hpp + experiment.cc + campaign.hpp + campaign.cc +) + +#### PROTOBUFS #### +find_package(Protobuf REQUIRED) +include_directories(${PROTOBUF_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +find_package(MySQL REQUIRED) +include_directories(${MYSQL_INCLUDE_DIR}) + +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS}) + +## Build library +add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS}) +add_dependencies(fail-${EXPERIMENT_NAME} fail-comm) +target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY}) + +## This is the example's campaign server distributing experiment parameters +add_executable(${EXPERIMENT_NAME}-server main.cc) +target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${MYSQL_LIBRARIES} -Wl,--end-group) +install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin) diff --git a/src/experiments/kesogc/campaign.cc b/src/experiments/kesogc/campaign.cc new file mode 100644 index 00000000..bb7c2aef --- /dev/null +++ b/src/experiments/kesogc/campaign.cc @@ -0,0 +1,20 @@ +#include +#include + +#include "campaign.hpp" +#include "experimentInfo.hpp" +#include "cpn/CampaignManager.hpp" +#include "util/Logger.hpp" +#include "util/ProtoStream.hpp" +#include "sal/SALConfig.hpp" + + +using namespace std; +using namespace fail; +using namespace google::protobuf; + +void KesoGcCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) { + KesoGcExperimentData *data = new KesoGcExperimentData; + data->msg.mutable_fsppilot()->CopyFrom(pilot); + campaignmanager.addParam(data); +} diff --git a/src/experiments/kesogc/campaign.hpp b/src/experiments/kesogc/campaign.hpp new file mode 100644 index 00000000..716e9666 --- /dev/null +++ b/src/experiments/kesogc/campaign.hpp @@ -0,0 +1,24 @@ +#ifndef __KESOGCCAMPAIGN_HPP__ + #define __KESOGCCAMPAIGN_HPP__ + +#include "cpn/DatabaseCampaign.hpp" +#include "comm/ExperimentData.hpp" +#include +#include "kesogc.pb.h" + + +class KesoGcExperimentData : public fail::ExperimentData { +public: + KesoGcProtoMsg msg; + KesoGcExperimentData() : fail::ExperimentData(&msg) {} +}; + + +class KesoGcCampaign : public fail::DatabaseCampaign { + virtual const google::protobuf::Descriptor * cb_result_message() + { return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("KesoGcProtoMsg"); } + + virtual void cb_send_pilot(DatabaseCampaignMessage pilot); +}; + +#endif // __KESOGCCAMPAIGN_HPP__ diff --git a/src/experiments/kesogc/experiment.cc b/src/experiments/kesogc/experiment.cc new file mode 100644 index 00000000..19f60219 --- /dev/null +++ b/src/experiments/kesogc/experiment.cc @@ -0,0 +1,327 @@ +#include +#include + +// getpid +#include +#include + + +#include +#include "experiment.hpp" +#include "experimentInfo.hpp" +#include "sal/SALConfig.hpp" +#include "sal/SALInst.hpp" +#include "sal/Memory.hpp" +#include "sal/Listener.hpp" + +#include "sal/bochs/BochsListener.hpp" +#include +#include + +#include "campaign.hpp" +#include "kesogc.pb.h" +#include "util/Disassembler.hpp" + +const char *parity_types[] = { + "LIST", + "STACK", + "STACK_POINTER", + "DOMAIN", + "BITMAP", + "LLREFS", + "COLOR" +}; + +using namespace std; +using namespace fail; + +// Check if configuration dependencies are satisfied: +#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) + #error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration. +#endif + +unsigned KESOgc::injectBitFlip(address_t data_address, unsigned bitpos){ + + MemoryManager& mm = simulator.getMemoryManager(); + unsigned int value, injectedval; + + value = mm.getByte(data_address); + injectedval = value ^ (1 << bitpos); + mm.setByte(data_address, injectedval); + + m_log << "INJECTION at: 0x" << hex<< setw(2) << setfill('0') << data_address + << " value: 0x" << setw(2) << setfill('0') << value << " -> 0x" << setw(2) << setfill('0') << mm.getByte(data_address) << endl; + + return value; +} + + +void handleEvent(KesoGcProtoMsg_Result& result, KesoGcProtoMsg_Result_ResultType restype, const std::string &msg) { + cout << "Result details: " << msg << endl; + result.set_resulttype(restype); + result.set_details(msg); +} + + +void handleMemoryAccessEvent(KesoGcProtoMsg_Result& result, const fail::MemAccessListener& l_mem){ + stringstream sstr; + sstr << "mem access ("; + switch (l_mem.getTriggerAccessType()) { + case MemAccessEvent::MEM_READ: + sstr << "r"; + break; + case MemAccessEvent::MEM_WRITE: + sstr << "w"; + break; + default: break; + } + sstr << ") @ 0x" << hex << l_mem.getTriggerAddress(); + + sstr << " ip @ 0x" << hex << l_mem.getTriggerInstructionPointer(); + + handleEvent(result, result.MEMACCESS, sstr.str()); +} + +bool KESOgc::run() +{ + address_t minimal_ip = INT_MAX; // 1 Mbyte + address_t maximal_ip = 0; + address_t minimal_data = 0x100000; // 1 Mbyte + address_t maximal_data = 0; + + for (ElfReader::section_iterator it = m_elf.sec_begin(); + it != m_elf.sec_end(); ++it) { + const ElfSymbol &symbol = *it; + std::string prefix(".text"); + if (symbol.getName().compare(0, prefix.size(), prefix) == 0) { + minimal_ip = std::min(minimal_ip, symbol.getStart()); + maximal_ip = std::max(maximal_ip, symbol.getEnd()); + } else { + minimal_data = std::min(minimal_data, symbol.getStart()); + maximal_data = std::max(maximal_data, symbol.getEnd()); + } + } + + std::cout << "Code section from " << hex << minimal_ip << " to " << maximal_ip << std::endl; + std::cout << "Whole programm section from " << hex << minimal_data << " to " << maximal_data << std::endl; + + + + // m_dis.init(); + //******* Boot, and store state *******// + m_log << "STARTING EXPERIMENT" << endl; + + unsigned executed_jobs = 0; + + // Setup exit points + const ElfSymbol &s_error = m_elf.getSymbol("keso_throw_error"); + BPSingleListener l_error(s_error.getAddress()); + + const ElfSymbol &s_nullp = m_elf.getSymbol("keso_throw_nullpointer"); + BPSingleListener l_nullp(s_nullp.getAddress()); + + const ElfSymbol &s_oobounds = m_elf.getSymbol("keso_throw_index_out_of_bounds"); + BPSingleListener l_oobounds(s_oobounds.getAddress()); + + const ElfSymbol &s_gc_parity = m_elf.getSymbol("keso_throw_gc_parity"); + BPSingleListener l_gc_parity(s_gc_parity.getAddress()); + + const ElfSymbol &s_parity = m_elf.getSymbol("keso_throw_parity"); + BPSingleListener l_parity(s_parity.getAddress()); + + //BPSingleListener l_dump(m_elf.getSymbol("c17_Main_m4_dumpResults_console").getAddress()); + BPSingleListener l_end(m_elf.getSymbol("keso_end").getAddress()); + + MemAccessListener l_mem_text(minimal_ip, MemAccessEvent::MEM_WRITE); + l_mem_text.setWatchWidth(maximal_ip - minimal_ip); + + MemAccessListener l_mem_outerspace( maximal_data, MemAccessEvent::MEM_WRITE); + l_mem_outerspace.setWatchWidth(0xfffffff0); + + TrapListener l_trap(ANY_TRAP); + + TimerListener l_timeout(5 * 1000 * 1000); // 5 seconds in microseconds + + const ElfSymbol &s_resilient_heap_repaired = m_elf.getSymbol("keso_resilient_gcHeapPointer_repaired"); + BPSingleListener l_resilient_heap_repaired(s_resilient_heap_repaired.getAddress()); + + const ElfSymbol &s_ft_list_repaired = m_elf.getSymbol("keso_ft_list_repaired"); + BPSingleListener l_ft_list_repaired(s_ft_list_repaired.getAddress()); + + const ElfSymbol &s_ft_list_broken = m_elf.getSymbol("keso_ft_list_broken"); + BPSingleListener l_ft_list_broken(s_ft_list_broken.getAddress()); + + const ElfSymbol &s_resilient_stack_repaired = m_elf.getSymbol("keso_resilient_gcStackPointer_repaired"); + BPSingleListener l_resilient_stack_repaired(s_resilient_stack_repaired.getAddress()); + + while (executed_jobs < 25 || m_jc->getNumberOfUndoneJobs() > 0) { + m_log << "asking jobserver for parameters" << endl; + KesoGcExperimentData param; + if(!m_jc->getParam(param)){ + m_log << "Dying." << endl; // We were told to die. + simulator.terminate(1); + } + + // Get input data from Jobserver + unsigned injection_instr = param.msg.fsppilot().injection_instr(); + address_t data_address = param.msg.fsppilot().data_address(); + + for (int bit_offset = 0; bit_offset < 8; ++bit_offset) { + // 8 results in one job + KesoGcProtoMsg_Result *result = param.msg.add_result(); + result->set_bitoffset(bit_offset); + + m_log << "restoring state" << endl; + // Restore to the image, which starts at address(main) + simulator.restore("state"); + executed_jobs ++; + + m_log << "Trying to inject @ instr #" << dec << injection_instr << endl; + + + if (injection_instr > 0) { + simulator.clearListeners(); + // XXX could be improved with intermediate states (reducing runtime until injection) + simulator.addListener(&l_end); + + BPSingleListener bp; + bp.setWatchInstructionPointer(ANY_ADDR); + + // Fix offset by 1 error + bp.setCounter(injection_instr + 1); + + simulator.addListener(&bp); + + bool inject = true; + while (1) { + fail::BaseListener * listener = simulator.resume(); + // finish() before FI? + if (listener == &l_end) { + m_log << "experiment reached finish() before FI" << endl; + handleEvent(*result, result->NOINJECTION, "time_marker reached before instr2"); + inject = false; + break; + } else if (listener == &bp) { + break; + } else { + inject = false; + handleEvent(*result, result->NOINJECTION, "WTF"); + break; + } + } + + // Next experiment + if (!inject) + continue; + } + + address_t injection_instr_absolute = param.msg.fsppilot().injection_instr_absolute(); + if (simulator.getCPU(0).getInstructionPointer() != injection_instr_absolute) { + m_log << "Invalid Injection address EIP=0x" + << std::hex << simulator.getCPU(0).getInstructionPointer() + << " != 0x" << injection_instr_absolute << std::endl; + simulator.terminate(1); + } + + /// INJECT BITFLIP: + result->set_original_value(injectBitFlip(data_address, bit_offset)); + + cout << " outerspace : " << l_mem_outerspace.getWatchWidth() << " --- @ :" << l_mem_outerspace.getWatchAddress() << endl; + simulator.clearListeners(); + simulator.addListener(&l_trap); + if (s_error.isValid()) + simulator.addListener(&l_error); + if (s_nullp.isValid()) + simulator.addListener(&l_nullp); + if (s_oobounds.isValid()) + simulator.addListener(&l_oobounds); + if (s_gc_parity.isValid()) + simulator.addListener(&l_gc_parity); + if (s_parity.isValid()) + simulator.addListener(&l_parity); + simulator.addListener(&l_end); + simulator.addListener(&l_mem_text); + simulator.addListener(&l_mem_outerspace); + simulator.addListener(&l_timeout); + + if(s_resilient_heap_repaired.isValid()){ + simulator.addListener(&l_resilient_heap_repaired); + } + + if(s_resilient_stack_repaired.isValid()){ + simulator.addListener(&l_resilient_stack_repaired); + } + + if(s_ft_list_repaired.isValid()){ + simulator.addListener(&l_ft_list_repaired); + } + + if(s_ft_list_broken.isValid()){ + simulator.addListener(&l_ft_list_broken); + } + + m_log << "Resuming till the crash" << std::endl; + // resume and wait for results + fail::BaseListener* l = simulator.resume(); + m_log << "CDX has ended" << std::endl; + + // Evaluate result + if(l == &l_error) { + handleEvent(*result, result->EXC_ERROR, "exc error"); + } else if (l == &l_nullp) { + handleEvent(*result, result->EXC_NULLPOINTER, "exc nullpointer"); + + } else if ( l == &l_oobounds ) { + handleEvent(*result, result->EXC_OOBOUNDS, "exc out of bounds"); + + } else if (l == &l_gc_parity) { + address_t stack_pointer = simulator.getCPU(0).getStackPointer(); + int32_t parity_type = simulator.getMemoryManager().getByte(stack_pointer + 4); // 1st argument is at esp+4 + stringstream sstr; + sstr << "exc gc_parity of type: " << parity_types[parity_type]; + handleEvent(*result, result->EXC_GC_PARITY, sstr.str()); + + } else if (l == &l_parity) { + handleEvent(*result, result->EXC_PARITY, "exc parity"); + + } else if (l == &l_end) { + handleEvent(*result, result->CALCDONE, "calculation done"); + + } else if (l == &l_timeout) { + handleEvent(*result, result->TIMEOUT, "5s"); + + } else if (l == &l_trap) { + stringstream sstr; + sstr << "trap #" << l_trap.getTriggerNumber(); + handleEvent(*result, result->TRAP, sstr.str()); + + } else if (l == &l_mem_text){ + handleMemoryAccessEvent(*result, l_mem_text); + + } else if (l == &l_mem_outerspace){ + handleMemoryAccessEvent(*result, l_mem_outerspace); + + } else if (l == &l_resilient_heap_repaired){ + handleEvent(*result, result->RESILIENT_HEAP_REPAIRED, "resilient heap pointer repaired"); + + } else if (l == &l_resilient_stack_repaired){ + handleEvent(*result, result->RESILIENT_STACK_REPAIRED, "resilient stack pointer repaired"); + + } else if (l == &l_ft_list_repaired){ + handleEvent(*result, result->FT_LIST_REPAIRED, "ft list repaired"); + + } else if (l == &l_ft_list_broken){ + handleEvent(*result, result->FT_LIST_BROKEN, "ft list broken"); + + } else { + handleEvent(*result, result->UNKNOWN, "UNKNOWN event"); + } + simulator.clearListeners(); + } + + m_jc->sendResult(param); + } + // Explicitly terminate, or the simulator will continue to run. + simulator.terminate(); +} + diff --git a/src/experiments/kesogc/experiment.hpp b/src/experiments/kesogc/experiment.hpp new file mode 100644 index 00000000..c69c4956 --- /dev/null +++ b/src/experiments/kesogc/experiment.hpp @@ -0,0 +1,44 @@ +#ifndef __KESO_GC_EXPERIMENT_HPP__ + #define __KESO_GC_EXPERIMENT_HPP__ + + +#include "sal/SALInst.hpp" +#include "efw/ExperimentFlow.hpp" +#include "efw/JobClient.hpp" +#include "util/Logger.hpp" +#include "util/ElfReader.hpp" +#include "util/Disassembler.hpp" +#include +#include + + +class KESOgc : public fail::ExperimentFlow { + fail::JobClient *m_jc; + fail::Logger m_log; + fail::MemoryManager& m_mm; + fail::ElfReader m_elf; + fail::Disassembler m_dis; + + void printEIP(); + void setupExitBPs(const std::string&); + void enableBPs(); + void clearExitBPs(); + void showStaticRefs(); + + unsigned injectBitFlip(fail::address_t data_address, unsigned bitpos); + +public: + KESOgc() : m_log("KESOgc", false), m_mm(fail::simulator.getMemoryManager()) { + + char *server_host = getenv("FAIL_SERVER_HOST"); + if(server_host != NULL){ + this->m_jc = new fail::JobClient(std::string(server_host)); + } else { + this->m_jc = new fail::JobClient(); + } + + }; + bool run(); +}; + +#endif // __KESO_GC_EXPERIMENT_HPP__ diff --git a/src/experiments/kesogc/experimentInfo.hpp b/src/experiments/kesogc/experimentInfo.hpp new file mode 100644 index 00000000..bcc57e18 --- /dev/null +++ b/src/experiments/kesogc/experimentInfo.hpp @@ -0,0 +1,24 @@ +#ifndef __EXPERIMENT_INFO_HPP__ + #define __EXPERIMENT_INFO_HPP__ + +// FIXME autogenerate this + + +// the task function's entry address: +// nm -C ecc.elf|fgrep main +#define OOSTUBS_FUNC_ENTRY 0x001009d0 +// empty function that is called explicitly when the experiment finished +// nm -C ecc.elf|fgrep "finished()" +#define OOSTUBS_FUNC_FINISH 0x001009d6 +// function executing HLT with no chance for further progress (after panic()) +// nm -C ecc.elf|fgrep cpu_halt +#define OOSTUBS_FUNC_CPU_HALT 0x001009f7 + +// nm -C ecc.elf | fgrep "_TEXT_" +#define OOSTUBS_TEXT_START 0x00100000 +#define OOSTUBS_TEXT_END 0x00100a1b + +#define OOSTUBS_NUMINSTR 5 + + +#endif // __EXPERIMENT_INFO_HPP__ diff --git a/src/experiments/kesogc/kesogc.proto b/src/experiments/kesogc/kesogc.proto new file mode 100644 index 00000000..03420a40 --- /dev/null +++ b/src/experiments/kesogc/kesogc.proto @@ -0,0 +1,31 @@ +import "DatabaseCampaignMessage.proto"; + +message KesoGcProtoMsg { + required DatabaseCampaignMessage fsppilot = 1; + + repeated group Result = 2 { + // make these optional to reduce overhead for server->client communication + enum ResultType { + CALCDONE = 1; + TIMEOUT = 2; + TRAP = 3; + EXC_ERROR = 4; + FT_LIST_REPAIRED = 5; + EXC_NULLPOINTER = 6; + RESILIENT_HEAP_REPAIRED = 7; + MEMACCESS = 8; + NOINJECTION = 9; + FT_LIST_BROKEN = 10; + UNKNOWN = 11; + RESILIENT_STACK_REPAIRED = 12; + EXC_PARITY = 13; + EXC_GC_PARITY = 14; + EXC_OOBOUNDS = 15; + } + // result type, see above + required ResultType resulttype = 4; + required uint32 original_value = 5; + required uint32 bitoffset = 6 [(sql_primary_key) = true]; + optional string details = 7; + } +} diff --git a/src/experiments/kesogc/main.cc b/src/experiments/kesogc/main.cc new file mode 100644 index 00000000..c00c7b3f --- /dev/null +++ b/src/experiments/kesogc/main.cc @@ -0,0 +1,20 @@ +#include +#include + +#include "cpn/CampaignManager.hpp" +#include "util/CommandLine.hpp" +#include "campaign.hpp" + +int main(int argc, char **argv) +{ + fail::CommandLine &cmd = fail::CommandLine::Inst(); + for (int i = 1; i < argc; ++i) + cmd.add_args(argv[i]); + + KesoGcCampaign c; + if (fail::campaignmanager.runCampaign(&c)) { + return 0; + } else { + return 1; + } +}