diff --git a/src/experiments/ecos_kernel_test/campaign.cc b/src/experiments/ecos_kernel_test/campaign.cc index 9be02c4d..a85b759e 100644 --- a/src/experiments/ecos_kernel_test/campaign.cc +++ b/src/experiments/ecos_kernel_test/campaign.cc @@ -19,7 +19,7 @@ using namespace std; using namespace fail; -char const * const trace_filename = "trace.tc"; +char const * const trace_filename = "trace.tc"; //TODO: sync with experiment.cc char const * const results_filename = "ecos_kernel_test.csv"; char const * const mm_filename = "memory_map.txt"; //TODO: sync with experiment.cc @@ -31,17 +31,17 @@ bool EcosKernelTestCampaign::readMemoryMap(fail::MemoryMap &mm, char const * con } string buf; - stringstream ss(ios::in); unsigned guest_addr, guest_len; unsigned count = 0; while (getline(file, buf)) { - ss.str(buf); + stringstream ss(buf, ios::in); ss >> guest_addr >> guest_len; mm.add(guest_addr, guest_len); count++; } file.close(); + assert(count > 0); return (count > 0); } diff --git a/src/experiments/ecos_kernel_test/experiment.cc b/src/experiments/ecos_kernel_test/experiment.cc index e940fe62..e52a8f89 100644 --- a/src/experiments/ecos_kernel_test/experiment.cc +++ b/src/experiments/ecos_kernel_test/experiment.cc @@ -6,7 +6,7 @@ #include #include -#include "util/Logger.hpp" + #include "experiment.hpp" #include "experimentInfo.hpp" #include "campaign.hpp" @@ -22,6 +22,8 @@ #define LOCAL 0 +#define PREREQUISITES 0 // 1: do step 0-2 ; 0: do step 3 + using namespace std; using namespace fail; @@ -33,170 +35,173 @@ using namespace fail; char const * const mm_filename = "memory_map.txt"; +char const *statename = "ecos_kernel_test.state"; + +#if PREREQUISITES +bool EcosKernelTestExperiment::retrieveGuestAddresses() { + log << "STEP 0: record memory map with addresses of 'interesting' objects" << endl; + + // workaround for 00002808875p[BIOS ] >>PANIC<< Keyboard error:21 + BPSingleEvent bp; + bp.setWatchInstructionPointer(ANY_ADDR); + simulator.addEventAndWait(&bp); + + GuestEvent g; + simulator.addEvent(&g); + + // 10000us = 500000 instructions + TimerEvent record_timeout(50000000); //TODO: how long to wait? + simulator.addEvent(&record_timeout); + + // memory map serialization + ofstream mm(mm_filename, ios::out | ios::app); + if (!mm.is_open()) { + log << "failed to open " << mm_filename << endl; + return false; + } + + string *str = new string; // buffer for guest events + unsigned number_of_guest_events = 0; + + while (simulator.waitAny() != &record_timeout) { + simulator.addEvent(&g); + str->push_back(g.getData()); + if (g.getData() == '\t') { + // addr complete? + //cout << "full: " << *str << "sub: " << str->substr(str->find_last_of('x') - 1) << endl; + // interpret the string obtained by the guest events as address in hex + unsigned guest_addr; + stringstream converter(str->substr(str->find_last_of('x') + 1)); + converter >> hex >> guest_addr; + mm << guest_addr << '\t'; + str->clear(); + } else if (g.getData() == '\n') { + // len complete? + // interpret the string obtained by the guest events as length in decimal + unsigned guest_len; + stringstream converter(*str); + converter >> dec >> guest_len; + mm << guest_len << '\n'; + str->clear(); + number_of_guest_events++; + } + } + assert(number_of_guest_events > 0); + log << "Record timeout reached: created memory map (" << number_of_guest_events << " entries)" << endl; + delete str; + + // close serialized mm + mm.flush(); + mm.close(); + + // clean up simulator + simulator.clearEvents(); + return true; +} + +bool EcosKernelTestExperiment::establishState() { + log << "STEP 1: run until interesting function starts, and save state" << endl; + + GuestEvent g; + + while (true) { + simulator.addEventAndWait(&g); + if(g.getData() == 'Q') { + log << "Guest system triggered: " << g.getData() << endl; + break; + } + } + + BPSingleEvent bp; + bp.setWatchInstructionPointer(ECOS_FUNC_ENTRY); + simulator.addEventAndWait(&bp); + log << "test function entry reached, saving state" << endl; + log << "EIP = " << hex << bp.getTriggerInstructionPointer() << endl; + //log << "error_corrected = " << dec << ((int)simulator.getMemoryManager().getByte(OOSTUBS_ERROR_CORRECTED)) << endl; + simulator.save(statename); + assert(bp.getTriggerInstructionPointer() == ECOS_FUNC_ENTRY); + assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY); + + // clean up simulator + simulator.clearEvents(); + return true; +} + +bool EcosKernelTestExperiment::performTrace() { + log << "STEP 2: record trace for fault-space pruning" << endl; + + log << "restoring state" << endl; + simulator.restore(statename); + log << "EIP = " << hex << simulator.getRegisterManager().getInstructionPointer() << endl; + assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY); + + log << "enabling tracing" << endl; + TracingPlugin tp; + + // restrict memory access logging to injection target + MemoryMap mm; + EcosKernelTestCampaign::readMemoryMap(mm, mm_filename); + + tp.restrictMemoryAddresses(&mm); + + // record trace + char const *tracefile = "trace.tc"; + ofstream of(tracefile); + tp.setTraceFile(&of); + // this must be done *after* configuring the plugin: + simulator.addFlow(&tp); + + BPSingleEvent bp; +#if 1 + // trace WEATHER_NUMITER_TRACING measurement loop iterations + // -> calibration + bp.setWatchInstructionPointer(ECOS_FUNC_FINISH); + //bp.setCounter(WEATHER_NUMITER_TRACING); // single event, only +#else + // FIXME this doesn't work properly: trace is one instruction too short as + // tp is removed before all events were delivered + // trace WEATHER_NUMINSTR_TRACING instructions + // -> campaign-ready traces with identical lengths + bp.setWatchInstructionPointer(ANY_ADDR); + bp.setCounter(OOSTUBS_NUMINSTR); +#endif + simulator.addEvent(&bp); + BPSingleEvent ev_count(ANY_ADDR); + simulator.addEvent(&ev_count); + + // count instructions + // FIXME add SAL functionality for this? + int instr_counter = 0; + while (simulator.waitAny() == &ev_count) { + ++instr_counter; + simulator.addEvent(&ev_count); + } + + log << dec << "tracing finished after " << instr_counter << " instructions" << endl; + //TODO: safe this value for experiment STEP 3 + + simulator.removeFlow(&tp); + + // serialize trace to file + if (of.fail()) { + log << "failed to write " << tracefile << endl; + simulator.clearEvents(this); + return false; + } + of.close(); + log << "trace written to " << tracefile << endl; + + // clean up simulator + simulator.clearEvents(); + return true; +} + +#else // !PREREQUISITES +bool EcosKernelTestExperiment::faultInjection() { + log << "STEP 3: The actual experiment." << endl; -bool EcosKernelTestExperiment::run() -{ - char const *statename = "ecos_kernel_test.state"; - Logger log("eCos Kernel Test", false); BPSingleEvent bp; - log << "startup" << endl; - - log << "STEP 0: record memory map with addresses of 'interesting' objects" << endl; - { - // workaround for 00002808875p[BIOS ] >>PANIC<< Keyboard error:21 - bp.setWatchInstructionPointer(ANY_ADDR); - simulator.addEventAndWait(&bp); - - GuestEvent g; - simulator.addEvent(&g); - - // 10000us = 500000 instructions - TimerEvent record_timeout(50000000); //TODO: how long to wait? - simulator.addEvent(&record_timeout); - - // memory map serialization - ofstream mm(mm_filename, ios::out | ios::app); - if (!mm.is_open()) { - log << "failed to open " << mm_filename << endl; - return false; - } - - string *str = new string; // buffer for guest events - unsigned number_of_guest_events = 0; - - while (simulator.waitAny() != &record_timeout) { - simulator.addEvent(&g); - str->push_back(g.getData()); - - if (g.getData() == '\t') { - // addr complete? - //cout << "full: " << *str << "sub: " << str->substr(str->find_last_of('x') - 1) << endl; - // interpret the string obtained by the guest events as address in hex - unsigned guest_addr; - stringstream converter(str->substr(str->find_last_of('x') + 1)); - converter >> hex >> guest_addr; - mm << guest_addr << '\t'; - str->clear(); - } else if (g.getData() == '\n') { - // len complete? - // interpret the string obtained by the guest events as length in decimal - unsigned guest_len; - stringstream converter(*str); - converter >> dec >> guest_len; - mm << guest_len << '\n'; - str->clear(); - number_of_guest_events++; - } - } - assert(number_of_guest_events > 0); - cout << "Record timeout reached: created memory map (" << number_of_guest_events << " entries)" << endl; - delete str; - - // close serialized mm - mm.flush(); - mm.close(); - - // clean up simulator and reboot the guest system - simulator.clearEvents(); - log << "rebooting ..." << endl; - simulator.reboot(); - } - - log << "STEP 1: run until interesting function starts, and save state" << endl; - { - GuestEvent g; - - while (true) { - simulator.addEventAndWait(&g); - if(g.getData() == 'Q') { - cout << "Guest system triggered: " << g.getData() << endl; - break; - } - } - - bp.setWatchInstructionPointer(ECOS_FUNC_ENTRY); - simulator.addEventAndWait(&bp); - log << "test function entry reached, saving state" << endl; - log << "EIP = " << hex << bp.getTriggerInstructionPointer() << endl; - //log << "error_corrected = " << dec << ((int)simulator.getMemoryManager().getByte(OOSTUBS_ERROR_CORRECTED)) << endl; - simulator.save(statename); - assert(bp.getTriggerInstructionPointer() == ECOS_FUNC_ENTRY); - assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY); - - // clean up simulator and reboot the guest system - simulator.clearEvents(); - log << "rebooting ..." << endl; - simulator.reboot(); - } - - log << "STEP 2: record trace for fault-space pruning" << endl; - { - log << "restoring state" << endl; - simulator.restore(statename); - log << "EIP = " << hex << simulator.getRegisterManager().getInstructionPointer() << endl; - assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY); - - log << "enabling tracing" << endl; - TracingPlugin tp; - - // restrict memory access logging to injection target - MemoryMap mm; - EcosKernelTestCampaign::readMemoryMap(mm, mm_filename); - - tp.restrictMemoryAddresses(&mm); - - // record trace - char const *tracefile = "trace.tc"; - ofstream of(tracefile); - tp.setTraceFile(&of); - - // this must be done *after* configuring the plugin: - simulator.addFlow(&tp); - -#if 1 - // trace WEATHER_NUMITER_TRACING measurement loop iterations - // -> calibration - bp.setWatchInstructionPointer(ECOS_FUNC_FINISH); - //bp.setCounter(WEATHER_NUMITER_TRACING); // single event, only -#else - // FIXME this doesn't work properly: trace is one instruction too short as - // tp is removed before all events were delivered - // trace WEATHER_NUMINSTR_TRACING instructions - // -> campaign-ready traces with identical lengths - bp.setWatchInstructionPointer(ANY_ADDR); - bp.setCounter(OOSTUBS_NUMINSTR); -#endif - simulator.addEvent(&bp); - BPSingleEvent ev_count(ANY_ADDR); - simulator.addEvent(&ev_count); - - // count instructions - // FIXME add SAL functionality for this? - int instr_counter = 0; - while (simulator.waitAny() == &ev_count) { - ++instr_counter; - simulator.addEvent(&ev_count); - } - - log << dec << "tracing finished after " << instr_counter << " instructions" << endl; - //TODO: safe this value for experiment STEP 3 - - - simulator.removeFlow(&tp); - - // serialize trace to file - if (of.fail()) { - log << "failed to write " << tracefile << endl; - simulator.clearEvents(this); - return false; - } - of.close(); - log << "trace written to " << tracefile << endl; - } - -#if 0 - // STEP 3: The actual experiment. #if !LOCAL for (int i = 0; i < 400; ++i) { // more than 400 will be very slow (500 is max) #endif @@ -431,8 +436,37 @@ bool EcosKernelTestExperiment::run() #if !LOCAL } #endif +} +#endif // PREREQUISITES + +bool EcosKernelTestExperiment::run() +{ + log << "startup" << endl; + + #if PREREQUISITES + // step 0 + if(retrieveGuestAddresses()) { + log << "STEP 0 finished: rebooting ..." << endl; + simulator.reboot(); + } else { return false; } + + // step 1 + if(establishState()) { + log << "STEP 1 finished: rebooting ..." << endl; + simulator.reboot(); + } else { return false; } + + // step 2 + if(performTrace()) { + log << "STEP 2 finished: terminating ..." << endl; + } else { return false; } + + #else // !PREREQUISITES + // step 3 + faultInjection(); + #endif // PREREQUISITES -#endif // Explicitly terminate, or the simulator will continue to run. simulator.terminate(); + return true; } diff --git a/src/experiments/ecos_kernel_test/experiment.hpp b/src/experiments/ecos_kernel_test/experiment.hpp index 77ac2296..ed52ab7a 100644 --- a/src/experiments/ecos_kernel_test/experiment.hpp +++ b/src/experiments/ecos_kernel_test/experiment.hpp @@ -2,11 +2,18 @@ #include "efw/ExperimentFlow.hpp" #include "efw/JobClient.hpp" +#include "util/Logger.hpp" class EcosKernelTestExperiment : public fail::ExperimentFlow { fail::JobClient m_jc; + fail::Logger log; public: - EcosKernelTestExperiment() : m_jc("ios.cs.tu-dortmund.de") {} + EcosKernelTestExperiment() : m_jc("ios.cs.tu-dortmund.de"), log("eCos Kernel Test", false) {} bool run(); + + bool retrieveGuestAddresses(); // step 0 + bool establishState(); // step 1 + bool performTrace(); // step 2 + bool faultInjection(); // step 3 };