nanojpeg: campaign work-in-progress
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1778 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
@ -15,24 +15,30 @@ set(MY_CAMPAIGN_SRCS
|
||||
instantiateExperiment.cc
|
||||
experiment.hpp
|
||||
experiment.cc
|
||||
campaign.hpp
|
||||
campaign.cc
|
||||
UDIS86.hpp
|
||||
UDIS86.cc
|
||||
)
|
||||
# experimentInfo.hpp
|
||||
# campaign.hpp
|
||||
# campaign.cc
|
||||
|
||||
#### PROTOBUFS ####
|
||||
#find_package(Protobuf REQUIRED)
|
||||
#include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
#include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
find_package(Protobuf REQUIRED)
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
#PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
|
||||
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
|
||||
|
||||
# dependency: libudis86
|
||||
find_package(LibUdis86 REQUIRED)
|
||||
include_directories(${LIBUDIS86_INCLUDE_DIRS})
|
||||
link_directories(${LIBUDIS86_LINK_DIRS})
|
||||
|
||||
## Build library
|
||||
add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS})
|
||||
add_dependencies(fail-${EXPERIMENT_NAME} fail-tracing)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY})
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} ${LIBUDIS86_LIBRARIES} ${PROTOBUF_LIBRARY})
|
||||
|
||||
## This is the example's campaign server distributing experiment parameters
|
||||
#add_executable(${EXPERIMENT_NAME}-server main.cc)
|
||||
#target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY})
|
||||
#install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)
|
||||
add_executable(${EXPERIMENT_NAME}-server main.cc)
|
||||
target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${Boost_THREAD_LIBRARY})
|
||||
install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)
|
||||
|
||||
30
src/experiments/nanojpeg/UDIS86.cc
Normal file
30
src/experiments/nanojpeg/UDIS86.cc
Normal file
@ -0,0 +1,30 @@
|
||||
#include "UDIS86.hpp"
|
||||
|
||||
Udis86::Udis86(fail::address_t ip)
|
||||
: udis_instr(NULL), udis_instr_size(0)
|
||||
{
|
||||
// initialise the internal data structure
|
||||
ud_init(&ud_obj);
|
||||
ud_set_mode(&ud_obj, 32);
|
||||
ud_set_syntax(&ud_obj, UD_SYN_ATT);
|
||||
ud_set_pc(&ud_obj, ip);
|
||||
}
|
||||
|
||||
void Udis86::setInputBuffer(unsigned char const *instr, size_t size)
|
||||
{
|
||||
// initialise the buffer
|
||||
if (size > udis_instr_size) {
|
||||
void *new_instr = realloc(udis_instr, size);
|
||||
if (new_instr == NULL) {
|
||||
// highly improbable
|
||||
return;
|
||||
}
|
||||
udis_instr = reinterpret_cast<unsigned char*>(new_instr);
|
||||
}
|
||||
|
||||
udis_instr_size = size;
|
||||
memcpy(udis_instr, instr, udis_instr_size);
|
||||
|
||||
// assign the buffer to the data structure
|
||||
ud_set_input_buffer(&ud_obj, udis_instr, udis_instr_size);
|
||||
}
|
||||
95
src/experiments/nanojpeg/UDIS86.hpp
Normal file
95
src/experiments/nanojpeg/UDIS86.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
#ifndef __UDIS86_HPP__
|
||||
#define __UDIS86_HPP__
|
||||
|
||||
#include <udis86.h>
|
||||
#include "sal/bochs/BochsController.hpp"
|
||||
#include "sal/bochs/BochsRegister.hpp"
|
||||
|
||||
/**
|
||||
* \class Udis86
|
||||
*
|
||||
* \brief Class to disassemble instructions
|
||||
*
|
||||
* This class disassembles a stream of machine code instruction
|
||||
* by instruction.
|
||||
* It provides a (thin) wrapper around the C API of UDIS86.
|
||||
*/
|
||||
class Udis86
|
||||
{
|
||||
private:
|
||||
ud_t ud_obj; //<! the ud object of udis86
|
||||
unsigned char *udis_instr; //<! the instruction buffer for UDIs86
|
||||
size_t udis_instr_size; //<! the size of the instruction buffer
|
||||
public:
|
||||
/**
|
||||
* creates a new Uds86 object
|
||||
* @param ip the current instruction pointer of the simulator
|
||||
*/
|
||||
Udis86(fail::address_t ip);
|
||||
~Udis86() { free(udis_instr); }
|
||||
/**
|
||||
* sets the current IP
|
||||
* @param ip the current IP
|
||||
*/
|
||||
void setIP(fail::address_t ip) { ud_set_pc(&ud_obj, ip); }
|
||||
/**
|
||||
* sets a new input buffer
|
||||
* @param instr the encoded instruction
|
||||
* @param size the size of the instruction
|
||||
*/
|
||||
void setInputBuffer(unsigned char const *instr, size_t size);
|
||||
/**
|
||||
* retrieves the private ud structure of udis86
|
||||
* @returns a reference pointer to a ud_t variable
|
||||
*/
|
||||
inline ud_t const &getCurrentState() const { return ud_obj; }
|
||||
/**
|
||||
* Tries to decode the next instruction from the given buffer.
|
||||
* @returns \c true if a new instruction could be retrieved, \c false if the object has expired
|
||||
*/
|
||||
inline bool fetchNextInstruction() { return (ud_disassemble(&ud_obj) > 0); }
|
||||
/**
|
||||
* Returns the FailBochs equivalent to a UDIS86 GPR identifier.
|
||||
* Attention: this only returns either 32-bit or 64-bit registers, no general IDs
|
||||
* @param udisReg the udis86 GPR ID
|
||||
* @returns the FailBochs GPR ID, usable with the BochsRegisterManager class
|
||||
*/
|
||||
static inline fail::GPRegisterId udisGPRToFailBochsGPR(ud_type_t udisReg)
|
||||
{
|
||||
#define REG_CASE(REG) case UD_R_##REG: return fail::RID_##REG
|
||||
switch (udisReg) {
|
||||
#if BX_SUPPORT_X86_64 // 64 bit register id's:
|
||||
REG_CASE(RAX);
|
||||
REG_CASE(RCX);
|
||||
REG_CASE(RDX);
|
||||
REG_CASE(RBX);
|
||||
REG_CASE(RSP);
|
||||
REG_CASE(RBP);
|
||||
REG_CASE(RSI);
|
||||
REG_CASE(RDI);
|
||||
REG_CASE(R8);
|
||||
REG_CASE(R9);
|
||||
REG_CASE(R10);
|
||||
REG_CASE(R11);
|
||||
REG_CASE(R12);
|
||||
REG_CASE(R13);
|
||||
REG_CASE(R14);
|
||||
REG_CASE(R15);
|
||||
#else
|
||||
REG_CASE(EAX);
|
||||
REG_CASE(ECX);
|
||||
REG_CASE(EDX);
|
||||
REG_CASE(EBX);
|
||||
REG_CASE(ESP);
|
||||
REG_CASE(EBP);
|
||||
REG_CASE(ESI);
|
||||
REG_CASE(EDI);
|
||||
#endif
|
||||
default:
|
||||
return fail::RID_LAST_GP_ID;
|
||||
}
|
||||
#undef REG_CASE
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __UDIS86_HPP__
|
||||
142
src/experiments/nanojpeg/campaign.cc
Normal file
142
src/experiments/nanojpeg/campaign.cc
Normal file
@ -0,0 +1,142 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#include "campaign.hpp"
|
||||
#include "experimentInfo.hpp"
|
||||
#include "cpn/CampaignManager.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include "util/ProtoStream.hpp"
|
||||
|
||||
#include "UDIS86.hpp"
|
||||
|
||||
#include "../plugins/tracing/TracingPlugin.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
|
||||
bool get_file_contents(const char *filename, string& contents)
|
||||
{
|
||||
std::ifstream in(filename, std::ios::in | std::ios::binary);
|
||||
if (!in) {
|
||||
return false;
|
||||
}
|
||||
in.seekg(0, std::ios::end);
|
||||
contents.resize(in.tellg());
|
||||
in.seekg(0, std::ios::beg);
|
||||
in.read(&contents[0], contents.size());
|
||||
in.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NanoJPEGCampaign::run()
|
||||
{
|
||||
// read already existing results
|
||||
bool file_exists = false;
|
||||
/*
|
||||
set<uint64_t> existing_results;
|
||||
ifstream oldresults(results_filename, ios::in);
|
||||
if (oldresults.is_open()) {
|
||||
char buf[16*1024];
|
||||
uint64_t addr;
|
||||
int count = 0;
|
||||
m_log << "scanning existing results ..." << endl;
|
||||
file_exists = true;
|
||||
while (oldresults.getline(buf, sizeof(buf)).good()) {
|
||||
stringstream ss;
|
||||
ss << buf;
|
||||
ss >> addr;
|
||||
if (ss.fail()) {
|
||||
continue;
|
||||
}
|
||||
++count;
|
||||
if (!existing_results.insert(addr).second) {
|
||||
m_log << "duplicate: " << addr << endl;
|
||||
}
|
||||
}
|
||||
m_log << "found " << dec << count << " existing results" << endl;
|
||||
oldresults.close();
|
||||
}
|
||||
*/
|
||||
|
||||
// non-destructive: due to the CSV header we can always manually recover
|
||||
// from an accident (append mode)
|
||||
ofstream results(NANOJPEG_RESULTS, ios::out | ios::app);
|
||||
if (!results.is_open()) {
|
||||
m_log << "failed to open " << NANOJPEG_RESULTS << endl;
|
||||
return false;
|
||||
}
|
||||
// only write CSV header if file didn't exist before
|
||||
if (!file_exists) {
|
||||
results << "instr_offset\tinstr_address\tregister_id\ttimeout\tinjection_ip\tbitnr\tresulttype\tlatest_ip\tpsnr\tdetails" << endl;
|
||||
}
|
||||
|
||||
// load binary image (objcopy'ed system.elf = system.bin)
|
||||
string binimage;
|
||||
if (!get_file_contents(NANOJPEG_BIN, binimage)) {
|
||||
m_log << "couldn't open " << NANOJPEG_BIN << endl;
|
||||
return false;
|
||||
}
|
||||
Udis86 udis(0);
|
||||
|
||||
// load trace
|
||||
ifstream tracef(NANOJPEG_TRACE);
|
||||
if (tracef.fail()) {
|
||||
m_log << "couldn't open " << NANOJPEG_TRACE << endl;
|
||||
return false;
|
||||
}
|
||||
ProtoIStream ps(&tracef);
|
||||
|
||||
// experiment count
|
||||
int count = 0;
|
||||
|
||||
// instruction counter within trace
|
||||
int instr = 0;
|
||||
|
||||
Trace_Event ev;
|
||||
// for every event in the trace ...
|
||||
while (ps.getNext(&ev) && instr < NANOJPEG_INSTR_LIMIT) {
|
||||
// sanity check: skip memory access entries
|
||||
if (ev.has_memaddr()) {
|
||||
continue;
|
||||
}
|
||||
instr++;
|
||||
|
||||
// disassemble instruction
|
||||
if (ev.ip() < NANOJPEG_BIN_OFFSET || ev.ip() - NANOJPEG_BIN_OFFSET > binimage.size()) {
|
||||
m_log << "traced IP 0x" << hex << ev.ip() << " outside system image" << endl;
|
||||
continue;
|
||||
}
|
||||
udis.setIP(ev.ip());
|
||||
size_t ip_offset = ev.ip() - NANOJPEG_BIN_OFFSET;
|
||||
udis.setInputBuffer((unsigned char *) &binimage[ip_offset], min((size_t) 20, binimage.size() - ip_offset));
|
||||
|
||||
if (!udis.fetchNextInstruction()) {
|
||||
m_log << "fatal: cannot disassemble instruction at 0x" << hex << ev.ip() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ud_t ud = udis.getCurrentState();
|
||||
|
||||
// for now: debug output
|
||||
m_log << "0x" << hex << ev.ip() << " " << ::ud_insn_asm(&ud) << endl;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
switch (ud.operand[i].type) {
|
||||
case UD_NONE: cout << "-"; break;
|
||||
case UD_OP_MEM: cout << "M"; break;
|
||||
case UD_OP_PTR: cout << "P"; break;
|
||||
case UD_OP_IMM: cout << "I"; break;
|
||||
case UD_OP_JIMM: cout << "J"; break;
|
||||
case UD_OP_CONST: cout << "C"; break;
|
||||
case UD_OP_REG: cout << "R"; break;
|
||||
default: m_log << "WAT" << endl;
|
||||
}
|
||||
std::cout << " ";
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
22
src/experiments/nanojpeg/campaign.hpp
Normal file
22
src/experiments/nanojpeg/campaign.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef __NANOJPEG_CAMPAIGN_HPP__
|
||||
#define __NANOJPEG_CAMPAIGN_HPP__
|
||||
|
||||
#include "cpn/Campaign.hpp"
|
||||
#include "comm/ExperimentData.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include "nanojpeg.pb.h"
|
||||
|
||||
class NanoJPEGExperimentData : public fail::ExperimentData {
|
||||
public:
|
||||
NanoJPEGProtoMsg msg;
|
||||
NanoJPEGExperimentData() : fail::ExperimentData(&msg) {}
|
||||
};
|
||||
|
||||
class NanoJPEGCampaign : public fail::Campaign {
|
||||
fail::Logger m_log;
|
||||
public:
|
||||
NanoJPEGCampaign() : m_log("nJPEG Campaign") {}
|
||||
virtual bool run();
|
||||
};
|
||||
|
||||
#endif // __NANOJPEG_CAMPAIGN_HPP__
|
||||
11
src/experiments/nanojpeg/main.cc
Normal file
11
src/experiments/nanojpeg/main.cc
Normal file
@ -0,0 +1,11 @@
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "cpn/CampaignManager.hpp"
|
||||
#include "campaign.hpp"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NanoJPEGCampaign c;
|
||||
return !fail::campaignmanager.runCampaign(&c);
|
||||
}
|
||||
56
src/experiments/nanojpeg/nanojpeg.proto
Normal file
56
src/experiments/nanojpeg/nanojpeg.proto
Normal file
@ -0,0 +1,56 @@
|
||||
message NanoJPEGProtoMsg {
|
||||
// Input: experiment parameters
|
||||
// (client executes one experiment for every specified bit in the target register)
|
||||
|
||||
// FI at #instructions from experiment start
|
||||
required int32 instr_offset = 1;
|
||||
// the exact IP value at this point in time (from golden run)
|
||||
optional int32 instr_address = 2; // for sanity checks
|
||||
// ID of the register to inject faults into
|
||||
required int32 register_id = 3;
|
||||
// first bit to inject a flip into
|
||||
required int32 bit_start = 4;
|
||||
// last bit to inject a flip into (inclusive)
|
||||
required int32 bit_end = 5;
|
||||
// timeout in ms
|
||||
required int32 timeout = 6;
|
||||
|
||||
// ----------------------------------------------------
|
||||
|
||||
// Output: experiment results
|
||||
|
||||
// IP where we did the injection: for debugging purposes, must be identical
|
||||
// to instr_address
|
||||
optional int32 injection_ip = 8;
|
||||
|
||||
repeated group Result = 9 {
|
||||
// single experiment bit number
|
||||
required int32 bitnr = 1;
|
||||
|
||||
// result type:
|
||||
// FINISHED = planned number of instructions were executed
|
||||
// BROKEN = finished, but resulting image is broken (dimensions)
|
||||
// TRAP = premature guest "crash"
|
||||
// OUTSIDE = IP left text segment
|
||||
// TIMEOUT = none of the above happened for /timeout/ ms
|
||||
enum ResultType {
|
||||
FINISHED = 1;
|
||||
BROKEN = 2;
|
||||
TRAP = 3;
|
||||
OUTSIDE = 4;
|
||||
DETECTED = 5; // unused for now
|
||||
TIMEOUT = 6;
|
||||
UNKNOWN = 7;
|
||||
}
|
||||
required ResultType resulttype = 2;
|
||||
|
||||
// especially interesting for TRAP/UNKNOWN: latest IP
|
||||
required uint32 latest_ip = 3;
|
||||
|
||||
// PSNR golden run <-> this run
|
||||
required float psnr = 4;
|
||||
|
||||
// optional textual description of what happened
|
||||
optional string details = 5;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user