experiments/cored-tester: new CoRedOS test plugin
Change-Id: I5c9785ce8d36049a585a4f6084af6938438498be
This commit is contained in:
committed by
Christian Dietrich
parent
ac55b6c814
commit
0fb6653fa8
37
src/experiments/cored-tester/CMakeLists.txt
Normal file
37
src/experiments/cored-tester/CMakeLists.txt
Normal file
@ -0,0 +1,37 @@
|
||||
set(EXPERIMENT_NAME cored-tester)
|
||||
set(EXPERIMENT_TYPE CoredTester)
|
||||
configure_file(../instantiate-experiment.ah.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY
|
||||
)
|
||||
|
||||
## Setup desired protobuf descriptions HERE ##
|
||||
set(MY_PROTOS
|
||||
cored-tester.proto
|
||||
)
|
||||
|
||||
set(MY_CAMPAIGN_SRCS
|
||||
experiment.hpp
|
||||
experiment.cc
|
||||
campaign.hpp
|
||||
campaign.cc
|
||||
)
|
||||
|
||||
#### PROTOBUFS ####
|
||||
find_package(Protobuf REQUIRED)
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
|
||||
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-comm)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} fail-comm)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} fail-llvmdisassembler)
|
||||
|
||||
## This is the example's campaign server distributing experiment parameters
|
||||
add_executable(${EXPERIMENT_NAME}-server main.cc)
|
||||
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} ${Boost_SYSTEM_LIBRARY} -lmysqlclient -Wl,--end-group)
|
||||
install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)
|
||||
|
||||
20
src/experiments/cored-tester/campaign.cc
Normal file
20
src/experiments/cored-tester/campaign.cc
Normal file
@ -0,0 +1,20 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "campaign.hpp"
|
||||
#include "cpn/CampaignManager.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include "util/ElfReader.hpp"
|
||||
#include "util/ProtoStream.hpp"
|
||||
#include "sal/SALConfig.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
using namespace google::protobuf;
|
||||
|
||||
void CoredTesterCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) {
|
||||
CoredTesterExperimentData *data = new CoredTesterExperimentData;
|
||||
data->msg.mutable_fsppilot()->CopyFrom(pilot);
|
||||
campaignmanager.addParam(data);
|
||||
}
|
||||
|
||||
30
src/experiments/cored-tester/campaign.hpp
Normal file
30
src/experiments/cored-tester/campaign.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef __DCIAOCAMPAIGN_HPP__
|
||||
#define __DCIAOCAMPAIGN_HPP__
|
||||
|
||||
#include "cpn/DatabaseCampaign.hpp"
|
||||
#include "comm/ExperimentData.hpp"
|
||||
#include "cored-tester.pb.h"
|
||||
#include "util/ElfReader.hpp"
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
class CoredTesterExperimentData : public fail::ExperimentData {
|
||||
public:
|
||||
CoredTesterProtoMsg msg;
|
||||
CoredTesterExperimentData() : fail::ExperimentData(&msg) {}
|
||||
};
|
||||
|
||||
class CoredTesterCampaign : public fail::DatabaseCampaign {
|
||||
virtual const google::protobuf::Descriptor * cb_result_message()
|
||||
{ return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("CoredTesterProtoMsg"); }
|
||||
|
||||
virtual void cb_send_pilot(DatabaseCampaignMessage pilot);
|
||||
virtual int expected_number_of_results(std::string variant, std::string benchmark) {
|
||||
if (benchmark.find("jump") != std::string::npos)
|
||||
return 1;
|
||||
else
|
||||
return 8;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // __KESOREFCAMPAIGN_HPP__
|
||||
39
src/experiments/cored-tester/cored-tester.proto
Normal file
39
src/experiments/cored-tester/cored-tester.proto
Normal file
@ -0,0 +1,39 @@
|
||||
import "DatabaseCampaignMessage.proto";
|
||||
|
||||
message CoredTesterProtoMsg {
|
||||
required DatabaseCampaignMessage fsppilot = 1;
|
||||
|
||||
repeated group Result = 2 {
|
||||
enum ResultType {
|
||||
/* Test did the right thing */
|
||||
OK = 1;
|
||||
OK_DETECTED_ERROR = 3;
|
||||
|
||||
/* Test did the wrong thing */
|
||||
SDC_WRONG_RESULT = 4;
|
||||
|
||||
/* Test detected the error */
|
||||
ERR_TRAP = 5;
|
||||
ERR_TIMEOUT = 6;
|
||||
|
||||
ERR_ASSERT_UNKOWN = 7;
|
||||
ERR_ASSERT_SYSTEM_STATE = 8;
|
||||
ERR_ASSERT_CFG_REGION = 9;
|
||||
ERR_ASSERT_SPURIOUS = 10;
|
||||
|
||||
UNKNOWN = 20;
|
||||
NOINJECTION = 21;
|
||||
}
|
||||
|
||||
required int32 bitoffset = 1 [(sql_primary_key) = true];
|
||||
required ResultType resulttype = 2;
|
||||
required uint32 experiment_number = 3;
|
||||
|
||||
/* At which point in time did the crash occur */
|
||||
optional uint64 time_crash = 4;
|
||||
|
||||
optional uint32 original_value = 5;
|
||||
|
||||
optional string details = 6;
|
||||
}
|
||||
}
|
||||
586
src/experiments/cored-tester/experiment.cc
Normal file
586
src/experiments/cored-tester/experiment.cc
Normal file
@ -0,0 +1,586 @@
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "experiment.hpp"
|
||||
#include "sal/SALConfig.hpp"
|
||||
#include "sal/SALInst.hpp"
|
||||
#include "sal/Memory.hpp"
|
||||
#include "sal/Listener.hpp"
|
||||
|
||||
#include "sal/bochs/BochsListener.hpp"
|
||||
#include "sal/bochs/BochsMemory.hpp"
|
||||
#include "sal/bochs/BochsCPU.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "util/llvmdisassembler/LLVMtoFailTranslator.hpp"
|
||||
#include "util/llvmdisassembler/LLVMtoFailBochs.hpp"
|
||||
|
||||
#include "campaign.hpp"
|
||||
#include "cored-tester.pb.h"
|
||||
|
||||
#include "../plugins/randomgenerator/RandomGenerator.hpp"
|
||||
#include "../plugins/checkpoint/Checkpoint.hpp"
|
||||
|
||||
using namespace std;
|
||||
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.
|
||||
#endif
|
||||
#if !defined(CONFIG_EVENT_MEMREAD) || !defined(CONFIG_EVENT_MEMWRITE)
|
||||
#error This experiment needs: MemRead and MemWrite. Enable these in the configuration.
|
||||
#endif
|
||||
|
||||
void CoredTester::redecodeCurrentInstruction() {
|
||||
/* Flush Instruction Caches and Prefetch queue */
|
||||
BX_CPU_C *cpu_context = simulator.getCPUContext();
|
||||
cpu_context->invalidate_prefetch_q();
|
||||
cpu_context->iCache.flushICacheEntries();
|
||||
|
||||
|
||||
guest_address_t pc = simulator.getCPU(0).getInstructionPointer();
|
||||
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
|
||||
//unsigned length_in_bytes = currInstr->ilen();
|
||||
|
||||
m_log << "REDECODE INSTRUCTION @ IP 0x" << std::hex << pc << endl;
|
||||
|
||||
Bit32u eipBiased = pc + cpu_context->eipPageBias;
|
||||
Bit8u instr_plain[15];
|
||||
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
for(unsigned i=0; i<sizeof(instr_plain); i++) {
|
||||
if(!mm.isMapped(pc+i)) {
|
||||
m_log << "REDECODE: 0x" << std::hex << pc+i << "UNMAPPED" << endl;
|
||||
// TODO: error?
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mm.getBytes(pc, sizeof(instr_plain), instr_plain);
|
||||
|
||||
unsigned remainingInPage = cpu_context->eipPageWindowSize - eipBiased;
|
||||
int ret;
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (cpu_context->cpu_mode == BX_MODE_LONG_64)
|
||||
ret = cpu_context->fetchDecode64(instr_plain, currInstr, remainingInPage);
|
||||
else
|
||||
#endif
|
||||
ret = cpu_context->fetchDecode32(instr_plain, currInstr, remainingInPage);
|
||||
if (ret < 0) {
|
||||
// handle instrumentation callback inside boundaryFetch
|
||||
cpu_context->boundaryFetch(instr_plain, remainingInPage, currInstr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned CoredTester::injectBitFlip(address_t data_address, unsigned data_width, unsigned bitpos) {
|
||||
/* First 32 Registers, this might neeed adaption */
|
||||
if (data_address < (32 << 8)) {
|
||||
LLVMtoFailTranslator::reginfo_t reginfo = LLVMtoFailTranslator::reginfo_t::fromDataAddress(data_address, data_width);
|
||||
|
||||
unsigned int value, injectedval;
|
||||
|
||||
value = m_ltof->getRegisterContent(simulator.getCPU(0), reginfo);
|
||||
injectedval = value ^ (1 << bitpos);
|
||||
m_ltof->setRegisterContent(simulator.getCPU(0), reginfo, injectedval);
|
||||
|
||||
m_log << "INJECTING register (" << dec << reginfo.id
|
||||
<< " offset " << (int) reginfo.offset
|
||||
<< ") bitpos: " << bitpos
|
||||
<< " value: 0x" << hex << setw(2) << setfill('0') << value << " -> 0x" << setw(2) << setfill('0') << injectedval
|
||||
<< dec << endl;
|
||||
if (reginfo.id == RID_PC)
|
||||
redecodeCurrentInstruction();
|
||||
|
||||
return value;
|
||||
} else {
|
||||
unsigned int value, injectedval;
|
||||
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
if(!mm.isMapped(data_address)) {
|
||||
m_log << "DATA_ADDRESS NOT MAPPED" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = mm.getByte(data_address);
|
||||
injectedval = value ^ (1 << bitpos);
|
||||
mm.setByte(data_address, injectedval);
|
||||
|
||||
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;
|
||||
|
||||
/* If it is the current instruction redecode it */
|
||||
guest_address_t pc = simulator.getCPU(0).getInstructionPointer();
|
||||
m_log << "IP: 0x" << std::hex << pc << std::endl;
|
||||
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
|
||||
assert(currInstr != NULL && "FATAL ERROR: current instruction was NULL (not expected)!");
|
||||
unsigned length_in_bytes = currInstr->ilen();
|
||||
|
||||
if (currInstr == NULL || (pc <= data_address && data_address <= (pc + currInstr->ilen()))) {
|
||||
redecodeCurrentInstruction();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handleEvent(CoredTesterProtoMsg_Result& result, CoredTesterProtoMsg_Result_ResultType restype, const std::string &msg) {
|
||||
cout << msg << endl;
|
||||
result.set_resulttype(restype);
|
||||
result.set_details(msg);
|
||||
}
|
||||
|
||||
|
||||
std::string handleMemoryAccessEvent(fail::MemAccessListener* l_mem) {
|
||||
stringstream sstr;
|
||||
|
||||
sstr << "mem access (";
|
||||
switch (l_mem->getTriggerAccessType()) {
|
||||
case MemAccessEvent::MEM_READ:
|
||||
sstr << "r";
|
||||
break;
|
||||
case MemAccessEvent::MEM_WRITE:
|
||||
sstr << "w";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sstr << ") @ 0x" << hex << l_mem->getTriggerAddress();
|
||||
sstr << "; ip @ 0x" << hex << l_mem->getTriggerInstructionPointer();
|
||||
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
|
||||
const ElfSymbol& CoredTester::getELFSymbol(const std::string name) {
|
||||
const ElfSymbol &symbol = m_elf.getSymbol(name);
|
||||
if (!symbol.isValid()) {
|
||||
m_log << "Couldn't find symbol: " << name << std::endl;
|
||||
simulator.terminate(1);
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
|
||||
bool CoredTester::run() {
|
||||
m_log << "STARTING EXPERIMENT" << endl;
|
||||
|
||||
// seed random number generator
|
||||
timeval start;
|
||||
gettimeofday(&start, NULL);
|
||||
srand(start.tv_usec);
|
||||
|
||||
// get symbols
|
||||
const ElfSymbol &s_trace_end_marker = getELFSymbol("test_finish");
|
||||
BPSingleListener l_trace_end_marker(s_trace_end_marker.getAddress());
|
||||
|
||||
const ElfSymbol &s_stext_app = getELFSymbol("_stext_application");
|
||||
const ElfSymbol &s_etext_app = getELFSymbol("_etext_application");
|
||||
|
||||
const ElfSymbol &s_panic_handler = getELFSymbol("irq_handler_2");
|
||||
|
||||
const ElfSymbol &s_fail_trace = getELFSymbol("fail_trace");
|
||||
MemAccessListener l_fail_trace(s_fail_trace.getAddress());
|
||||
|
||||
const ElfSymbol &s_random_source = m_elf.getSymbol("random_source");
|
||||
|
||||
const ElfSymbol &s_color_assert_port = m_elf.getSymbol("color_assert_port");
|
||||
MemAccessListener l_color_assert_port(s_color_assert_port, MemAccessEvent::MEM_WRITE);
|
||||
|
||||
// allowed regions
|
||||
address_t text_tasks_start = s_stext_app.getAddress();
|
||||
address_t text_tasks_end = s_etext_app.getAddress();
|
||||
|
||||
m_log << "not injecting in application: " << std::hex << text_tasks_start << " -- " << text_tasks_end << std::endl;
|
||||
|
||||
// listeners for traps, code region
|
||||
//InterruptListener l_interrupt(2); // NMI interrupt
|
||||
//TrapListener l_trap(2); // NMI trap?
|
||||
BPSingleListener l_panic(s_panic_handler.getAddress());
|
||||
m_log << "PANIC handler @ " << std::hex << s_panic_handler.getAddress() << std::endl;
|
||||
|
||||
unsigned i_timeout = 50 * 1000;
|
||||
TimerListener l_timeout(i_timeout); // 1s in microseconds
|
||||
TimerListener l_timeout_hard(1 * 1000 * 1000); // 1s in microseconds
|
||||
|
||||
// initialize LLVM disassembler
|
||||
m_ltof = LLVMtoFailTranslator::createFromBinary(m_elf.getFilename());
|
||||
|
||||
// memory manager
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
|
||||
// job client with environment parameters
|
||||
char* server = getenv("FAIL_SERVER_HOST");
|
||||
if(server == NULL) server = (char*) SERVER_COMM_HOSTNAME;
|
||||
char* cport = getenv("FAIL_SERVER_PORT");
|
||||
int port = (cport != NULL) ? atoi(cport) : SERVER_COMM_TCP_PORT;
|
||||
fail::JobClient jobclient(server, port);
|
||||
|
||||
// execute jobs
|
||||
unsigned executed_jobs = 0;
|
||||
while (executed_jobs < 25 || jobclient.getNumberOfUndoneJobs() > 0) {
|
||||
// get next parameters from jobserver
|
||||
m_log << "asking jobserver for parameters" << endl;
|
||||
CoredTesterExperimentData param;
|
||||
if(!jobclient.getParam(param)){
|
||||
m_log << "Dying." << endl; // We were told to die.
|
||||
simulator.terminate(0);
|
||||
}
|
||||
|
||||
// extract parameters
|
||||
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();
|
||||
|
||||
// detect wheter we should inject the PC
|
||||
bool pc_injection = param.msg.fsppilot().benchmark().find("jump") != std::string::npos;
|
||||
|
||||
// setup experiments
|
||||
int experiments = pc_injection ? 1 : 8;
|
||||
|
||||
// run experiments
|
||||
for (int experiment_id = 0; experiment_id < experiments; ++experiment_id) {
|
||||
CoredTesterProtoMsg_Result *result = 0;
|
||||
|
||||
// restore to the image
|
||||
m_log << "restoring state" << endl;
|
||||
simulator.clearListeners(this);
|
||||
simulator.restore("state");
|
||||
m_log << "state restored" << endl;
|
||||
executed_jobs++;
|
||||
|
||||
// Check for Read Only Memory
|
||||
if (0x100000 <= data_address && data_address < 0x200000) {
|
||||
result = param.msg.add_result();
|
||||
handleEvent(*result, result->NOINJECTION, "ROM");
|
||||
|
||||
result->set_experiment_number(0);
|
||||
result->set_bitoffset(experiment_id);
|
||||
result->set_original_value(0);
|
||||
continue; // Produce experiments results
|
||||
}
|
||||
|
||||
// Extract stack ranges for checkpoint plugin
|
||||
Checkpoint::range_vector check_ranges;
|
||||
ElfReader::symbol_iterator it = m_elf.sym_begin();
|
||||
for( ; it != m_elf.sym_end(); ++it) {
|
||||
const std::string name = it->getName();
|
||||
|
||||
size_t pos = name.rfind("_stack");
|
||||
if((pos == std::string::npos) || (pos != (name.size() - 6))) continue;
|
||||
|
||||
const ElfSymbol &s_end = m_elf.getSymbol(name); // *it ?
|
||||
const std::string ptr_name = "OS_" + name + "ptr";
|
||||
stringstream ptrstr;
|
||||
ptrstr << "_ZN4arch";
|
||||
ptrstr << ptr_name.size();
|
||||
ptrstr << ptr_name;
|
||||
ptrstr << "E";
|
||||
const ElfSymbol &s_sptr = m_elf.getSymbol(ptrstr.str());
|
||||
if(!s_sptr.isValid()) {
|
||||
m_log << "no stack end symbol for " << name << " (" << ptrstr.str() << "), skipping!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_log << "found task stack symbol: " << name << std::endl;
|
||||
|
||||
Checkpoint::indirectable_address_t start = std::make_pair(s_sptr.getAddress(), true);
|
||||
Checkpoint::indirectable_address_t end = std::make_pair(s_end.getEnd(), false);
|
||||
check_ranges.push_back(std::make_pair(start, end));
|
||||
}
|
||||
|
||||
// Init Plugins
|
||||
Checkpoint cpoint(check_ranges, "checkpoint.trace");
|
||||
|
||||
RandomGenerator* rgen;
|
||||
if (s_random_source.isValid()) {
|
||||
const unsigned seed = 12342;
|
||||
rgen = new RandomGenerator(s_random_source, seed);
|
||||
simulator.addFlow(rgen);
|
||||
}
|
||||
|
||||
// fast forward to injection address
|
||||
m_log << "Trying to inject @ instr #" << dec << injection_instr << endl;
|
||||
simulator.clearListeners(this);
|
||||
simulator.addListener(&l_fail_trace);
|
||||
|
||||
BPSingleListener bp;
|
||||
bp.setWatchInstructionPointer(ANY_ADDR);
|
||||
// TODO: why does this need a +1?
|
||||
bp.setCounter(injection_instr+1);
|
||||
simulator.addListener(&bp);
|
||||
|
||||
fail::BaseListener * listener = simulator.resume();
|
||||
bool ok = true;
|
||||
|
||||
while ( ok && (listener == &l_fail_trace) ) {
|
||||
// m_log << "CP IP 0x" << std::hex << simulator.getCPU(0).getInstructionPointer() << std::endl;
|
||||
ok = cpoint.check(s_fail_trace, l_fail_trace.getTriggerInstructionPointer()) == Checkpoint::IDENTICAL;
|
||||
if(ok) listener = simulator.addListenerAndResume(&l_fail_trace);
|
||||
}
|
||||
|
||||
unsigned experiment_number = cpoint.getCount();
|
||||
|
||||
if(!ok) {
|
||||
result = param.msg.add_result();
|
||||
handleEvent(*result, result->NOINJECTION, "CHECKPOINT FAIL BEFORE INJECTION?!");
|
||||
|
||||
result->set_experiment_number((unsigned int) experiment_number);
|
||||
result->set_bitoffset(experiment_id);
|
||||
result->set_original_value(0);
|
||||
|
||||
break;
|
||||
}
|
||||
if (listener != &bp) {
|
||||
result = param.msg.add_result();
|
||||
handleEvent(*result, result->NOINJECTION, "WTF");
|
||||
|
||||
result->set_experiment_number((unsigned int) experiment_number);
|
||||
result->set_bitoffset(experiment_id);
|
||||
result->set_original_value(0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// program counter sanity check
|
||||
if (param.msg.fsppilot().has_injection_instr_absolute()) {
|
||||
address_t PC = param.msg.fsppilot().injection_instr_absolute();
|
||||
if (simulator.getCPU(0).getInstructionPointer() != PC) {
|
||||
m_log << "Invalid injection address EIP=0x"
|
||||
<< std::hex << simulator.getCPU(0).getInstructionPointer()
|
||||
<< " != injection_instr_absolute=0x" << PC << std::endl;
|
||||
simulator.terminate(1);
|
||||
}
|
||||
}
|
||||
|
||||
m_log << "Trace " << std::dec << experiment_number << std::endl;
|
||||
result = param.msg.add_result();
|
||||
result->set_experiment_number((unsigned int) experiment_number);
|
||||
result->set_bitoffset(experiment_id);
|
||||
result->set_original_value(0);
|
||||
|
||||
// abort if outside targeted region
|
||||
address_t PC = simulator.getCPU(0).getInstructionPointer();
|
||||
//if(PC < min_code || PC > max_code) {
|
||||
if(PC < text_tasks_end && PC >= text_tasks_start) {
|
||||
std::stringstream ss;
|
||||
ss << "0x" << hex << PC;
|
||||
ss << " inside task text: ";
|
||||
ss << "0x" << hex << text_tasks_start << " - 0x" << hex << text_tasks_end;
|
||||
handleEvent(*result, result->NOINJECTION, ss.str());
|
||||
continue; // next experiment
|
||||
}
|
||||
|
||||
// perform injection
|
||||
if (pc_injection) {
|
||||
// jump to "data" address
|
||||
address_t current_PC = simulator.getCPU(0).getInstructionPointer();
|
||||
address_t new_PC = param.msg.fsppilot().data_address();
|
||||
m_log << "jump from 0x" << hex << current_PC << " to 0x" << new_PC << std::endl;
|
||||
simulator.getCPU(0).setRegisterContent(simulator.getCPU(0).getRegister(RID_PC), new_PC);
|
||||
|
||||
// set program counter
|
||||
result->set_bitoffset(0);
|
||||
result->set_original_value(current_PC);
|
||||
redecodeCurrentInstruction();
|
||||
} else {
|
||||
// inject random bitflip
|
||||
// experiment_id == bitpos
|
||||
result->set_original_value(injectBitFlip(data_address, data_width, experiment_id));
|
||||
}
|
||||
|
||||
|
||||
// add listeners
|
||||
simulator.clearListeners(this);
|
||||
simulator.addListener(&l_panic);
|
||||
simulator.addListener(&l_timeout);
|
||||
simulator.addListener(&l_fail_trace);
|
||||
simulator.addListener(&l_color_assert_port);
|
||||
simulator.addListener(&l_trace_end_marker);
|
||||
|
||||
// BPSingleListener single_step;
|
||||
// single_step.setWatchInstructionPointer(ANY_ADDR);
|
||||
// simulator.addListener(&single_step);
|
||||
// fail::BaseListener* ll = simulator.resume();
|
||||
// while (ll == &single_step || ll == &l_fail_trace) {
|
||||
// if (ll == &l_fail_trace) {
|
||||
// Checkpoint::check_result res = cpoint.check(s_fail_trace, l_fail_trace.getTriggerInstructionPointer());
|
||||
|
||||
// if(res == Checkpoint::DIFFERENT_IP) {
|
||||
// std::stringstream ss;
|
||||
// ss << "different IP";
|
||||
// ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
// ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
// std::cout << ss.str() << endl;
|
||||
// break;
|
||||
// } else if(res == Checkpoint::DIFFERENT_VALUE) {
|
||||
// std::stringstream ss;
|
||||
// ss << "different value";
|
||||
// ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
// ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
// std::cout << ss.str() << endl;
|
||||
// break;
|
||||
// } else if(res == Checkpoint::DIFFERENT_DIGEST) {
|
||||
// std::stringstream ss;
|
||||
// ss << "different digest";
|
||||
// ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
// ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
// std::cout << ss.str() << endl;
|
||||
// break;
|
||||
// } else if(res == Checkpoint::INVALID) {
|
||||
// std::stringstream ss;
|
||||
// ss << "invalid checkpoint";
|
||||
// ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
// ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
// std::cout << ss.str() << endl;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// std::stringstream ss;
|
||||
// ss << "@ IP " << std::hex << simulator.getCPU(0).getInstructionPointer();
|
||||
// const ElfSymbol &sym = m_elf.getSymbol(simulator.getCPU(0).getInstructionPointer());
|
||||
// ss << " " << sym.getName();
|
||||
// std::cout << ss.str() << endl;
|
||||
// ll = simulator.addListenerAndResume(ll);
|
||||
// }
|
||||
|
||||
// std::cout << (ll == &l_color_assert_port) << " COLOR ASSERT" << endl;
|
||||
|
||||
// //continue;
|
||||
// simulator.terminate(0);
|
||||
|
||||
// resume and wait for results
|
||||
m_log << "Resuming till the crash (time: " << simulator.getTimerTicks() << ")"<< std::endl;
|
||||
bool reached_check_start = false;
|
||||
fail::BaseListener* l = simulator.resume();
|
||||
|
||||
while(l == &l_fail_trace) {
|
||||
Checkpoint::check_result res = cpoint.check(s_fail_trace, l_fail_trace.getTriggerInstructionPointer());
|
||||
if(res == Checkpoint::DIFFERENT_IP) {
|
||||
std::stringstream ss;
|
||||
ss << "different IP";
|
||||
ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
handleEvent(*result, result->SDC_WRONG_RESULT, ss.str());
|
||||
break;
|
||||
} else if(res == Checkpoint::DIFFERENT_VALUE) {
|
||||
std::stringstream ss;
|
||||
ss << "different value";
|
||||
ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
handleEvent(*result, result->SDC_WRONG_RESULT, ss.str());
|
||||
break;
|
||||
} else if(res == Checkpoint::DIFFERENT_DIGEST) {
|
||||
std::stringstream ss;
|
||||
ss << "different digest";
|
||||
ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
handleEvent(*result, result->SDC_WRONG_RESULT, ss.str());
|
||||
break;
|
||||
} else if(res == Checkpoint::INVALID) {
|
||||
std::stringstream ss;
|
||||
ss << "invalid checkpoint";
|
||||
ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
handleEvent(*result, result->SDC_WRONG_RESULT, ss.str());
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset the soft timeout listener
|
||||
simulator.removeListener(&l_timeout);
|
||||
simulator.addListener(&l_timeout);
|
||||
assert(l_timeout.getTimeout() == i_timeout);
|
||||
|
||||
l = simulator.addListenerAndResume(&l_fail_trace);
|
||||
}
|
||||
|
||||
// End of Injection Phase. Now we have crashed
|
||||
m_log << "Crashed (time: " << simulator.getTimerTicks() << ")"<< std::endl;
|
||||
result->set_time_crash(simulator.getTimerTicks());
|
||||
|
||||
if(l == &l_fail_trace) {
|
||||
// already reported invalid checkpoint
|
||||
} else if(l == &l_trace_end_marker) {
|
||||
// trace ended successfully
|
||||
std::stringstream ss;
|
||||
ss << "correct end after " << cpoint.getCount() << " checkpoints";
|
||||
handleEvent(*result, result->OK, ss.str());
|
||||
} else if (l == &l_panic) {
|
||||
// error detected
|
||||
stringstream sstr;
|
||||
sstr << "PANIC";
|
||||
|
||||
// CoRedOS specific trap information
|
||||
const Register *reg_eax = simulator.getCPU(0).getRegister(RID_CAX);
|
||||
uint32_t trap = simulator.getCPU(0).getRegisterContent(reg_eax);
|
||||
sstr << " trap " << dec << trap;
|
||||
|
||||
//address_t sp = simulator.getCPU(0).getStackPointer();
|
||||
//if(mm.isMapped(sp)) {
|
||||
// uint32_t ip;
|
||||
// mm.getBytes(sp, 4, &ip);
|
||||
// sstr << " @ 0x" << hex << ip;
|
||||
|
||||
const Register *reg_esi = simulator.getCPU(0).getRegister(RID_CSI);
|
||||
address_t sp = simulator.getCPU(0).getRegisterContent(reg_esi) + 4;
|
||||
if(mm.isMapped(sp) && mm.isMapped(sp+1) && mm.isMapped(sp+2) && mm.isMapped(sp+3)) {
|
||||
|
||||
uint32_t ip;
|
||||
mm.getBytes(sp, 4, &ip);
|
||||
sstr << " from 0x" << hex << ip;
|
||||
}
|
||||
|
||||
handleEvent(*result, result->OK_DETECTED_ERROR, sstr.str());
|
||||
} else if ( l == &l_color_assert_port ) {
|
||||
// A colored assert has occured
|
||||
uint32_t color = 0;
|
||||
mm.getBytes(s_color_assert_port.getAddress(), 4, &color);
|
||||
std::stringstream ss;
|
||||
ss << "@ IP" << std::hex << simulator.getCPU(0).getInstructionPointer();
|
||||
|
||||
if (color == 0xb83829de) {
|
||||
handleEvent(*result, result->ERR_ASSERT_UNKOWN, ss.str());
|
||||
} else if (color == 0xf4d9f7ca) {
|
||||
handleEvent(*result, result->ERR_ASSERT_CFG_REGION, ss.str());
|
||||
} else if (color == 0x9451210d) {
|
||||
handleEvent(*result, result->ERR_ASSERT_SYSTEM_STATE, ss.str());
|
||||
} else {
|
||||
handleEvent(*result, result->ERR_ASSERT_SPURIOUS, ss.str());
|
||||
}
|
||||
} else if ( l == &l_timeout || l == &l_timeout_hard) {
|
||||
// timeout, probably infinite loop
|
||||
handleEvent(*result, result->ERR_TIMEOUT, "");
|
||||
} else {
|
||||
// what happened?
|
||||
handleEvent(*result, result->UNKNOWN, "WTF");
|
||||
}
|
||||
|
||||
// For RandomJump do only one experiment not 8
|
||||
if (pc_injection) break;
|
||||
}
|
||||
|
||||
// send results
|
||||
jobclient.sendResult(param);
|
||||
}
|
||||
|
||||
// explicitly terminate, or the simulator will continue to run
|
||||
simulator.terminate();
|
||||
}
|
||||
|
||||
33
src/experiments/cored-tester/experiment.hpp
Normal file
33
src/experiments/cored-tester/experiment.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef __CORED_TESTER_EXPERIMENT_HPP__
|
||||
#define __CORED_TESTER_EXPERIMENT_HPP__
|
||||
|
||||
|
||||
#include "sal/SALInst.hpp"
|
||||
#include "efw/ExperimentFlow.hpp"
|
||||
#include "efw/JobClient.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include "util/ElfReader.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "util/llvmdisassembler/LLVMtoFailTranslator.hpp"
|
||||
|
||||
class CoredTester : public fail::ExperimentFlow {
|
||||
public:
|
||||
|
||||
private:
|
||||
fail::Logger m_log;
|
||||
fail::MemoryManager& m_mm;
|
||||
fail::ElfReader m_elf;
|
||||
fail::LLVMtoFailTranslator* m_ltof;
|
||||
|
||||
unsigned injectBitFlip(fail::address_t data_address, unsigned data_width, unsigned bitpos);
|
||||
void redecodeCurrentInstruction();
|
||||
const fail::ElfSymbol& getELFSymbol(const std::string name);
|
||||
|
||||
public:
|
||||
CoredTester() : m_log("CoredTester", false), m_mm(fail::simulator.getMemoryManager()) {}
|
||||
|
||||
bool run();
|
||||
};
|
||||
|
||||
#endif
|
||||
20
src/experiments/cored-tester/main.cc
Normal file
20
src/experiments/cored-tester/main.cc
Normal file
@ -0,0 +1,20 @@
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#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]);
|
||||
|
||||
CoredTesterCampaign c;
|
||||
if (fail::campaignmanager.runCampaign(&c)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user