experiments/dciao-kernelstructs: new database driven experiment for DCiAO
The dciao-kernelstructs experiment does a trace imported by the DCiAOKernelImporter: bin/import-trace -t trace.pb -i DCiAOKernelImporter --elf-file app.elf Pruned by the basic method: bin/prune-trace and does CiAO fault injection experiments, where the results are stored in the database. Change-Id: I485dc2e5097b3ebaf354241f474ee3d317213707
This commit is contained in:
@ -5,9 +5,10 @@ extend google.protobuf.FieldOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message DatabaseCampaignMessage {
|
message DatabaseCampaignMessage {
|
||||||
required int32 pilot_id = 1 [(sql_primary_key) = true];
|
required int32 pilot_id = 1 [(sql_primary_key) = true];
|
||||||
required int32 variant_id = 2 [(sql_ignore) = true];
|
required int32 variant_id = 2 [(sql_ignore) = true];
|
||||||
required int32 fspmethod_id = 3 [(sql_ignore) = true];
|
required int32 fspmethod_id = 3 [(sql_ignore) = true];
|
||||||
required int32 instr2 = 4 [(sql_ignore) = true];
|
required int32 injection_instr = 4 [(sql_ignore) = true];
|
||||||
required int32 data_address = 5 [(sql_ignore) = true];
|
optional int32 injection_instr_absolute = 5 [(sql_ignore) = true];
|
||||||
|
required int32 data_address = 6 [(sql_ignore) = true];
|
||||||
}
|
}
|
||||||
@ -82,15 +82,15 @@ bool DatabaseCampaign::run() {
|
|||||||
|
|
||||||
/* Gather all unfinished jobs */
|
/* Gather all unfinished jobs */
|
||||||
int experiment_count;
|
int experiment_count;
|
||||||
std::string sql_select = "SELECT pilot_id, fspgroup.fspmethod_id, fspgroup.variant_id, fspgroup.instr2, fspgroup.data_address ";
|
std::string sql_select = "SELECT pilot_id, g.fspmethod_id, g.variant_id, g.injection_instr, g.injection_instr_absolute, g.data_address";
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << " FROM fspgroup INNER JOIN fsppilot ON fsppilot.id = fspgroup.pilot_id "
|
ss << " FROM fspgroup g"
|
||||||
<< " WHERE known_outcome = 0 "
|
<< " INNER JOIN fsppilot p ON p.id = g.pilot_id "
|
||||||
<< " AND fspgroup.fspmethod_id = " << fspmethod_id
|
<< " WHERE p.known_outcome = 0 "
|
||||||
<< " AND fspgroup.variant_id = " << variant_id
|
<< " AND g.fspmethod_id = " << fspmethod_id
|
||||||
// << " AND fsppilot.data_address = 1346688"
|
<< " AND g.variant_id = " << variant_id
|
||||||
<< " AND (SELECT COUNT(*) FROM " + db_connect.result_table() + " as r WHERE r.pilot_id = fspgroup.pilot_id) = 0"
|
<< " AND (SELECT COUNT(*) FROM " + db_connect.result_table() + " as r WHERE r.pilot_id = g.pilot_id) = 0"
|
||||||
<< " ORDER BY fspgroup.instr2";
|
<< " ORDER BY g.injection_instr";
|
||||||
std::string sql_body = ss.str();
|
std::string sql_body = ss.str();
|
||||||
|
|
||||||
/* Get the number of unfinished experiments */
|
/* Get the number of unfinished experiments */
|
||||||
@ -105,15 +105,19 @@ bool DatabaseCampaign::run() {
|
|||||||
|
|
||||||
sent_pilots = 0;
|
sent_pilots = 0;
|
||||||
while ((row = mysql_fetch_row(pilots)) != 0) {
|
while ((row = mysql_fetch_row(pilots)) != 0) {
|
||||||
unsigned pilot_id = atoi(row[0]);
|
unsigned pilot_id = atoi(row[0]);
|
||||||
unsigned instr2 = atoi(row[3]);
|
unsigned injection_instr = atoi(row[3]);
|
||||||
unsigned data_address = atoi(row[4]);
|
unsigned data_address = atoi(row[5]);
|
||||||
|
|
||||||
DatabaseCampaignMessage pilot;
|
DatabaseCampaignMessage pilot;
|
||||||
pilot.set_pilot_id(pilot_id);
|
pilot.set_pilot_id(pilot_id);
|
||||||
pilot.set_fspmethod_id(fspmethod_id);
|
pilot.set_fspmethod_id(fspmethod_id);
|
||||||
pilot.set_variant_id(variant_id);
|
pilot.set_variant_id(variant_id);
|
||||||
pilot.set_instr2(instr2);
|
pilot.set_injection_instr(injection_instr);
|
||||||
|
if (row[4]) {
|
||||||
|
unsigned injection_instr_absolute = atoi(row[4]);
|
||||||
|
pilot.set_injection_instr_absolute(injection_instr_absolute);
|
||||||
|
}
|
||||||
pilot.set_data_address(data_address);
|
pilot.set_data_address(data_address);
|
||||||
|
|
||||||
this->cb_send_pilot(pilot);
|
this->cb_send_pilot(pilot);
|
||||||
|
|||||||
35
src/experiments/dciao-kernelstructs/CMakeLists.txt
Normal file
35
src/experiments/dciao-kernelstructs/CMakeLists.txt
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
set(EXPERIMENT_NAME dciao-kernelstructs)
|
||||||
|
set(EXPERIMENT_TYPE DCIAOKernelStructs)
|
||||||
|
configure_file(../instantiate-experiment.ah.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
## Setup desired protobuf descriptions HERE ##
|
||||||
|
set(MY_PROTOS
|
||||||
|
dciao_kernel.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})
|
||||||
|
|
||||||
|
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} ${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} -lmysqlclient)
|
||||||
|
install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
20
src/experiments/dciao-kernelstructs/campaign.cc
Normal file
20
src/experiments/dciao-kernelstructs/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 DCIAOKernelCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) {
|
||||||
|
DCIAOKernelExperimentData *data = new DCIAOKernelExperimentData;
|
||||||
|
data->msg.mutable_fsppilot()->CopyFrom(pilot);
|
||||||
|
campaignmanager.addParam(data);
|
||||||
|
}
|
||||||
|
|
||||||
23
src/experiments/dciao-kernelstructs/campaign.hpp
Normal file
23
src/experiments/dciao-kernelstructs/campaign.hpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef __DCIAOCAMPAIGN_HPP__
|
||||||
|
#define __DCIAOCAMPAIGN_HPP__
|
||||||
|
|
||||||
|
#include "cpn/DatabaseCampaign.hpp"
|
||||||
|
#include "comm/ExperimentData.hpp"
|
||||||
|
#include "dciao_kernel.pb.h"
|
||||||
|
#include "util/ElfReader.hpp"
|
||||||
|
#include <google/protobuf/descriptor.h>
|
||||||
|
|
||||||
|
class DCIAOKernelExperimentData : public fail::ExperimentData {
|
||||||
|
public:
|
||||||
|
DCIAOKernelProtoMsg msg;
|
||||||
|
DCIAOKernelExperimentData() : fail::ExperimentData(&msg) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DCIAOKernelCampaign : public fail::DatabaseCampaign {
|
||||||
|
virtual const google::protobuf::Descriptor * cb_result_message()
|
||||||
|
{ return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("DCIAOKernelProtoMsg"); }
|
||||||
|
|
||||||
|
virtual void cb_send_pilot(DatabaseCampaignMessage pilot);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __KESOREFCAMPAIGN_HPP__
|
||||||
29
src/experiments/dciao-kernelstructs/dciao_kernel.proto
Normal file
29
src/experiments/dciao-kernelstructs/dciao_kernel.proto
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import "DatabaseCampaignMessage.proto";
|
||||||
|
|
||||||
|
message DCIAOKernelProtoMsg {
|
||||||
|
required DatabaseCampaignMessage fsppilot = 1;
|
||||||
|
|
||||||
|
repeated group Result = 2 {
|
||||||
|
enum ResultType {
|
||||||
|
OK = 1;
|
||||||
|
TIMEOUT = 2;
|
||||||
|
TRAP = 3;
|
||||||
|
ERR_ERROR_HOOK = 4;
|
||||||
|
ERR_DIFFERENT_ACTIVATION = 5;
|
||||||
|
ERR_DIFFERENT_KERNEL_TRANSITIONS = 6;
|
||||||
|
|
||||||
|
ERR_MEMACCESS = 7;
|
||||||
|
ERR_OUTSIDE_TEXT = 8;
|
||||||
|
|
||||||
|
UNKNOWN = 9;
|
||||||
|
NOINJECTION = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
required int32 bitoffset = 1 [(sql_primary_key) = true];
|
||||||
|
required ResultType resulttype = 2;
|
||||||
|
optional uint32 original_value = 3;
|
||||||
|
|
||||||
|
repeated uint32 activation_scheme = 4;
|
||||||
|
optional string details = 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
378
src/experiments/dciao-kernelstructs/experiment.cc
Normal file
378
src/experiments/dciao-kernelstructs/experiment.cc
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
// getpid
|
||||||
|
#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 <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
|
#include "campaign.hpp"
|
||||||
|
#include "dciao_kernel.pb.h"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
unsigned DCIAOKernelStructs::injectBitFlip(address_t data_address, unsigned bitpos){
|
||||||
|
|
||||||
|
MemoryManager& mm = simulator.getMemoryManager();
|
||||||
|
unsigned int value, injectedval;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void handleEvent(DCIAOKernelProtoMsg_Result& result, DCIAOKernelProtoMsg_Result_ResultType restype, const std::string &msg) {
|
||||||
|
cout << msg << endl;
|
||||||
|
result.set_resulttype(restype);
|
||||||
|
result.set_details(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void handleMemoryAccessEvent(DCIAOKernelExperimentData& param, const 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();
|
||||||
|
|
||||||
|
// handleEvent(param, param.msg.ERR_MEMACCESS, sstr.str());
|
||||||
|
// }
|
||||||
|
|
||||||
|
DCIAOKernelStructs::time_markers_t *DCIAOKernelStructs::getTimeMarkerList() {
|
||||||
|
const ElfSymbol & sym_time_marker_index = m_elf.getSymbol("time_marker_index");
|
||||||
|
const ElfSymbol & sym_time_markers = m_elf.getSymbol("time_markers");
|
||||||
|
|
||||||
|
assert(sym_time_marker_index.isValid());
|
||||||
|
assert(sym_time_markers.isValid());
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int time_marker_index;
|
||||||
|
|
||||||
|
simulator.getMemoryManager().getBytes(sym_time_marker_index.getAddress(),
|
||||||
|
sym_time_marker_index.getSize(),
|
||||||
|
&time_marker_index);
|
||||||
|
if (time_marker_index > 500) {
|
||||||
|
time_marker_index = 500;
|
||||||
|
}
|
||||||
|
time_markers_t *time_markers = new time_markers_t(time_marker_index);
|
||||||
|
|
||||||
|
simulator.getMemoryManager().getBytes(sym_time_markers.getAddress(),
|
||||||
|
time_marker_index * sizeof(time_marker),
|
||||||
|
time_markers->data());
|
||||||
|
return time_markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DCIAOKernelStructs::time_markers_compare(const time_markers_t &a, const time_markers_t &b) {
|
||||||
|
int pos = -1;
|
||||||
|
unsigned max_index = std::min(a.size(), b.size());
|
||||||
|
for (unsigned i = 0; i < max_index; i++) {
|
||||||
|
if (a[i].time != b[i].time
|
||||||
|
|| a[i].at != b[i].at) {
|
||||||
|
pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pos == -1 && (a.size() != b.size())) {
|
||||||
|
pos = max_index;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool DCIAOKernelStructs::run() {
|
||||||
|
//******* Boot, and store state *******//
|
||||||
|
m_log << "STARTING EXPERIMENT" << endl;
|
||||||
|
|
||||||
|
char * statedir = getenv("FAIL_STATEDIR");
|
||||||
|
if(statedir == NULL){
|
||||||
|
m_log << "FAIL_STATEDIR not set :(" << std::endl;
|
||||||
|
simulator.terminate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
address_t minimal_ip = 0x100000; // 1 Mbyte
|
||||||
|
address_t minimal_data = 0x100000; // 1 Mbyte
|
||||||
|
address_t maximal_ip = 0;
|
||||||
|
address_t maximal_data = 0;
|
||||||
|
for (ElfReader::symbol_iterator it = m_elf.sym_begin();
|
||||||
|
it != m_elf.sym_end(); ++it) {
|
||||||
|
const ElfSymbol &symbol = *it;
|
||||||
|
if (symbol.getSymbolType() == STT_FUNC
|
||||||
|
|| symbol.getSymbolType() == STT_GNU_IFUNC /*indirect codeasm object */) {
|
||||||
|
maximal_ip = std::max(maximal_ip, symbol.getEnd());
|
||||||
|
}
|
||||||
|
maximal_data = std::max(maximal_data, symbol.getEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Code section from " << hex << minimal_ip << " to " << maximal_ip << std::endl;
|
||||||
|
std::cout << "Data section from " << hex << minimal_ip << " to " << maximal_data << std::endl;
|
||||||
|
|
||||||
|
m_log << "Booting, and saving state at main";
|
||||||
|
BPSingleListener bp;
|
||||||
|
|
||||||
|
// STEP 1: run until interesting function starts, and save state
|
||||||
|
bp.setWatchInstructionPointer(m_elf.getSymbol("main").getAddress());
|
||||||
|
if(simulator.addListenerAndResume(&bp) == &bp){
|
||||||
|
m_log << "main function entry reached, saving state" << endl;
|
||||||
|
} else {
|
||||||
|
m_log << "Couldn't reach entry function. Dying" << std::endl;
|
||||||
|
simulator.terminate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
simulator.save(statedir);
|
||||||
|
guest_address_t enter_kernel_address = m_elf.getSymbol("os::dep::KernelStructs::correct").getAddress();
|
||||||
|
BPSingleListener l_enter_kernel(enter_kernel_address);
|
||||||
|
BPSingleListener l_time_marker_print(m_elf.getSymbol("time_marker_print").getAddress());
|
||||||
|
|
||||||
|
|
||||||
|
simulator.clearListeners();
|
||||||
|
simulator.addListener(&l_enter_kernel);
|
||||||
|
simulator.addListener(&l_time_marker_print);
|
||||||
|
|
||||||
|
bool in_kernelspace = false;
|
||||||
|
unsigned kernel_activations = 0;
|
||||||
|
while (1) {
|
||||||
|
fail::BaseListener *l = simulator.resume();
|
||||||
|
simulator.addListener(l);
|
||||||
|
|
||||||
|
if (l == &l_time_marker_print) {
|
||||||
|
break;
|
||||||
|
} else if (l == &l_enter_kernel) {
|
||||||
|
kernel_activations ++;
|
||||||
|
} else {
|
||||||
|
m_log << "THIS SHOULD'T HAPPEN" << std::endl;
|
||||||
|
simulator.terminate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
correct.time_markers = getTimeMarkerList();
|
||||||
|
correct.kernel_activation_count = kernel_activations;
|
||||||
|
|
||||||
|
assert(kernel_activations > 0);
|
||||||
|
assert(correct.time_markers->size() > 0);
|
||||||
|
|
||||||
|
m_log << "correct run is done:" << dec << std::endl;
|
||||||
|
m_log << " kernel_transitions " << correct.kernel_activation_count << std::endl;
|
||||||
|
m_log << " time_markers " << correct.time_markers->size() << std::endl;
|
||||||
|
|
||||||
|
// //******* Fault injection *******//
|
||||||
|
// // #warning "Building restore state variant"
|
||||||
|
|
||||||
|
unsigned executed_jobs = 0;
|
||||||
|
|
||||||
|
while (executed_jobs < 25 || m_jc.getNumberOfUndoneJobs() > 0) {
|
||||||
|
m_log << "asking jobserver for parameters" << endl;
|
||||||
|
DCIAOKernelExperimentData param;
|
||||||
|
if(!m_jc.getParam(param)){
|
||||||
|
m_log << "Dying." << endl; // We were told to die.
|
||||||
|
simulator.terminate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get input data from Jobserver
|
||||||
|
unsigned injection_instr = param.msg.fsppilot().injection_instr();
|
||||||
|
address_t data_address = param.msg.fsppilot().data_address();
|
||||||
|
|
||||||
|
for (int bit_offset = 0; bit_offset < 8; ++bit_offset) {
|
||||||
|
// 8 results in one job
|
||||||
|
DCIAOKernelProtoMsg_Result *result = param.msg.add_result();
|
||||||
|
result->set_bitoffset(bit_offset);
|
||||||
|
|
||||||
|
m_log << "restoring state" << endl;
|
||||||
|
|
||||||
|
// Restore to the image, which starts at address(main)
|
||||||
|
simulator.restore(statedir);
|
||||||
|
executed_jobs ++;
|
||||||
|
|
||||||
|
kernel_activations = 0;
|
||||||
|
|
||||||
|
m_log << "Trying to inject @ instr #" << dec << injection_instr << endl;
|
||||||
|
|
||||||
|
|
||||||
|
if (injection_instr > 0) {
|
||||||
|
simulator.clearListeners();
|
||||||
|
// XXX could be improved with intermediate states (reducing runtime until injection)
|
||||||
|
simulator.addListener(&l_time_marker_print);
|
||||||
|
simulator.addListener(&l_enter_kernel);
|
||||||
|
|
||||||
|
bp.setWatchInstructionPointer(ANY_ADDR);
|
||||||
|
bp.setCounter(injection_instr);
|
||||||
|
simulator.addListener(&bp);
|
||||||
|
|
||||||
|
bool inject = true;
|
||||||
|
while (1) {
|
||||||
|
fail::BaseListener * listener = simulator.resume();
|
||||||
|
// finish() before FI?
|
||||||
|
if (listener == &l_time_marker_print) {
|
||||||
|
m_log << "experiment reached finish() before FI" << endl;
|
||||||
|
handleEvent(*result, result->NOINJECTION, "time_marker reached before instr2");
|
||||||
|
inject = false;
|
||||||
|
break;
|
||||||
|
} else if (listener == &l_enter_kernel) {
|
||||||
|
// Count all kernel activations
|
||||||
|
simulator.addListener(&l_enter_kernel);
|
||||||
|
kernel_activations++;
|
||||||
|
} else if (listener == &bp) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
inject = false;
|
||||||
|
handleEvent(*result, result->NOINJECTION, "WTF");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next experiment
|
||||||
|
if (!inject)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a working sanitiy check. Because of instruction
|
||||||
|
// offsets!
|
||||||
|
//
|
||||||
|
// if (simulator.getCPU(0).getInstructionPointer() != param.msg.fsppilot().instr2_absolute()) {
|
||||||
|
// m_log << "Invalid Injection address EIP=0x"
|
||||||
|
// << std::hex << simulator.getCPU(0).getInstructionPointer()
|
||||||
|
// << " != enter_kernel=0x" << param.msg.fsppilot().instr2_absolute() << std::endl;
|
||||||
|
// simulator.terminate(1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// INJECT BITFLIP:
|
||||||
|
result->set_original_value(injectBitFlip(data_address, bit_offset));
|
||||||
|
|
||||||
|
// // Setup exit points
|
||||||
|
BPSingleListener l_error_hook(m_elf.getSymbol("copter_mock_panic").getAddress());
|
||||||
|
|
||||||
|
TrapListener l_trap(ANY_TRAP);
|
||||||
|
TimerListener l_timeout(1000 * 1000); // 1 second in microseconds
|
||||||
|
|
||||||
|
simulator.clearListeners();
|
||||||
|
simulator.addListener(&l_enter_kernel);
|
||||||
|
simulator.addListener(&l_timeout);
|
||||||
|
simulator.addListener(&l_trap);
|
||||||
|
simulator.addListener(&l_time_marker_print);
|
||||||
|
simulator.addListener(&l_error_hook);
|
||||||
|
|
||||||
|
// jump outside text segment
|
||||||
|
BPRangeListener ev_below_text(ANY_ADDR, minimal_ip - 1);
|
||||||
|
BPRangeListener ev_beyond_text(maximal_ip + 1, ANY_ADDR);
|
||||||
|
simulator.addListener(&ev_below_text);
|
||||||
|
simulator.addListener(&ev_beyond_text);
|
||||||
|
|
||||||
|
// memory access outside of bound determined in the golden run [lowest_addr, highest_addr]
|
||||||
|
MemAccessListener ev_mem_low(0x0, MemAccessEvent::MEM_READWRITE);
|
||||||
|
ev_mem_low.setWatchWidth(minimal_data);
|
||||||
|
MemAccessListener ev_mem_high(maximal_data + 1, MemAccessEvent::MEM_READWRITE);
|
||||||
|
ev_mem_high.setWatchWidth(0xFFFFFFFFU - (maximal_data + 1));
|
||||||
|
simulator.addListener(&ev_mem_low);
|
||||||
|
simulator.addListener(&ev_mem_high);
|
||||||
|
|
||||||
|
|
||||||
|
// resume and wait for results while counting kernel
|
||||||
|
// activations
|
||||||
|
fail::BaseListener* l;
|
||||||
|
while (1) {
|
||||||
|
l = simulator.resume();
|
||||||
|
|
||||||
|
// Evaluate result
|
||||||
|
if (l == &l_enter_kernel) {
|
||||||
|
kernel_activations++;
|
||||||
|
simulator.addListener(&l_enter_kernel);
|
||||||
|
// continue experiment
|
||||||
|
} else if (l == &l_time_marker_print) {
|
||||||
|
m_log << "experiment ran to the end" << std::endl;
|
||||||
|
DCIAOKernelStructs::time_markers_t * time_markers = getTimeMarkerList();
|
||||||
|
int pos = time_markers_compare(*time_markers, *correct.time_markers);
|
||||||
|
if (pos != -1) {
|
||||||
|
m_log << "Different activation scheme" << std::endl;
|
||||||
|
m_log << " size " << std::dec << time_markers->size() << std::endl;
|
||||||
|
m_log << " at " << std::dec << pos << std::endl;
|
||||||
|
|
||||||
|
stringstream sstr;
|
||||||
|
sstr << "diff after #" << pos;
|
||||||
|
handleEvent(*result, result->ERR_DIFFERENT_ACTIVATION, sstr.str());
|
||||||
|
/* In case of an error append the activation scheme */
|
||||||
|
for (unsigned i = pos; i < time_markers->size(); ++i) {
|
||||||
|
result->add_activation_scheme( (*time_markers)[i].time );
|
||||||
|
result->add_activation_scheme( (*time_markers)[i].at );
|
||||||
|
}
|
||||||
|
} else if (kernel_activations != correct.kernel_activation_count) {
|
||||||
|
stringstream sstr;
|
||||||
|
sstr << "kernel activations " << kernel_activations << " (expt: " << correct.kernel_activation_count << ")";
|
||||||
|
handleEvent(*result, result->ERR_DIFFERENT_KERNEL_TRANSITIONS, sstr.str());
|
||||||
|
} else {
|
||||||
|
stringstream sstr;
|
||||||
|
sstr << "calc done (kernel #" << kernel_activations << ")";
|
||||||
|
handleEvent(*result, result->OK, sstr.str());
|
||||||
|
}
|
||||||
|
delete time_markers;
|
||||||
|
// End of experiment
|
||||||
|
break;
|
||||||
|
} else if (l == &l_trap) {
|
||||||
|
stringstream sstr;
|
||||||
|
sstr << "trap #" << l_trap.getTriggerNumber();
|
||||||
|
handleEvent(*result, result->TRAP, sstr.str());
|
||||||
|
break; // EOExperiment
|
||||||
|
} else if (l == &l_timeout){
|
||||||
|
handleEvent(*result, result->TIMEOUT, "timeout: 1 second");
|
||||||
|
break; // EOExperiment
|
||||||
|
} else if (l == &l_error_hook){
|
||||||
|
handleEvent(*result, result->ERR_ERROR_HOOK, "called error hook");
|
||||||
|
break; // EOExperiment
|
||||||
|
} else if (l == &ev_below_text || l == &ev_beyond_text) {
|
||||||
|
handleEvent(*result, result->ERR_OUTSIDE_TEXT, (l == &ev_below_text) ? "< .text" : ">.text");
|
||||||
|
break; // EOExperiment
|
||||||
|
} else if (l == &ev_mem_low || l == &ev_mem_high) {
|
||||||
|
handleEvent(*result, result->ERR_MEMACCESS, (l == &ev_mem_low) ? "< .data" : ">.data");
|
||||||
|
break; // EOFExperiment
|
||||||
|
} else {
|
||||||
|
handleEvent(*result, result->UNKNOWN, "UNKNOWN event");
|
||||||
|
break; // EOExperiment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulator.clearListeners();
|
||||||
|
} // injection done, continue with next bit
|
||||||
|
|
||||||
|
m_jc.sendResult(param);
|
||||||
|
} // end while (1)
|
||||||
|
|
||||||
|
// Explicitly terminate, or the simulator will continue to run.
|
||||||
|
simulator.terminate();
|
||||||
|
}
|
||||||
|
|
||||||
50
src/experiments/dciao-kernelstructs/experiment.hpp
Normal file
50
src/experiments/dciao-kernelstructs/experiment.hpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef __DCIAO_KERNEL_EXPERIMENT_HPP__
|
||||||
|
#define __DCIAO_KERNEL_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>
|
||||||
|
|
||||||
|
class DCIAOKernelStructs : public fail::ExperimentFlow {
|
||||||
|
public:
|
||||||
|
/** timer_markers indicate the activation flow inside the
|
||||||
|
coper_mock application. For a correct run the activation flow
|
||||||
|
is deterministic. Therefore we can say wheter a the
|
||||||
|
application had a correct control flow */
|
||||||
|
struct time_marker {
|
||||||
|
uint32_t time;
|
||||||
|
uint32_t at;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<time_marker> time_markers_t;
|
||||||
|
|
||||||
|
private:
|
||||||
|
fail::JobClient m_jc;
|
||||||
|
fail::Logger m_log;
|
||||||
|
fail::MemoryManager& m_mm;
|
||||||
|
fail::ElfReader m_elf;
|
||||||
|
|
||||||
|
struct correct_run {
|
||||||
|
time_markers_t *time_markers;
|
||||||
|
unsigned int kernel_activation_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
correct_run correct;
|
||||||
|
|
||||||
|
unsigned injectBitFlip(fail::address_t data_address, unsigned bitpos);
|
||||||
|
time_markers_t *getTimeMarkerList();
|
||||||
|
static int time_markers_compare(const time_markers_t &, const time_markers_t &);
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
DCIAOKernelStructs() : m_log("DCIAOKernelStructs", false), m_mm(fail::simulator.getMemoryManager()) {}
|
||||||
|
|
||||||
|
bool run();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __KESO_REFS_EXPERIMENT_HPP__
|
||||||
20
src/experiments/dciao-kernelstructs/main.cc
Normal file
20
src/experiments/dciao-kernelstructs/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]);
|
||||||
|
|
||||||
|
DCIAOKernelCampaign c;
|
||||||
|
if (fail::campaignmanager.runCampaign(&c)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,9 +11,9 @@ using namespace fail;
|
|||||||
bool DCiAOKernelImporter::inDynamicKernelMemory(fail::address_t addr) {
|
bool DCiAOKernelImporter::inDynamicKernelMemory(fail::address_t addr) {
|
||||||
const std::string &name = m_elf->getSymbol(addr).getDemangledName();
|
const std::string &name = m_elf->getSymbol(addr).getDemangledName();
|
||||||
bool dynamic = name.find("os::data::dynamic", 0) != std::string::npos;
|
bool dynamic = name.find("os::data::dynamic", 0) != std::string::npos;
|
||||||
bool stack = name.find("_stack") != std::string::npos;
|
// bool stack = name.find("_stack") != std::string::npos;
|
||||||
|
// return dynamic && !stack;
|
||||||
return dynamic && !stack;
|
return dynamic;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DCiAOKernelImporter::copy_to_database(fail::ProtoIStream &ps) {
|
bool DCiAOKernelImporter::copy_to_database(fail::ProtoIStream &ps) {
|
||||||
|
|||||||
@ -7,8 +7,8 @@ static fail::Logger LOG ("BasicPruner");
|
|||||||
bool BasicPruner::prune_all() {
|
bool BasicPruner::prune_all() {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr2, data_address, fspmethod_id) "
|
ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr1, instr2, data_address, fspmethod_id) "
|
||||||
"SELECT 0, variant_id, instr2, data_address, " << m_method_id << " "
|
"SELECT 0, variant_id, instr1, instr2, data_address, " << m_method_id << " "
|
||||||
"FROM trace "
|
"FROM trace "
|
||||||
"WHERE variant_id = " << m_variant_id << " AND accesstype = 'R'";
|
"WHERE variant_id = " << m_variant_id << " AND accesstype = 'R'";
|
||||||
if (!db->query(ss.str().c_str())) return false;
|
if (!db->query(ss.str().c_str())) return false;
|
||||||
@ -16,8 +16,8 @@ bool BasicPruner::prune_all() {
|
|||||||
|
|
||||||
int rows = db->affected_rows();
|
int rows = db->affected_rows();
|
||||||
// single entry for known outcome (write access)
|
// single entry for known outcome (write access)
|
||||||
ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr2, data_address, fspmethod_id) "
|
ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr1, instr2, data_address, fspmethod_id) "
|
||||||
"SELECT 1, variant_id, instr2, data_address, " << m_method_id << " "
|
"SELECT 1, variant_id, instr1, instr2, data_address, " << m_method_id << " "
|
||||||
"FROM trace "
|
"FROM trace "
|
||||||
"WHERE variant_id = " << m_variant_id << " AND accesstype = 'W' "
|
"WHERE variant_id = " << m_variant_id << " AND accesstype = 'W' "
|
||||||
"LIMIT 1";
|
"LIMIT 1";
|
||||||
@ -27,19 +27,30 @@ bool BasicPruner::prune_all() {
|
|||||||
|
|
||||||
LOG << "created " << rows << " fsppilot entries" << std::endl;
|
LOG << "created " << rows << " fsppilot entries" << std::endl;
|
||||||
|
|
||||||
ss << "INSERT INTO fspgroup (variant_id, instr2, data_address, fspmethod_id, pilot_id) "
|
/* When we are in basic-left mode we use the left boundary of the
|
||||||
"SELECT variant_id, instr2, data_address, fspmethod_id, id "
|
equivalence interval. Sine the current database scheme has no
|
||||||
"FROM fsppilot "
|
instr2_absolute, we set this to NULL in the basic-left mode. */
|
||||||
"WHERE known_outcome = 0 AND fspmethod_id = " << m_method_id << " AND variant_id = " << m_variant_id;
|
std::string injection_instr = this->use_instr1 ? "t.instr1" : "t.instr2";
|
||||||
|
std::string injection_instr_absolute = this->use_instr1 ? "NULL" : "t.instr2_absolute";
|
||||||
|
|
||||||
|
ss << "INSERT INTO fspgroup (variant_id, injection_instr, injection_instr_absolute, "
|
||||||
|
<< " data_address, fspmethod_id, pilot_id) "
|
||||||
|
<< "SELECT p.variant_id, " << injection_instr << ", " << injection_instr_absolute << ", p.data_address, p.fspmethod_id, p.id "
|
||||||
|
<< "FROM fsppilot p "
|
||||||
|
<< " JOIN trace t ON t.variant_id = p.variant_id AND t.instr2 = p.instr2"
|
||||||
|
<< " AND t.data_address = p.data_address "
|
||||||
|
<< "WHERE known_outcome = 0 AND p.fspmethod_id = " << m_method_id << " AND p.variant_id = " << m_variant_id;
|
||||||
|
|
||||||
if (!db->query(ss.str().c_str())) return false;
|
if (!db->query(ss.str().c_str())) return false;
|
||||||
ss.str("");
|
ss.str("");
|
||||||
|
|
||||||
rows = db->affected_rows();
|
rows = db->affected_rows();
|
||||||
ss << "INSERT INTO fspgroup (variant_id, instr2, data_address, fspmethod_id, pilot_id) "
|
ss << "INSERT INTO fspgroup (variant_id, injection_instr, injection_instr_absolute, data_address, fspmethod_id, pilot_id) "
|
||||||
"SELECT t.variant_id, t.instr2, t.data_address, p.fspmethod_id, p.id "
|
"SELECT t.variant_id, "<< injection_instr << ", " << injection_instr_absolute <<", t.data_address, p.fspmethod_id, p.id "
|
||||||
"FROM trace t "
|
"FROM trace t "
|
||||||
"JOIN fsppilot p "
|
"JOIN fsppilot p "
|
||||||
"ON t.variant_id = p.variant_id AND p.fspmethod_id = " << m_method_id << " AND p.known_outcome = 1 "
|
"ON t.variant_id = p.variant_id AND p.fspmethod_id = " << m_method_id << " AND p.known_outcome = 1 "
|
||||||
"WHERE t.variant_id = " << m_variant_id << " AND t.accesstype = 'W'";
|
"WHERE t.variant_id = " << m_variant_id << " AND t.accesstype = 'W'";
|
||||||
if (!db->query(ss.str().c_str())) return false;
|
if (!db->query(ss.str().c_str())) return false;
|
||||||
ss.str("");
|
ss.str("");
|
||||||
rows += db->affected_rows();
|
rows += db->affected_rows();
|
||||||
|
|||||||
@ -4,7 +4,10 @@
|
|||||||
#include "Pruner.hpp"
|
#include "Pruner.hpp"
|
||||||
|
|
||||||
class BasicPruner : public Pruner {
|
class BasicPruner : public Pruner {
|
||||||
virtual std::string method_name() { return "basic"; }
|
bool use_instr1;
|
||||||
|
public:
|
||||||
|
BasicPruner(bool use_instr1 = false) : Pruner(), use_instr1(use_instr1) {}
|
||||||
|
virtual std::string method_name() { return std::string("basic") + (use_instr1 ? "-left" : ""); }
|
||||||
virtual bool prune_all();
|
virtual bool prune_all();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -28,22 +28,24 @@ bool Pruner::create_database() {
|
|||||||
" id int(11) NOT NULL AUTO_INCREMENT,"
|
" id int(11) NOT NULL AUTO_INCREMENT,"
|
||||||
" known_outcome tinyint(4) NOT NULL,"
|
" known_outcome tinyint(4) NOT NULL,"
|
||||||
" variant_id int(11) NOT NULL,"
|
" variant_id int(11) NOT NULL,"
|
||||||
|
" instr1 int(10) unsigned NOT NULL,"
|
||||||
" instr2 int(10) unsigned NOT NULL,"
|
" instr2 int(10) unsigned NOT NULL,"
|
||||||
" data_address int(10) unsigned NOT NULL,"
|
" data_address int(10) unsigned NOT NULL,"
|
||||||
" fspmethod_id int(11) NOT NULL,"
|
" fspmethod_id int(11) NOT NULL,"
|
||||||
" PRIMARY KEY (id),"
|
" PRIMARY KEY (id),"
|
||||||
" KEY fspmethod_id (fspmethod_id,variant_id,instr2,data_address)"
|
" KEY fspmethod_id (fspmethod_id,variant_id,instr1,instr2,data_address)"
|
||||||
") engine=MyISAM ";
|
") engine=MyISAM ";
|
||||||
bool success = (bool) db->query(create_statement.c_str());
|
bool success = (bool) db->query(create_statement.c_str());
|
||||||
if (!success) return false;
|
if (!success) return false;
|
||||||
|
|
||||||
create_statement = "CREATE TABLE IF NOT EXISTS fspgroup ("
|
create_statement = "CREATE TABLE IF NOT EXISTS fspgroup ("
|
||||||
" variant_id int(11) NOT NULL,"
|
" variant_id int(11) NOT NULL,"
|
||||||
" instr2 int(10) unsigned NOT NULL,"
|
" injection_instr int(10) unsigned NOT NULL,"
|
||||||
" data_address int(10) unsigned NOT NULL,"
|
" injection_instr_absolute int(10) unsigned,"
|
||||||
" fspmethod_id int(11) NOT NULL,"
|
" data_address int(10) unsigned NOT NULL,"
|
||||||
" pilot_id int(11) NOT NULL,"
|
" fspmethod_id int(11) NOT NULL,"
|
||||||
" PRIMARY KEY (variant_id, instr2, data_address, fspmethod_id, pilot_id),"
|
" pilot_id int(11) NOT NULL,"
|
||||||
|
" PRIMARY KEY (variant_id, injection_instr, data_address, fspmethod_id, pilot_id),"
|
||||||
" KEY joinresults (pilot_id,fspmethod_id))";
|
" KEY joinresults (pilot_id,fspmethod_id))";
|
||||||
|
|
||||||
return db->query(create_statement.c_str());
|
return db->query(create_statement.c_str());
|
||||||
|
|||||||
@ -43,6 +43,10 @@ int main(int argc, char *argv[]) {
|
|||||||
if (imp == "basic") {
|
if (imp == "basic") {
|
||||||
LOG << "Using BasicPruner" << endl;
|
LOG << "Using BasicPruner" << endl;
|
||||||
pruner = new BasicPruner();
|
pruner = new BasicPruner();
|
||||||
|
} else if (imp == "basic-left") {
|
||||||
|
LOG << "Using BasicPruner (use left border, instr1)" << endl;
|
||||||
|
pruner = new BasicPruner(true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LOG << "Unkown import method: " << imp << endl;
|
LOG << "Unkown import method: " << imp << endl;
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
|||||||
Reference in New Issue
Block a user