From c2242f2bb47b119b39de610cf44ec218cb175df9 Mon Sep 17 00:00:00 2001 From: hsc Date: Fri, 9 Nov 2012 15:37:21 +0000 Subject: [PATCH] ecos: guest-image independent fail client TODO: campaign needs to be updated, too git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1908 8c4709b5-6ec9-48aa-a5cd-a96041d1645a --- src/experiments/ecos_kernel_test/campaign.cc | 20 +++- src/experiments/ecos_kernel_test/campaign.hpp | 4 +- .../ecos_kernel_test/ecos_kernel_test.proto | 15 ++- .../ecos_kernel_test/experiment.cc | 103 +++++++++++++----- .../ecos_kernel_test/experiment.hpp | 21 +++- .../ecos_kernel_test/experimentInfo.hpp | 22 +--- 6 files changed, 124 insertions(+), 61 deletions(-) diff --git a/src/experiments/ecos_kernel_test/campaign.cc b/src/experiments/ecos_kernel_test/campaign.cc index 2de5b311..2c746be6 100644 --- a/src/experiments/ecos_kernel_test/campaign.cc +++ b/src/experiments/ecos_kernel_test/campaign.cc @@ -57,8 +57,9 @@ bool EcosKernelTestCampaign::writeTraceInfo(unsigned instr_counter, unsigned tim return true; } -bool EcosKernelTestCampaign::readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &lowest_addr, unsigned &highest_addr) { - ifstream file(filename_traceinfo().c_str()); +bool EcosKernelTestCampaign::readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &lowest_addr, unsigned &highest_addr, + const std::string& variant, const std::string& benchmark) { + ifstream file(filename_traceinfo(variant, benchmark).c_str()); if (!file.is_open()) { cout << "failed to open " << filename_traceinfo() << endl; return false; @@ -127,6 +128,14 @@ std::string EcosKernelTestCampaign::filename_results(const std::string& variant, return dir_results + "/" + variant + "_" + benchmark + "_" + "results.csv"; } +std::string EcosKernelTestCampaign::filename_elf(const std::string& variant, const std::string& benchmark) +{ + if (variant.size() && benchmark.size()) { + return dir_images + "/" + variant + "/" + benchmark + ".elf"; + } + return "kernel.elf"; +} + // equivalence class type: addr, [i1, i2] // addr: byte to inject a bit-flip into // [i1, i2]: interval of instruction numbers, counted from experiment @@ -355,6 +364,9 @@ bool EcosKernelTestCampaign::run() // instantly enqueue job: that way the job clients can already // start working in parallel EcosKernelTestExperimentData *d = new EcosKernelTestExperimentData; + // FIXME use correct variant/benchmark + d->msg.set_variant(""); + d->msg.set_benchmark(""); // we pick the rightmost instruction in that interval d->msg.set_instr_offset(current_ec.instr2); d->msg.set_instr_address(current_ec.instr2_absolute); @@ -460,7 +472,7 @@ bool EcosKernelTestCampaign::run() " experiments to " << ecs_need_experiment.size() * 8 << endl; // CSV header - results << "ec_instr1\tec_instr2\tec_instr2_absolute\tec_data_address\tbitnr\tbit_width\tresulttype\tecos_test_result\tlatest_ip\terror_corrected\tdetails" << endl; + results << "variant\tbenchmark\tec_instr1\tec_instr2\tec_instr2_absolute\tec_data_address\tbitnr\tbit_width\tresulttype\tecos_test_result\tlatest_ip\terror_corrected\tdetails" << endl; // store no-effect "experiment" results for (vector::const_iterator it = ecs_no_effect.begin(); @@ -509,6 +521,8 @@ bool EcosKernelTestCampaign::run() for (int idx = 0; idx < res->msg.result_size(); ++idx) { results // repeated for all single experiments: + << res->msg.variant() << "\t" + << res->msg.benchmark() << "\t" << ec.instr1 << "\t" << ec.instr2 << "\t" << ec.instr2_absolute << "\t" diff --git a/src/experiments/ecos_kernel_test/campaign.hpp b/src/experiments/ecos_kernel_test/campaign.hpp index e6f84899..743d8c53 100644 --- a/src/experiments/ecos_kernel_test/campaign.hpp +++ b/src/experiments/ecos_kernel_test/campaign.hpp @@ -21,11 +21,11 @@ public: virtual bool run(); static bool readMemoryMap(fail::MemoryMap &mm, char const * const filename); static bool writeTraceInfo(unsigned instr_counter, unsigned timeout, unsigned lowest_addr, unsigned highest_addr); - static bool readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &lowest_addr, unsigned &highest_addr); + static bool readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &lowest_addr, unsigned &highest_addr, const std::string& variant = "", const std::string& benchmark = ""); static std::string filename_memorymap(const std::string& variant = "", const std::string& benchmark = ""); static std::string filename_state(const std::string& variant = "", const std::string& benchmark = ""); static std::string filename_trace(const std::string& variant = "", const std::string& benchmark = ""); static std::string filename_traceinfo(const std::string& variant = "", const std::string& benchmark = ""); static std::string filename_results(const std::string& variant, const std::string& benchmark); + static std::string filename_elf(const std::string& variant = "", const std::string& benchmark = ""); }; - diff --git a/src/experiments/ecos_kernel_test/ecos_kernel_test.proto b/src/experiments/ecos_kernel_test/ecos_kernel_test.proto index da3a3a96..ec7973b5 100644 --- a/src/experiments/ecos_kernel_test/ecos_kernel_test.proto +++ b/src/experiments/ecos_kernel_test/ecos_kernel_test.proto @@ -2,12 +2,17 @@ message EcosKernelTestProtoMsg { // Input: experiment parameters // (client executes 8 experiments, one for each bit at mem_addr) + // EDM/ERM variant + required string variant = 1; + // benchmark + required string benchmark = 2; + // FI at #instructions from experiment start - required int32 instr_offset = 1; + required int32 instr_offset = 3; // the exact IP value at this point in time (from golden run) - optional int32 instr_address = 2; // for sanity checks + optional int32 instr_address = 4; // for sanity checks // address of the byte to inject bit-flips - required int32 mem_addr = 3; + required int32 mem_addr = 5; // ---------------------------------------------------- @@ -15,9 +20,9 @@ message EcosKernelTestProtoMsg { // IP where we did the injection: for debugging purposes, must be identical // to instr_address - optional int32 injection_ip = 4; + optional int32 injection_ip = 6; - repeated group Result = 5 { + repeated group Result = 7 { // single experiment bit offset required int32 bit_offset = 1; diff --git a/src/experiments/ecos_kernel_test/experiment.cc b/src/experiments/ecos_kernel_test/experiment.cc index ad0d04b3..a8b79dec 100644 --- a/src/experiments/ecos_kernel_test/experiment.cc +++ b/src/experiments/ecos_kernel_test/experiment.cc @@ -16,6 +16,7 @@ #include "sal/bochs/BochsRegister.hpp" #include "sal/bochs/BochsListener.hpp" #include "sal/Listener.hpp" +#include "util/ElfReader.hpp" // You need to have the tracing plugin enabled for this #include "../plugins/tracing/TracingPlugin.hpp" @@ -36,12 +37,12 @@ using namespace fail; #endif #if PREREQUISITES -bool EcosKernelTestExperiment::retrieveGuestAddresses() { +bool EcosKernelTestExperiment::retrieveGuestAddresses(guest_address_t addr_finish) { log << "STEP 0: record memory map with addresses of 'interesting' objects" << endl; - // run until 'ECOS_FUNC_FINISH' is reached + // run until func_finish is reached BPSingleListener bp; - bp.setWatchInstructionPointer(ECOS_FUNC_FINISH); + bp.setWatchInstructionPointer(addr_finish); // memory map serialization ofstream mm(EcosKernelTestCampaign::filename_memorymap().c_str(), ios::out); @@ -82,7 +83,7 @@ bool EcosKernelTestExperiment::retrieveGuestAddresses() { } } assert(number_of_guest_events > 0); - log << "Breakpoint at 'ECOS_FUNC_FINISH' reached: created memory map (" << number_of_guest_events << " entries)" << endl; + log << "Breakpoint at func_finish reached: created memory map (" << number_of_guest_events << " entries)" << endl; delete str; // close serialized mm @@ -94,7 +95,7 @@ bool EcosKernelTestExperiment::retrieveGuestAddresses() { return true; } -bool EcosKernelTestExperiment::establishState() { +bool EcosKernelTestExperiment::establishState(guest_address_t addr_entry, guest_address_t addr_errors_corrected) { log << "STEP 1: run until interesting function starts, and save state" << endl; GuestListener g; @@ -108,27 +109,27 @@ bool EcosKernelTestExperiment::establishState() { } BPSingleListener bp; - bp.setWatchInstructionPointer(ECOS_FUNC_ENTRY); + bp.setWatchInstructionPointer(addr_entry); simulator.addListenerAndResume(&bp); log << "test function entry reached, saving state" << endl; log << "EIP = " << hex << bp.getTriggerInstructionPointer() << endl; - //log << "error_corrected = " << dec << ((int)simulator.getMemoryManager().getByte(ECC_ERROR_CORRECTED)) << endl; + //log << "error_corrected = " << dec << ((int)simulator.getMemoryManager().getByte(addr_errors_corrected)) << endl; simulator.save(EcosKernelTestCampaign::filename_state()); - assert(bp.getTriggerInstructionPointer() == ECOS_FUNC_ENTRY); - assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY); + assert(bp.getTriggerInstructionPointer() == addr_entry); + assert(simulator.getRegisterManager().getInstructionPointer() == addr_entry); // clean up simulator simulator.clearListeners(); return true; } -bool EcosKernelTestExperiment::performTrace() { +bool EcosKernelTestExperiment::performTrace(guest_address_t addr_entry, guest_address_t addr_finish) { log << "STEP 2: record trace for fault-space pruning" << endl; log << "restoring state" << endl; simulator.restore(EcosKernelTestCampaign::filename_state()); log << "EIP = " << hex << simulator.getRegisterManager().getInstructionPointer() << endl; - assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY); + assert(simulator.getRegisterManager().getInstructionPointer() == addr_entry); log << "enabling tracing" << endl; TracingPlugin tp; @@ -148,7 +149,7 @@ bool EcosKernelTestExperiment::performTrace() { // again, run until 'ECOS_FUNC_FINISH' is reached BPSingleListener bp; - bp.setWatchInstructionPointer(ECOS_FUNC_FINISH); + bp.setWatchInstructionPointer(addr_finish); simulator.addListener(&bp); // on the way, count instructions // FIXME add SAL functionality for this? @@ -236,9 +237,11 @@ bool EcosKernelTestExperiment::performTrace() { bool EcosKernelTestExperiment::faultInjection() { log << "STEP 3: The actual experiment." << endl; - // read trace info + // trace info unsigned instr_counter, estimated_timeout, lowest_addr, highest_addr; - EcosKernelTestCampaign::readTraceInfo(instr_counter, estimated_timeout, lowest_addr, highest_addr); + // ELF symbol addresses + guest_address_t addr_entry, addr_finish, addr_test_output, addr_errors_corrected, + addr_panic, addr_text_start, addr_text_end; BPSingleListener bp; @@ -258,15 +261,24 @@ bool EcosKernelTestExperiment::faultInjection() { } #else // XXX debug + param.msg.set_variant("bitmap_CRC"); + param.msg.set_benchmark("bin_sem0"); param.msg.set_instr_offset(7462); //param.msg.set_instr_address(12345); param.msg.set_mem_addr(44540); #endif int id = param.getWorkloadID(); + m_variant = param.msg.variant(); + m_benchmark = param.msg.benchmark(); int instr_offset = param.msg.instr_offset(); int mem_addr = param.msg.mem_addr(); + EcosKernelTestCampaign::readTraceInfo(instr_counter, estimated_timeout, + lowest_addr, highest_addr, m_variant, m_benchmark); + readELFSymbols(addr_entry, addr_finish, addr_test_output, + addr_errors_corrected, addr_panic, addr_text_start, addr_text_end); + // for each job we're actually doing *8* experiments (one for each bit) for (int bit_offset = 0; bit_offset < 8; ++bit_offset) { // 8 results in one job @@ -288,7 +300,7 @@ bool EcosKernelTestExperiment::faultInjection() { */ // reaching finish() could happen before OR after FI - BPSingleListener func_finish(ECOS_FUNC_FINISH); + BPSingleListener func_finish(addr_finish); simulator.addListener(&func_finish); // no need to wait if offset is 0 @@ -350,8 +362,8 @@ bool EcosKernelTestExperiment::faultInjection() { simulator.addListener(&ev_trap); // jump outside text segment - BPRangeListener ev_below_text(ANY_ADDR, ECOS_TEXT_START - 1); - BPRangeListener ev_beyond_text(ECOS_TEXT_END + 1, ANY_ADDR); + BPRangeListener ev_below_text(ANY_ADDR, addr_text_start - 1); + BPRangeListener ev_beyond_text(addr_text_end + 1, ANY_ADDR); simulator.addListener(&ev_below_text); simulator.addListener(&ev_beyond_text); @@ -374,12 +386,14 @@ bool EcosKernelTestExperiment::faultInjection() { //simulator.addListener(&ev_end); // eCos' test output function, which will show if the test PASSed or FAILed - BPSingleListener func_test_output(ECOS_FUNC_TEST_OUTPUT); + BPSingleListener func_test_output(addr_test_output); simulator.addListener(&func_test_output); // function called by ecc aspects, when an uncorrectable error is detected - BPSingleListener func_ecc_panic(ECC_FUNC_PANIC); - simulator.addListener(&func_ecc_panic); + BPSingleListener func_ecc_panic(addr_panic); + if (addr_panic != ADDR_INV) { + simulator.addListener(&func_ecc_panic); + } #if LOCAL && 0 // XXX debug @@ -433,8 +447,12 @@ bool EcosKernelTestExperiment::faultInjection() { result->set_latest_ip(simulator.getRegisterManager().getInstructionPointer()); // record error_corrected regardless of result - int32_t error_corrected = simulator.getMemoryManager().getByte(ECC_ERROR_CORRECTED); - result->set_error_corrected(error_corrected); + if (addr_errors_corrected != ADDR_INV) { + int32_t error_corrected = simulator.getMemoryManager().getByte(addr_errors_corrected); + result->set_error_corrected(error_corrected); + } else { + result->set_error_corrected(0); + } // record ecos_test_result if ( (ecos_test_passed == true) && (ecos_test_failed == false) ) { @@ -492,24 +510,59 @@ bool EcosKernelTestExperiment::faultInjection() { } #endif // PREREQUISITES +bool EcosKernelTestExperiment::readELFSymbols( + fail::guest_address_t& entry, + fail::guest_address_t& finish, + fail::guest_address_t& test_output, + fail::guest_address_t& errors_corrected, + fail::guest_address_t& panic, + fail::guest_address_t& text_start, + fail::guest_address_t& text_end) +{ + ElfReader elfreader(EcosKernelTestCampaign::filename_elf(m_variant, m_benchmark).c_str()); + entry = elfreader.getAddressByName("cyg_start"); + finish = elfreader.getAddressByName("cyg_test_exit"); + test_output = elfreader.getAddressByName("cyg_test_output"); + errors_corrected = elfreader.getAddressByName("errors_corrected"); + panic = elfreader.getAddressByName("_Z9ecc_panicv"); + text_start = elfreader.getAddressByName("_stext"); + text_end = elfreader.getAddressByName("_etext"); + + // it's OK if errors_corrected or ecc_panic are missing + if (entry == ADDR_INV || finish == ADDR_INV || test_output == ADDR_INV || + text_start == ADDR_INV || text_end == ADDR_INV) { + return false; + } + return true; +} + bool EcosKernelTestExperiment::run() { log << "startup" << endl; #if PREREQUISITES + log << "retrieving ELF symbol addresses ..." << endl; + guest_address_t entry, finish, test_output, errors_corrected, + panic, text_start, text_end; + if (!readELFSymbols(entry, finish, test_output, errors_corrected, + panic, text_start, text_end)) { + log << "failed, essential symbols are missing!" << endl; + simulator.terminate(1); + } + // step 0 - if(retrieveGuestAddresses()) { + if(retrieveGuestAddresses(finish)) { log << "STEP 0 finished: rebooting ..." << endl; simulator.reboot(); } else { return false; } // step 1 - if(establishState()) { + if(establishState(entry, errors_corrected)) { log << "STEP 1 finished: proceeding ..." << endl; } else { return false; } // step 2 - if(performTrace()) { + if(performTrace(entry, finish)) { log << "STEP 2 finished: terminating ..." << endl; } else { return false; } diff --git a/src/experiments/ecos_kernel_test/experiment.hpp b/src/experiments/ecos_kernel_test/experiment.hpp index 4bd0636e..0dc2f7a2 100644 --- a/src/experiments/ecos_kernel_test/experiment.hpp +++ b/src/experiments/ecos_kernel_test/experiment.hpp @@ -1,8 +1,11 @@ #pragma once - + +#include + #include "efw/ExperimentFlow.hpp" #include "efw/JobClient.hpp" #include "util/Logger.hpp" +#include "sal/SALConfig.hpp" class EcosKernelTestExperiment : public fail::ExperimentFlow { fail::JobClient m_jc; @@ -12,9 +15,17 @@ public: EcosKernelTestExperiment() : log("eCos Kernel Test", false) {} bool run(); - bool retrieveGuestAddresses(); // step 0 - bool establishState(); // step 1 - bool performTrace(); // step 2 + bool retrieveGuestAddresses(fail::guest_address_t addr_finish); // step 0 + bool establishState(fail::guest_address_t addr_entry, fail::guest_address_t addr_errors_corrected); // step 1 + bool performTrace(fail::guest_address_t addr_entry, fail::guest_address_t addr_finish); // step 2 bool faultInjection(); // step 3 -}; + bool readELFSymbols( + fail::guest_address_t& entry, + fail::guest_address_t& finish, + fail::guest_address_t& test_output, + fail::guest_address_t& errors_corrected, + fail::guest_address_t& panic, + fail::guest_address_t& text_start, + fail::guest_address_t& text_end); +}; diff --git a/src/experiments/ecos_kernel_test/experimentInfo.hpp b/src/experiments/ecos_kernel_test/experimentInfo.hpp index c6be2a75..051b7006 100644 --- a/src/experiments/ecos_kernel_test/experimentInfo.hpp +++ b/src/experiments/ecos_kernel_test/experimentInfo.hpp @@ -1,23 +1,3 @@ #pragma once -// autogenerated, don't edit! - -// user-specified start-function address: -// nm -C thread1.elf|fgrep cyg_start -#define ECOS_FUNC_ENTRY 0x0000409c -// cyg_test_exit address -#define ECOS_FUNC_FINISH 0x00005f0c -// cyg_test_output address -#define ECOS_FUNC_TEST_OUTPUT 0x00005f14 -// the variable that's increased if ECC corrects an error: -#define ECOS_ERROR_CORRECTED 0x99999999 - -// text begin: -// nm -C thread1.elf|fgrep _stext -#define ECOS_TEXT_START 0x00003000 -// text end: -// nm -C thread1.elf|fgrep _etext -#define ECOS_TEXT_END 0x0001627a - - - +#define PREREQUISITES 0