From 844e15293dbccf0f8e124b8d512e37baed5dd3d7 Mon Sep 17 00:00:00 2001 From: Christian Dietrich Date: Sat, 1 Jun 2013 18:18:51 +0200 Subject: [PATCH] experiments: new cored-voter experiment The experiment does support - 1 bit faults in registers/memory/IP - 2 bit faults in registers (all) - n bit faults monte-carlo in registers Change-Id: Ifdd7df6ec4bc88cfc75391b5e19e0d648fd0d087 --- src/experiments/cored-voter/CMakeLists.txt | 35 ++ src/experiments/cored-voter/campaign.cc | 20 + src/experiments/cored-voter/campaign.hpp | 38 ++ src/experiments/cored-voter/cored_voter.proto | 33 ++ src/experiments/cored-voter/experiment.cc | 550 ++++++++++++++++++ src/experiments/cored-voter/experiment.hpp | 32 + src/experiments/cored-voter/main.cc | 20 + 7 files changed, 728 insertions(+) create mode 100644 src/experiments/cored-voter/CMakeLists.txt create mode 100644 src/experiments/cored-voter/campaign.cc create mode 100644 src/experiments/cored-voter/campaign.hpp create mode 100644 src/experiments/cored-voter/cored_voter.proto create mode 100644 src/experiments/cored-voter/experiment.cc create mode 100644 src/experiments/cored-voter/experiment.hpp create mode 100644 src/experiments/cored-voter/main.cc diff --git a/src/experiments/cored-voter/CMakeLists.txt b/src/experiments/cored-voter/CMakeLists.txt new file mode 100644 index 00000000..3e605c29 --- /dev/null +++ b/src/experiments/cored-voter/CMakeLists.txt @@ -0,0 +1,35 @@ +set(EXPERIMENT_NAME cored-voter) +set(EXPERIMENT_TYPE CoredVoter) +configure_file(../instantiate-experiment.ah.in + ${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY +) + +## Setup desired protobuf descriptions HERE ## +set(MY_PROTOS + cored_voter.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}) + +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} fail-llvmdisassembler) + +## 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} -lmysqlclient -Wl,--end-group) +install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin) + diff --git a/src/experiments/cored-voter/campaign.cc b/src/experiments/cored-voter/campaign.cc new file mode 100644 index 00000000..badbb916 --- /dev/null +++ b/src/experiments/cored-voter/campaign.cc @@ -0,0 +1,20 @@ +#include +#include + +#include "campaign.hpp" +#include "cpn/CampaignManager.hpp" +#include "util/Logger.hpp" +#include "util/ElfReader.hpp" +#include "util/ProtoStream.hpp" +#include "sal/SALConfig.hpp" + +using namespace std; +using namespace fail; +using namespace google::protobuf; + +void CoredVoterCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) { + CoredVoterExperimentData *data = new CoredVoterExperimentData; + data->msg.mutable_fsppilot()->CopyFrom(pilot); + campaignmanager.addParam(data); +} + diff --git a/src/experiments/cored-voter/campaign.hpp b/src/experiments/cored-voter/campaign.hpp new file mode 100644 index 00000000..32cbf0e5 --- /dev/null +++ b/src/experiments/cored-voter/campaign.hpp @@ -0,0 +1,38 @@ +#ifndef __DCIAOCAMPAIGN_HPP__ +#define __DCIAOCAMPAIGN_HPP__ + +#include "cpn/DatabaseCampaign.hpp" +#include "comm/ExperimentData.hpp" +#include "cored_voter.pb.h" +#include "util/ElfReader.hpp" +#include + +class CoredVoterExperimentData : public fail::ExperimentData { +public: + CoredVoterProtoMsg msg; + CoredVoterExperimentData() : fail::ExperimentData(&msg) {} +}; + +class CoredVoterCampaign : public fail::DatabaseCampaign { + virtual const google::protobuf::Descriptor * cb_result_message() + { return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("CoredVoterProtoMsg"); } + + virtual void cb_send_pilot(DatabaseCampaignMessage pilot); + virtual int expected_number_of_results(std::string variant, std::string benchmark) { + if (benchmark.find("random-2") != std::string::npos) + return 248; // 32 * 31 / 4 + else if (benchmark.find("random") != std::string::npos) + /* This number was choosen arbitrarily. It should be high + enough to get at least 5000 experiments per qtrace + event. But since we're doing Monte Carlo it does not + matter whether we reach this number. */ + return 5000; + else if (benchmark.find("jump") != std::string::npos) + return 1; + else + return 8; + } + +}; + +#endif // __KESOREFCAMPAIGN_HPP__ diff --git a/src/experiments/cored-voter/cored_voter.proto b/src/experiments/cored-voter/cored_voter.proto new file mode 100644 index 00000000..2ea877ac --- /dev/null +++ b/src/experiments/cored-voter/cored_voter.proto @@ -0,0 +1,33 @@ +import "DatabaseCampaignMessage.proto"; + +message CoredVoterProtoMsg { + required DatabaseCampaignMessage fsppilot = 1; + + repeated group Result = 2 { + enum ResultType { + /* Voter did the right thing */ + OK = 1; + OK_WRONG_CONTROL_FLOW = 2; + OK_DETECTED_ERROR = 3; + + /* Voter did the wrong thing */ + ERR_WRONG_RESULT = 4; + + ERR_TRAP = 5; + ERR_TIMEOUT = 6; + ERR_OUTSIDE_TEXT = 7; + ERR_OUTSIDE_DATA = 8; + + UNKNOWN = 9; + NOINJECTION = 10; + } + + required int32 bitoffset = 1 [(sql_primary_key) = true]; + required ResultType resulttype = 2; + required uint32 experiment_number = 3; + + optional uint32 original_value = 4; + + optional string details = 5; + } +} diff --git a/src/experiments/cored-voter/experiment.cc b/src/experiments/cored-voter/experiment.cc new file mode 100644 index 00000000..a09af3ad --- /dev/null +++ b/src/experiments/cored-voter/experiment.cc @@ -0,0 +1,550 @@ +#include +#include +#include + +// getpid +#include +#include + + +#include +#include "experiment.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 +#include + +#include "util/llvmdisassembler/LLVMtoFailTranslator.hpp" +#include "util/llvmdisassembler/LLVMtoFailBochs.hpp" +#include "campaign.hpp" +#include "cored_voter.pb.h" + +using namespace std; +using namespace fail; + +#define SAFESTATE (1) + +// Check if configuration dependencies are satisfied: +#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \ + !defined(CONFIG_SR_SAVE) || !defined(CONFIG_EVENT_MEMREAD) || !defined(CONFIG_EVENT_MEMWRITE) || !defined(CONFIG_EVENT_TRAP) +#error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration. +#endif + +void CoredVoter::redecodeCurrentInstruction() { + /* Flush Instruction Caches and Prefetch queue */ + BX_CPU_C *cpu_context = simulator.getCPUContext(); + cpu_context->invalidate_prefetch_q(); + cpu_context->iCache.flushICacheEntries(); + + + guest_address_t pc = simulator.getCPU(0).getInstructionPointer(); + bxInstruction_c *currInstr = simulator.getCurrentInstruction(); + + m_log << "REDECODE INSTRUCTION!" << endl; + + Bit32u eipBiased = pc + cpu_context->eipPageBias; + Bit8u instr_plain[32]; + + MemoryManager& mm = simulator.getMemoryManager(); + mm.getBytes(pc, 32, instr_plain); + + unsigned remainingInPage = cpu_context->eipPageWindowSize - eipBiased; + int ret; +#if BX_SUPPORT_X86_64 + if (cpu_context->cpu_mode == BX_MODE_LONG_64) + ret = cpu_context->fetchDecode64(instr_plain, currInstr, remainingInPage); + else +#endif + ret = cpu_context->fetchDecode32(instr_plain, currInstr, remainingInPage); + if (ret < 0) { + // handle instrumentation callback inside boundaryFetch + cpu_context->boundaryFetch(instr_plain, remainingInPage, currInstr); + } + +} + +/** generate_random_bits does generate a vector of bit numbers for a + wide register. All contained bitnumbers are + unique, and the resulting vector is sorted in ascending order. The + ordering makes the vectors easily comparable. */ +static +std::vector generate_randoms_bits(int register_width, unsigned int count) { + std::vector ret; + while (ret.size() != count) { + another_number: + unsigned char candidate = rand() & ((1<< register_width)-1); + for (std::vector::const_iterator it = ret.begin(); it != ret.end(); ++it) { + if (*it == candidate) + goto another_number; + } + ret.push_back(candidate); + } + + // Sort vector to avoid duplicates + std::sort(ret.begin(), ret.end()); + + return ret; +} + + + +typedef std::pair two_bit_error_t; +std::vector generate_two_bit_errors(int register_width_in_bits) { + std::vector ret; + for (unsigned char x = 0; x < register_width_in_bits; x++) { + for (unsigned char y = 0; y < x; y++) { + ret.push_back(std::make_pair(y, x)); + } + } + return ret; +} + + +unsigned CoredVoter::injectBitFlip(address_t data_address, unsigned data_width, unsigned bitpos){ + + /* First 32 Registers, this might neeed adaption */ + if (data_address < (32 << 8)) { + LLVMtoFailTranslator * ltof = new LLVMtoFailBochs; + LLVMtoFailTranslator::reginfo_t reginfo = LLVMtoFailTranslator::reginfo_t::fromDataAddress(data_address, data_width); + + unsigned int value, injectedval; + + value = ltof->getRegisterContent(simulator.getCPU(0), reginfo); + injectedval = value ^ (1 << bitpos); + ltof->setRegisterContent(simulator.getCPU(0), reginfo, injectedval); + + m_log << "INJECTING register (" << dec << reginfo.id + << " offset " << (int) reginfo.offset + << ") bitpos: " << bitpos + << " value: 0x" << hex << setw(2) << setfill('0') << value << " -> 0x" << setw(2) << setfill('0') << injectedval + << dec << endl; + if (reginfo.id == RID_PC) + redecodeCurrentInstruction(); + delete ltof; + + return value; + } else { + 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') << injectedval << endl; + + /* If it is the current instruction redecode it */ + guest_address_t pc = simulator.getCPU(0).getInstructionPointer(); + bxInstruction_c *currInstr = simulator.getCurrentInstruction(); + unsigned length_in_bytes = currInstr->ilen(); + + if (pc <= data_address && data_address <= (pc + length_in_bytes)) { + redecodeCurrentInstruction(); + } + + return value; + } +} + + +void handleEvent(CoredVoterProtoMsg_Result& result, CoredVoterProtoMsg_Result_ResultType restype, const std::string &msg) { + cout << msg << endl; + result.set_resulttype(restype); + result.set_details(msg); +} + +std::string handleMemoryAccessEvent(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(); + + return sstr.str(); +} + + +bool CoredVoter::run() { + //******* Boot, and store state *******// + m_log << "STARTING EXPERIMENT" << endl; + + timeval start; + gettimeofday(&start, NULL); + srand(start.tv_usec); + + unsigned executed_jobs = 0; + + // Setup exit points + const ElfSymbol &s_trace_end_marker = m_elf.getSymbol("_trace_end_marker"); + BPSingleListener l_trace_end_marker(s_trace_end_marker.getAddress()); + if (!s_trace_end_marker.isValid()) { + m_log << "Couldn't find symbol: _trace_end_marker" << std::endl; + simulator.terminate(1); + } + + + const ElfSymbol &s_subexperiment_end = m_elf.getSymbol("_subexperiment_end"); + BPSingleListener l_subexperiment_end(s_subexperiment_end.getAddress()); + if (!s_subexperiment_end.isValid()) { + m_log << "Couldn't find symbol: _subexperiment_end" << std::endl; + simulator.terminate(1); + } + + const ElfSymbol &s_subexperiment_marker_1 = m_elf.getSymbol("_subexperiment_marker_1"); + BPSingleListener l_subexperiment_marker_1(s_subexperiment_marker_1.getAddress()); + if (!s_subexperiment_marker_1.isValid()) { + m_log << "Couldn't find symbol: _subexperiment_marker_1" << std::endl; + simulator.terminate(1); + } + + const ElfSymbol &s_subexperiment_marker_1_ptr = m_elf.getSymbol("subexperiment_marker_1"); + BPSingleListener l_subexperiment_marker_1_ptr(s_subexperiment_marker_1_ptr.getAddress()); + if (!s_subexperiment_marker_1_ptr.isValid()) { + m_log << "Couldn't find symbol: subexperiment_marker_1" << std::endl; + simulator.terminate(1); + } + + + + const ElfSymbol &s_experiment_number = m_elf.getSymbol("experiment_number"); + if (!s_experiment_number.isValid()) { + m_log << "Couldn't find symbol: experiment_number" << std::endl; + simulator.terminate(1); + } + + const ElfSymbol &s_chose_right_input = m_elf.getSymbol("chose_right_input"); + if (!s_chose_right_input.isValid()) { + m_log << "Couldn't find symbol: chose_right_input" << std::endl; + simulator.terminate(1); + } + + const ElfSymbol &s_chose_right_output = m_elf.getSymbol("chose_right_output"); + if (!s_chose_right_output.isValid()) { + m_log << "Couldn't find symbol: chose_right_output" << std::endl; + simulator.terminate(1); + } + + const ElfSymbol &s_detected_error = m_elf.getSymbol("detected_error"); + if (!s_detected_error.isValid()) { + m_log << "Couldn't find symbol: detected_error" << std::endl; + simulator.terminate(1); + } + + const ElfSymbol &s_voterImpl = m_elf.getSymbol("voterImpl"); + if (!s_voterImpl.isValid()) { + m_log << "Couldn't find symbol: voterImpl" << std::endl; + simulator.terminate(1); + } + + + + + + + address_t min_code = INT_MAX; + address_t max_code = 0; + std::vector allowed_text_regions; + allowed_text_regions.push_back("voterImpl"); + allowed_text_regions.push_back("Alpha::functionTaskTask0"); + allowed_text_regions.push_back("do_experiment"); + allowed_text_regions.push_back("_trace_end_marker"); + allowed_text_regions.push_back("_subexperiment_end"); + allowed_text_regions.push_back("_subexperiment_marker_1"); + + + + for (std::vector::iterator it = allowed_text_regions.begin(); + it != allowed_text_regions.end(); ++it) { + const ElfSymbol &sym = m_elf.getSymbol(*it); + if (!sym.isValid()) { + m_log << "Couldn't find symbol: " << (*it) << std::endl; + simulator.terminate(1); + + } + min_code = std::min(min_code, sym.getStart()); + max_code = std::max(max_code, sym.getEnd()); + } + + + m_log << "_trace_end_marker: " << std::hex << s_trace_end_marker << std::endl; + m_log << "_subexperiment_end: " << std::hex << s_subexperiment_end << std::endl; + m_log << "code_region: " << std::hex << min_code << " -- " << max_code << std::endl; + + + TrapListener l_trap(ANY_TRAP); + TimerListener l_timeout(1000 * 1000); // 1 second in microseconds + BPRangeListener l_below_text(0, min_code - 1); + BPRangeListener l_above_text(max_code + 1, 0xfffffff0); + + + while (executed_jobs < 25 || m_jc.getNumberOfUndoneJobs() > 0) { + m_log << "asking jobserver for parameters" << endl; + CoredVoterExperimentData 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(); + unsigned data_width = param.msg.fsppilot().data_width(); + + + /* Detect wheter we should inject the PC and jump to a + random data address? */ + bool pc_injection = param.msg.fsppilot().benchmark().find("jump") != std::string::npos; + bool random_injection = param.msg.fsppilot().benchmark().find("random") != std::string::npos; + + int randomly_injected_bits = 0; + + + LLVMtoFailTranslator::reginfo_t reginfo; + std::vector two_bit_errors; + int experiments = 8; + if (pc_injection) + experiments = 1; + else if (random_injection) { + reginfo = LLVMtoFailTranslator::reginfo_t::fromDataAddress(data_address, data_width); + experiments = 256; + std::string benchmark = param.msg.fsppilot().benchmark(); + size_t idx = benchmark.find("random") + 7; + std::stringstream ss(benchmark.substr(idx)); + ss >> randomly_injected_bits; + + if (randomly_injected_bits == 2) { + two_bit_errors = generate_two_bit_errors(data_width * 8); + experiments = two_bit_errors.size(); + } + } + + for (int experiment_id = 0; experiment_id < experiments; ++experiment_id) { + CoredVoterProtoMsg_Result *result = 0; + + m_log << "restoring state" << endl; + + // Restore to the image, which starts at address(main) + simulator.restore("state"); + executed_jobs ++; + + address_t stack_pointer = simulator.getCPU(0).getStackPointer(); + m_log << "stackpointer: " << std::hex << stack_pointer << std::dec << std::endl; + + // Fast forward to injection address + m_log << "Trying to inject @ instr #" << dec << injection_instr << endl; + + if ((injection_instr + 2) > 0) { + simulator.clearListeners(); + BPSingleListener bp; + bp.setWatchInstructionPointer(ANY_ADDR); + bp.setCounter(injection_instr + 2); // FIXME: FISHY! + simulator.addListener(&bp); + + fail::BaseListener * listener = simulator.resume(); + if (listener != &bp) { + result = param.msg.add_result(); + handleEvent(*result, result->NOINJECTION, "WTF"); + break; + } + } + + // Not a working sanitiy check. Because of instruction + // offsets! + if (param.msg.fsppilot().has_injection_instr_absolute()) { + address_t PC = param.msg.fsppilot().injection_instr_absolute(); + if (simulator.getCPU(0).getInstructionPointer() != PC) { + m_log << "Invalid Injection address EIP=0x" + << std::hex << simulator.getCPU(0).getInstructionPointer() + << " != injection_instr_absolute=0x" << PC << std::endl; + simulator.terminate(1); + } + } + + // address_t stack_pointer = simulator.getCPU(0).getRegisterContent(simulator.getCPU(0).getRegister(RID_CSP)); + // m_log << "stack pointer: " << std::hex << stack_pointer << std::endl; + // simulator.terminate(1); + + MemoryManager& mm = simulator.getMemoryManager(); + /* Which experiment was evaluated */ + char experiment_number = mm.getByte(s_experiment_number.getAddress()); + + if (pc_injection) { + // Jump to data address */ + address_t current_PC = simulator.getCPU(0).getInstructionPointer(); + address_t new_PC = param.msg.fsppilot().data_address(); + m_log << "jump from 0x" << hex << current_PC << " to 0x" << new_PC << std::endl; + simulator.getCPU(0).setRegisterContent(simulator.getCPU(0).getRegister(RID_PC), + new_PC ); // set + // program + // counter + result = param.msg.add_result(); + result->set_bitoffset(0); + result->set_original_value(current_PC); + redecodeCurrentInstruction(); + } else if (random_injection) { + // Inject random bitflips + LLVMtoFailTranslator * ltof = new LLVMtoFailBochs; + assert(reginfo.offset == 0); + + m_log << "Inject " << randomly_injected_bits << " bit flips" << endl; + unsigned int ret_bitoffset = 0; + + std::vector bits; + if (randomly_injected_bits == 2) { + m_log << two_bit_errors.size() << " " << experiment_id << endl; + two_bit_error_t two_bit = two_bit_errors[experiment_id]; + bits.push_back(two_bit.first); + bits.push_back(two_bit.second); + } else { + /* Generate a random vector */ + bits = generate_randoms_bits(5, randomly_injected_bits); + } + + bool original_value_set = false; + result = param.msg.add_result(); + for (std::vector::const_iterator it = bits.begin(); it != bits.end(); ++it) { + int bitoffset = *it; + ret_bitoffset = (ret_bitoffset << 5) | bitoffset; + int original_value = injectBitFlip(data_address, data_width, bitoffset); + if (!original_value_set) { + result->set_original_value(original_value); + original_value_set = true; + } + } + result->set_bitoffset(ret_bitoffset); + delete ltof; + } else { + // INJECT BITFLIP into Register: + // experiment_id == bitpos + result = param.msg.add_result(); + result->set_bitoffset(experiment_id); + result->set_original_value(injectBitFlip(data_address, data_width, experiment_id)); + result->set_experiment_number((unsigned int) experiment_number); + + address_t PC = simulator.getCPU(0).getInstructionPointer(); + if (PC < s_voterImpl.getStart() || PC > s_voterImpl.getEnd()) { + handleEvent(*result, result->ERR_OUTSIDE_TEXT, "injection"); + simulator.clearListeners(); + continue; // next experiment + } + } + + result->set_experiment_number((unsigned int) experiment_number); + + + /* We use the current stackpointer to determine a region, + that is used by the function. This region includes the + working data and the used arguments. */ + + address_t min_data = stack_pointer - 152; + address_t max_data = min_data + 0x5C; + m_log << "data region: " << std::hex << min_data << " -- " << max_data << std::dec << std::endl; + + MemAccessListener l_below_data(0); + l_below_data.setWatchWidth(min_data - 1); + MemAccessListener l_above_data(max_data + 1); + l_above_data.setWatchWidth(0xfffffff0); + + simulator.clearListeners(); + simulator.addListener(&l_trap); + simulator.addListener(&l_timeout); + simulator.addListener(&l_below_text); + simulator.addListener(&l_above_text); + simulator.addListener(&l_below_data); + simulator.addListener(&l_above_data); + simulator.addListener(&l_subexperiment_marker_1); + simulator.addListener(&l_subexperiment_end); + // simulator.addListener(&l_trace_end_marker); + + m_log << "Resuming till the crash" << std::endl; + // resume and wait for results + fail::BaseListener* l = simulator.resume(); + bool visited_marker_1 = false; + address_t mem_access = 0x0; + if (l == &l_below_data || l == &l_above_data) { + fail::MemAccessListener *lm = (fail::MemAccessListener *) l; + mem_access = lm->getTriggerAddress(); + } + + if (l == &l_subexperiment_marker_1 || mem_access == s_subexperiment_marker_1_ptr.getAddress()) { + visited_marker_1 = true; + simulator.clearListeners(); + simulator.addListener(&l_subexperiment_end); + simulator.addListener(&l_trap); + simulator.addListener(&l_timeout); + l = simulator.resume(); + } + + // Evaluate result + if(l == &l_subexperiment_end) { + bool chose_right_output = mm.getByte(s_chose_right_output.getAddress()); + bool chose_right_input = mm.getByte(s_chose_right_input.getAddress()); + bool detected_error = mm.getByte(s_detected_error.getAddress()); + + /* When we did not visit marker 1 before end marker, + we took the wrong exit point. The MMU would have + caught this error. */ + if (!visited_marker_1) { + handleEvent(*result, result->ERR_OUTSIDE_TEXT, "wrong exit point"); + } else if (chose_right_output) { + if (chose_right_input) { + handleEvent(*result, result->OK, "OK"); + } else { + handleEvent(*result, result->OK_WRONG_CONTROL_FLOW, ""); + } + } else { + if (detected_error) { + handleEvent(*result, result->OK_DETECTED_ERROR, ""); + } else { + handleEvent(*result, result->ERR_WRONG_RESULT, ""); + } + } + } else if (l == &l_trap) { + stringstream sstr; + sstr << "trap #" << l_trap.getTriggerNumber(); + handleEvent(*result, result->ERR_TRAP, sstr.str()); + } else if ( l == &l_timeout ) { + handleEvent(*result, result->ERR_TIMEOUT, "timeout"); + } else if (l == &l_below_text || l == &l_above_text) { + std::stringstream ss; + ss << ((l == &l_below_text) ? "< .text" : ">.text") << " "; + ss << handleMemoryAccessEvent(*(fail::MemAccessListener *)l); + handleEvent(*result, result->ERR_OUTSIDE_TEXT, ss.str()); + } else if (l == &l_below_data || l == &l_above_data) { + std::stringstream ss; + ss << ((l == &l_below_text) ? "< .data" : ">.data") << " "; + ss << handleMemoryAccessEvent(*(fail::MemAccessListener *)l); + handleEvent(*result, result->ERR_OUTSIDE_DATA, ss.str()); + } else { + handleEvent(*result, result->UNKNOWN, "WTF"); + } + simulator.clearListeners(); + + // For RandomJump do only one experiment not 8 + if (pc_injection) + break; + } + + m_jc.sendResult(param); + } + // Explicitly terminate, or the simulator will continue to run. + simulator.terminate(); + +} + diff --git a/src/experiments/cored-voter/experiment.hpp b/src/experiments/cored-voter/experiment.hpp new file mode 100644 index 00000000..15178682 --- /dev/null +++ b/src/experiments/cored-voter/experiment.hpp @@ -0,0 +1,32 @@ +#ifndef __CORED_VOTER_EXPERIMENT_HPP__ +#define __CORED_VOTER_EXPERIMENT_HPP__ + + +#include "sal/SALInst.hpp" +#include "efw/ExperimentFlow.hpp" +#include "efw/JobClient.hpp" +#include "util/Logger.hpp" +#include "util/ElfReader.hpp" +#include +#include + +class CoredVoter : public fail::ExperimentFlow { +public: + +private: + fail::JobClient m_jc; + fail::Logger m_log; + fail::MemoryManager& m_mm; + fail::ElfReader m_elf; + + + unsigned injectBitFlip(fail::address_t data_address, unsigned data_width, unsigned bitpos); + void redecodeCurrentInstruction(); + +public: + CoredVoter() : m_log("CoredVoter", false), m_mm(fail::simulator.getMemoryManager()) {} + + bool run(); +}; + +#endif diff --git a/src/experiments/cored-voter/main.cc b/src/experiments/cored-voter/main.cc new file mode 100644 index 00000000..efdca50f --- /dev/null +++ b/src/experiments/cored-voter/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]); + + CoredVoterCampaign c; + if (fail::campaignmanager.runCampaign(&c)) { + return 0; + } else { + return 1; + } +}