diff --git a/core/experiments/checksum-oostubs/campaign.cc b/core/experiments/checksum-oostubs/campaign.cc index 0ad3ad27..180e4c05 100644 --- a/core/experiments/checksum-oostubs/campaign.cc +++ b/core/experiments/checksum-oostubs/campaign.cc @@ -88,9 +88,11 @@ bool CoolChecksumCampaign::run() for (int bit_offset = 0; bit_offset < (memoryMap[member][1])*8; ++bit_offset) { for (int instr_offset = 0; instr_offset < OOSTUBS_NUMINSTR; ++instr_offset) { CoolChecksumExperimentData *d = new CoolChecksumExperimentData; + /* d->msg.set_instr_offset(instr_offset); d->msg.set_mem_addr(memoryMap[member][0]); d->msg.set_bit_offset(bit_offset); + */ fi::campaignmanager.addParam(d); ++count; @@ -122,6 +124,7 @@ bool CoolChecksumCampaign::run() while ((res = static_cast(fi::campaignmanager.getDone()))) { rescount++; + /* results << res->msg.injection_ip() << "\t" << res->msg.instr_offset() << "\t" @@ -131,6 +134,7 @@ bool CoolChecksumCampaign::run() << res->msg.resultdata() << "\t" << res->msg.error_corrected() << "\t" << res->msg.details() << "\n"; + */ delete res; } log << "done. sent " << count << " received " << rescount << endl; diff --git a/core/experiments/checksum-oostubs/checksum-oostubs.proto b/core/experiments/checksum-oostubs/checksum-oostubs.proto index 9cca70d1..11c9ad2b 100644 --- a/core/experiments/checksum-oostubs/checksum-oostubs.proto +++ b/core/experiments/checksum-oostubs/checksum-oostubs.proto @@ -1,29 +1,41 @@ message OOStuBSProtoMsg { - // parameters + // Input: experiment parameters required int32 instr_offset = 1; - required int32 mem_addr = 2; - required int32 bit_offset = 3; + optional int32 instr_address = 2; // for sanity checks + required int32 mem_addr = 3; + required int32 bit_offset = 4; + + // ---------------------------------------------------- + + // Output: experiment results + // (make these optional to reduce overhead for server->client communication) - // results - // make these optional to reduce overhead for server->client communication - enum ResultType { - CALCDONE = 1; - TIMEOUT = 2; - TRAP = 3; - UNKNOWN = 4; - } // instruction pointer where injection was done - optional uint32 injection_ip = 4; - // result type, see above - optional ResultType resulttype = 5; - // result data, depending on resulttype: - // CALCDONE: resultdata = calculated value - // TIMEOUT: resultdata = latest EIP - // TRAP: resultdata = latest EIP - // UNKNOWN: resultdata = latest EIP - optional uint32 resultdata = 6; + optional uint32 injection_ip = 5; + + // result type: + // FINISHED = planned number of instructions were executed + // TRAP = premature guest "crash" + enum ResultType { + FINISHED = 1; + TRAP = 2; + UNKNOWN = 3; + } + optional ResultType resulttype = 6; + + // result details: + // resultdata = result[0-2] + repeated uint32 resultdata = 7 [packed=true]; + + // was finish() ever reached? + optional bool finish_reached = 8; + + // especially interesting for TRAP/ UNKNOWN: latest IP + optional uint32 latest_ip = 9; + // did ECC correct the fault? - optional int32 error_corrected = 7; + optional int32 error_corrected = 10; + // optional textual description of what happened - optional string details = 8; + optional string details = 11; } diff --git a/core/experiments/checksum-oostubs/experiment.cc b/core/experiments/checksum-oostubs/experiment.cc index 0c96239d..0e4ebfc6 100644 --- a/core/experiments/checksum-oostubs/experiment.cc +++ b/core/experiments/checksum-oostubs/experiment.cc @@ -22,6 +22,7 @@ using std::endl; bool CoolChecksumExperiment::run() { + char const *statename = "checksum-oostubs.state"; Logger log("Checksum-OOStuBS", false); fi::BPEvent bp; @@ -41,11 +42,11 @@ bool CoolChecksumExperiment::run() log << "test function entry reached, saving state" << endl; log << "EIP = " << std::hex << bp.getTriggerInstructionPointer() << " or " << sal::simulator.getRegisterManager().getInstructionPointer() << endl; log << "error_corrected = " << std::dec << ((int)sal::simulator.getMemoryManager().getByte(OOSTUBS_ERROR_CORRECTED)) << endl; - sal::simulator.save("checksum-oostubs.state"); + sal::simulator.save(statename); #elif 1 // STEP 2: record trace for fault-space pruning log << "restoring state" << endl; - sal::simulator.restore("checksum-oostubs.state"); + sal::simulator.restore(statename); log << "EIP = " << std::hex << sal::simulator.getRegisterManager().getInstructionPointer() << endl; log << "enabling tracing" << endl; @@ -67,7 +68,15 @@ bool CoolChecksumExperiment::run() bp.setWatchInstructionPointer(fi::ANY_ADDR); bp.setCounter(OOSTUBS_NUMINSTR); - sal::simulator.addEventAndWait(&bp); + sal::simulator.addEvent(&bp); + fi::BPEvent func_finish(OOSTUBS_FUNC_FINISH); + sal::simulator.addEvent(&func_finish); + + if (sal::simulator.waitAny() == &func_finish) { + log << "experiment reached finish()" << endl; + // FIXME add instruction counter to SimulatorController + sal::simulator.waitAny(); + } log << "experiment finished after " << std::dec << OOSTUBS_NUMINSTR << " instructions" << endl; uint32_t results[OOSTUBS_RESULTS_BYTES / sizeof(uint32_t)]; @@ -93,83 +102,124 @@ bool CoolChecksumExperiment::run() // FIXME consider moving experiment repetition into Fail* or even the // SAL -- whether and how this is possible with the chosen backend is // backend specific - for (int i = 0; i < 20; ++i) { + //for (int i = 0; i < 2000; ++i) { // STEP 3: The actual experiment. log << "restoring state" << endl; - sal::simulator.restore("coolecc.state"); + sal::simulator.restore(statename); + // get an experiment parameter set log << "asking job server for experiment parameters" << endl; CoolChecksumExperimentData param; +/* if (!m_jc.getParam(param)) { log << "Dying." << endl; // communicate that we were told to die sal::simulator.terminate(1); } +*/ + param.msg.set_instr_offset(1); + param.msg.set_mem_addr(1024*1024*8); + param.msg.set_bit_offset(0); + int id = param.getWorkloadID(); int instr_offset = param.msg.instr_offset(); + int mem_addr = param.msg.mem_addr(); int bit_offset = param.msg.bit_offset(); - log << "job " << id << " instr " << instr_offset << " bit " << bit_offset << endl; + log << "job " << id << " instr " << instr_offset << " mem " << mem_addr << "+" << bit_offset << endl; - // FIXME could be improved (especially for backends supporting - // breakpoints natively) by utilizing a previously recorded instruction - // trace + // reaching finish() could happen before OR after FI + fi::BPEvent func_finish(OOSTUBS_FUNC_FINISH); + sal::simulator.addEvent(&func_finish); + bool finish_reached = false; + + // XXX test this with coolchecksum first (or reassure with sanity checks) + // XXX could be improved with intermediate states (reducing runtime until injection) bp.setWatchInstructionPointer(fi::ANY_ADDR); - for (int count = 0; count < instr_offset; ++count) { - sal::simulator.addEventAndWait(&bp); + bp.setCounter(instr_offset); + sal::simulator.addEvent(&bp); + + // finish() before FI? + if (sal::simulator.waitAny() == &func_finish) { + finish_reached = true; + log << "experiment reached finish() before FI" << endl; + + // wait for bp + sal::simulator.waitAny(); } - // inject - sal::guest_address_t inject_addr = COOL_ECC_OBJUNDERTEST + bit_offset / 8; + // --- fault injection --- sal::MemoryManager& mm = sal::simulator.getMemoryManager(); - sal::byte_t data = mm.getByte(inject_addr); - sal::byte_t newdata = data ^ (1 << (bit_offset % 8)); - mm.setByte(inject_addr, newdata); + sal::byte_t data = mm.getByte(mem_addr); + sal::byte_t newdata = data ^ (1 << bit_offset); + mm.setByte(mem_addr, newdata); // note at what IP we did it int32_t injection_ip = sal::simulator.getRegisterManager().getInstructionPointer(); param.msg.set_injection_ip(injection_ip); - log << "inject @ ip " << injection_ip - << " offset " << std::dec << (bit_offset / 8) - << " (bit " << (bit_offset % 8) << ") 0x" - << std::hex << ((int)data) << " -> 0x" << ((int)newdata) << endl; + log << "fault injected @ ip " << injection_ip + << " 0x" << std::hex << ((int)data) << " -> 0x" << ((int)newdata) << endl; + // XXX sanity check - // aftermath - fi::BPEvent ev_done(COOL_ECC_CALCDONE); - sal::simulator.addEvent(&ev_done); - fi::BPEvent ev_timeout(fi::ANY_ADDR); - ev_timeout.setCounter(COOL_ECC_NUMINSTR + 3000); - sal::simulator.addEvent(&ev_timeout); + // --- aftermath --- + // four possible outcomes: + // - guest causes a trap, "crashes" + // - guest runs OOSTUBS_NUMINSTR+OOSTUBS_RECOVERYINSTR instructions but + // never reaches finish() + // - guest reaches finish() within OOSTUBS_NUMINSTR+OOSTUBS_RECOVERYINSTR + // instructions with + // * a wrong result[0-2] + // * a correct result[0-2] + + // catch traps as "extraordinary" ending fi::TrapEvent ev_trap(fi::ANY_TRAP); sal::simulator.addEvent(&ev_trap); + // remaining instructions until "normal" ending + fi::BPEvent ev_done(fi::ANY_ADDR); + ev_done.setCounter(OOSTUBS_NUMINSTR + OOSTUBS_RECOVERYINSTR - instr_offset); + sal::simulator.addEvent(&ev_done); fi::BaseEvent* ev = sal::simulator.waitAny(); + + // Do we reach finish() while waiting for ev_trap/ev_done? + if (ev == &func_finish) { + finish_reached = true; + log << "experiment reached finish()" << endl; + + // wait for ev_trap/ev_done + ev = sal::simulator.waitAny(); + } + + // record resultdata, finish_reached and error_corrected regardless of result + uint32_t results[OOSTUBS_RESULTS_BYTES / sizeof(uint32_t)]; + sal::simulator.getMemoryManager().getBytes(OOSTUBS_RESULTS_ADDR, sizeof(results), results); + for (unsigned i = 0; i < sizeof(results) / sizeof(*results); ++i) { + log << "results[" << i << "]: " << std::dec << results[i] << endl; + param.msg.add_resultdata(results[i]); + } + param.msg.set_finish_reached(finish_reached); + int32_t error_corrected = sal::simulator.getMemoryManager().getByte(OOSTUBS_ERROR_CORRECTED); + param.msg.set_error_corrected(error_corrected); + param.msg.set_latest_ip(sal::simulator.getRegisterManager().getInstructionPointer()); + if (ev == &ev_done) { - int32_t data = sal::simulator.getRegisterManager().getRegister(targetreg)->getData(); - log << std::dec << "Result EDX = " << data << endl; - param.msg.set_resulttype(CoolChecksumProtoMsg_ResultType_CALCDONE); - param.msg.set_resultdata(data); - } else if (ev == &ev_timeout) { - log << std::dec << "Result TIMEOUT" << endl; - param.msg.set_resulttype(CoolChecksumProtoMsg_ResultType_TIMEOUT); - param.msg.set_resultdata(sal::simulator.getRegisterManager().getInstructionPointer()); + log << std::dec << "Result FINISHED" << endl; + param.msg.set_resulttype(param.msg.FINISHED); } else if (ev == &ev_trap) { log << std::dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl; - param.msg.set_resulttype(CoolChecksumProtoMsg_ResultType_TRAP); - param.msg.set_resultdata(sal::simulator.getRegisterManager().getInstructionPointer()); + param.msg.set_resulttype(param.msg.TRAP); } else { log << std::dec << "Result WTF?" << endl; - param.msg.set_resulttype(CoolChecksumProtoMsg_ResultType_UNKNOWN); - param.msg.set_resultdata(sal::simulator.getRegisterManager().getInstructionPointer()); + param.msg.set_resulttype(param.msg.UNKNOWN); std::stringstream ss; - ss << "eventid " << ev << " EIP " << sal::simulator.getRegisterManager().getInstructionPointer(); + ss << "eventid " << ev->getId() << " EIP " << sal::simulator.getRegisterManager().getInstructionPointer(); param.msg.set_details(ss.str()); } - int32_t error_corrected = sal::simulator.getMemoryManager().getByte(COOL_ECC_ERROR_CORRECTED); - param.msg.set_error_corrected(error_corrected); +/* m_jc.sendResult(param); +*/ - } + //} #endif // Explicitly terminate, or the simulator will continue to run. sal::simulator.terminate(); diff --git a/core/experiments/checksum-oostubs/experimentInfo.hpp b/core/experiments/checksum-oostubs/experimentInfo.hpp index 2218c9b8..f40dbb00 100644 --- a/core/experiments/checksum-oostubs/experimentInfo.hpp +++ b/core/experiments/checksum-oostubs/experimentInfo.hpp @@ -10,7 +10,7 @@ #define OOSTUBS_FUNC_ENTRY 0x00103f2c // empty function that is called explicitly when the experiment finished // nm -C ecc.elf|fgrep "finished()" -#define OOSTUBS_FUNC_DONE 0x001093f0 +#define OOSTUBS_FUNC_FINISH 0x001093f0 // number of instructions the target executes under non-error conditions from ENTRY to DONE: // (result of experiment's step #2) #define OOSTUBS_NUMINSTR 0x4a3401