|
|
|
|
@ -10,19 +10,21 @@
|
|
|
|
|
#include "util/WallclockTimer.hpp"
|
|
|
|
|
|
|
|
|
|
#include "util/gzstream/gzstream.h"
|
|
|
|
|
#include "util/WallclockTimer.hpp"
|
|
|
|
|
|
|
|
|
|
#include "efw/JobClient.hpp"
|
|
|
|
|
|
|
|
|
|
#include "lra_simple.pb.h"
|
|
|
|
|
#include "campaign.hpp"
|
|
|
|
|
|
|
|
|
|
#include "cpn/InjectionPoint.hpp"
|
|
|
|
|
#include "config/FailConfig.hpp"
|
|
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
// you need to have the tracing plugin enabled for this
|
|
|
|
|
#include "../plugins/tracing/TracingPlugin.hpp"
|
|
|
|
|
|
|
|
|
|
@ -36,10 +38,26 @@ using namespace fail;
|
|
|
|
|
|
|
|
|
|
#define PREPARATION 0
|
|
|
|
|
|
|
|
|
|
int32_t correct_result[100] = {
|
|
|
|
|
0, 6, 5, 1, 6, 2, 7, 3,
|
|
|
|
|
8, 4, 1, 6, 5, 9, 5, 3,
|
|
|
|
|
0, 6, 5, 3, 7, 1, 7, 2,
|
|
|
|
|
8, 3, 9, 4, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ToDo: Move this functionality to SimulatorController
|
|
|
|
|
void LRASimplePandaExperiment::navigateToInjectionPoint(ConcreteInjectionPoint &ip) {
|
|
|
|
|
Logger log_nav("navigator");
|
|
|
|
|
bool LRASimplePandaExperiment::navigateToInjectionPoint(ConcreteInjectionPoint &ip) {
|
|
|
|
|
Logger log_nav("navigator", false);
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_INJECTIONPOINT_HOPS
|
|
|
|
|
// Hop nav
|
|
|
|
|
@ -60,6 +78,10 @@ void LRASimplePandaExperiment::navigateToInjectionPoint(ConcreteInjectionPoint &
|
|
|
|
|
InjectionPointMessage_Hops h = ipm.hops(i);
|
|
|
|
|
BaseListener *hop, *ev;
|
|
|
|
|
|
|
|
|
|
// Nav-fail-bp
|
|
|
|
|
BPSingleListener ev_func_end(elfReader->getSymbol("main").getEnd() - 4 - LRASP_MAIN_ENDOFFSET);
|
|
|
|
|
simulator.addListener(&ev_func_end);
|
|
|
|
|
|
|
|
|
|
if (h.accesstype() == h.EXECUTE) {
|
|
|
|
|
log_nav << "BP at " << hex << h.address() << dec << endl;
|
|
|
|
|
BPSingleListener bp (h.address());
|
|
|
|
|
@ -76,56 +98,69 @@ void LRASimplePandaExperiment::navigateToInjectionPoint(ConcreteInjectionPoint &
|
|
|
|
|
|
|
|
|
|
log_nav << "Halted" << endl;
|
|
|
|
|
|
|
|
|
|
if (ev == &ev_func_end) {
|
|
|
|
|
log_nav << "Navigational error..." << endl;
|
|
|
|
|
simulator.clearListeners();
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
simulator.removeListener(&ev_func_end);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ev != hop) {
|
|
|
|
|
log_nav << "FATAL ERROR: Unexpected event while navigating!" << endl;
|
|
|
|
|
simulator.terminate(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
// Step nav
|
|
|
|
|
InjectionPointMessage ipm;
|
|
|
|
|
ip.copyInjectionPointMessage(ipm);
|
|
|
|
|
log_nav << ipm.injection_instr() << endl;
|
|
|
|
|
log_nav << "Navigating to instruction " << ipm.injection_instr() << endl;
|
|
|
|
|
BPSingleListener step(ANY_ADDR);
|
|
|
|
|
step.setCounter(ipm.injection_instr());
|
|
|
|
|
simulator.addListenerAndResume(&step);
|
|
|
|
|
#endif
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LRASimplePandaExperiment::run()
|
|
|
|
|
{
|
|
|
|
|
Logger _log("lra-simpla-panda", false);
|
|
|
|
|
_log << "Startup" << endl;
|
|
|
|
|
|
|
|
|
|
fail::ElfReader elfReader;
|
|
|
|
|
fail::JobClient jobClient;
|
|
|
|
|
Logger logger("lra-simpla-panda", false);
|
|
|
|
|
logger << "Startup" << endl;
|
|
|
|
|
|
|
|
|
|
elfReader = new ElfReader();
|
|
|
|
|
fail::JobClient *jobClient = new JobClient();
|
|
|
|
|
|
|
|
|
|
#if PREPARATION == 1
|
|
|
|
|
_log << "Preparation mode" << endl;
|
|
|
|
|
logger << "Preparation mode" << endl;
|
|
|
|
|
|
|
|
|
|
// STEP 1: run until main starts, save state, record trace
|
|
|
|
|
// TODO: store golden run output
|
|
|
|
|
BPSingleListener func_begin(elfReader.getSymbol("test_code_due").getAddress());
|
|
|
|
|
BPSingleListener func_begin(elfReader->getSymbol("main").getStart());
|
|
|
|
|
simulator.addListenerAndResume(&func_begin);
|
|
|
|
|
|
|
|
|
|
_log << "test_func() reached, beginning trace recording" << endl;
|
|
|
|
|
logger << "test_func() reached, beginning trace recording" << endl;
|
|
|
|
|
|
|
|
|
|
TracingPlugin tp;
|
|
|
|
|
|
|
|
|
|
// ogzstream of(LRASP_TRACE);
|
|
|
|
|
ofstream of(LRASP_TRACE);
|
|
|
|
|
ogzstream of(LRASP_TRACE);
|
|
|
|
|
if (of.bad()) {
|
|
|
|
|
_log << "FATAL ERROR: Trace file could not be opened." << endl;
|
|
|
|
|
logger << "FATAL ERROR: Trace file could not be opened." << endl;
|
|
|
|
|
simulator.terminate();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tp.setTraceFile(&of);
|
|
|
|
|
//tp.setOstream(&of);
|
|
|
|
|
tp.setOstream(&of);
|
|
|
|
|
// this must be done *after* configuring the plugin:
|
|
|
|
|
simulator.addFlow(&tp);
|
|
|
|
|
|
|
|
|
|
BPSingleListener func_end(elfReader.getSymbol("test_code_due").getAddress() + elfReader.getSymbol("test_code_due").getSize() - 4);
|
|
|
|
|
BPSingleListener func_end(elfReader->getSymbol("main").getEnd() - 4 - 28);
|
|
|
|
|
simulator.addListener(&func_end);
|
|
|
|
|
BPSingleListener step(ANY_ADDR);
|
|
|
|
|
|
|
|
|
|
WallclockTimer timer;
|
|
|
|
|
timer.startTimer();
|
|
|
|
|
|
|
|
|
|
// count instructions
|
|
|
|
|
long counter = 0;
|
|
|
|
|
while (true) {
|
|
|
|
|
@ -135,80 +170,207 @@ bool LRASimplePandaExperiment::run()
|
|
|
|
|
}
|
|
|
|
|
counter++;
|
|
|
|
|
if ((counter % 1000) == 0) {
|
|
|
|
|
_log << "Traced " << counter << " insturctions" << endl;
|
|
|
|
|
of.flush();
|
|
|
|
|
timer.stopTimer();
|
|
|
|
|
logger << "Traced " << counter << " insturctions in " << timer << " seconds" << endl;
|
|
|
|
|
timer.reset();
|
|
|
|
|
timer.startTimer();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_log << "golden run took " << dec << counter << " instructions" << endl;
|
|
|
|
|
logger << "Traced " << counter << " insturctions in " << timer << " seconds" << endl << endl;
|
|
|
|
|
|
|
|
|
|
logger << "golden run took " << dec << counter << " instructions" << endl;
|
|
|
|
|
simulator.removeFlow(&tp);
|
|
|
|
|
|
|
|
|
|
of.flush();
|
|
|
|
|
// serialize trace to file
|
|
|
|
|
if (of.fail()) {
|
|
|
|
|
_log << "failed to write to trace file"<< std::endl;
|
|
|
|
|
logger << "failed to write to trace file"<< std::endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
of.close();
|
|
|
|
|
#else
|
|
|
|
|
#else // PREPARATION
|
|
|
|
|
|
|
|
|
|
unsigned executed_jobs = 0;
|
|
|
|
|
|
|
|
|
|
_log << "Startup!" << endl;
|
|
|
|
|
|
|
|
|
|
// std::ofstream exp_output ("exp.txt");
|
|
|
|
|
|
|
|
|
|
ConcreteCPU cpu = simulator.getCPU(0);
|
|
|
|
|
ConcreteCPU::iterator it = cpu.begin();
|
|
|
|
|
it++; it++;
|
|
|
|
|
while (jobClient.getNumberOfUndoneJobs() > 0 || executed_jobs < 500) {
|
|
|
|
|
_log << "asking jobserver for parameters" << endl;
|
|
|
|
|
while (true) {
|
|
|
|
|
logger << "asking jobserver for parameters. Undone: "<<jobClient->getNumberOfUndoneJobs() << endl;
|
|
|
|
|
LraSimpleExperimentData param;
|
|
|
|
|
if(!jobClient.getParam(param)){
|
|
|
|
|
_log << "Dying." << endl; // We were told to die.
|
|
|
|
|
if(!jobClient->getParam(param)){
|
|
|
|
|
logger << "Dying." << endl; // We were told to die.
|
|
|
|
|
simulator.terminate(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger << "New param" << param.msg.DebugString() << endl;
|
|
|
|
|
|
|
|
|
|
// Get input data from Jobserver
|
|
|
|
|
unsigned injection_instr = param.msg.fsppilot().injection_instr();
|
|
|
|
|
address_t data_address = param.msg.fsppilot().data_address();
|
|
|
|
|
unsigned data_width = param.msg.fsppilot().data_width();
|
|
|
|
|
// unsigned data_width = param.msg.fsppilot().data_width();
|
|
|
|
|
ConcreteInjectionPoint ip;
|
|
|
|
|
ip.parseFromCampaignMessage(param.msg.fsppilot());
|
|
|
|
|
|
|
|
|
|
// ToDo: Insert into all 8 Bits
|
|
|
|
|
for (int experiment_id = 0; experiment_id < 1; ++experiment_id) {
|
|
|
|
|
LraSimpleProtoMsg_Result *result = 0;
|
|
|
|
|
for (unsigned experiment_id = 0; experiment_id < LRASP_NUM_EXP_PER_PILOT; ++experiment_id) {
|
|
|
|
|
LraSimpleProtoMsg_Result *result = param.msg.add_result();
|
|
|
|
|
executed_jobs ++;
|
|
|
|
|
|
|
|
|
|
_log << "rebooting device" << endl;
|
|
|
|
|
WallclockTimer timer;
|
|
|
|
|
timer.startTimer();
|
|
|
|
|
|
|
|
|
|
/********************
|
|
|
|
|
* INITIALIZATION *
|
|
|
|
|
********************/
|
|
|
|
|
|
|
|
|
|
logger << "rebooting device" << endl;
|
|
|
|
|
|
|
|
|
|
// Restore to the image, which starts at address(main)
|
|
|
|
|
simulator.reboot();
|
|
|
|
|
executed_jobs ++;
|
|
|
|
|
|
|
|
|
|
// Fast forward to injection address
|
|
|
|
|
_log << "Trying to inject @ instr #" << dec << injection_instr << endl;
|
|
|
|
|
// In this case, no entry navigation is needed
|
|
|
|
|
// Otherwise we will have to navigate to the pre entry instruction!!!
|
|
|
|
|
BPSingleListener func_begin(elfReader->getSymbol("main").getStart());
|
|
|
|
|
simulator.addListenerAndResume(&func_begin);
|
|
|
|
|
|
|
|
|
|
navigateToInjectionPoint(ip);
|
|
|
|
|
timer.stopTimer();
|
|
|
|
|
result->set_time_init(float(timer));
|
|
|
|
|
timer.reset();
|
|
|
|
|
|
|
|
|
|
uint32_t iteration_counter;
|
|
|
|
|
simulator.getMemoryManager().getBytes(elfReader.getSymbol("test_code_idx").getAddress(), 4, (void*)(&iteration_counter));
|
|
|
|
|
/****************
|
|
|
|
|
* NAVIGATION *
|
|
|
|
|
****************/
|
|
|
|
|
logger << "Fastforwarding to instr #" << injection_instr << endl;
|
|
|
|
|
|
|
|
|
|
result = param.msg.add_result();
|
|
|
|
|
timer.startTimer();
|
|
|
|
|
if (!navigateToInjectionPoint(ip)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
timer.stopTimer();
|
|
|
|
|
result->set_time_nav(float(timer));
|
|
|
|
|
timer.reset();
|
|
|
|
|
|
|
|
|
|
/***************
|
|
|
|
|
* INJECTION *
|
|
|
|
|
***************/
|
|
|
|
|
// We do a 8-bit flip burst
|
|
|
|
|
|
|
|
|
|
// Alternatively for single-bit-flips:
|
|
|
|
|
// data ^= 1 << experiment_id;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger << "Injection bitflips at address " << hex << data_address << dec << endl;
|
|
|
|
|
|
|
|
|
|
timer.startTimer();
|
|
|
|
|
byte_t data = simulator.getMemoryManager().getByte(data_address);
|
|
|
|
|
data = ~data;
|
|
|
|
|
simulator.getMemoryManager().setByte(data_address, data); // write back data to register
|
|
|
|
|
timer.stopTimer();
|
|
|
|
|
result->set_time_inject(float(timer));
|
|
|
|
|
timer.reset();
|
|
|
|
|
|
|
|
|
|
/***************
|
|
|
|
|
* AFTERMATH *
|
|
|
|
|
***************/
|
|
|
|
|
logger << "Aftermath: Checking for wrong mem access, traps, timeout, wrong result or success" << endl;
|
|
|
|
|
|
|
|
|
|
timer.startTimer();
|
|
|
|
|
|
|
|
|
|
// Setup MMU
|
|
|
|
|
/*
|
|
|
|
|
* As the false positive rate is very high, if we watch a
|
|
|
|
|
* page with actively used memory and because of the high
|
|
|
|
|
* costs for a false positive (in the magnitude of seconds),
|
|
|
|
|
* we don't want to watch those areas.
|
|
|
|
|
*
|
|
|
|
|
* We must not watch the following areas:
|
|
|
|
|
* - UART I/O Port at 0x48020014 => don't watch page 0x48020000
|
|
|
|
|
* - .text-, .bss- and .data-segment at 0x83000000 to 0x83411000 (exclusive)
|
|
|
|
|
* - Stack at 0xBFD00000 to 0xC0000000
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
MemAccessListener ev_unauth_mem_acc_1(0x0);
|
|
|
|
|
ev_unauth_mem_acc_1.setWatchWidth(0x48020000);
|
|
|
|
|
simulator.addListener(&ev_unauth_mem_acc_1);
|
|
|
|
|
|
|
|
|
|
MemAccessListener ev_unauth_mem_acc_2(0x48021000);
|
|
|
|
|
ev_unauth_mem_acc_2.setWatchWidth(0x83000000 - 0x48021000);
|
|
|
|
|
simulator.addListener(&ev_unauth_mem_acc_2);
|
|
|
|
|
|
|
|
|
|
MemAccessListener ev_unauth_mem_acc_3(0x83411000);
|
|
|
|
|
ev_unauth_mem_acc_3.setWatchWidth(0xBFD00000 - 0x83411000);
|
|
|
|
|
simulator.addListener(&ev_unauth_mem_acc_3);
|
|
|
|
|
|
|
|
|
|
MemAccessListener ev_unauth_mem_acc_4(0xC0000000);
|
|
|
|
|
ev_unauth_mem_acc_4.setWatchWidth(0xFFFFFFFF - 0xC0000000);
|
|
|
|
|
simulator.addListener(&ev_unauth_mem_acc_4);
|
|
|
|
|
|
|
|
|
|
// Traps
|
|
|
|
|
|
|
|
|
|
TrapListener ev_trap(fail::ANY_TRAP, NULL);
|
|
|
|
|
simulator.addListener(&ev_trap);
|
|
|
|
|
|
|
|
|
|
// Timeout
|
|
|
|
|
|
|
|
|
|
TimerListener ev_timeout(LRASP_TIMEOUT);
|
|
|
|
|
simulator.addListener(&ev_timeout);
|
|
|
|
|
|
|
|
|
|
// Termination
|
|
|
|
|
|
|
|
|
|
BPSingleListener ev_func_end(elfReader->getSymbol("main").getEnd() - 4 - LRASP_MAIN_ENDOFFSET);
|
|
|
|
|
simulator.addListener(&ev_func_end);
|
|
|
|
|
|
|
|
|
|
logger << "waiting for function exit, trap or timeout(1 second)" << endl;
|
|
|
|
|
BaseListener* ev = simulator.resume();
|
|
|
|
|
|
|
|
|
|
if (ev == &ev_timeout) {
|
|
|
|
|
logger << "Timeout!" << endl;
|
|
|
|
|
result->set_resulttype(result->ERR_TIMEOUT);
|
|
|
|
|
} else if (ev == &ev_trap) {
|
|
|
|
|
logger << "Trap!" << endl;
|
|
|
|
|
result->set_resulttype(result->ERR_TRAP);
|
|
|
|
|
} else if (ev == &ev_unauth_mem_acc_1 ||
|
|
|
|
|
ev == &ev_unauth_mem_acc_2 ||
|
|
|
|
|
ev == &ev_unauth_mem_acc_3 ||
|
|
|
|
|
ev == &ev_unauth_mem_acc_4) {
|
|
|
|
|
|
|
|
|
|
result->set_resulttype(result->ERR_OUTSIDE_TEXT);
|
|
|
|
|
logger << hex << "Unauthorized memory access (" << ((((MemAccessListener*)ev)->getTriggerAccessType() == fail::MemAccessEvent::MEM_READ) ? "R" : "W") <<
|
|
|
|
|
") at instruction " << ((MemAccessListener*)ev)->getTriggerInstructionPointer() << " access address: " <<
|
|
|
|
|
((MemAccessListener*)ev)->getTriggerAddress() << dec << endl;
|
|
|
|
|
} else if (ev == &ev_func_end) {
|
|
|
|
|
logger << "Function terminated!" << endl;
|
|
|
|
|
|
|
|
|
|
int32_t results[elfReader->getSymbol("result").getSize()/sizeof(int32_t)];
|
|
|
|
|
simulator.getMemoryManager().getBytes(elfReader->getSymbol("result").getAddress(),
|
|
|
|
|
elfReader->getSymbol("result").getSize(),
|
|
|
|
|
(unsigned char*)results);
|
|
|
|
|
|
|
|
|
|
result->set_resulttype(result->OK);
|
|
|
|
|
for (unsigned i = 0; i < sizeof(results) / sizeof(*results); ++i) {
|
|
|
|
|
if (correct_result[i] != results[i]) {
|
|
|
|
|
result->set_resulttype(result->ERR_WRONG_RESULT);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
timer.stopTimer();
|
|
|
|
|
result->set_time_aftermath(float(timer));
|
|
|
|
|
|
|
|
|
|
result->set_bitoffset(experiment_id);
|
|
|
|
|
result->set_loop_iteration(iteration_counter);
|
|
|
|
|
result->set_resulttype(result->OK);
|
|
|
|
|
result->set_experiment_number(executed_jobs);
|
|
|
|
|
|
|
|
|
|
simulator.clearListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jobClient.sendResult(param);
|
|
|
|
|
jobClient->sendResult(param);
|
|
|
|
|
logger << param.debugString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_log << "jobClient.getNumberOfUndoneJobs() = " << jobClient.getNumberOfUndoneJobs() << "executed_jobs = " << executed_jobs << endl;
|
|
|
|
|
logger << "jobClient.getNumberOfUndoneJobs() = " << jobClient->getNumberOfUndoneJobs() << "executed_jobs = " << executed_jobs << endl;
|
|
|
|
|
|
|
|
|
|
#endif // PREPARATION
|
|
|
|
|
|
|
|
|
|
delete elfReader;
|
|
|
|
|
delete jobClient;
|
|
|
|
|
|
|
|
|
|
simulator.terminate();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|