L4Sys: refactoring
* more more stuff into functions * try to have generic experiment code only once Change-Id: I4f037bd972243665a10941fcc3607f015b0bb1f9
This commit is contained in:
@ -215,21 +215,22 @@ void L4SysExperiment::terminateWithError(string details, int reason) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void L4SysExperiment::startAndSaveInitState(fail::BPSingleListener& bp)
|
void L4SysExperiment::startAndSaveInitState(fail::BPSingleListener* bp)
|
||||||
{
|
{
|
||||||
bp.setWatchInstructionPointer(L4SYS_FUNC_ENTRY);
|
bp->setWatchInstructionPointer(L4SYS_FUNC_ENTRY);
|
||||||
simulator.addListenerAndResume(&bp);
|
simulator.addListenerAndResume(bp);
|
||||||
|
|
||||||
log << "test function entry reached, saving state" << endl;
|
log << "test function entry reached, saving state" << endl;
|
||||||
log << "EIP: expected " << hex << bp.getTriggerInstructionPointer()
|
log << "EIP: expected " << hex << bp->getTriggerInstructionPointer()
|
||||||
<< " and actually got "
|
<< " and actually got "
|
||||||
<< simulator.getCPU(0).getInstructionPointer()
|
<< simulator.getCPU(0).getInstructionPointer()
|
||||||
<< endl;
|
<< endl;
|
||||||
log << "check the source code if the two instruction pointers are not equal" << endl;
|
log << "check the source code if the two instruction pointers are not equal" << endl;
|
||||||
simulator.save(L4SYS_STATE_FOLDER);
|
simulator.save(L4SYS_STATE_FOLDER);
|
||||||
|
delete bp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
|
void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener* bp)
|
||||||
{
|
{
|
||||||
log << "restoring state" << endl;
|
log << "restoring state" << endl;
|
||||||
simulator.restore(L4SYS_STATE_FOLDER);
|
simulator.restore(L4SYS_STATE_FOLDER);
|
||||||
@ -240,14 +241,14 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
|
|||||||
#ifdef L4SYS_FILTER_INSTRUCTIONS
|
#ifdef L4SYS_FILTER_INSTRUCTIONS
|
||||||
ofstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::binary);
|
ofstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::binary);
|
||||||
RangeSetInstructionFilter filtering(L4SYS_FILTER);
|
RangeSetInstructionFilter filtering(L4SYS_FILTER);
|
||||||
bp.setWatchInstructionPointer(ANY_ADDR);
|
bp->setWatchInstructionPointer(ANY_ADDR);
|
||||||
|
|
||||||
fail::MemAccessListener ML(ANY_ADDR, MemAccessEvent::MEM_READWRITE);
|
fail::MemAccessListener ML(ANY_ADDR, MemAccessEvent::MEM_READWRITE);
|
||||||
if (!simulator.addListener(&ML)) {
|
if (!simulator.addListener(&ML)) {
|
||||||
log << "did not add memory listener..." << std::endl;
|
log << "did not add memory listener..." << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (!simulator.addListener(&bp)) {
|
if (!simulator.addListener(bp)) {
|
||||||
log << "did not add breakpoint listener..." << std::endl;
|
log << "did not add breakpoint listener..." << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -256,12 +257,10 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
|
|||||||
map<address_t, unsigned> times_called_map;
|
map<address_t, unsigned> times_called_map;
|
||||||
bool injecting = false;
|
bool injecting = false;
|
||||||
|
|
||||||
ogzstream out_instr("trace_inst.pb");
|
ogzstream out("trace.pb");
|
||||||
ogzstream out_mem("trace_mem.pb");
|
ProtoOStream *os = new ProtoOStream(&out);
|
||||||
ProtoOStream *os_instr = new ProtoOStream(&out_instr);
|
|
||||||
ProtoOStream *os_mem = new ProtoOStream(&out_mem);
|
|
||||||
|
|
||||||
while (bp.getTriggerInstructionPointer() != L4SYS_FUNC_EXIT) {
|
while (bp->getTriggerInstructionPointer() != L4SYS_FUNC_EXIT) {
|
||||||
fail::BaseListener *res = simulator.resume();
|
fail::BaseListener *res = simulator.resume();
|
||||||
address_t curr_addr = 0;
|
address_t curr_addr = 0;
|
||||||
|
|
||||||
@ -270,16 +269,17 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
|
|||||||
curr_addr = ML.getTriggerInstructionPointer();
|
curr_addr = ML.getTriggerInstructionPointer();
|
||||||
simulator.addListener(&ML);
|
simulator.addListener(&ML);
|
||||||
++mem;
|
++mem;
|
||||||
} else if (res == &bp) {
|
} else if (res == bp) {
|
||||||
curr_addr = bp.getTriggerInstructionPointer();
|
curr_addr = bp->getTriggerInstructionPointer();
|
||||||
assert(curr_addr == simulator.getCPU(0).getInstructionPointer());
|
assert(curr_addr == simulator.getCPU(0).getInstructionPointer());
|
||||||
simulator.addListener(&bp);
|
simulator.addListener(bp);
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned times_called = times_called_map[curr_addr];
|
simtime_t prevtime = 0, currtime;
|
||||||
++times_called;
|
simtime_diff_t deltatime;
|
||||||
times_called_map[curr_addr] = times_called;
|
currtime = simulator.getTimerTicks();
|
||||||
|
deltatime = currtime - prevtime;
|
||||||
|
|
||||||
if (curr_addr == L4SYS_FILTER_ENTRY) {
|
if (curr_addr == L4SYS_FILTER_ENTRY) {
|
||||||
injecting = true;
|
injecting = true;
|
||||||
@ -305,13 +305,17 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
|
|||||||
++mem_valid;
|
++mem_valid;
|
||||||
|
|
||||||
Trace_Event te;
|
Trace_Event te;
|
||||||
te.set_time_delta(1);
|
if (deltatime != 0) { te.set_time_delta(deltatime); };
|
||||||
te.set_ip(curr_addr);
|
te.set_ip(curr_addr);
|
||||||
te.set_memaddr(ML.getTriggerAddress());
|
te.set_memaddr(ML.getTriggerAddress());
|
||||||
te.set_accesstype( (ML.getTriggerAccessType() & MemAccessEvent::MEM_READ) ? te.READ : te.WRITE );
|
te.set_accesstype( (ML.getTriggerAccessType() & MemAccessEvent::MEM_READ) ? te.READ : te.WRITE );
|
||||||
te.set_width(ML.getTriggerWidth());
|
te.set_width(ML.getTriggerWidth());
|
||||||
os_mem->writeMessage(&te);
|
os->writeMessage(&te);
|
||||||
} else if (res == &bp) {
|
} else if (res == bp) {
|
||||||
|
unsigned times_called = times_called_map[curr_addr];
|
||||||
|
++times_called;
|
||||||
|
times_called_map[curr_addr] = times_called;
|
||||||
|
|
||||||
//log << "breakpoint event" << std::endl;
|
//log << "breakpoint event" << std::endl;
|
||||||
// now check if we want to add the instruction for fault injection
|
// now check if we want to add the instruction for fault injection
|
||||||
++inst_accepted;
|
++inst_accepted;
|
||||||
@ -332,12 +336,13 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
|
|||||||
// the generic *-trace tools
|
// the generic *-trace tools
|
||||||
// XXX: need to log CR3 if we want multiple binaries here
|
// XXX: need to log CR3 if we want multiple binaries here
|
||||||
Trace_Event e;
|
Trace_Event e;
|
||||||
e.set_time_delta(1);
|
if (deltatime != 0) { e.set_time_delta(deltatime); };
|
||||||
e.set_ip(curr_addr);
|
e.set_ip(curr_addr);
|
||||||
os_instr->writeMessage(&e);
|
os->writeMessage(&e);
|
||||||
} else {
|
} else {
|
||||||
printf("Unknown res? %p\n", res);
|
printf("Unknown res? %p\n", res);
|
||||||
}
|
}
|
||||||
|
prevtime = currtime;
|
||||||
|
|
||||||
//short sanity check
|
//short sanity check
|
||||||
//log << "continue..." << std::endl;
|
//log << "continue..." << std::endl;
|
||||||
@ -365,9 +370,10 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
|
|||||||
<< dec << count << " instructions; "
|
<< dec << count << " instructions; "
|
||||||
<< "ul: " << ul << ", kernel: " << kernel << endl;
|
<< "ul: " << ul << ", kernel: " << kernel << endl;
|
||||||
#endif
|
#endif
|
||||||
|
delete bp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void L4SysExperiment::goldenRun(fail::BPSingleListener& bp)
|
void L4SysExperiment::goldenRun(fail::BPSingleListener* bp)
|
||||||
{
|
{
|
||||||
log << "restoring state" << endl;
|
log << "restoring state" << endl;
|
||||||
simulator.restore(L4SYS_STATE_FOLDER);
|
simulator.restore(L4SYS_STATE_FOLDER);
|
||||||
@ -377,10 +383,10 @@ void L4SysExperiment::goldenRun(fail::BPSingleListener& bp)
|
|||||||
|
|
||||||
std::string golden_run;
|
std::string golden_run;
|
||||||
ofstream golden_run_file(L4SYS_CORRECT_OUTPUT);
|
ofstream golden_run_file(L4SYS_CORRECT_OUTPUT);
|
||||||
bp.setWatchInstructionPointer(L4SYS_FUNC_EXIT);
|
bp->setWatchInstructionPointer(L4SYS_FUNC_EXIT);
|
||||||
simulator.addListener(&bp);
|
simulator.addListener(bp);
|
||||||
BaseListener* ev = waitIOOrOther(true);
|
BaseListener* ev = waitIOOrOther(true);
|
||||||
if (ev == &bp) {
|
if (ev == bp) {
|
||||||
golden_run.assign(currentOutput.c_str());
|
golden_run.assign(currentOutput.c_str());
|
||||||
golden_run_file << currentOutput.c_str();
|
golden_run_file << currentOutput.c_str();
|
||||||
log << "Output successfully logged!" << endl;
|
log << "Output successfully logged!" << endl;
|
||||||
@ -395,50 +401,12 @@ void L4SysExperiment::goldenRun(fail::BPSingleListener& bp)
|
|||||||
|
|
||||||
log << "saving output generated during normal execution" << endl;
|
log << "saving output generated during normal execution" << endl;
|
||||||
golden_run_file.close();
|
golden_run_file.close();
|
||||||
|
delete bp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool L4SysExperiment::run() {
|
void L4SysExperiment::getJobParameters()
|
||||||
BPSingleListener bp(0, L4SYS_ADDRESS_SPACE);
|
{
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
log << "startup" << endl;
|
|
||||||
|
|
||||||
#if PREPARATION_STEP == 1
|
|
||||||
// STEP 1: run until interesting function starts, and save state
|
|
||||||
startAndSaveInitState(bp);
|
|
||||||
#elif PREPARATION_STEP == 2
|
|
||||||
// STEP 2: determine instructions executed
|
|
||||||
collectInstructionTrace(bp);
|
|
||||||
|
|
||||||
#elif PREPARATION_STEP == 3
|
|
||||||
// STEP 3: determine the output of a "golden run"
|
|
||||||
goldenRun(bp);
|
|
||||||
|
|
||||||
#elif PREPARATION_STEP == 0
|
|
||||||
// LAST STEP: The actual experiment.
|
|
||||||
struct stat teststruct;
|
|
||||||
if (stat(L4SYS_STATE_FOLDER, &teststruct) == -1 ||
|
|
||||||
stat(L4SYS_CORRECT_OUTPUT, &teststruct) == -1) {
|
|
||||||
log << "Important data missing - call \"prepare\" first." << endl;
|
|
||||||
terminate(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the golden run output for validation purposes
|
|
||||||
std::string golden_run;
|
|
||||||
ifstream golden_run_file(L4SYS_CORRECT_OUTPUT);
|
|
||||||
|
|
||||||
if (!golden_run_file.good()) {
|
|
||||||
log << "Could not open file " << L4SYS_CORRECT_OUTPUT << endl;
|
|
||||||
terminate(20);
|
|
||||||
}
|
|
||||||
golden_run.reserve(teststruct.st_size);
|
|
||||||
|
|
||||||
golden_run.assign((istreambuf_iterator<char>(golden_run_file)),
|
|
||||||
istreambuf_iterator<char>());
|
|
||||||
|
|
||||||
golden_run_file.close();
|
|
||||||
|
|
||||||
// get the experiment parameters
|
// get the experiment parameters
|
||||||
log << "asking job server for experiment parameters" << endl;
|
log << "asking job server for experiment parameters" << endl;
|
||||||
if (!m_jc.getParam(*param)) {
|
if (!m_jc.getParam(*param)) {
|
||||||
@ -446,203 +414,250 @@ bool L4SysExperiment::run() {
|
|||||||
// communicate that we were told to die
|
// communicate that we were told to die
|
||||||
terminate(1);
|
terminate(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void L4SysExperiment::validatePrerequisites()
|
||||||
|
{
|
||||||
|
struct stat teststruct;
|
||||||
|
if (stat(L4SYS_STATE_FOLDER, &teststruct) == -1 ||
|
||||||
|
stat(L4SYS_CORRECT_OUTPUT, &teststruct) == -1) {
|
||||||
|
log << "Important data missing - call \"prepare\" first." << endl;
|
||||||
|
terminate(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void L4SysExperiment::readGoldenRun(std::string& target)
|
||||||
|
{
|
||||||
|
ifstream golden_run_file(L4SYS_CORRECT_OUTPUT);
|
||||||
|
|
||||||
|
if (!golden_run_file.good()) {
|
||||||
|
log << "Could not open file " << L4SYS_CORRECT_OUTPUT << endl;
|
||||||
|
terminate(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
target.assign((istreambuf_iterator<char>(golden_run_file)),
|
||||||
|
istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
golden_run_file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fail::BPSingleListener*
|
||||||
|
L4SysExperiment::prepareMemoryExperiment(int ip, int offset, int dataAddress)
|
||||||
|
{
|
||||||
|
fail::BPSingleListener *bp = new BPSingleListener(0, L4SYS_ADDRESS_SPACE);
|
||||||
|
log << "Memory fault injection at instruction " << std::hex << offset
|
||||||
|
<< ", ip " << ip << ", address " << dataAddress << std::endl;
|
||||||
|
bp->setWatchInstructionPointer(ip & 0xFFFFFFFF);
|
||||||
|
bp->setCounter(offset);
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fail::BPSingleListener*
|
||||||
|
L4SysExperiment::prepareRegisterExperiment(int ip, int offset, int dataAddress)
|
||||||
|
{
|
||||||
|
fail::BPSingleListener *bp = new BPSingleListener(0, L4SYS_ADDRESS_SPACE);
|
||||||
|
|
||||||
|
int reg, width, regOffset;
|
||||||
|
reg = ((dataAddress >> 8) & 0xF) + 1; // regs start at 1
|
||||||
|
width = (dataAddress >> 4) & 0xF;
|
||||||
|
regOffset = dataAddress & 0xF;
|
||||||
|
|
||||||
|
log << "GPR bitflip at instr. offset " << offset
|
||||||
|
<< " reg data (" << reg << ", " << width << ", "
|
||||||
|
<< regOffset << ")" << std::endl;
|
||||||
|
|
||||||
|
#ifdef L4SYS_FILTER_INSTRUCTIONS
|
||||||
|
// XXX still needed???
|
||||||
|
ifstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::binary);
|
||||||
|
|
||||||
|
if (!instr_list_file.good()) {
|
||||||
|
log << "Missing instruction trace" << endl;
|
||||||
|
terminate(21);
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceInstr curr_instr;
|
||||||
|
instr_list_file.seekg(offset * sizeof(TraceInstr));
|
||||||
|
log << instr_list_file.eof() << " " << instr_list_file.bad() << " "
|
||||||
|
<< instr_list_file.fail() << endl;
|
||||||
|
if (instr_list_file.eof()) {
|
||||||
|
log << "Job parameters indicate position outside the traced instruction list." << endl;
|
||||||
|
terminate(1);
|
||||||
|
}
|
||||||
|
instr_list_file.read(reinterpret_cast<char*>(&curr_instr), sizeof(TraceInstr));
|
||||||
|
instr_list_file.close();
|
||||||
|
|
||||||
|
log << "setting watchpoint at " << hex << curr_instr.trigger_addr << endl;
|
||||||
|
bp->setWatchInstructionPointer(curr_instr.trigger_addr);
|
||||||
|
log << "setting bp counter " << hex << curr_instr.bp_counter << endl;
|
||||||
|
bp->setCounter(curr_instr.bp_counter);
|
||||||
|
#else
|
||||||
|
bp->setWatchInstructionPointer(ANY_ADDR);
|
||||||
|
bp->setCounter(instr_offset);
|
||||||
|
#endif
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void L4SysExperiment::doMemoryInjection(int address, int bit)
|
||||||
|
{
|
||||||
|
MemoryManager& mm = simulator.getMemoryManager();
|
||||||
|
byte_t data = mm.getByte(address);
|
||||||
|
byte_t newdata = data ^ (1 << bit);
|
||||||
|
mm.setByte(address, newdata);
|
||||||
|
log << "[" << std::hex << address << "] " << (int)data
|
||||||
|
<< " -> " << (int)newdata << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void L4SysExperiment::doRegisterInjection(int regDesc, int bit)
|
||||||
|
{
|
||||||
|
int reg, width, offset;
|
||||||
|
reg = ((regDesc >> 8) & 0xF) + 1; // regs start at 1
|
||||||
|
width = (regDesc >> 4) & 0xF;
|
||||||
|
offset = regDesc & 0xF;
|
||||||
|
|
||||||
|
ConcreteCPU& cpu = simulator.getCPU(0);
|
||||||
|
Register *reg_target = cpu.getRegister(reg - 1);
|
||||||
|
regdata_t data = cpu.getRegisterContent(reg_target);
|
||||||
|
regdata_t newdata = data ^ (1 << (bit + 8 * offset));
|
||||||
|
cpu.setRegisterContent(reg_target, newdata);
|
||||||
|
log << "Reg[" << reg << "]: " << std::hex << data << " -> "
|
||||||
|
<< newdata << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool L4SysExperiment::run()
|
||||||
|
{
|
||||||
|
BPSingleListener *bp = 0;
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
log << "Starting L4Sys Experiment, phase " << PREPARATION_STEP << endl;
|
||||||
|
|
||||||
|
#if PREPARATION_STEP == 1
|
||||||
|
// STEP 1: run until interesting function starts, and save state
|
||||||
|
startAndSaveInitState(new BPSingleListener(0, L4SYS_ADDRESS_SPACE));
|
||||||
|
#elif PREPARATION_STEP == 2
|
||||||
|
// STEP 2: determine instructions executed
|
||||||
|
collectInstructionTrace(new BPSingleListener(0, L4SYS_ADDRESS_SPACE));
|
||||||
|
|
||||||
|
#elif PREPARATION_STEP == 3
|
||||||
|
// STEP 3: determine the output of a "golden run"
|
||||||
|
goldenRun(new BPSingleListener(0, L4SYS_ADDRESS_SPACE));
|
||||||
|
|
||||||
|
#elif PREPARATION_STEP == 0
|
||||||
|
// LAST STEP: The actual experiment.
|
||||||
|
validatePrerequisites();
|
||||||
|
|
||||||
|
// Read the golden run output for validation purposes
|
||||||
|
std::string golden_run;
|
||||||
|
readGoldenRun(golden_run);
|
||||||
|
|
||||||
|
getJobParameters();
|
||||||
|
|
||||||
int exp_type = param->msg.exp_type();
|
int exp_type = param->msg.exp_type();
|
||||||
int instr_offset = param->msg.fsppilot().injection_instr();
|
int instr_offset = param->msg.fsppilot().injection_instr();
|
||||||
int regData = param->msg.fsppilot().data_address();
|
int regData = param->msg.fsppilot().data_address();
|
||||||
|
|
||||||
|
|
||||||
if (exp_type == param->msg.MEM) {
|
if (exp_type == param->msg.MEM) {
|
||||||
currentOutput.clear();
|
bp = prepareMemoryExperiment(param->msg.fsppilot().injection_instr_absolute(),
|
||||||
currentOutput.reserve(teststruct.st_size);
|
param->msg.fsppilot().injection_instr(),
|
||||||
simulator.clearListeners();
|
param->msg.fsppilot().data_address());
|
||||||
|
} else if (exp_type == param->msg.GPRFLIP) {
|
||||||
log << "Memory fault injection at instruction " << std::hex << instr_offset
|
bp = prepareRegisterExperiment(param->msg.fsppilot().injection_instr_absolute(),
|
||||||
<< ", ip " << param->msg.fsppilot().injection_instr_absolute() << ", address "
|
param->msg.fsppilot().injection_instr(),
|
||||||
<< regData << std::endl;
|
param->msg.fsppilot().data_address());
|
||||||
bp.setWatchInstructionPointer(
|
} else {
|
||||||
param->msg.fsppilot().injection_instr_absolute() & 0xFFFFFFFF);
|
log << "Unsupported experiment type: " << exp_type << std::endl;
|
||||||
bp.setCounter(1);
|
terminate(1);
|
||||||
log << bp.getWatchInstructionPointer() << " - " << bp.getCounter() << std::endl;
|
|
||||||
|
|
||||||
simulator.restore(L4SYS_STATE_FOLDER);
|
|
||||||
|
|
||||||
simtime_t now = simulator.getTimerTicks();
|
|
||||||
simulator.addListener(&bp);
|
|
||||||
//and log the output
|
|
||||||
waitIOOrOther(true);
|
|
||||||
log << "Hit BP. Start time " << now << ", new time " << simulator.getTimerTicks()
|
|
||||||
<< ", diff = " << simulator.getTimerTicks() - now << std::endl;
|
|
||||||
//assert(ev == &bp);
|
|
||||||
for (unsigned bit_offset = 0; bit_offset < 8; ++bit_offset) {
|
|
||||||
currentOutput.clear();
|
|
||||||
currentOutput.reserve(teststruct.st_size);
|
|
||||||
simulator.clearListeners();
|
|
||||||
|
|
||||||
log << "restoring state" << endl;
|
|
||||||
simulator.restore(L4SYS_STATE_FOLDER);
|
|
||||||
log << simulator.getCPU(0).getInstructionPointer()
|
|
||||||
<< " injecting bit " << bit_offset << std::endl;
|
|
||||||
|
|
||||||
L4SysProtoMsg_Result *result = param->msg.add_result();
|
|
||||||
result->set_instr_offset(instr_offset);
|
|
||||||
result->set_bit_offset(bit_offset);
|
|
||||||
|
|
||||||
MemoryManager& mm = simulator.getMemoryManager();
|
|
||||||
byte_t data = mm.getByte(regData);
|
|
||||||
byte_t newdata = data ^ (1 << bit_offset);
|
|
||||||
mm.setByte(regData, newdata);
|
|
||||||
log << (int)data << " -> " << (int)newdata << std::endl;
|
|
||||||
|
|
||||||
BPSingleListener ev_done(L4SYS_FUNC_EXIT, L4SYS_ADDRESS_SPACE);
|
|
||||||
simulator.addListener(&ev_done);
|
|
||||||
|
|
||||||
unsigned instr_left = L4SYS_TOTINSTR - instr_offset; // XXX offset is in NUMINSTR, TOTINSTR is higher
|
|
||||||
BPSingleListener ev_incomplete(ANY_ADDR, L4SYS_ADDRESS_SPACE);
|
|
||||||
ev_incomplete.setCounter(static_cast<unsigned>(instr_left * 1.1));
|
|
||||||
simulator.addListener(&ev_incomplete);
|
|
||||||
|
|
||||||
TimerListener ev_timeout(calculateTimeout(instr_left));
|
|
||||||
simulator.addListener(&ev_timeout);
|
|
||||||
|
|
||||||
//do not discard output recorded so far
|
|
||||||
BaseListener *ev = waitIOOrOther(false);
|
|
||||||
|
|
||||||
/* copying a string object that contains control sequences
|
|
||||||
* unfortunately does not work with the library I am using,
|
|
||||||
* which is why output is passed on as C string and
|
|
||||||
* the string compare is done on C strings
|
|
||||||
*/
|
|
||||||
if (ev == &ev_done) {
|
|
||||||
if (strcmp(currentOutput.c_str(), golden_run.c_str()) == 0) {
|
|
||||||
log << "Result DONE" << endl;
|
|
||||||
result->set_resulttype(param->msg.DONE);
|
|
||||||
} else {
|
|
||||||
log << "Result WRONG" << endl;
|
|
||||||
result->set_resulttype(param->msg.WRONG);
|
|
||||||
result->set_output(sanitised(currentOutput.c_str()));
|
|
||||||
}
|
|
||||||
} else if (ev == &ev_incomplete) {
|
|
||||||
log << "Result INCOMPLETE" << endl;
|
|
||||||
result->set_resulttype(param->msg.INCOMPLETE);
|
|
||||||
result->set_resultdata(simulator.getCPU(0).getInstructionPointer());
|
|
||||||
result->set_output(sanitised(currentOutput.c_str()));
|
|
||||||
} else if (ev == &ev_timeout) {
|
|
||||||
log << "Result TIMEOUT" << endl;
|
|
||||||
result->set_resulttype(param->msg.TIMEOUT);
|
|
||||||
result->set_resultdata(simulator.getCPU(0).getInstructionPointer());
|
|
||||||
result->set_output(sanitised(currentOutput.c_str()));
|
|
||||||
} else {
|
|
||||||
log << "Result WTF?" << endl;
|
|
||||||
stringstream ss;
|
|
||||||
ss << "eventid " << ev;
|
|
||||||
terminateWithError(ss.str(), 50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_jc.sendResult(*param);
|
|
||||||
terminate(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int reg, width, offset;
|
assert(bp);
|
||||||
reg = ((regData >> 8) & 0xF) + 1; // regs start at 1
|
|
||||||
width = (regData >> 4) & 0xF;
|
|
||||||
offset = regData & 0xF;
|
|
||||||
|
|
||||||
log << "Inject type " << exp_type << " at instr. offset " << instr_offset
|
for (unsigned bit = 0; bit < 8; ++bit) {
|
||||||
<< " reg data (" << reg << ", " << width << ", "
|
|
||||||
<< offset << ")" << std::endl;
|
|
||||||
|
|
||||||
/* Each experiment message stands for 8 bits to be tested */
|
|
||||||
for (unsigned bit_offset = 0; bit_offset < 8; ++bit_offset) {
|
|
||||||
|
|
||||||
//the generated output probably has a similar length
|
|
||||||
currentOutput.clear();
|
|
||||||
currentOutput.reserve(teststruct.st_size);
|
|
||||||
simulator.clearListeners();
|
|
||||||
|
|
||||||
L4SysProtoMsg_Result *result = param->msg.add_result();
|
L4SysProtoMsg_Result *result = param->msg.add_result();
|
||||||
result->set_instr_offset(instr_offset);
|
result->set_instr_offset(instr_offset);
|
||||||
result->set_bit_offset(bit_offset);
|
|
||||||
result->set_register_offset(static_cast<L4SysProtoMsg_RegisterType>(reg));
|
|
||||||
|
|
||||||
// restore experiment state
|
simulator.clearListeners();
|
||||||
log << "restoring state" << endl;
|
|
||||||
simulator.restore(L4SYS_STATE_FOLDER);
|
|
||||||
log << "EIP = " << hex << simulator.getCPU(0).getInstructionPointer() << endl;
|
|
||||||
|
|
||||||
#ifdef L4SYS_FILTER_INSTRUCTIONS
|
log << "Bit " << bit << ", restoring state." << endl;
|
||||||
// XXX still needed???
|
simulator.restore(L4SYS_STATE_FOLDER);
|
||||||
ifstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::binary);
|
log << " ... EIP = " << std::hex << simulator.getCPU(0).getInstructionPointer() << std::endl;
|
||||||
|
|
||||||
|
simulator.addListener(bp);
|
||||||
|
|
||||||
|
simtime_t now = simulator.getTimerTicks();
|
||||||
|
fail::BaseListener *go = waitIOOrOther(true);
|
||||||
|
assert(go == bp);
|
||||||
|
|
||||||
|
log << "Hit BP. Start time " << now << ", new time " << simulator.getTimerTicks()
|
||||||
|
<< ", diff = " << simulator.getTimerTicks() - now << std::endl;
|
||||||
|
|
||||||
if (!instr_list_file.good()) {
|
assert(bp->getTriggerInstructionPointer() == bp->getWatchInstructionPointer());
|
||||||
log << "Missing instruction trace" << endl;
|
result->set_injection_ip(bp->getTriggerInstructionPointer());
|
||||||
terminate(21);
|
|
||||||
}
|
if (exp_type == param->msg.MEM) {
|
||||||
|
result->set_bit_offset(bit);
|
||||||
|
doMemoryInjection(param->msg.fsppilot().data_address(), bit);
|
||||||
|
} else if (exp_type == param->msg.GPRFLIP) {
|
||||||
|
result->set_bit_offset(bit + 8 * (param->msg.fsppilot().data_address() & 0xF));
|
||||||
|
doRegisterInjection(param->msg.fsppilot().data_address(), bit);
|
||||||
|
} else {
|
||||||
|
log << "doing nothing for experiment type " << exp_type << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
BPSingleListener ev_done(L4SYS_FUNC_EXIT, L4SYS_ADDRESS_SPACE);
|
||||||
|
simulator.addListener(&ev_done);
|
||||||
|
|
||||||
TraceInstr curr_instr;
|
unsigned instr_left = L4SYS_TOTINSTR - instr_offset; // XXX offset is in NUMINSTR, TOTINSTR is higher
|
||||||
instr_list_file.seekg(instr_offset * sizeof(TraceInstr));
|
BPSingleListener ev_incomplete(ANY_ADDR, L4SYS_ADDRESS_SPACE);
|
||||||
log << instr_list_file.eof() << " " << instr_list_file.bad() << " "
|
ev_incomplete.setCounter(static_cast<unsigned>(instr_left * 1.1));
|
||||||
<< instr_list_file.fail() << endl;
|
simulator.addListener(&ev_incomplete);
|
||||||
if (instr_list_file.eof()) {
|
|
||||||
log << "Job parameters indicate position outside the traced instruction list." << endl;
|
|
||||||
terminate(1);
|
|
||||||
}
|
|
||||||
instr_list_file.read(reinterpret_cast<char*>(&curr_instr), sizeof(TraceInstr));
|
|
||||||
instr_list_file.close();
|
|
||||||
|
|
||||||
log << "setting watchpoint at " << hex << curr_instr.trigger_addr << endl;
|
TimerListener ev_timeout(calculateTimeout(instr_left));
|
||||||
bp.setWatchInstructionPointer(curr_instr.trigger_addr);
|
simulator.addListener(&ev_timeout);
|
||||||
log << "setting bp counter " << hex << curr_instr.bp_counter << endl;
|
|
||||||
bp.setCounter(curr_instr.bp_counter);
|
|
||||||
#else
|
|
||||||
bp.setWatchInstructionPointer(ANY_ADDR);
|
|
||||||
bp.setCounter(instr_offset);
|
|
||||||
#endif
|
|
||||||
simulator.addListener(&bp);
|
|
||||||
//and log the output
|
|
||||||
waitIOOrOther(true);
|
|
||||||
|
|
||||||
// note at what IP we will do the injection
|
//do not discard output recorded so far
|
||||||
address_t testIP = param->msg.fsppilot().injection_instr_absolute() & 0xFFFFFFFF;
|
BaseListener *ev = waitIOOrOther(false);
|
||||||
address_t injection_ip =
|
|
||||||
simulator.getCPU(0).getInstructionPointer();
|
|
||||||
result->set_injection_ip(injection_ip);
|
|
||||||
log << std::hex << "testIP " << testIP << " <-> " << injection_ip
|
|
||||||
<< " inject_ip_abs" << std::endl;
|
|
||||||
if (testIP != injection_ip) {
|
|
||||||
stringstream ss;
|
|
||||||
ss << std::hex << "Test IP " << testIP << " does not match injection IP "
|
|
||||||
<< injection_ip << std::endl;
|
|
||||||
terminateWithError(ss.str(), 19);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef L4SYS_FILTER_INSTRUCTIONS
|
/* copying a string object that contains control sequences
|
||||||
// only works if we filter instructions
|
* unfortunately does not work with the library I am using,
|
||||||
// sanity check (only works if we're working with an instruction trace)
|
* which is why output is passed on as C string and
|
||||||
if (injection_ip != curr_instr.trigger_addr) {
|
* the string compare is done on C strings
|
||||||
stringstream ss;
|
*/
|
||||||
ss << "SANITY CHECK FAILED: " << injection_ip << " != "
|
if (ev == &ev_done) {
|
||||||
<< curr_instr.trigger_addr;
|
if (strcmp(currentOutput.c_str(), golden_run.c_str()) == 0) {
|
||||||
log << ss.str() << endl;
|
log << "Result DONE" << endl;
|
||||||
terminateWithError(ss.str(), 20);
|
result->set_resulttype(param->msg.DONE);
|
||||||
}
|
} else {
|
||||||
#endif
|
log << "Result WRONG" << endl;
|
||||||
|
result->set_resulttype(param->msg.WRONG);
|
||||||
|
result->set_output(sanitised(currentOutput.c_str()));
|
||||||
|
}
|
||||||
|
} else if (ev == &ev_incomplete) {
|
||||||
|
log << "Result INCOMPLETE" << endl;
|
||||||
|
result->set_resulttype(param->msg.INCOMPLETE);
|
||||||
|
result->set_resultdata(simulator.getCPU(0).getInstructionPointer());
|
||||||
|
result->set_output(sanitised(currentOutput.c_str()));
|
||||||
|
} else if (ev == &ev_timeout) {
|
||||||
|
log << "Result TIMEOUT" << endl;
|
||||||
|
result->set_resulttype(param->msg.TIMEOUT);
|
||||||
|
result->set_resultdata(simulator.getCPU(0).getInstructionPointer());
|
||||||
|
result->set_output(sanitised(currentOutput.c_str()));
|
||||||
|
} else {
|
||||||
|
log << "Result WTF?" << endl;
|
||||||
|
stringstream ss;
|
||||||
|
ss << "eventid " << ev;
|
||||||
|
terminateWithError(ss.str(), 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_jc.sendResult(*param);
|
||||||
|
|
||||||
// inject
|
|
||||||
if (exp_type == param->msg.GPRFLIP) {
|
|
||||||
int reg_offset = reg; // XXX redundant
|
|
||||||
ConcreteCPU& cpu = simulator.getCPU(0);
|
|
||||||
Register *reg_target = cpu.getRegister(reg_offset - 1);
|
|
||||||
regdata_t data = cpu.getRegisterContent(reg_target);
|
|
||||||
regdata_t newdata = data ^ (1 << (bit_offset + 8 * offset));
|
|
||||||
cpu.setRegisterContent(reg_target, newdata);
|
|
||||||
|
|
||||||
// do the logging in case everything worked out
|
|
||||||
logInjection();
|
|
||||||
log << "IP " << hex << simulator.getCPU(0).getInstructionPointer()
|
|
||||||
<< " register data: 0x" << hex << ((int) data) << " -> 0x"
|
|
||||||
<< ((int) newdata) << endl;
|
|
||||||
}
|
|
||||||
// XXX: Fixme to work with database campaign!
|
// XXX: Fixme to work with database campaign!
|
||||||
#if 0
|
#if 0
|
||||||
else if (exp_type == param->msg.IDCFLIP) {
|
else if (exp_type == param->msg.IDCFLIP) {
|
||||||
@ -857,58 +872,9 @@ bool L4SysExperiment::run() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// aftermath
|
|
||||||
BPSingleListener ev_done(L4SYS_FUNC_EXIT, L4SYS_ADDRESS_SPACE);
|
|
||||||
simulator.addListener(&ev_done);
|
|
||||||
|
|
||||||
unsigned instr_left = L4SYS_TOTINSTR - instr_offset; // XXX offset is in NUMINSTR, TOTINSTR is higher
|
|
||||||
BPSingleListener ev_incomplete(ANY_ADDR, L4SYS_ADDRESS_SPACE);
|
|
||||||
ev_incomplete.setCounter(static_cast<unsigned>(instr_left * 1.1));
|
|
||||||
simulator.addListener(&ev_incomplete);
|
|
||||||
|
|
||||||
TimerListener ev_timeout(calculateTimeout(instr_left));
|
|
||||||
simulator.addListener(&ev_timeout);
|
|
||||||
|
|
||||||
//do not discard output recorded so far
|
|
||||||
BaseListener *ev = waitIOOrOther(false);
|
|
||||||
|
|
||||||
/* copying a string object that contains control sequences
|
|
||||||
* unfortunately does not work with the library I am using,
|
|
||||||
* which is why output is passed on as C string and
|
|
||||||
* the string compare is done on C strings
|
|
||||||
*/
|
|
||||||
if (ev == &ev_done) {
|
|
||||||
if (strcmp(currentOutput.c_str(), golden_run.c_str()) == 0) {
|
|
||||||
log << "Result DONE" << endl;
|
|
||||||
result->set_resulttype(param->msg.DONE);
|
|
||||||
} else {
|
|
||||||
log << "Result WRONG" << endl;
|
|
||||||
result->set_resulttype(param->msg.WRONG);
|
|
||||||
result->set_output(sanitised(currentOutput.c_str()));
|
|
||||||
}
|
|
||||||
} else if (ev == &ev_incomplete) {
|
|
||||||
log << "Result INCOMPLETE" << endl;
|
|
||||||
result->set_resulttype(param->msg.INCOMPLETE);
|
|
||||||
result->set_resultdata(simulator.getCPU(0).getInstructionPointer());
|
|
||||||
result->set_output(sanitised(currentOutput.c_str()));
|
|
||||||
} else if (ev == &ev_timeout) {
|
|
||||||
log << "Result TIMEOUT" << endl;
|
|
||||||
result->set_resulttype(param->msg.TIMEOUT);
|
|
||||||
result->set_resultdata(simulator.getCPU(0).getInstructionPointer());
|
|
||||||
result->set_output(sanitised(currentOutput.c_str()));
|
|
||||||
} else {
|
|
||||||
log << "Result WTF?" << endl;
|
|
||||||
stringstream ss;
|
|
||||||
ss << "eventid " << ev;
|
|
||||||
terminateWithError(ss.str(), 50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_jc.sendResult(*param);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
terminate(0);
|
terminate(0);
|
||||||
|
|
||||||
// experiment successfully conducted
|
// experiment successfully conducted
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,16 +112,25 @@ private:
|
|||||||
* Run until L4SYS_FUNC_ENTRY and save state (experiment preparation,
|
* Run until L4SYS_FUNC_ENTRY and save state (experiment preparation,
|
||||||
* phase 1)
|
* phase 1)
|
||||||
*/
|
*/
|
||||||
void startAndSaveInitState(fail::BPSingleListener& bp);
|
void startAndSaveInitState(fail::BPSingleListener* bp);
|
||||||
/**
|
/**
|
||||||
* Collect list of executed instructions, considering instruction
|
* Collect list of executed instructions, considering instruction
|
||||||
* filtering if configured (experiment preparation, phase 2).
|
* filtering if configured (experiment preparation, phase 2).
|
||||||
*/
|
*/
|
||||||
void collectInstructionTrace(fail::BPSingleListener& bp);
|
void collectInstructionTrace(fail::BPSingleListener* bp);
|
||||||
/**
|
/**
|
||||||
* Perform the golden run (experiment preparation, phase 3)
|
* Perform the golden run (experiment preparation, phase 3)
|
||||||
*/
|
*/
|
||||||
void goldenRun(fail::BPSingleListener& bp);
|
void goldenRun(fail::BPSingleListener* bp);
|
||||||
|
|
||||||
|
void validatePrerequisites();
|
||||||
|
void getJobParameters();
|
||||||
|
void readGoldenRun(std::string& target);
|
||||||
|
|
||||||
|
fail::BPSingleListener* prepareMemoryExperiment(int ip, int offset, int dataAddress);
|
||||||
|
fail::BPSingleListener* prepareRegisterExperiment(int ip, int offset, int dataAddress);
|
||||||
|
void doMemoryInjection(int address, int bit);
|
||||||
|
void doRegisterInjection(int regDesc, int bit);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __L4SYS_EXPERIMENT_HPP__
|
#endif // __L4SYS_EXPERIMENT_HPP__
|
||||||
|
|||||||
Reference in New Issue
Block a user