From 11d9690a67d034b7a6e948d43736f5235b126e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20B=C3=B6ckenkamp?= Date: Tue, 23 Apr 2013 14:34:27 +0200 Subject: [PATCH 01/17] Typos in BochsController.hpp fixed Change-Id: Ib94d63707fdeb3e0dc77cccd3ffde04df25329c2 --- src/core/sal/bochs/BochsController.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/sal/bochs/BochsController.hpp b/src/core/sal/bochs/BochsController.hpp index a9d3491d..e6bb2743 100644 --- a/src/core/sal/bochs/BochsController.hpp +++ b/src/core/sal/bochs/BochsController.hpp @@ -43,7 +43,7 @@ private: bxInstruction_c *m_CurrentInstruction; //!< dito. public: /** - * Initialize the controller, i.e. add the number of simulated CPUs. + * Initialize the controller, i.e., add the number of simulated CPUs. */ BochsController(); ~BochsController(); @@ -56,7 +56,7 @@ public: * @param cpu the CPU that caused the IO port access * @param data the data transmitted * @param port the port it was transmitted on - * @param out true if the I/O traffic has been outbound, false otherwise + * @param out \c true if the I/O traffic has been outbound, \c false otherwise */ void onIOPort(ConcreteCPU* cpu, unsigned char data, unsigned port, bool out); /** @@ -130,7 +130,7 @@ public: const std::string& getMnemonic() const; /** * Retrieves the current Bochs instruction cache entry - * @returns a pointer to a bxICacheEntry_c object + * @return a pointer to a \c bxICacheEntry_c object */ inline bxInstruction_c *getCurrentInstruction() const { return m_CurrentInstruction; } /** @@ -149,7 +149,7 @@ public: * Retrieves the concrete CPU object, based on the given Bochs' internal pointer \a pCPU. * @param pCPU the Bochs' internal CPU object * @return the FailBochs CPU representation that corresponds to Bochs' internal CPU \a pCPU - * @see The uses SimulatorController::getCPU(). + * @see SimulatorController::getCPU(). */ ConcreteCPU& detectCPU(BX_CPU_C* pCPU) const; }; From 2753a165ba6677e8bcd7a702ddb0d67296ff5d09 Mon Sep 17 00:00:00 2001 From: Christian Dietrich Date: Sun, 28 Apr 2013 12:43:56 +0200 Subject: [PATCH 02/17] ElfReader: Add support for getting a section iterator Change-Id: I6241ea2de9da1a1e709fae6374df4fc06ef26aaa --- src/core/util/ElfReader.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/core/util/ElfReader.hpp b/src/core/util/ElfReader.hpp index 1722e0e0..2d12ec10 100644 --- a/src/core/util/ElfReader.hpp +++ b/src/core/util/ElfReader.hpp @@ -80,6 +80,8 @@ namespace fail { typedef ElfSymbol entry_t; typedef std::vector container_t; typedef container_t::const_iterator symbol_iterator; + typedef container_t::const_iterator section_iterator; + /** * Constructor. @@ -144,6 +146,14 @@ namespace fail { container_t::const_iterator sym_begin() { return m_symboltable.begin(); } container_t::const_iterator sym_end() { return m_symboltable.end(); } + /** + * Get section iterator. Derefences to a ElfSymbol + * @return iterator + */ + container_t::const_iterator sec_begin() { return m_sectiontable.begin(); } + container_t::const_iterator sec_end() { return m_sectiontable.end(); } + + private: Logger m_log; From 923ba362fac9b166bb7d818c0e847f23c69db8e7 Mon Sep 17 00:00:00 2001 From: Christian Dietrich Date: Wed, 24 Apr 2013 07:50:28 +0200 Subject: [PATCH 03/17] experiments/kesorefs: convert to DatabaseCampaign Change-Id: I7607911c28ffb2427681db241ac721f1ae2c002a --- src/experiments/kesorefs/CMakeLists.txt | 2 +- src/experiments/kesorefs/campaign.cc | 74 +------ src/experiments/kesorefs/campaign.hpp | 13 +- src/experiments/kesorefs/experiment.cc | 281 ++++++++++++++---------- src/experiments/kesorefs/kesoref.proto | 47 ++-- src/experiments/kesorefs/main.cc | 5 + 6 files changed, 213 insertions(+), 209 deletions(-) diff --git a/src/experiments/kesorefs/CMakeLists.txt b/src/experiments/kesorefs/CMakeLists.txt index 6aaaae5e..d3dfb253 100644 --- a/src/experiments/kesorefs/CMakeLists.txt +++ b/src/experiments/kesorefs/CMakeLists.txt @@ -30,5 +30,5 @@ 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 fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY}) +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/kesorefs/campaign.cc b/src/experiments/kesorefs/campaign.cc index a656d2cd..9d5ea419 100644 --- a/src/experiments/kesorefs/campaign.cc +++ b/src/experiments/kesorefs/campaign.cc @@ -5,80 +5,16 @@ #include "experimentInfo.hpp" #include "cpn/CampaignManager.hpp" #include "util/Logger.hpp" -#include "util/ElfReader.hpp" #include "util/ProtoStream.hpp" #include "sal/SALConfig.hpp" -//#if COOL_FAULTSPACE_PRUNING -//#include "../plugins/tracing/TracingPlugin.hpp" -//char const * const trace_filename = "trace.pb"; -//#endif using namespace std; using namespace fail; +using namespace google::protobuf; -char const * const results_csv = "kesorefs.csv"; - -bool KesoRefCampaign::run() -{ - Logger log("KesoRefCampaign"); - ElfReader elf; - - ifstream test(results_csv); - if (test.is_open()) { - log << results_csv << " already exists" << endl; - return false; - } - ofstream results(results_csv); - if (!results.is_open()) { - log << "failed to open " << results_csv << endl; - return false; - } - - address_t injip = elf.getSymbol("c23_PersistentDetectorScopeEntry_m5_run").getAddress(); - - address_t rambase = elf.getSymbol("__CIAO_APPDATA_cdx_det__heap").getAddress(); - // address_t ramend = rambase + 0x80000; - address_t ramend = rambase + 4; - cout << "ramend: " << hex << ramend << endl; - - log << "startup, injecting ram @ " << hex << rambase << endl; - - int count = 0; - for (address_t ram_address = rambase; ram_address < ramend ; ram_address += 4) { - for (int bit_offset = 23; bit_offset < 24; ++bit_offset) { - KesoRefExperimentData *d = new KesoRefExperimentData; - - d->msg.set_pc_address(injip); - d->msg.set_ram_address(ram_address); - d->msg.set_bit_offset(bit_offset); - - campaignmanager.addParam(d); - ++count; - } - } - campaignmanager.noMoreParameters(); - log << "done enqueueing parameter sets (" << dec << count << ")." << endl; - - // collect results - KesoRefExperimentData *res; - int rescount = 0; - results << "injection_ip\tram_address\tbit_offset\tresulttype\toriginal_value\tdetails" << endl; - while ((res = static_cast(campaignmanager.getDone()))) { - rescount++; - - results - << "0x" << hex << res->msg.pc_address() << "\t" - << "0x" << hex << res->msg.ram_address() << "\t" - << dec << res->msg.bit_offset() << "\t" - << res->msg.resulttype() << "\t" - << res->msg.original_value() << "\t" - << res->msg.details() << "\n"; - delete res; - } - - log << "done. sent " << count << " received " << rescount << endl; - results.close(); - - return true; +void KesoRefCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) { + KesoRefExperimentData *data = new KesoRefExperimentData; + data->msg.mutable_fsppilot()->CopyFrom(pilot); + campaignmanager.addParam(data); } diff --git a/src/experiments/kesorefs/campaign.hpp b/src/experiments/kesorefs/campaign.hpp index d9c2859f..994631bc 100644 --- a/src/experiments/kesorefs/campaign.hpp +++ b/src/experiments/kesorefs/campaign.hpp @@ -1,19 +1,24 @@ #ifndef __KESOREFCAMPAIGN_HPP__ #define __KESOREFCAMPAIGN_HPP__ -#include "cpn/Campaign.hpp" +#include "cpn/DatabaseCampaign.hpp" #include "comm/ExperimentData.hpp" +#include #include "kesoref.pb.h" + class KesoRefExperimentData : public fail::ExperimentData { public: KesoRefProtoMsg msg; KesoRefExperimentData() : fail::ExperimentData(&msg) {} }; -class KesoRefCampaign : public fail::Campaign { -public: - virtual bool run(); + +class KesoRefCampaign : public fail::DatabaseCampaign { + virtual const google::protobuf::Descriptor * cb_result_message() + { return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("KesoRefProtoMsg"); } + + virtual void cb_send_pilot(DatabaseCampaignMessage pilot); }; #endif // __KESOREFCAMPAIGN_HPP__ diff --git a/src/experiments/kesorefs/experiment.cc b/src/experiments/kesorefs/experiment.cc index 1d39c8f2..2decaf79 100644 --- a/src/experiments/kesorefs/experiment.cc +++ b/src/experiments/kesorefs/experiment.cc @@ -28,9 +28,8 @@ 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) -#error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration. +#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) + #error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration. #endif // //void KESOrefs::printEIP() { @@ -39,27 +38,28 @@ using namespace fail; unsigned KESOrefs::injectBitFlip(address_t data_address, unsigned bitpos){ - MemoryManager& mm = simulator.getMemoryManager(); - unsigned value, injectedval; + MemoryManager& mm = simulator.getMemoryManager(); + unsigned int value, injectedval; - mm.getBytes(data_address, 4, (void*)&value); - injectedval = value ^ (1< 0x" << setw(8) << setfill('0') << injectedval << endl; + 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; - return value; + return value; } -void handleEvent(KesoRefExperimentData& param, KesoRefProtoMsg_ResultType restype, const std::string &msg){ - cout << msg << endl; - param.msg.set_resulttype(restype); - param.msg.set_details(msg); +void handleEvent(KesoRefProtoMsg_Result& result, KesoRefProtoMsg_Result_ResultType restype, const std::string &msg) { + cout << msg << endl; + result.set_resulttype(restype); + result.set_details(msg); } -void handleMemoryAccessEvent(KesoRefExperimentData& param, const fail::MemAccessListener& l_mem){ + +void handleMemoryAccessEvent(KesoRefProtoMsg_Result& result, const fail::MemAccessListener& l_mem){ stringstream sstr; sstr << "mem access ("; switch (l_mem.getTriggerAccessType()) { @@ -75,128 +75,187 @@ void handleMemoryAccessEvent(KesoRefExperimentData& param, const fail::MemAccess sstr << " ip @ 0x" << hex << l_mem.getTriggerInstructionPointer(); - handleEvent(param, param.msg.MEMACCESS, sstr.str()); + handleEvent(result, result.MEMACCESS, sstr.str()); } bool KESOrefs::run() { - m_dis.init(); -//******* Boot, and store state *******// - m_log << "STARTING EXPERIMENT" << endl; -#if SAFESTATE // define SS (SafeState) when building: make -DSS -#warning "Building safe state variant" - m_log << "Booting, and saving state at main" << std::endl; - // m_elf.printSections(); - // m_elf.printDemangled(); + 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; - simulator.terminate(); - BPSingleListener bp; - // STEP 1: run until interesting function starts, and save state - bp.setWatchInstructionPointer(m_elf.getSymbol("main").getAddress()); - if(simulator.addListenerAndResume(&bp) == &bp){ - m_log << "main function entry reached, saving state" << endl; - } + 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()); + } + } - simulator.save("keso.state"); - simulator.terminate(); -#else + 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; -//******* Fault injection *******// -#warning "Building restore state variant" - for (int experiment_count = 0; experiment_count < 200 || (m_jc.getNumberOfUndoneJobs() != 0) ; ) { // only do 200 sequential experiments, to prevent swapping - m_log << "asking jobserver for parameters" << endl; - KesoRefExperimentData param; - if(!m_jc.getParam(param)){ - m_log << "Dying." << endl; // We were told to die. - simulator.terminate(1); - } + // m_dis.init(); + //******* Boot, and store state *******// + m_log << "STARTING EXPERIMENT" << endl; - // Get input data from Jobserver - address_t injectionPC = param.msg.pc_address(); - address_t data_address = param.msg.ram_address(); - unsigned bitpos = param.msg.bit_offset(); + unsigned executed_jobs = 0; - simulator.restore("keso.state"); - // Goto injection point - BPSingleListener injBP; - m_log << "Trying to inject @ " << hex << m_elf.getSymbol(injectionPC).getAddress() << endl; + // 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_parity = m_elf.getSymbol("keso_throw_parity"); + BPSingleListener l_parity(s_parity.getAddress()); + const ElfSymbol &s_oobounds = m_elf.getSymbol("keso_throw_index_out_of_bounds"); + BPSingleListener l_oobounds(s_oobounds.getAddress()); + BPSingleListener l_dump(m_elf.getSymbol("c17_Main_m4_dumpResults_console").getAddress()); - injBP.setWatchInstructionPointer(injectionPC); + MemAccessListener l_mem_text(minimal_ip, MemAccessEvent::MEM_WRITE); + l_mem_text.setWatchWidth(maximal_ip - minimal_ip); - simulator.addListenerAndResume(&injBP); - /// INJECT BITFLIP: - param.msg.set_original_value(injectBitFlip(data_address, bitpos)); + MemAccessListener l_mem_outerspace( maximal_data); + l_mem_outerspace.setWatchWidth(0xfffffff0); + TrapListener l_trap(ANY_TRAP); - // Setup exit points - BPSingleListener l_error(m_elf.getSymbol("keso_throw_error").getAddress()); - BPSingleListener l_nullp(m_elf.getSymbol("keso_throw_nullpointer").getAddress()); - BPSingleListener l_parity(m_elf.getSymbol("keso_throw_parity").getAddress()); - BPSingleListener l_oobounds(m_elf.getSymbol("keso_throw_index_out_of_bounds").getAddress()); - BPSingleListener l_dump(m_elf.getSymbol("c17_Main_m4_dumpResults_console").getAddress()); + TimerListener l_timeout(1000 * 1000); // 1 second in microseconds - ElfSymbol sym = m_elf.getSection(".text"); - MemAccessListener l_mem_text(sym.getStart(), , AccessEvent::MEM_WRITE); l_mem_text.setWatchWidth(sym.getSize()); + while (executed_jobs < 25 || m_jc.getNumberOfUndoneJobs() > 0) { + m_log << "asking jobserver for parameters" << endl; + KesoRefExperimentData param; + if(!m_jc.getParam(param)){ + m_log << "Dying." << endl; // We were told to die. + simulator.terminate(1); + } - sym = m_elf.getSection(".text.cdx_det"); - MemAccessListener l_mem_textcdx_det(sym.getStart(), MemAccessEvent::MEM_WRITE ); l_mem_textcdx_det.setWatchWidth(sym.getSize()); + // Get input data from Jobserver + unsigned injection_instr = param.msg.fsppilot().injection_instr(); + address_t data_address = param.msg.fsppilot().data_address(); - sym = m_elf.getSection(".copy_sec"); - MemAccessListener l_mem_outerspace( sym.getStart() ); l_mem_outerspace.setWatchWidth(0xfffffff0); - TrapListener l_trap(ANY_TRAP); + for (int bit_offset = 0; bit_offset < 8; ++bit_offset) { + // 8 results in one job + KesoRefProtoMsg_Result *result = param.msg.add_result(); + result->set_bitoffset(bit_offset); -cout << " outerspace : " << l_mem_outerspace.getWatchWidth() << " --- @ :" << l_mem_outerspace.getWatchAddress() << endl; - simulator.addListener(&l_trap); - simulator.addListener(&l_error); - simulator.addListener(&l_nullp); - simulator.addListener(&l_oobounds); - simulator.addListener(&l_dump); - simulator.addListener(&l_parity); - simulator.addListener(&l_mem_text); - simulator.addListener(&l_mem_outerspace); - simulator.addListener(&l_mem_textcdx_det); - // resume and wait for results - fail::BaseListener* l = simulator.resume(); + m_log << "restoring state" << endl; + // Restore to the image, which starts at address(main) + simulator.restore("state"); + executed_jobs ++; - // Evaluate result - if(l == &l_error) { - handleEvent(param, param.msg.EXC_ERROR, "exc error"); + m_log << "Trying to inject @ instr #" << dec << injection_instr << endl; - } else if ( l == &l_nullp ) { - handleEvent(param, param.msg.EXC_NULLPOINTER, "exc nullpointer"); - } else if ( l == &l_oobounds ) { - handleEvent(param, param.msg.EXC_OOBOUNDS, "exc out of bounds"); + if (injection_instr > 0) { + simulator.clearListeners(); + // XXX could be improved with intermediate states (reducing runtime until injection) + simulator.addListener(&l_dump); - } else if (l == &l_dump) { - handleEvent(param, param.msg.CALCDONE, "calculation done"); + BPSingleListener bp; + bp.setWatchInstructionPointer(ANY_ADDR); + bp.setCounter(injection_instr + 1); + simulator.addListener(&bp); - } else if (l == &l_parity) { - handleEvent(param, param.msg.EXC_PARITY, "exc parity"); + bool inject = true; + while (1) { + fail::BaseListener * listener = simulator.resume(); + // finish() before FI? + if (listener == &l_dump) { + 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; + } + } - } else if (l == &l_trap) { - stringstream sstr; - sstr << "trap #" << l_trap.getTriggerNumber(); - handleEvent(param, param.msg.TRAP, sstr.str()); + // 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); + } - } else if (l == &l_mem_text){ - handleMemoryAccessEvent(param, l_mem_text); + /// INJECT BITFLIP: + result->set_original_value(injectBitFlip(data_address, bit_offset)); - } else if (l == &l_mem_textcdx_det){ - handleMemoryAccessEvent(param, l_mem_textcdx_det); + 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); + simulator.addListener(&l_dump); + if (s_parity.isValid()) + simulator.addListener(&l_parity); + simulator.addListener(&l_mem_text); + simulator.addListener(&l_mem_outerspace); + simulator.addListener(&l_timeout); + 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; - } else if (l == &l_mem_outerspace){ - handleMemoryAccessEvent(param, l_mem_outerspace); + // 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 { - handleEvent(param, param.msg.UNKNOWN, "UNKNOWN event"); - } - simulator.clearListeners(); - m_jc.sendResult(param); -} // end while (1) -// Explicitly terminate, or the simulator will continue to run. -#endif -simulator.terminate(); + } else if ( l == &l_oobounds ) { + handleEvent(*result, result->EXC_OOBOUNDS, "exc out of bounds"); + + } else if (l == &l_dump) { + handleEvent(*result, result->CALCDONE, "calculation done"); + + } else if (l == &l_parity) { + handleEvent(*result, result->EXC_PARITY, "exc parity"); + + } else if (l == &l_timeout) { + handleEvent(*result, result->TIMEOUT, "1s"); + + + } 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 { + 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/kesorefs/kesoref.proto b/src/experiments/kesorefs/kesoref.proto index 799ff0e1..d5209fe6 100644 --- a/src/experiments/kesorefs/kesoref.proto +++ b/src/experiments/kesorefs/kesoref.proto @@ -1,27 +1,26 @@ -message KesoRefProtoMsg { - // parameters - required int32 pc_address = 1; - required int32 ram_address = 2; - required int32 bit_offset = 3; +import "DatabaseCampaignMessage.proto"; - // results - // make these optional to reduce overhead for server->client communication - enum ResultType { - CALCDONE = 1; - TIMEOUT = 2; - TRAP = 3; - EXC_ERROR = 4; - EXC_PARITY = 5; - EXC_NULLPOINTER = 6; - EXC_OOBOUNDS = 7; - MEMACCESS = 8; - UNKNOWN = 9; +message KesoRefProtoMsg { + 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; + EXC_PARITY = 5; + EXC_NULLPOINTER = 6; + EXC_OOBOUNDS = 7; + MEMACCESS = 8; + NOINJECTION = 9; + UNKNOWN = 10; + } + // 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; } - // result type, see above - optional ResultType resulttype = 4; - optional uint32 original_value = 5; - // did ECC correct the fault? - //optional int32 error_corrected = 6; - // optional textual description of what happened - optional string details = 7; } diff --git a/src/experiments/kesorefs/main.cc b/src/experiments/kesorefs/main.cc index 4af91718..93105c47 100644 --- a/src/experiments/kesorefs/main.cc +++ b/src/experiments/kesorefs/main.cc @@ -2,10 +2,15 @@ #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]); + KesoRefCampaign c; if (fail::campaignmanager.runCampaign(&c)) { return 0; From 33c0584dda89300b43caa78bb233c10bce9aff90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20B=C3=B6ckenkamp?= Date: Wed, 24 Apr 2013 13:06:44 +0200 Subject: [PATCH 04/17] gem5: revisited breakpoint implementation Now, the gem5 implementation equals the Bochs variant. Note that it's *not* necessary to enable CONFIG_EVENTS_BREAKPOINTS_RANGE in order to use range breakpoints. In addition, gem5 distinguishes between macro- and microops. With the new implementation, onBreakpoint() is only called when a macroop changes. Change-Id: Ib86d1802fc70c20d22ca1a1ece0e8d1221b2e7db --- simulators/gem5/src/cpu/simple/base.cc | 14 +++++++------ src/core/sal/gem5/Gem5Breakpoint.hpp | 18 ---------------- src/core/sal/gem5/Gem5Listener.ah | 29 -------------------------- src/core/sal/gem5/Gem5Wrapper.cc | 22 ------------------- src/core/sal/gem5/Gem5Wrapper.hpp | 6 ------ 5 files changed, 8 insertions(+), 81 deletions(-) delete mode 100644 src/core/sal/gem5/Gem5Breakpoint.hpp delete mode 100644 src/core/sal/gem5/Gem5Listener.ah diff --git a/simulators/gem5/src/cpu/simple/base.cc b/simulators/gem5/src/cpu/simple/base.cc index 1eb98e0d..2b8e16ee 100644 --- a/simulators/gem5/src/cpu/simple/base.cc +++ b/simulators/gem5/src/cpu/simple/base.cc @@ -377,12 +377,6 @@ BaseSimpleCPU::preExecute() TheISA::PCState pcState = thread->pcState(); - // FAIL* - #if defined(CONFIG_EVENT_BREAKPOINTS) && defined(CONFIG_EVENT_BREAKPOINTS_RANGE) - fail::ConcreteCPU* cpu = &fail::simulator.getCPU(cpuId()); - fail::simulator.onBreakpoint(cpu, instAddr(), -1); - #endif - if (isRomMicroPC(pcState.microPC())) { stayAtPC = false; curStaticInst = microcodeRom.fetchMicroop(pcState.microPC(), @@ -406,6 +400,14 @@ BaseSimpleCPU::preExecute() //Decode an instruction if one is ready. Otherwise, we'll have to //fetch beyond the MachInst at the current pc. instPtr = decoder->decode(pcState); + + // FAIL* + #if defined(CONFIG_EVENT_BREAKPOINTS) || defined(CONFIG_EVENT_BREAKPOINTS_RANGE) + fail::ConcreteCPU* cpu = &fail::simulator.getCPU(cpuId()); + fail::simulator.setMnemonic(instPtr->getName()); + fail::simulator.onBreakpoint(cpu, instAddr(), -1); + #endif + if (instPtr) { stayAtPC = false; thread->pcState(pcState); diff --git a/src/core/sal/gem5/Gem5Breakpoint.hpp b/src/core/sal/gem5/Gem5Breakpoint.hpp deleted file mode 100644 index 93da9e2f..00000000 --- a/src/core/sal/gem5/Gem5Breakpoint.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __GEM5_BREAKPOINT_HPP__ - #define __GEM5_BREAKPOINT_HPP__ - -#include "../SALConfig.hpp" -#include "cpu/pc_event.hh" - -namespace fail { - -class Gem5Breakpoint : public PCEvent { -public: - Gem5Breakpoint(PCEventQueue* queue, Addr ip) - : PCEvent(queue, "Fail* experiment breakpoint", ip) { } - virtual void process(ThreadContext *tc); -}; - -} // end-of-namespace: fail - -#endif // __GEM5_BREAKPOINT_HPP__ diff --git a/src/core/sal/gem5/Gem5Listener.ah b/src/core/sal/gem5/Gem5Listener.ah deleted file mode 100644 index e69a0d74..00000000 --- a/src/core/sal/gem5/Gem5Listener.ah +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __GEM5_LISTENER_AH__ - #define __GEM5_LISTENER_AH__ - -#include "config/FailConfig.hpp" -#include "config/VariantConfig.hpp" - -#if defined(BUILD_GEM5) && defined(CONFIG_EVENT_BREAKPOINTS) && !defined(CONFIG_EVENT_BREAKPOINTS_RANGE) - -aspect Gem5Listener { - advice "fail::BPSingleListener" : slice class { - private: - Gem5Breakpoint* m_Breakpoint; - public: - virtual bool onAddition() - { - m_Breakpoint = OnBreakpointAddition(Gem5Breakpoint* bp, address_t watchInstrPtr) - return true; - } - virtual void onDeletion() - { - OnBreakpointDeletion(m_Breakpoint); - m_Breakpoint = 0; - } - }; -}; - -#endif // defined(BUILD_GEM5) && defined(CONFIG_EVENT_BREAKPOINTS) && !defined(CONFIG_EVENT_BREAKPOINTS_RANGE) - -#endif // __GEM5_LISTENER_AH__ diff --git a/src/core/sal/gem5/Gem5Wrapper.cc b/src/core/sal/gem5/Gem5Wrapper.cc index f0848531..65a8aaaf 100644 --- a/src/core/sal/gem5/Gem5Wrapper.cc +++ b/src/core/sal/gem5/Gem5Wrapper.cc @@ -1,6 +1,5 @@ #include "../SALInst.hpp" #include "Gem5Wrapper.hpp" -#include "Gem5Breakpoint.hpp" #include "sim/system.hh" #include "mem/packet.hh" @@ -61,27 +60,6 @@ void WriteMemory(System* sys, guest_address_t addr, size_t cnt, void const *src) size_t GetPoolSize(System* sys) { return sys->getPhysMem().totalSize(); } -// Breakpoint-related: -void Gem5Breakpoint::process(ThreadContext *tc) -{ - fail::simulator.onBreakpoint(&fail::simulator.getCPU(tc->cpuId()), this->evpc, fail::ANY_ADDR); -} - -Gem5Breakpoint* OnBreakpointAddition(address_t watchInstrPtr) -{ - System* sys = *System::systemList.begin(); - // FIXME: begin() vs. front() (see Gem5Controller::startup()) - // FIXME: Provide "sys" using the simulator-inst? - return new Gem5Breakpoint(&sys->pcEventQueue, watchInstrPtr); -} - -void OnBreakpointDeletion(Gem5Breakpoint* bp) -{ - if (bp) { - delete bp; // TODO: required? - } -} - // Controller-related: unsigned int GetCPUId(System* sys, int context) { diff --git a/src/core/sal/gem5/Gem5Wrapper.hpp b/src/core/sal/gem5/Gem5Wrapper.hpp index 141a87b6..c5ecfd21 100644 --- a/src/core/sal/gem5/Gem5Wrapper.hpp +++ b/src/core/sal/gem5/Gem5Wrapper.hpp @@ -9,8 +9,6 @@ class System; namespace fail { -class Gem5Breakpoint; - // Register-/Memory-related: regdata_t GetRegisterContent(System* sys, unsigned int id, RegisterType type, size_t idx); void SetRegisterContent(System* sys, unsigned int id, RegisterType type, size_t idx, @@ -19,10 +17,6 @@ void WriteMemory(System* sys, guest_address_t addr, size_t cnt, void const *src) void ReadMemory(System* sys, guest_address_t addr, size_t cnt, void *dest); size_t GetPoolSize(System* sys); -// Breakpoint-related: -Gem5Breakpoint* OnBreakpointAddition(address_t watchInstrPtr); -void OnBreakpointDeletion(Gem5Breakpoint* bp); - // Controller-related: unsigned int GetCPUId(System* sys, int context); System* GetSystemObject(); From 392a6e6eb859181e612d0bccd00cef8364ff393c Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Thu, 11 Apr 2013 10:39:34 +0200 Subject: [PATCH 05/17] core/sal: correct timer ticks/sec calculation Change-Id: I0971fe8a21c9ed3415d98b5e6387299beb3121e6 --- src/core/sal/bochs/BochsController.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/sal/bochs/BochsController.hpp b/src/core/sal/bochs/BochsController.hpp index e6bb2743..70deabe3 100644 --- a/src/core/sal/bochs/BochsController.hpp +++ b/src/core/sal/bochs/BochsController.hpp @@ -116,7 +116,7 @@ public: */ void fireInterruptDone(); virtual simtime_t getTimerTicks() { return bx_pc_system.time_ticks(); } - virtual simtime_t getTimerTicksPerSecond() { return bx_pc_system.time_ticks() / bx_pc_system.time_usec(); /* imprecise hack */ } + virtual simtime_t getTimerTicksPerSecond() { return bx_pc_system.time_ticks() / bx_pc_system.time_usec() * 1000000; /* imprecise hack */ } /* ******************************************************************** * BochsController-specific (not implemented in SimulatorController!): * ********************************************************************/ From 0887a53d1df9297180854767af3035987db1af7b Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Wed, 24 Apr 2013 17:19:38 +0200 Subject: [PATCH 06/17] ecos: campaign rewrite for MySQL data store We're not yet using the common DatabaseCampaign as it doesn't allow for additional experiment parameters (such as "variant" and "benchmark") yet. TODO: Integrate changes in DatabaseCampaign in a generic way and use it. Change-Id: I45480003be433654aea8d3a417fbfa66be31155b --- .../ecos_kernel_test/CMakeLists.txt | 4 +- src/experiments/ecos_kernel_test/campaign.cc | 493 +++++++----------- src/experiments/ecos_kernel_test/campaign.hpp | 31 +- .../ecos_kernel_test/ecos_kernel_test.proto | 4 +- src/experiments/ecos_kernel_test/main.cc | 5 + 5 files changed, 195 insertions(+), 342 deletions(-) diff --git a/src/experiments/ecos_kernel_test/CMakeLists.txt b/src/experiments/ecos_kernel_test/CMakeLists.txt index d106abd4..883e2039 100644 --- a/src/experiments/ecos_kernel_test/CMakeLists.txt +++ b/src/experiments/ecos_kernel_test/CMakeLists.txt @@ -27,9 +27,9 @@ 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-tracing fail-comm) -target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY}) +target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} -lmysqlclient_r) ## This is the example's campaign server distributing experiment parameters add_executable(${EXPERIMENT_NAME}-server main.cc) -target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY}) +target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} -lmysqlclient_r) install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin) diff --git a/src/experiments/ecos_kernel_test/campaign.cc b/src/experiments/ecos_kernel_test/campaign.cc index 3e231d73..1f7fe974 100644 --- a/src/experiments/ecos_kernel_test/campaign.cc +++ b/src/experiments/ecos_kernel_test/campaign.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include "campaign.hpp" #include "experimentInfo.hpp" @@ -9,11 +10,10 @@ #include "util/ProtoStream.hpp" #include "util/MemoryMap.hpp" #include "util/gzstream/gzstream.h" +#include "util/CommandLine.hpp" #include "../plugins/tracing/TracingPlugin.hpp" -//#define PRUNING_DEBUG_OUTPUT - using namespace std; using namespace fail; @@ -114,14 +114,6 @@ std::string EcosKernelTestCampaign::filename_traceinfo(const std::string& varian return "traceinfo.txt"; } -std::string EcosKernelTestCampaign::filename_results(const std::string& variant, const std::string& benchmark) -{ - if (variant.size() && benchmark.size()) { - return dir_results + "/" + variant + "-" + benchmark + "-" + "results.csv"; - } - return "results.csv"; -} - std::string EcosKernelTestCampaign::filename_elf(const std::string& variant, const std::string& benchmark) { if (variant.size() && benchmark.size()) { @@ -146,350 +138,217 @@ char const *variants[] = { 0 }; +// big four (three): (mutex3,) bin_sem2, clocktruth, sync2 +// busy waiters, sloooow at ips=2666mhz: kill, mutex3, clocktruth +// batch 1: line 1 char const *benchmarks[] = { +#if 1 "bin_sem0", "bin_sem1", "bin_sem2", "bin_sem3", "clock1", "clockcnv", - "clocktruth", "cnt_sem1", "except1", "flag1", "kill", "mqueue1", "mutex1", - "mutex2", "mutex3", "release", "sched1", "sync2", "sync3", "thread0", + /*"clocktruth",*/ "cnt_sem1", "except1", "flag1", /*"kill",*/ "mqueue1", "mutex1", + "mutex2", /*"mutex3",*/ "release", "sched1", "sync2", "sync3", "thread0", "thread1", "thread2", +#elif 0 + "sync2", +#endif 0 }; bool EcosKernelTestCampaign::run() { - m_log << "startup" << endl; + CommandLine &cmd = CommandLine::Inst(); - if (!init_results()) { - return false; + cmd.addOption("", "", Arg::None, "USAGE: fail-server [options...]"); + CommandLine::option_handle HELP = + cmd.addOption("h", "help", Arg::None, "-h/--help \tPrint usage and exit"); + CommandLine::option_handle RESULTTABLE = + cmd.addOption("r", "resulttable", Arg::Required, "-r/--resulttable \tTable to store results in (default: 'result')"); + Database::cmdline_setup(); + + if (!cmd.parse()) { + m_log << "Error parsing arguments." << std::endl; + exit(1); } + if (cmd[HELP].count() > 0) { + cmd.printUsage(); + exit(0); + } + if (cmd[RESULTTABLE].count() > 0) { + m_result_table = std::string(cmd[RESULTTABLE].first()->arg); + } else { + m_result_table = std::string("result"); + } + m_log << "Storing results in table '" << m_result_table << "'\n"; + db = Database::cmdline_connect(); + db_recv = Database::cmdline_connect(); + fspmethod_id = 1; // constant for now + + std::stringstream ss; + ss << "CREATE TABLE IF NOT EXISTS " << m_result_table << " (" + "pilot_id int(11) NOT NULL,\n" + "bitnr tinyint(4) NOT NULL,\n" + "bit_width tinyint(4) NOT NULL,\n" + "resulttype tinyint(4) NOT NULL,\n" + "ecos_test_result tinyint(4) NOT NULL,\n" + "latest_ip int(10) unsigned DEFAULT NULL,\n" + "error_corrected tinyint(4) NOT NULL,\n" + "details varchar(255) DEFAULT NULL,\n" + "runtime float NOT NULL,\n" + "PRIMARY KEY (pilot_id,bitnr))\n" + "ENGINE = MyISAM"; + if (!db->query(ss.str().c_str())) return false; // collect results in parallel to avoid deadlock #ifndef __puma boost::thread collect_thread(&EcosKernelTestCampaign::collect_results, this); #endif + ss.str(""); + + /* Gather all unfinished jobs */ + m_log << "Looking for unfinished jobs in the database ..." << std::endl; + ss << "("; for (int variant_nr = 0; variants[variant_nr]; ++variant_nr) { char const *variant = variants[variant_nr]; - for (int benchmark_nr = 0; benchmarks[benchmark_nr]; ++benchmark_nr) { - char const *benchmark = benchmarks[benchmark_nr]; - - // local copies of experiment/job count (to calculate differences) - int local_count_exp = count_exp, local_count_exp_jobs = count_exp_jobs, - local_count_known = count_known, local_count_known_jobs = count_known_jobs; - - // load trace - igzstream tracef(filename_trace(variant, benchmark).c_str()); - if (tracef.fail()) { - m_log << "couldn't open " << filename_trace(variant, benchmark) << endl; - return false; - } - ProtoIStream ps(&tracef); - - // read trace info - unsigned instr_counter, estimated_timeout, lowest_addr, highest_addr; - // FIXME properly deal with 2nd memory range - EcosKernelTestCampaign::readTraceInfo(instr_counter, - estimated_timeout, lowest_addr, highest_addr, lowest_addr, highest_addr, variant, benchmark); - - // a map of addresses of ECC protected objects - MemoryMap mm; - mm.readFromFile(filename_memorymap(variant, benchmark).c_str()); - - // map for keeping one "open" EC for every address - // (maps injection data address => equivalence class) - AddrLastaccessMap open_ecs; - - // instruction counter within trace - unsigned instr = 0; - // "rightmost" instr where we did a FI experiment - unsigned instr_rightmost = 0; - - // fill open_ecs with one EC for every address - for (MemoryMap::iterator it = mm.begin(); it != mm.end(); ++it) { - open_ecs[*it] = instr; - } - - // absolute address of current trace instruction - address_t instr_absolute = 0; - - Trace_Event ev; - // for every event in the trace ... - while (ps.getNext(&ev) && instr < instr_counter) { - // instruction events just get counted - if (!ev.has_memaddr()) { - // new instruction - instr++; - instr_absolute = ev.ip(); - continue; - } - - // for each single byte in this memory access ... - for (address_t data_address = ev.memaddr(); - data_address < ev.memaddr() + ev.width(); - ++data_address) { - // skip accesses to data outside our map of interesting addresses - AddrLastaccessMap::iterator lastuse_it; - if ((lastuse_it = open_ecs.find(data_address)) == open_ecs.end()) { - continue; - } - int instr1 = lastuse_it->second; - int instr2 = instr; - - // skip zero-sized intervals: these can occur when an instruction - // accesses a memory location more than once (e.g., INC, CMPXCHG) - if (instr1 > instr2) { - continue; - } - - // we now have an interval-terminating R/W event to the memaddr - // we're currently looking at; the EC is defined by - // data_address [instr1, instr2] (instr_absolute) - - if (ev.accesstype() == ev.READ) { - // a sequence ending with READ: we need to do one experiment to - // cover it completely - add_experiment_ec(variant, benchmark, data_address, instr1, instr2, instr_absolute); - instr_rightmost = instr2; - } else if (ev.accesstype() == ev.WRITE) { - // a sequence ending with WRITE: an injection anywhere here - // would have no effect. - add_known_ec(variant, benchmark, data_address, instr1, instr2, instr_absolute); - } else { - m_log << "WAT" << endl; - } - - // next interval must start at next instruction; the aforementioned - // skipping mechanism wouldn't work otherwise - lastuse_it->second = instr2 + 1; - } - } - - // close all open intervals (right end of the fault-space) - for (AddrLastaccessMap::iterator lastuse_it = open_ecs.begin(); - lastuse_it != open_ecs.end(); ++lastuse_it) { - address_t data_address = lastuse_it->first; - int instr1 = lastuse_it->second; + ss << "v.variant = '" << variant << "' OR "; + } + ss << "0) AND ("; // dummy terminator + for (int benchmark_nr = 0; benchmarks[benchmark_nr]; ++benchmark_nr) { + char const *benchmark = benchmarks[benchmark_nr]; + ss << "v.benchmark = '" << benchmark << "' OR "; + } + ss << "0)"; // dummy terminator + std::string sql_variants = ss.str(); + ss.str(""); #if 0 - // Why -1? In most cases it does not make sense to inject before the - // very last instruction, as we won't execute it anymore. This *only* - // makes sense if we also inject into parts of the result vector. This - // is not the case in this experiment, and with -1 we'll get a result - // comparable to the non-pruned campaign. - int instr2 = instr - 1; -#else - // EcosKernelTestCampaign only variant: fault space ends with the last FI experiment - int instr2 = instr_rightmost; + ss << "SELECT STRAIGHT_JOIN p.id AS pilot_id, v.id AS variant_id, v.variant, v.benchmark, p.injection_instr, p.injection_instr_absolute, p.data_address, SUM(r.bit_width) AS existing_results " + << "FROM variant v " + << "JOIN fsppilot p ON p.variant_id = v.id " + << "LEFT JOIN result r ON r.pilot_id = p.id " + << "WHERE p.known_outcome = 0 " + << " AND p.fspmethod_id = " << fspmethod_id << " " + << " AND (" << sql_variants << ") " + << "GROUP BY p.id " + << "HAVING existing_results < 8 OR existing_results IS NULL "; // 8 results per pilot +#elif 0 + std::string sql_select = "SELECT p.id AS pilot_id, v.id AS variant_id, v.variant, v.benchmark, p.injection_instr, p.injection_instr_absolute, p.data_address "; + ss << "FROM variant v " + << "JOIN fsppilot p ON p.variant_id = v.id " + << "LEFT JOIN " << m_result_table << " r ON r.pilot_id = p.id " + << "WHERE p.known_outcome = 0 " + << " AND p.fspmethod_id = " << fspmethod_id << " " + << " AND (" << sql_variants << ") " + << " AND r.pilot_id IS NULL "; +#elif 0 + std::string sql_select = "SELECT p.id AS pilot_id, v.id AS variant_id, v.variant, v.benchmark, p.injection_instr, p.injection_instr_absolute, p.data_address "; + ss << "FROM variant v " + << "JOIN fsppilot p ON p.variant_id = v.id " +// << "WHERE p.known_outcome = 0 " + << " AND p.fspmethod_id = " << fspmethod_id << " " + << " AND (" << sql_variants << ") "; +#elif 1 + if (!db->query("CREATE TEMPORARY TABLE done_pilots (id INT UNSIGNED NOT NULL PRIMARY KEY)")) return false; + ss << "INSERT INTO done_pilots SELECT pilot_id FROM " << m_result_table << " GROUP BY pilot_id HAVING SUM(bit_width) = 8"; + if (!db->query(ss.str().c_str())) return false; + unsigned finished_jobs = db->affected_rows(); + ss.str(""); + ss << "DELETE r FROM " << m_result_table << " r LEFT JOIN done_pilots ON r.pilot_id = done_pilots.id WHERE done_pilots.id IS NULL"; + if (!db->query(ss.str().c_str())) return false; + unsigned deleted_rows = db->affected_rows(); + ss.str(""); + m_log << "Deleted " << deleted_rows << " rows from incomplete jobs" << std::endl; + std::string sql_select = "SELECT STRAIGHT_JOIN p.id AS pilot_id, v.id AS variant_id, v.variant, v.benchmark, p.injection_instr, p.injection_instr_absolute, p.data_address "; + ss << "FROM variant v " + << "JOIN fsppilot p ON p.variant_id = v.id " + << "LEFT JOIN done_pilots d ON d.id = p.id " + << "WHERE d.id IS NULL " + << " AND p.fspmethod_id = " << fspmethod_id << " " + << " AND (" << sql_variants << ") "; #endif - int instr_absolute = 0; // unknown + std::string sql_body = ss.str(); + //std::string sql_order = "ORDER BY v.benchmark, v.variant"; + std::string sql_order = "ORDER BY v.id"; + //std::string sql_order = ""; - // zero-sized? skip. - if (instr1 > instr2) { - continue; - } + /* Get the number of unfinished experiments */ + std::string sql_count = "SELECT COUNT(*) " + sql_body; + m_log << sql_count << std::endl; + MYSQL_RES *count = db->query(sql_count.c_str(), true); + if (!count) { + return false; + } + MYSQL_ROW row = mysql_fetch_row(count); + unsigned unfinished_jobs; + unfinished_jobs = strtoul(row[0], NULL, 10); -#if 0 - // the run continues after the FI window, so do this experiment - // XXX this creates at least one experiment for *every* bit! - // fix: full trace, limited FI window + m_log << "Found " << unfinished_jobs << " unfinished jobs (" << finished_jobs << " already finished)." << std::endl; - ecs_need_experiment.push_back(current_ec); - add_experiment_ec(variant, benchmark, data_address, instr1, instr2, instr_absolute); -#else - // as the experiment ends, this byte is a "don't care": - add_known_ec(variant, benchmark, data_address, instr1, instr2, instr_absolute); -#endif - } - // conserve some memory - open_ecs.clear(); - - // progress report - m_log << variant << "/" << benchmark - << " exp " << (count_exp - local_count_exp) << " (" << (count_exp_jobs - local_count_exp_jobs) << " jobs)" - << " known " << (count_known - local_count_known) << " (" << (count_known_jobs - local_count_known_jobs) << " jobs)" - << " faultspace cutoff @ " << instr_rightmost << " out of " << instr - << endl; - } + std::string sql_pilots = sql_select + sql_body + sql_order; + m_log << sql_pilots << std::endl; + MYSQL_RES *pilots = db->query_stream(sql_pilots.c_str()); + if (!pilots) { + return false; } - available_results.clear(); + m_log << "Filling queue ..." << std::endl; + unsigned prev_variant_id = 0; + while ((row = mysql_fetch_row(pilots))) { + unsigned pilot_id = atoi(row[0]); + unsigned variant_id = atoi(row[1]); + unsigned injection_instr = atoi(row[4]); + unsigned data_address = atoi(row[6]); + + EcosKernelTestExperimentData *d = new EcosKernelTestExperimentData; + d->msg.set_pilot_id(pilot_id); + d->msg.set_variant(row[2]); + d->msg.set_benchmark(row[3]); + d->msg.set_instr2_offset(injection_instr); + if (row[5]) { + unsigned injection_instr_absolute = atoi(row[5]); + d->msg.set_instr2_address(injection_instr_absolute); + } + d->msg.set_mem_addr(data_address); + d->msg.set_faultmodel(ECOS_FAULTMODEL_BURST ? d->msg.BURST : d->msg.SINGLEBITFLIP); + + if (prev_variant_id != variant_id) { + m_log << "Enqueueing jobs for " << row[2] << "/" << row[3] << std::endl; + } + prev_variant_id = variant_id; + + campaignmanager.addParam(d); + } + + if (mysql_errno(db->getHandle())) { + std::cerr << "mysql_fetch_row failed: " << mysql_error(db->getHandle()) << std::endl; + } + + delete db; + + m_log << "finished, waiting for the clients to complete ..." << std::endl; campaignmanager.noMoreParameters(); - m_log << "total" - << " exp " << count_exp << " (" << count_exp_jobs << " jobs)" - << " known " << count_known << " (" << count_known_jobs << " jobs)" - << endl; - // collect results #ifndef __puma collect_thread.join(); #endif - finalize_results(); - m_log << "done." << endl; - + delete db_recv; + m_log << "results complete, terminating." << std::endl; return true; } -bool EcosKernelTestCampaign::add_experiment_ec(const std::string& variant, const std::string& benchmark, - address_t data_address, int instr1, int instr2, address_t instr_absolute) -{ - if (check_available(variant, benchmark, data_address, instr2)) { - return false; - } - count_exp_jobs++; - if (ECOS_FAULTMODEL_BURST) { - count_exp++; - } else { - count_exp += 8; - } - - // enqueue job -#if 1 - EcosKernelTestExperimentData *d = new EcosKernelTestExperimentData; - d->msg.set_variant(variant); - d->msg.set_benchmark(benchmark); - d->msg.set_instr1_offset(instr1); - d->msg.set_instr2_offset(instr2); - d->msg.set_instr2_address(instr_absolute); - d->msg.set_mem_addr(data_address); - d->msg.set_faultmodel(ECOS_FAULTMODEL_BURST ? d->msg.BURST : d->msg.SINGLEBITFLIP); - campaignmanager.addParam(d); -#endif - - return true; -} - -bool EcosKernelTestCampaign::add_known_ec(const std::string& variant, const std::string& benchmark, - address_t data_address, int instr1, int instr2, address_t instr_absolute) -{ - if (check_available(variant, benchmark, data_address, instr2)) { - return false; - } - - count_known_jobs++; - if (ECOS_FAULTMODEL_BURST) { - count_known++; - } else { - count_known += 8; - } - -#if 1 - add_result(variant, benchmark, instr1, instr2, instr_absolute, data_address, - 0, 8, // bitnr, bit_width - 1, // resulttype - 1, // ecos_test_result - 99, // latest_ip - 0, // error_corrected - "", // details - 0 // runtime - ); -#endif - return true; -} - -bool EcosKernelTestCampaign::init_results() -{ - // read already existing results - bool file_exists = false; - ifstream oldresults(filename_results().c_str(), ios::in); - if (oldresults.is_open()) { - file_exists = true; - char buf[16*1024]; - std::string variant, benchmark; - unsigned ignore; - int instr2; - address_t data_address; - int bit_width; - int rowcount = 0; - int expcount = 0; - m_log << "scanning existing results ..." << endl; - while (oldresults.getline(buf, sizeof(buf)).good()) { - stringstream ss; - ss << buf; - ss >> hex >> variant >> benchmark >> ignore >> instr2 >> ignore - >> data_address >> ignore >> bit_width; - if (ss.fail()) { - continue; - } - ++rowcount; - expcount += bit_width; - // TODO: sanity check (duplicates?) - available_results - [AvailableResultMap::key_type(variant, benchmark)] - [data_address].insert(instr2); - } - m_log << "found " << dec << expcount << " existing experiment results (" - << rowcount << " CSV rows)" << endl; - oldresults.close(); - } - - // non-destructive: due to the CSV header we can always manually recover - // from an accident (append mode) - resultstream.open(filename_results().c_str(), ios::out | ios::app); - if (!resultstream.is_open()) { - m_log << "failed to open " << filename_results() << endl; - return false; - } - // only write CSV header if file didn't exist before - if (!file_exists) { - resultstream << "variant\tbenchmark\tec_instr1\tec_instr2\t" - "ec_instr2_absolute\tec_data_address\tbitnr\tbit_width\t" - "resulttype\tecos_test_result\tlatest_ip\t" - "error_corrected\tdetails\truntime" << endl; - } - return true; -} - -bool EcosKernelTestCampaign::check_available(const std::string& variant, const std::string& benchmark, - address_t data_address, int instr2) -{ - AvailableResultMap::const_iterator it_variant = - available_results.find(AvailableResultMap::key_type(variant, benchmark)); - if (it_variant == available_results.end()) { - return false; - } - AvailableResultMap::mapped_type::const_iterator it_address = - it_variant->second.find(data_address); - if (it_address == it_variant->second.end()) { - return false; - } - AvailableResultMap::mapped_type::mapped_type::const_iterator it_instr = - it_address->second.find(instr2); - if (it_instr == it_address->second.end()) { - return false; - } - return true; -} - -void EcosKernelTestCampaign::add_result(const std::string& variant, const std::string& benchmark, - int instr1, int instr2, address_t instr2_absolute, address_t ec_data_address, +void EcosKernelTestCampaign::add_result(unsigned pilot_id, + int instr2, address_t instr2_absolute, address_t ec_data_address, int bitnr, int bit_width, int resulttype, int ecos_test_result, address_t latest_ip, int error_corrected, const std::string& details, float runtime) { -#ifndef __puma - boost::lock_guard guard(m_result_mutex); -#endif - resultstream << hex - << variant << "\t" - << benchmark << "\t" - << instr1 << "\t" - << instr2 << "\t" - << instr2_absolute << "\t" - << ec_data_address << "\t" - << bitnr << "\t" - << bit_width << "\t" - << resulttype << "\t" - << ecos_test_result << "\t" - << latest_ip << "\t" - << error_corrected << "\t" - << details << "\t" - << runtime << "\n"; - //resultstream.flush(); // for debugging purposes -} - -void EcosKernelTestCampaign::finalize_results() -{ - resultstream.close(); + std::stringstream ss; + ss << "INSERT DELAYED INTO " << m_result_table << " " + << "(pilot_id, bitnr, bit_width, resulttype, ecos_test_result, latest_ip, error_corrected, details, runtime) VALUES " + << "(" << pilot_id << "," << bitnr << "," << bit_width << "," << resulttype << "," << ecos_test_result << "," + << latest_ip << "," << error_corrected << ",'" << details << "'," << runtime << ")"; + // Database::query is protected by a mutex + db_recv->query(ss.str().c_str()); } void EcosKernelTestCampaign::collect_results() @@ -526,7 +385,7 @@ void EcosKernelTestCampaign::collect_results() bit_width++; continue; } - add_result(res->msg.variant(), res->msg.benchmark(), res->msg.instr1_offset(), + add_result(res->msg.pilot_id(), res->msg.instr2_offset(), res->msg.instr2_address(), res->msg.mem_addr(), first_bit, bit_width, prev_singleres->resulttype(), prev_singleres->ecos_test_result(), prev_singleres->latest_ip(), prev_singleres->error_corrected(), prev_singleres->details(), @@ -541,7 +400,7 @@ void EcosKernelTestCampaign::collect_results() bit_width = 8; prev_singleres = &res->msg.result(0); #endif - add_result(res->msg.variant(), res->msg.benchmark(), res->msg.instr1_offset(), + add_result(res->msg.pilot_id(), res->msg.instr2_offset(), res->msg.instr2_address(), res->msg.mem_addr(), first_bit, bit_width, prev_singleres->resulttype(), prev_singleres->ecos_test_result(), prev_singleres->latest_ip(), prev_singleres->error_corrected(), prev_singleres->details(), diff --git a/src/experiments/ecos_kernel_test/campaign.hpp b/src/experiments/ecos_kernel_test/campaign.hpp index 2828955e..8508a90b 100644 --- a/src/experiments/ecos_kernel_test/campaign.hpp +++ b/src/experiments/ecos_kernel_test/campaign.hpp @@ -2,11 +2,13 @@ #include #include +#include #ifndef __puma #include #endif +#include "util/Database.hpp" #include "cpn/Campaign.hpp" #include "comm/ExperimentData.hpp" #include "ecos_kernel_test.pb.h" @@ -20,33 +22,21 @@ public: }; class EcosKernelTestCampaign : public fail::Campaign { + fail::Database *db; + fail::Database *db_recv; + int fspmethod_id; + static const std::string dir_images; static const std::string dir_prerequisites; - static const std::string dir_results; + std::string m_result_table; fail::Logger m_log; - int count_exp, count_exp_jobs; - int count_known, count_known_jobs; - bool add_experiment_ec(const std::string& variant, const std::string& benchmark, - fail::address_t data_address, int instr1, int instr2, fail::address_t instr_absolute); - bool add_known_ec(const std::string& variant, const std::string& benchmark, - fail::address_t data_address, int instr1, int instr2, fail::address_t instr_absolute); - bool init_results(); - void add_result(const std::string& variant, const std::string& benchmark, - int instr1, int instr2, fail::address_t instr2_absolute, fail::address_t ec_data_address, + void add_result(unsigned pilot_id, + int instr2, fail::address_t instr2_absolute, fail::address_t ec_data_address, int bitnr, int bit_width, int resulttype, int ecos_test_result, fail::address_t latest_ip, int error_corrected, const std::string& details, float runtime); - void finalize_results(); void collect_results(); - bool check_available(const std::string& variant, const std::string& benchmark, fail::address_t data_address, int instr2); - std::ofstream resultstream; - typedef std::map, std::map > > AvailableResultMap; - AvailableResultMap available_results; -#ifndef __puma - boost::mutex m_result_mutex; -#endif public: - EcosKernelTestCampaign() : m_log("EcosKernelTest Campaign"), - count_exp(0), count_exp_jobs(0), count_known(0), count_known_jobs(0) {} + EcosKernelTestCampaign() : m_log("EcosKernelTest Campaign") {} virtual bool run(); static bool readMemoryMap(fail::MemoryMap &mm, char const * const filename); static bool writeTraceInfo(unsigned instr_counter, unsigned timeout, unsigned mem1_low, unsigned mem1_high, unsigned mem2_low, unsigned mem2_high, const std::string& variant = "", const std::string& benchmark = ""); @@ -55,6 +45,5 @@ public: static std::string filename_state(unsigned instr_offset, 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 60947814..0b433dad 100644 --- a/src/experiments/ecos_kernel_test/ecos_kernel_test.proto +++ b/src/experiments/ecos_kernel_test/ecos_kernel_test.proto @@ -7,8 +7,8 @@ message EcosKernelTestProtoMsg { // benchmark required string benchmark = 2; - // equivalence class start (for storage) - required int32 instr1_offset = 3; + // pilot ID (database) + required int32 pilot_id = 3; // FI at #instructions from experiment start required int32 instr2_offset = 4; // the exact IP value at this point in time (from golden run) diff --git a/src/experiments/ecos_kernel_test/main.cc b/src/experiments/ecos_kernel_test/main.cc index 85103323..d4c48897 100644 --- a/src/experiments/ecos_kernel_test/main.cc +++ b/src/experiments/ecos_kernel_test/main.cc @@ -3,9 +3,14 @@ #include "cpn/CampaignManager.hpp" #include "campaign.hpp" +#include "util/CommandLine.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]); + EcosKernelTestCampaign c; if (fail::campaignmanager.runCampaign(&c)) { return 0; From c0b36f623675493759e20ea1771db1a4416e43ec Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Wed, 24 Apr 2013 17:25:50 +0200 Subject: [PATCH 07/17] ecos: use new timer iface to record benchmark runtime ... instead of the previous TimerListener workaround. Change-Id: I3e712540e93b668301f50ecf4f5a5760e0a8fdb3 --- .../ecos_kernel_test/experiment.cc | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/src/experiments/ecos_kernel_test/experiment.cc b/src/experiments/ecos_kernel_test/experiment.cc index ec7a62a1..e3960b4a 100644 --- a/src/experiments/ecos_kernel_test/experiment.cc +++ b/src/experiments/ecos_kernel_test/experiment.cc @@ -35,8 +35,6 @@ #define MULTIPLE_SNAPSHOTS 0 #define MULTIPLE_SNAPSHOTS_DISTANCE 1000000 -#define TIMER_GRANULARITY 10 // microseconds - #define VIDEOMEM_START 0xb8000 #define VIDEOMEM_SIZE (80*25*2 *2) // two text mode screens #define VIDEOMEM_END (VIDEOMEM_START + VIDEOMEM_SIZE) @@ -199,13 +197,8 @@ bool EcosKernelTestExperiment::performTrace(guest_address_t addr_entry, guest_ad simulator.addListener(&ev_count); unsigned instr_counter = 0; - // on the way, count elapsed time - TimerListener time_step(TIMER_GRANULARITY); //TODO: granularity? - //elapsed_time.setCounter(0xFFFFFFFFU); // not working for TimerListener - simulator.addListener(&time_step); - unsigned elapsed_time = 1; // always run 1 step - // just increase elapsed_time counter by 1, which serves as time for ECC recovery algorithm - ++elapsed_time; // (this is a rough guess ... TODO) + // measure elapsed time + simtime_t time_start = simulator.getTimerTicks(); // on the way, record lowest and highest memory address accessed MemAccessListener ev_mem(ANY_ADDR, MemAccessEvent::MEM_READWRITE); @@ -227,13 +220,6 @@ bool EcosKernelTestExperiment::performTrace(guest_address_t addr_entry, guest_ad } simulator.addListener(&ev_count); } - else if(ev == &time_step) { - if(elapsed_time++ == 0xFFFFFFFFU) { - log << "ERROR: elapsed_time overflowed" << endl; - return false; - } - simulator.addListener(&time_step); - } else if(ev == &ev_mem) { unsigned lo = ev_mem.getTriggerAddress(); unsigned hi = lo + ev_mem.getTriggerWidth() - 1; @@ -252,16 +238,14 @@ bool EcosKernelTestExperiment::performTrace(guest_address_t addr_entry, guest_ad ev = simulator.resume(); } - unsigned long long estimated_timeout_overflow_check = ((unsigned long long)elapsed_time) * time_step.getTimeout(); - if(estimated_timeout_overflow_check > 0xFFFFFFFFU) { - log << "Timeout estimation overflowed" << endl; - return false; - } - unsigned estimated_timeout = (unsigned)estimated_timeout_overflow_check; + unsigned long long estimated_timeout_overflow_check = + simulator.getTimerTicks() - time_start + 10000; + unsigned estimated_timeout = + (unsigned) (estimated_timeout_overflow_check * 1000000 / simulator.getTimerTicksPerSecond()); log << dec << "tracing finished after " << instr_counter << " instructions" << endl; log << hex << "all memory accesses within [0x" << mem1_low << ", 0x" << mem1_high << "] u [0x" << mem2_low << ", 0x" << mem2_high << "] (ignoring VGA mem)" << endl; - log << dec << "elapsed simulated time (plus safety margin): " << (estimated_timeout * TIMER_GRANULARITY / 1000000.0) << "s" << endl; + log << dec << "elapsed simulated time (plus safety margin): " << (estimated_timeout / 1000000.0) << "s" << endl; // sanitize memory ranges if (mem1_low > mem1_high) { From 403886e54134d59ebfb0e3c95d8c85f9cc398a31 Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Wed, 24 Apr 2013 17:29:44 +0200 Subject: [PATCH 08/17] ecos: minor changes, cleanup - Count experiments, not jobs - Debug output Change-Id: Ide5e1219cdcc8112d1a0d4e7367beca2dd5821ef --- .../ecos_kernel_test/experiment.cc | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/experiments/ecos_kernel_test/experiment.cc b/src/experiments/ecos_kernel_test/experiment.cc index e3960b4a..35d4b670 100644 --- a/src/experiments/ecos_kernel_test/experiment.cc +++ b/src/experiments/ecos_kernel_test/experiment.cc @@ -27,7 +27,7 @@ #define LOCAL 0 #ifndef PREREQUISITES - #define PREREQUISITES 0 // 1: do step 0-2 ; 0: do step 3 + #error Configure experimentInfo.hpp properly! #endif // create/use multiple snapshots to speed up long experiments @@ -285,7 +285,8 @@ bool EcosKernelTestExperiment::faultInjection() { BPSingleListener bp; #if !LOCAL - for (int i = 0; i < 50 || (m_jc.getNumberOfUndoneJobs() != 0) ; ++i) { // only do 50 sequential experiments, to prevent swapping + for (int experiments = 0; + experiments < 500 || (m_jc.getNumberOfUndoneJobs() != 0); ) { // stop after ~500 experiments to prevent swapping // 50 exp ~ 0.5GB RAM usage per instance (linearly increasing) #endif @@ -340,6 +341,8 @@ bool EcosKernelTestExperiment::faultInjection() { // for each job with the SINGLEBITFLIP fault model we're actually doing *8* // experiments (one for each bit) for (int bit_offset = 0; bit_offset < 8; ++bit_offset) { + ++experiments; + // 8 results in one job EcosKernelTestProtoMsg_Result *result = param.msg.add_result(); result->set_bit_offset(bit_offset); @@ -409,6 +412,9 @@ bool EcosKernelTestExperiment::faultInjection() { continue; } + if (param.msg.has_instr2_address()) { + log << "Absolute IP sanity check OK" << endl; + } // --- aftermath --- // possible outcomes: @@ -664,7 +670,7 @@ bool EcosKernelTestExperiment::run() parseOptions(); #endif - #if PREREQUISITES +#if PREREQUISITES log << "retrieving ELF symbol addresses ..." << endl; guest_address_t entry, finish, test_output, errors_corrected, panic, text_start, text_end; @@ -681,19 +687,19 @@ bool EcosKernelTestExperiment::run() } else { return false; } // step 1 - if(establishState(entry, finish, errors_corrected)) { + if (establishState(entry, finish, errors_corrected)) { log << "STEP 1 finished: proceeding ..." << endl; } else { return false; } // step 2 - if(performTrace(entry, finish)) { + if (performTrace(entry, finish)) { log << "STEP 2 finished: terminating ..." << endl; } else { return false; } - #else // !PREREQUISITES +#else // !PREREQUISITES // step 3 faultInjection(); - #endif // PREREQUISITES +#endif // PREREQUISITES // Explicitly terminate, or the simulator will continue to run. simulator.terminate(); From 091e8dcae00c43de3b585920db315049396224d3 Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Wed, 24 Apr 2013 17:35:45 +0200 Subject: [PATCH 09/17] ecos: baseline assessment integrated into main experiment Change-Id: Iaf2a31c917b6ddd50568e5fb784ab8457193ee7d --- src/experiments/ecos_kernel_test/campaign.cc | 7 ++++- .../ecos_kernel_test/experiment.cc | 30 ++++++++++++++----- .../ecos_kernel_test/experiment.hpp | 6 ++-- .../ecos_kernel_test/experimentInfo.hpp | 1 + 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/experiments/ecos_kernel_test/campaign.cc b/src/experiments/ecos_kernel_test/campaign.cc index 1f7fe974..1a4387ef 100644 --- a/src/experiments/ecos_kernel_test/campaign.cc +++ b/src/experiments/ecos_kernel_test/campaign.cc @@ -17,8 +17,13 @@ using namespace std; using namespace fail; -const std::string EcosKernelTestCampaign::dir_images("images"); +#if BASELINE_ASSESSMENT +const std::string EcosKernelTestCampaign::dir_prerequisites("prerequisites-baseline"); +const std::string EcosKernelTestCampaign::dir_images("images-baseline"); +#else const std::string EcosKernelTestCampaign::dir_prerequisites("prerequisites"); +const std::string EcosKernelTestCampaign::dir_images("images"); +#endif const std::string EcosKernelTestCampaign::dir_results("results"); bool EcosKernelTestCampaign::writeTraceInfo(unsigned instr_counter, unsigned timeout, diff --git a/src/experiments/ecos_kernel_test/experiment.cc b/src/experiments/ecos_kernel_test/experiment.cc index 35d4b670..d09bc7ef 100644 --- a/src/experiments/ecos_kernel_test/experiment.cc +++ b/src/experiments/ecos_kernel_test/experiment.cc @@ -59,7 +59,13 @@ using namespace fail; #endif #if PREREQUISITES -bool EcosKernelTestExperiment::retrieveGuestAddresses(guest_address_t addr_finish) { +bool EcosKernelTestExperiment::retrieveGuestAddresses(guest_address_t addr_finish, guest_address_t addr_data_start, guest_address_t addr_data_end) { +#if BASELINE_ASSESSMENT + log << "STEP 0: creating memory map spanning all of DATA and BSS" << endl; + MemoryMap mm; + mm.add(addr_data_start, addr_data_end - addr_data_start); + mm.writeToFile(EcosKernelTestCampaign::filename_memorymap(m_variant, m_benchmark).c_str()); +#else log << "STEP 0: record memory map with addresses of 'interesting' objects" << endl; // run until func_finish is reached @@ -111,6 +117,7 @@ bool EcosKernelTestExperiment::retrieveGuestAddresses(guest_address_t addr_finis // close serialized mm mm.close(); +#endif return true; } @@ -280,7 +287,8 @@ bool EcosKernelTestExperiment::faultInjection() { unsigned instr_counter, estimated_timeout, mem1_low, mem1_high, mem2_low, mem2_high; // ELF symbol addresses guest_address_t addr_entry, addr_finish, addr_test_output, addr_errors_corrected, - addr_panic, addr_text_start, addr_text_end; + addr_panic, addr_text_start, addr_text_end, + addr_data_start, addr_data_end; BPSingleListener bp; @@ -320,7 +328,8 @@ bool EcosKernelTestExperiment::faultInjection() { EcosKernelTestCampaign::readTraceInfo(instr_counter, estimated_timeout, mem1_low, mem1_high, mem2_low, mem2_high, m_variant, m_benchmark); readELFSymbols(addr_entry, addr_finish, addr_test_output, - addr_errors_corrected, addr_panic, addr_text_start, addr_text_end); + addr_errors_corrected, addr_panic, addr_text_start, addr_text_end, + addr_data_start, addr_data_end); int state_instr_offset = instr_offset - (instr_offset % MULTIPLE_SNAPSHOTS_DISTANCE); string statename; @@ -615,7 +624,9 @@ bool EcosKernelTestExperiment::readELFSymbols( fail::guest_address_t& errors_corrected, fail::guest_address_t& panic, fail::guest_address_t& text_start, - fail::guest_address_t& text_end) + fail::guest_address_t& text_end, + fail::guest_address_t& data_start, + fail::guest_address_t& data_end) { ElfReader elfreader(EcosKernelTestCampaign::filename_elf(m_variant, m_benchmark).c_str()); entry = elfreader.getSymbol("cyg_start").getAddress(); @@ -625,10 +636,13 @@ bool EcosKernelTestExperiment::readELFSymbols( panic = elfreader.getSymbol("_Z9ecc_panicv").getAddress(); text_start = elfreader.getSymbol("_stext").getAddress(); text_end = elfreader.getSymbol("_etext").getAddress(); + data_start = elfreader.getSymbol("__ram_data_start").getAddress(); + data_end = elfreader.getSymbol("__bss_end").getAddress(); // 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) { + text_start == ADDR_INV || text_end == ADDR_INV || + data_start == ADDR_INV || data_end == ADDR_INV) { return false; } return true; @@ -673,15 +687,15 @@ bool EcosKernelTestExperiment::run() #if PREREQUISITES log << "retrieving ELF symbol addresses ..." << endl; guest_address_t entry, finish, test_output, errors_corrected, - panic, text_start, text_end; + panic, text_start, text_end, data_start, data_end; if (!readELFSymbols(entry, finish, test_output, errors_corrected, - panic, text_start, text_end)) { + panic, text_start, text_end, data_start, data_end)) { log << "failed, essential symbols are missing!" << endl; simulator.terminate(1); } // step 0 - if(retrieveGuestAddresses(finish)) { + if (retrieveGuestAddresses(finish, data_start, data_end)) { log << "STEP 0 finished: rebooting ..." << endl; simulator.reboot(); } else { return false; } diff --git a/src/experiments/ecos_kernel_test/experiment.hpp b/src/experiments/ecos_kernel_test/experiment.hpp index eadfbb5c..9f7a880b 100644 --- a/src/experiments/ecos_kernel_test/experiment.hpp +++ b/src/experiments/ecos_kernel_test/experiment.hpp @@ -16,7 +16,7 @@ public: bool run(); void parseOptions(); - bool retrieveGuestAddresses(fail::guest_address_t addr_finish); // step 0 + bool retrieveGuestAddresses(fail::guest_address_t addr_finish, fail::guest_address_t addr_data_start, fail::guest_address_t addr_data_end); // step 0 bool establishState(fail::guest_address_t addr_entry, fail::guest_address_t addr_finish, 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 @@ -28,5 +28,7 @@ public: fail::guest_address_t& errors_corrected, fail::guest_address_t& panic, fail::guest_address_t& text_start, - fail::guest_address_t& text_end); + fail::guest_address_t& text_end, + fail::guest_address_t& data_start, + fail::guest_address_t& data_end); }; diff --git a/src/experiments/ecos_kernel_test/experimentInfo.hpp b/src/experiments/ecos_kernel_test/experimentInfo.hpp index ac74b560..80da8298 100644 --- a/src/experiments/ecos_kernel_test/experimentInfo.hpp +++ b/src/experiments/ecos_kernel_test/experimentInfo.hpp @@ -1,4 +1,5 @@ #pragma once +#define BASELINE_ASSESSMENT 1 #define PREREQUISITES 0 #define ECOS_FAULTMODEL_BURST 0 From 880e7a81ff503d2b20852ef62b968250b8debc47 Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Thu, 25 Apr 2013 16:21:59 +0200 Subject: [PATCH 10/17] comm: ignore SIGPIPE This prevents client and server from being sent a SIGPIPE (and terminating) when the other side unexpectedly closes the connection. It's way easier to handle this condition when checking the write() return value, than to do anything smart in a SIGPIPE handler. More details: Change-Id: I1da5bf5ef79c8b7b00ede976e96ed4f1c560049d --- src/core/comm/SocketComm.cc | 8 ++++++++ src/core/comm/SocketComm.hpp | 4 ++++ src/core/cpn/JobServer.hpp | 2 ++ src/core/efw/JobClient.cc | 2 ++ 4 files changed, 16 insertions(+) diff --git a/src/core/comm/SocketComm.cc b/src/core/comm/SocketComm.cc index 0ae632e9..3cd7593c 100644 --- a/src/core/comm/SocketComm.cc +++ b/src/core/comm/SocketComm.cc @@ -1,10 +1,18 @@ #include #include +#include #include "SocketComm.hpp" namespace fail { +void SocketComm::init() +{ + // It's usually much easier to handle the error on write(), than to do + // anything intelligent in a SIGPIPE handler. + signal(SIGPIPE, SIG_IGN); +} + bool SocketComm::sendMsg(int sockfd, google::protobuf::Message& msg) { #ifdef USE_SIZE_PREFIX diff --git a/src/core/comm/SocketComm.hpp b/src/core/comm/SocketComm.hpp index 99459281..1d6ef1a8 100644 --- a/src/core/comm/SocketComm.hpp +++ b/src/core/comm/SocketComm.hpp @@ -21,6 +21,10 @@ namespace fail { class SocketComm { public: + /** + * This allows us to ignore SIGPIPE. + */ + static void init(); /** * Send Protobuf-generated message * @param sockfd open socket descriptor to write to diff --git a/src/core/cpn/JobServer.hpp b/src/core/cpn/JobServer.hpp index 5ab6d5ba..7c1bf521 100644 --- a/src/core/cpn/JobServer.hpp +++ b/src/core/cpn/JobServer.hpp @@ -7,6 +7,7 @@ #include "util/SynchronizedMap.hpp" #include "config/FailConfig.hpp" #include "comm/FailControlMessage.pb.h" +#include "comm/SocketComm.hpp" #include #include @@ -81,6 +82,7 @@ public: JobServer(int port = SERVER_COMM_TCP_PORT) : m_port(port), m_finish(false), m_noMoreExps(false), m_maxThreads(128), m_threadtimeout(0), m_undoneJobs(SERVER_OUT_QUEUE_SIZE) { + SocketComm::init(); m_runid = std::time(0); #ifndef __puma m_serverThread = new boost::thread(&JobServer::run, this); // run operator()() in a thread. diff --git a/src/core/efw/JobClient.cc b/src/core/efw/JobClient.cc index a102a10f..638cfe0a 100644 --- a/src/core/efw/JobClient.cc +++ b/src/core/efw/JobClient.cc @@ -1,4 +1,5 @@ #include "JobClient.hpp" +#include "comm/SocketComm.hpp" using namespace std; @@ -6,6 +7,7 @@ namespace fail { JobClient::JobClient(const std::string& server, int port) { + SocketComm::init(); m_server_port = port; m_server = server; m_server_ent = gethostbyname(m_server.c_str()); From 20b70df651663a748c1a53a0988411c2ddd8b24e Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Thu, 25 Apr 2013 16:35:13 +0200 Subject: [PATCH 11/17] efw/JobClient: knock less often when there are no jobs yet Change-Id: If769b402a7b00ed3aebedd5f4d0954831a0ee905 --- src/core/efw/JobClient.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/efw/JobClient.cc b/src/core/efw/JobClient.cc index 638cfe0a..3d36accb 100644 --- a/src/core/efw/JobClient.cc +++ b/src/core/efw/JobClient.cc @@ -85,7 +85,7 @@ bool JobClient::getParam(ExperimentData& exp) return true; // Nothing to do right now, but maybe later case FailControlMessage::COME_AGAIN: - sleep(1); + sleep(10); continue; default: return false; From bc95c8dda5fab0e43c4724dc3dd79bf96c7093c0 Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Fri, 26 Apr 2013 17:05:24 +0200 Subject: [PATCH 12/17] .mailmap for consistent git shortlog and blame Change-Id: Ib86719b71ee18f3858e076a7be51274a4362c0e4 --- .mailmap | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .mailmap diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000..bdf2e7f6 --- /dev/null +++ b/.mailmap @@ -0,0 +1,7 @@ +Adrian Böckenkamp adrian +Christoph Borchert chb +Horst Schirmeier hsc +Martin Hoffmann hoffmann +Martin Unzner unzner +Richard Hellwig hellwig +Tobias Friemel friemel From 578e7defd0766d595e9610fafcead458d77f2149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20B=C3=B6ckenkamp?= Date: Wed, 24 Apr 2013 13:19:40 +0200 Subject: [PATCH 13/17] gem5: compiles again Change-Id: Ia95f64953af86003c4be4cbeb01a927d6638f1be --- src/core/util/MemoryMap.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/util/MemoryMap.cc b/src/core/util/MemoryMap.cc index 90db5c26..1855bd3d 100644 --- a/src/core/util/MemoryMap.cc +++ b/src/core/util/MemoryMap.cc @@ -1,6 +1,8 @@ #include #include #include +#include + #include "MemoryMap.hpp" namespace fail { From 619f62b09f29796227992c8f9eefc5759098192b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20B=C3=B6ckenkamp?= Date: Wed, 24 Apr 2013 14:14:15 +0200 Subject: [PATCH 14/17] gem5: added getMnemonic() (requires breakpoints) Change-Id: I5a2862a0ad3c3d506189a6196682e227205ebe09 --- src/core/sal/gem5/Gem5Controller.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/core/sal/gem5/Gem5Controller.hpp b/src/core/sal/gem5/Gem5Controller.hpp index c4c664f0..70bdf38a 100644 --- a/src/core/sal/gem5/Gem5Controller.hpp +++ b/src/core/sal/gem5/Gem5Controller.hpp @@ -1,6 +1,9 @@ #ifndef __GEM5_CONTROLLER_HPP__ #define __GEM5_CONTROLLER_HPP__ +#include + +#include "config/FailConfig.hpp" #include "../SimulatorController.hpp" #include "Gem5Memory.hpp" @@ -13,10 +16,16 @@ namespace fail { * \class Gem5Controller * * Gem5-specific implementation of a SimulatorController. + * + * \todo setRegisterContent() does not work with the program counter (RI_IP). */ class Gem5Controller : public SimulatorController { private: System* m_System; //!< the gem5 system object +#if defined(CONFIG_EVENT_BREAKPOINTS) ||\ + defined(CONFIG_EVENT_BREAKPOINTS_RANGE) + std::string m_Mnemonic; //!< mnemonic of the instr. (only with BPs) +#endif public: void startup(); ~Gem5Controller(); @@ -24,6 +33,11 @@ public: bool save(const std::string &path); void restore(const std::string &path); void reboot(); +#if defined(CONFIG_EVENT_BREAKPOINTS) ||\ + defined(CONFIG_EVENT_BREAKPOINTS_RANGE) + void setMnemonic(const std::string& mn) { m_Mnemonic = mn; } + const std::string& getMnemonic() const { return m_Mnemonic; } +#endif }; } // end-of-namespace: fail From 924b40615dc5dc3714a72c706d196b0b1bfb41ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20B=C3=B6ckenkamp?= Date: Wed, 24 Apr 2013 14:16:25 +0200 Subject: [PATCH 15/17] gem5: revisited register implementation The previous implementation wasn't in a working state because the register content retrieval was buggy. (For example, RT_FP does *not* denote a "floating point" register. Instead, it is the frame pointer!) Change-Id: I31fd80d374c945adaf35b47958d6437a8e2d48c3 --- src/core/sal/arm/ArmArchitecture.cc | 16 +++++++++------- src/core/sal/arm/ArmArchitecture.hpp | 4 +++- src/core/sal/gem5/Gem5Wrapper.cc | 18 +++++++----------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/core/sal/arm/ArmArchitecture.cc b/src/core/sal/arm/ArmArchitecture.cc index cf2475df..4121ef8a 100644 --- a/src/core/sal/arm/ArmArchitecture.cc +++ b/src/core/sal/arm/ArmArchitecture.cc @@ -9,15 +9,17 @@ ArmArchitecture::ArmArchitecture() // TODO: Add missing registers // 16x 32-Bit GP Registers for (int i = 0; i < 16; i++) { - Register *reg = new Register(i, RT_GP, 32); - // Build and set the register name: - std::stringstream sstr; - sstr << "R" << i+1; - reg->setName(sstr.str().c_str()); - m_addRegister(reg); + if (i != RI_IP) { // IP will be added separately (see below) + Register *reg = new Register(i, RT_GP, 32); + // Build and set the register name: + std::stringstream sstr; + sstr << "R" << i+1; + reg->setName(sstr.str().c_str()); + m_addRegister(reg); + } } - // Instruction Pointer + // Instruction Pointer: Register *reg = new Register(RI_IP, RT_IP, 32); reg->setName("IP"); m_addRegister(reg); diff --git a/src/core/sal/arm/ArmArchitecture.hpp b/src/core/sal/arm/ArmArchitecture.hpp index 45c07a30..5ea821fe 100644 --- a/src/core/sal/arm/ArmArchitecture.hpp +++ b/src/core/sal/arm/ArmArchitecture.hpp @@ -67,7 +67,9 @@ enum GPRegIndex { RI_R14_FIQ }; -// TODO: Enum for misc registers +// TODO: Enum for misc registers, see (e.g.) +// simulators/gem5/src/arch/arm/miscregs.hh and +// simulators/gem5/src/arch/arm/intregs.hh } // end-of-namespace: fail diff --git a/src/core/sal/gem5/Gem5Wrapper.cc b/src/core/sal/gem5/Gem5Wrapper.cc index 65a8aaaf..149c4822 100644 --- a/src/core/sal/gem5/Gem5Wrapper.cc +++ b/src/core/sal/gem5/Gem5Wrapper.cc @@ -11,12 +11,8 @@ namespace fail { regdata_t GetRegisterContent(System* sys, unsigned int id, RegisterType type, size_t idx) { switch (type) { - case RT_GP: - if (idx == 15) { - return sys->getThreadContext(id)->pcState().pc(); - } - return sys->getThreadContext(id)->readIntReg(idx); - case RT_FP: return sys->getThreadContext(id)->readFloatReg(idx); // FIXME: correct?! (FP <-> Float?!) + case RT_GP: // pass on... + case RT_FP: return sys->getThreadContext(id)->readIntReg(idx); case RT_ST: return sys->getThreadContext(id)->readMiscReg(idx); case RT_IP: return sys->getThreadContext(id)->pcState().pc(); } @@ -29,13 +25,13 @@ void SetRegisterContent(System* sys, unsigned int id, RegisterType type, size_t regdata_t value) { switch (type) { - case RT_GP: sys->getThreadContext(id)->setIntReg(idx, value); break; - case RT_FP: sys->getThreadContext(id)->setFloatReg(idx, value); break; // FIXME: correct?! (FP <-> Float?!) - case RT_ST: sys->getThreadContext(id)->setMiscReg(idx, value); break; - case RT_IP: sys->getThreadContext(id)->pcState().pc(static_cast(value)); break; + case RT_GP: // pass on... + case RT_FP: sys->getThreadContext(id)->setIntReg(idx, value); return; + case RT_ST: sys->getThreadContext(id)->setMiscReg(idx, value); return; + case RT_IP: sys->getThreadContext(id)->pcState().pc(static_cast(value)); return; } // This shouldn't be reached if a valid register is passed - assert(false && "FATAL ERROR: invalid register type (should never be reached)!"); + assert(false && "FATAL ERROR: Invalid register type (should never be reached)!"); } void ReadMemory(System* sys, guest_address_t addr, size_t cnt, void *dest) From 72c9ba6363a7a4402802f15fe0880b7c4433ad6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20B=C3=B6ckenkamp?= Date: Wed, 24 Apr 2013 14:26:11 +0200 Subject: [PATCH 16/17] Added abo-simple-arm experiment code It is a simple and short experiment that performs single stepping through the target. It is designed to be used with gem5 (+ ARM). Change-Id: Id48b2b087a3650bd0298454ff168c0dbdaaae0c8 --- src/experiments/abo-simple-arm/CMakeLists.txt | 17 ++++++++ src/experiments/abo-simple-arm/experiment.cc | 40 +++++++++++++++++++ src/experiments/abo-simple-arm/experiment.hpp | 13 ++++++ 3 files changed, 70 insertions(+) create mode 100644 src/experiments/abo-simple-arm/CMakeLists.txt create mode 100644 src/experiments/abo-simple-arm/experiment.cc create mode 100644 src/experiments/abo-simple-arm/experiment.hpp diff --git a/src/experiments/abo-simple-arm/CMakeLists.txt b/src/experiments/abo-simple-arm/CMakeLists.txt new file mode 100644 index 00000000..71fa28a4 --- /dev/null +++ b/src/experiments/abo-simple-arm/CMakeLists.txt @@ -0,0 +1,17 @@ +set(EXPERIMENT_NAME abo-simple-arm) +set(EXPERIMENT_TYPE ABOSimpleARMExperiment) +configure_file(../instantiate-experiment.ah.in + ${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY +) + +#experiment sources +set(MY_EXPERIMENT_SRCS + experiment.hpp + experiment.cc +) + +#### include directories #### +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +## build library +add_library(fail-${EXPERIMENT_NAME} ${MY_EXPERIMENT_SRCS}) diff --git a/src/experiments/abo-simple-arm/experiment.cc b/src/experiments/abo-simple-arm/experiment.cc new file mode 100644 index 00000000..593df46c --- /dev/null +++ b/src/experiments/abo-simple-arm/experiment.cc @@ -0,0 +1,40 @@ +#include "util/Logger.hpp" +#include "experiment.hpp" +#include "sal/SALConfig.hpp" +#include "sal/SALInst.hpp" +#include "sal/Listener.hpp" +#include "config/FailConfig.hpp" + +using namespace std; +using namespace fail; + +// Check if configuration dependencies are satisfied: +#if !defined(CONFIG_EVENT_BREAKPOINTS) && !defined(CONFIG_EVENT_BREAKPOINTS_RANGE) + #error This experiment needs: breakpoints. Enable them in the configuration. +#endif + +bool ABOSimpleARMExperiment::run() +{ + Logger log("abo-simple", false); + log << "Startup!" << endl; + + BPSingleListener* ret; + BPSingleListener bp(0x800334); + ret = (BPSingleListener*)simulator.addListenerAndResume(&bp); + log << hex << ret->getTriggerInstructionPointer() << ": " + << simulator.getMnemonic() << endl; + bp.setWatchInstructionPointer(ANY_ADDR); + simulator.clearListeners(); + while ((ret = (BPSingleListener*)simulator.addListenerAndResume(&bp)) != 0) { + log << hex << ret->getTriggerInstructionPointer() << ": " + << simulator.getMnemonic() << " => Abort? " << flush; + char ch; + cin.clear(); cin.sync(); cin >> ch; + cout << endl; + if (ch == 'y' || ch == 'Y') + break; + } + + // Explicitly terminate, or the simulator will continue to run. + simulator.terminate(); +} diff --git a/src/experiments/abo-simple-arm/experiment.hpp b/src/experiments/abo-simple-arm/experiment.hpp new file mode 100644 index 00000000..dd73b7bc --- /dev/null +++ b/src/experiments/abo-simple-arm/experiment.hpp @@ -0,0 +1,13 @@ +#ifndef __ABO_SIMPLE_ARM_EXPERIMENT_HPP__ + #define __ABO_SIMPLE_ARM_EXPERIMENT_HPP__ + +#include "efw/ExperimentFlow.hpp" +#include "efw/JobClient.hpp" + +class ABOSimpleARMExperiment : public fail::ExperimentFlow { +public: + ABOSimpleARMExperiment() { } + bool run(); +}; + +#endif // __ABO_SIMPLE_ARM_EXPERIMENT_HPP__ From 515eb9973b8f2843a09693c3a3ec70d8596f9170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20B=C3=B6ckenkamp?= Date: Mon, 29 Apr 2013 16:09:28 +0200 Subject: [PATCH 17/17] Fail* CPUState: set/getRegisterContent() uses "const Register*" as 1st param The first parameter (Register* reg) is only used as input (const-correctness). Change-Id: I5a75a9f7378913e491a8a22872f51a385e910af6 --- src/core/sal/CPUState.hpp | 4 ++-- src/core/sal/bochs/BochsCPU.cc | 4 ++-- src/core/sal/bochs/BochsCPU.hpp | 4 ++-- src/core/sal/gem5/Gem5ArmCPU.cc | 4 ++-- src/core/sal/gem5/Gem5ArmCPU.hpp | 4 ++-- src/core/sal/t32/T32ArmCPU.cc | 4 ++-- src/core/sal/t32/T32ArmCPU.hpp | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/core/sal/CPUState.hpp b/src/core/sal/CPUState.hpp index e1e73c61..44618941 100644 --- a/src/core/sal/CPUState.hpp +++ b/src/core/sal/CPUState.hpp @@ -20,13 +20,13 @@ public: * Gets the content of the passed Register. * @param reg the register to get the content from */ - virtual regdata_t getRegisterContent(Register* reg) const = 0; + virtual regdata_t getRegisterContent(const Register* reg) const = 0; /** * Writes the passed value into the given register. * @param reg the register that should be written to * @param value the value that should be written into the register */ - virtual void setRegisterContent(Register* reg, regdata_t value) = 0; + virtual void setRegisterContent(const Register* reg, regdata_t value) = 0; /** * Returns the current instruction pointer. * @return the current eip diff --git a/src/core/sal/bochs/BochsCPU.cc b/src/core/sal/bochs/BochsCPU.cc index d12eebd0..3ba78a35 100644 --- a/src/core/sal/bochs/BochsCPU.cc +++ b/src/core/sal/bochs/BochsCPU.cc @@ -5,7 +5,7 @@ namespace fail { -regdata_t BochsCPU::getRegisterContent(Register* reg) const +regdata_t BochsCPU::getRegisterContent(const Register* reg) const { assert(reg != NULL && "FATAL ERROR: reg-ptr cannot be NULL!"); // TODO: BX_CPU(0) *always* correct? @@ -26,7 +26,7 @@ regdata_t BochsCPU::getRegisterContent(Register* reg) const #endif // SIM_SUPPORT_64 } -void BochsCPU::setRegisterContent(Register* reg, regdata_t value) +void BochsCPU::setRegisterContent(const Register* reg, regdata_t value) { assert(reg != NULL && "FATAL ERROR: reg-ptr cannot be NULL!"); // TODO: BX_CPU(0) *always* correct? diff --git a/src/core/sal/bochs/BochsCPU.hpp b/src/core/sal/bochs/BochsCPU.hpp index a312aac0..9a0870a0 100644 --- a/src/core/sal/bochs/BochsCPU.hpp +++ b/src/core/sal/bochs/BochsCPU.hpp @@ -36,13 +36,13 @@ public: * @param reg the register pointer of interest (cannot be \c NULL) * @return the content of the register \c reg */ - regdata_t getRegisterContent(Register* reg) const; + regdata_t getRegisterContent(const Register* reg) const; /** * Sets the content of the register \c reg to \c value. * @param reg the destination register object pointer (cannot be \c NULL) * @param value the new value to assign */ - void setRegisterContent(Register* reg, regdata_t value); + void setRegisterContent(const Register* reg, regdata_t value); /** * Returns the current instruction pointer (aka program counter). * @return the current (e)ip register content diff --git a/src/core/sal/gem5/Gem5ArmCPU.cc b/src/core/sal/gem5/Gem5ArmCPU.cc index 481a38b8..fb5eb552 100644 --- a/src/core/sal/gem5/Gem5ArmCPU.cc +++ b/src/core/sal/gem5/Gem5ArmCPU.cc @@ -4,12 +4,12 @@ namespace fail { -regdata_t Gem5ArmCPU::getRegisterContent(Register* reg) const +regdata_t Gem5ArmCPU::getRegisterContent(const Register* reg) const { return GetRegisterContent(m_System, m_Id, reg->getType(), reg->getIndex()); } -void Gem5ArmCPU::setRegisterContent(Register* reg, regdata_t value) +void Gem5ArmCPU::setRegisterContent(const Register* reg, regdata_t value) { SetRegisterContent(m_System, m_Id, reg->getType(), reg->getIndex(), value); } diff --git a/src/core/sal/gem5/Gem5ArmCPU.hpp b/src/core/sal/gem5/Gem5ArmCPU.hpp index 26215502..2d0b0ffd 100644 --- a/src/core/sal/gem5/Gem5ArmCPU.hpp +++ b/src/core/sal/gem5/Gem5ArmCPU.hpp @@ -33,13 +33,13 @@ public: * @param reg the destination register whose content should be retrieved * @return the content of register \c reg */ - regdata_t getRegisterContent(Register* reg) const; + regdata_t getRegisterContent(const Register* reg) const; /** * Sets the register content for the \a current gem5 CPU. * @param reg the (initialized) register object whose content should be set * @param value the new content of the register \c reg */ - void setRegisterContent(Register* reg, regdata_t value); + void setRegisterContent(const Register* reg, regdata_t value); /** * Retrieves the current instruction pointer (IP aka program counter, PC for short) * for the current CPU \c this. diff --git a/src/core/sal/t32/T32ArmCPU.cc b/src/core/sal/t32/T32ArmCPU.cc index 1743b50a..8f8f8ed1 100644 --- a/src/core/sal/t32/T32ArmCPU.cc +++ b/src/core/sal/t32/T32ArmCPU.cc @@ -6,7 +6,7 @@ namespace fail { static const uint64_t lower = 0x00000000ffffffff; -regdata_t T32ArmCPU::getRegisterContent(Register* reg) const +regdata_t T32ArmCPU::getRegisterContent(const Register* reg) const { // T32_ReadRegister wants a mask of bits representig the registers to read: // e.g., reading R1 and R4 and R63 @@ -28,7 +28,7 @@ regdata_t T32ArmCPU::getRegisterContent(Register* reg) const return 0; // we should not come here. } -void T32ArmCPU::setRegisterContent(Register* reg, regdata_t value) +void T32ArmCPU::setRegisterContent(const Register* reg, regdata_t value) { uint64_t mask = (1 << reg->getIndex()); diff --git a/src/core/sal/t32/T32ArmCPU.hpp b/src/core/sal/t32/T32ArmCPU.hpp index 768b8017..4fc58bfb 100644 --- a/src/core/sal/t32/T32ArmCPU.hpp +++ b/src/core/sal/t32/T32ArmCPU.hpp @@ -29,13 +29,13 @@ public: * @param reg the destination register whose content should be retrieved * @return the content of register \c reg */ - regdata_t getRegisterContent(Register* reg) const; + regdata_t getRegisterContent(const Register* reg) const; /** * Sets the register content for the \a current CPU. * @param reg the (initialized) register object whose content should be set * @param value the new content of the register \c reg */ - void setRegisterContent(Register* reg, regdata_t value); + void setRegisterContent(const Register* reg, regdata_t value); /** * Retrieves the current instruction pointer (IP aka program counter, PC for short) * for the current CPU \c this.