ecos: guest-image independent fail client

TODO: campaign needs to be updated, too

git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1908 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
hsc
2012-11-09 15:37:21 +00:00
parent 805f67e23c
commit c2242f2bb4
6 changed files with 124 additions and 61 deletions

View File

@ -57,8 +57,9 @@ bool EcosKernelTestCampaign::writeTraceInfo(unsigned instr_counter, unsigned tim
return true;
}
bool EcosKernelTestCampaign::readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &lowest_addr, unsigned &highest_addr) {
ifstream file(filename_traceinfo().c_str());
bool EcosKernelTestCampaign::readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &lowest_addr, unsigned &highest_addr,
const std::string& variant, const std::string& benchmark) {
ifstream file(filename_traceinfo(variant, benchmark).c_str());
if (!file.is_open()) {
cout << "failed to open " << filename_traceinfo() << endl;
return false;
@ -127,6 +128,14 @@ std::string EcosKernelTestCampaign::filename_results(const std::string& variant,
return dir_results + "/" + variant + "_" + benchmark + "_" + "results.csv";
}
std::string EcosKernelTestCampaign::filename_elf(const std::string& variant, const std::string& benchmark)
{
if (variant.size() && benchmark.size()) {
return dir_images + "/" + variant + "/" + benchmark + ".elf";
}
return "kernel.elf";
}
// equivalence class type: addr, [i1, i2]
// addr: byte to inject a bit-flip into
// [i1, i2]: interval of instruction numbers, counted from experiment
@ -355,6 +364,9 @@ bool EcosKernelTestCampaign::run()
// instantly enqueue job: that way the job clients can already
// start working in parallel
EcosKernelTestExperimentData *d = new EcosKernelTestExperimentData;
// FIXME use correct variant/benchmark
d->msg.set_variant("");
d->msg.set_benchmark("");
// we pick the rightmost instruction in that interval
d->msg.set_instr_offset(current_ec.instr2);
d->msg.set_instr_address(current_ec.instr2_absolute);
@ -460,7 +472,7 @@ bool EcosKernelTestCampaign::run()
" experiments to " << ecs_need_experiment.size() * 8 << endl;
// CSV header
results << "ec_instr1\tec_instr2\tec_instr2_absolute\tec_data_address\tbitnr\tbit_width\tresulttype\tecos_test_result\tlatest_ip\terror_corrected\tdetails" << endl;
results << "variant\tbenchmark\tec_instr1\tec_instr2\tec_instr2_absolute\tec_data_address\tbitnr\tbit_width\tresulttype\tecos_test_result\tlatest_ip\terror_corrected\tdetails" << endl;
// store no-effect "experiment" results
for (vector<equivalence_class>::const_iterator it = ecs_no_effect.begin();
@ -509,6 +521,8 @@ bool EcosKernelTestCampaign::run()
for (int idx = 0; idx < res->msg.result_size(); ++idx) {
results
// repeated for all single experiments:
<< res->msg.variant() << "\t"
<< res->msg.benchmark() << "\t"
<< ec.instr1 << "\t"
<< ec.instr2 << "\t"
<< ec.instr2_absolute << "\t"

View File

@ -21,11 +21,11 @@ public:
virtual bool run();
static bool readMemoryMap(fail::MemoryMap &mm, char const * const filename);
static bool writeTraceInfo(unsigned instr_counter, unsigned timeout, unsigned lowest_addr, unsigned highest_addr);
static bool readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &lowest_addr, unsigned &highest_addr);
static bool readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &lowest_addr, unsigned &highest_addr, const std::string& variant = "", const std::string& benchmark = "");
static std::string filename_memorymap(const std::string& variant = "", const std::string& benchmark = "");
static std::string filename_state(const std::string& variant = "", const std::string& benchmark = "");
static std::string filename_trace(const std::string& variant = "", const std::string& benchmark = "");
static std::string filename_traceinfo(const std::string& variant = "", const std::string& benchmark = "");
static std::string filename_results(const std::string& variant, const std::string& benchmark);
static std::string filename_elf(const std::string& variant = "", const std::string& benchmark = "");
};

View File

@ -2,12 +2,17 @@ message EcosKernelTestProtoMsg {
// Input: experiment parameters
// (client executes 8 experiments, one for each bit at mem_addr)
// EDM/ERM variant
required string variant = 1;
// benchmark
required string benchmark = 2;
// FI at #instructions from experiment start
required int32 instr_offset = 1;
required int32 instr_offset = 3;
// the exact IP value at this point in time (from golden run)
optional int32 instr_address = 2; // for sanity checks
optional int32 instr_address = 4; // for sanity checks
// address of the byte to inject bit-flips
required int32 mem_addr = 3;
required int32 mem_addr = 5;
// ----------------------------------------------------
@ -15,9 +20,9 @@ message EcosKernelTestProtoMsg {
// IP where we did the injection: for debugging purposes, must be identical
// to instr_address
optional int32 injection_ip = 4;
optional int32 injection_ip = 6;
repeated group Result = 5 {
repeated group Result = 7 {
// single experiment bit offset
required int32 bit_offset = 1;

View File

@ -16,6 +16,7 @@
#include "sal/bochs/BochsRegister.hpp"
#include "sal/bochs/BochsListener.hpp"
#include "sal/Listener.hpp"
#include "util/ElfReader.hpp"
// You need to have the tracing plugin enabled for this
#include "../plugins/tracing/TracingPlugin.hpp"
@ -36,12 +37,12 @@ using namespace fail;
#endif
#if PREREQUISITES
bool EcosKernelTestExperiment::retrieveGuestAddresses() {
bool EcosKernelTestExperiment::retrieveGuestAddresses(guest_address_t addr_finish) {
log << "STEP 0: record memory map with addresses of 'interesting' objects" << endl;
// run until 'ECOS_FUNC_FINISH' is reached
// run until func_finish is reached
BPSingleListener bp;
bp.setWatchInstructionPointer(ECOS_FUNC_FINISH);
bp.setWatchInstructionPointer(addr_finish);
// memory map serialization
ofstream mm(EcosKernelTestCampaign::filename_memorymap().c_str(), ios::out);
@ -82,7 +83,7 @@ bool EcosKernelTestExperiment::retrieveGuestAddresses() {
}
}
assert(number_of_guest_events > 0);
log << "Breakpoint at 'ECOS_FUNC_FINISH' reached: created memory map (" << number_of_guest_events << " entries)" << endl;
log << "Breakpoint at func_finish reached: created memory map (" << number_of_guest_events << " entries)" << endl;
delete str;
// close serialized mm
@ -94,7 +95,7 @@ bool EcosKernelTestExperiment::retrieveGuestAddresses() {
return true;
}
bool EcosKernelTestExperiment::establishState() {
bool EcosKernelTestExperiment::establishState(guest_address_t addr_entry, guest_address_t addr_errors_corrected) {
log << "STEP 1: run until interesting function starts, and save state" << endl;
GuestListener g;
@ -108,27 +109,27 @@ bool EcosKernelTestExperiment::establishState() {
}
BPSingleListener bp;
bp.setWatchInstructionPointer(ECOS_FUNC_ENTRY);
bp.setWatchInstructionPointer(addr_entry);
simulator.addListenerAndResume(&bp);
log << "test function entry reached, saving state" << endl;
log << "EIP = " << hex << bp.getTriggerInstructionPointer() << endl;
//log << "error_corrected = " << dec << ((int)simulator.getMemoryManager().getByte(ECC_ERROR_CORRECTED)) << endl;
//log << "error_corrected = " << dec << ((int)simulator.getMemoryManager().getByte(addr_errors_corrected)) << endl;
simulator.save(EcosKernelTestCampaign::filename_state());
assert(bp.getTriggerInstructionPointer() == ECOS_FUNC_ENTRY);
assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY);
assert(bp.getTriggerInstructionPointer() == addr_entry);
assert(simulator.getRegisterManager().getInstructionPointer() == addr_entry);
// clean up simulator
simulator.clearListeners();
return true;
}
bool EcosKernelTestExperiment::performTrace() {
bool EcosKernelTestExperiment::performTrace(guest_address_t addr_entry, guest_address_t addr_finish) {
log << "STEP 2: record trace for fault-space pruning" << endl;
log << "restoring state" << endl;
simulator.restore(EcosKernelTestCampaign::filename_state());
log << "EIP = " << hex << simulator.getRegisterManager().getInstructionPointer() << endl;
assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY);
assert(simulator.getRegisterManager().getInstructionPointer() == addr_entry);
log << "enabling tracing" << endl;
TracingPlugin tp;
@ -148,7 +149,7 @@ bool EcosKernelTestExperiment::performTrace() {
// again, run until 'ECOS_FUNC_FINISH' is reached
BPSingleListener bp;
bp.setWatchInstructionPointer(ECOS_FUNC_FINISH);
bp.setWatchInstructionPointer(addr_finish);
simulator.addListener(&bp);
// on the way, count instructions // FIXME add SAL functionality for this?
@ -236,9 +237,11 @@ bool EcosKernelTestExperiment::performTrace() {
bool EcosKernelTestExperiment::faultInjection() {
log << "STEP 3: The actual experiment." << endl;
// read trace info
// trace info
unsigned instr_counter, estimated_timeout, lowest_addr, highest_addr;
EcosKernelTestCampaign::readTraceInfo(instr_counter, estimated_timeout, lowest_addr, highest_addr);
// ELF symbol addresses
guest_address_t addr_entry, addr_finish, addr_test_output, addr_errors_corrected,
addr_panic, addr_text_start, addr_text_end;
BPSingleListener bp;
@ -258,15 +261,24 @@ bool EcosKernelTestExperiment::faultInjection() {
}
#else
// XXX debug
param.msg.set_variant("bitmap_CRC");
param.msg.set_benchmark("bin_sem0");
param.msg.set_instr_offset(7462);
//param.msg.set_instr_address(12345);
param.msg.set_mem_addr(44540);
#endif
int id = param.getWorkloadID();
m_variant = param.msg.variant();
m_benchmark = param.msg.benchmark();
int instr_offset = param.msg.instr_offset();
int mem_addr = param.msg.mem_addr();
EcosKernelTestCampaign::readTraceInfo(instr_counter, estimated_timeout,
lowest_addr, highest_addr, m_variant, m_benchmark);
readELFSymbols(addr_entry, addr_finish, addr_test_output,
addr_errors_corrected, addr_panic, addr_text_start, addr_text_end);
// for each job we're actually doing *8* experiments (one for each bit)
for (int bit_offset = 0; bit_offset < 8; ++bit_offset) {
// 8 results in one job
@ -288,7 +300,7 @@ bool EcosKernelTestExperiment::faultInjection() {
*/
// reaching finish() could happen before OR after FI
BPSingleListener func_finish(ECOS_FUNC_FINISH);
BPSingleListener func_finish(addr_finish);
simulator.addListener(&func_finish);
// no need to wait if offset is 0
@ -350,8 +362,8 @@ bool EcosKernelTestExperiment::faultInjection() {
simulator.addListener(&ev_trap);
// jump outside text segment
BPRangeListener ev_below_text(ANY_ADDR, ECOS_TEXT_START - 1);
BPRangeListener ev_beyond_text(ECOS_TEXT_END + 1, ANY_ADDR);
BPRangeListener ev_below_text(ANY_ADDR, addr_text_start - 1);
BPRangeListener ev_beyond_text(addr_text_end + 1, ANY_ADDR);
simulator.addListener(&ev_below_text);
simulator.addListener(&ev_beyond_text);
@ -374,12 +386,14 @@ bool EcosKernelTestExperiment::faultInjection() {
//simulator.addListener(&ev_end);
// eCos' test output function, which will show if the test PASSed or FAILed
BPSingleListener func_test_output(ECOS_FUNC_TEST_OUTPUT);
BPSingleListener func_test_output(addr_test_output);
simulator.addListener(&func_test_output);
// function called by ecc aspects, when an uncorrectable error is detected
BPSingleListener func_ecc_panic(ECC_FUNC_PANIC);
simulator.addListener(&func_ecc_panic);
BPSingleListener func_ecc_panic(addr_panic);
if (addr_panic != ADDR_INV) {
simulator.addListener(&func_ecc_panic);
}
#if LOCAL && 0
// XXX debug
@ -433,8 +447,12 @@ bool EcosKernelTestExperiment::faultInjection() {
result->set_latest_ip(simulator.getRegisterManager().getInstructionPointer());
// record error_corrected regardless of result
int32_t error_corrected = simulator.getMemoryManager().getByte(ECC_ERROR_CORRECTED);
result->set_error_corrected(error_corrected);
if (addr_errors_corrected != ADDR_INV) {
int32_t error_corrected = simulator.getMemoryManager().getByte(addr_errors_corrected);
result->set_error_corrected(error_corrected);
} else {
result->set_error_corrected(0);
}
// record ecos_test_result
if ( (ecos_test_passed == true) && (ecos_test_failed == false) ) {
@ -492,24 +510,59 @@ bool EcosKernelTestExperiment::faultInjection() {
}
#endif // PREREQUISITES
bool EcosKernelTestExperiment::readELFSymbols(
fail::guest_address_t& entry,
fail::guest_address_t& finish,
fail::guest_address_t& test_output,
fail::guest_address_t& errors_corrected,
fail::guest_address_t& panic,
fail::guest_address_t& text_start,
fail::guest_address_t& text_end)
{
ElfReader elfreader(EcosKernelTestCampaign::filename_elf(m_variant, m_benchmark).c_str());
entry = elfreader.getAddressByName("cyg_start");
finish = elfreader.getAddressByName("cyg_test_exit");
test_output = elfreader.getAddressByName("cyg_test_output");
errors_corrected = elfreader.getAddressByName("errors_corrected");
panic = elfreader.getAddressByName("_Z9ecc_panicv");
text_start = elfreader.getAddressByName("_stext");
text_end = elfreader.getAddressByName("_etext");
// it's OK if errors_corrected or ecc_panic are missing
if (entry == ADDR_INV || finish == ADDR_INV || test_output == ADDR_INV ||
text_start == ADDR_INV || text_end == ADDR_INV) {
return false;
}
return true;
}
bool EcosKernelTestExperiment::run()
{
log << "startup" << endl;
#if PREREQUISITES
log << "retrieving ELF symbol addresses ..." << endl;
guest_address_t entry, finish, test_output, errors_corrected,
panic, text_start, text_end;
if (!readELFSymbols(entry, finish, test_output, errors_corrected,
panic, text_start, text_end)) {
log << "failed, essential symbols are missing!" << endl;
simulator.terminate(1);
}
// step 0
if(retrieveGuestAddresses()) {
if(retrieveGuestAddresses(finish)) {
log << "STEP 0 finished: rebooting ..." << endl;
simulator.reboot();
} else { return false; }
// step 1
if(establishState()) {
if(establishState(entry, errors_corrected)) {
log << "STEP 1 finished: proceeding ..." << endl;
} else { return false; }
// step 2
if(performTrace()) {
if(performTrace(entry, finish)) {
log << "STEP 2 finished: terminating ..." << endl;
} else { return false; }

View File

@ -1,8 +1,11 @@
#pragma once
#include <string>
#include "efw/ExperimentFlow.hpp"
#include "efw/JobClient.hpp"
#include "util/Logger.hpp"
#include "sal/SALConfig.hpp"
class EcosKernelTestExperiment : public fail::ExperimentFlow {
fail::JobClient m_jc;
@ -12,9 +15,17 @@ public:
EcosKernelTestExperiment() : log("eCos Kernel Test", false) {}
bool run();
bool retrieveGuestAddresses(); // step 0
bool establishState(); // step 1
bool performTrace(); // step 2
bool retrieveGuestAddresses(fail::guest_address_t addr_finish); // step 0
bool establishState(fail::guest_address_t addr_entry, fail::guest_address_t addr_errors_corrected); // step 1
bool performTrace(fail::guest_address_t addr_entry, fail::guest_address_t addr_finish); // step 2
bool faultInjection(); // step 3
};
bool readELFSymbols(
fail::guest_address_t& entry,
fail::guest_address_t& finish,
fail::guest_address_t& test_output,
fail::guest_address_t& errors_corrected,
fail::guest_address_t& panic,
fail::guest_address_t& text_start,
fail::guest_address_t& text_end);
};

View File

@ -1,23 +1,3 @@
#pragma once
// autogenerated, don't edit!
// user-specified start-function address:
// nm -C thread1.elf|fgrep cyg_start
#define ECOS_FUNC_ENTRY 0x0000409c
// cyg_test_exit address
#define ECOS_FUNC_FINISH 0x00005f0c
// cyg_test_output address
#define ECOS_FUNC_TEST_OUTPUT 0x00005f14
// the variable that's increased if ECC corrects an error:
#define ECOS_ERROR_CORRECTED 0x99999999
// text begin:
// nm -C thread1.elf|fgrep _stext
#define ECOS_TEXT_START 0x00003000
// text end:
// nm -C thread1.elf|fgrep _etext
#define ECOS_TEXT_END 0x0001627a
#define PREREQUISITES 0