Introduces instruction filtering, e.g. to filter for kernel instructions
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1864 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
@ -18,6 +18,8 @@ set(MY_CAMPAIGN_SRCS
|
|||||||
campaign.cc
|
campaign.cc
|
||||||
UDIS86.hpp
|
UDIS86.hpp
|
||||||
UDIS86.cc
|
UDIS86.cc
|
||||||
|
InstructionFilter.hpp
|
||||||
|
InstructionFilter.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
#### PROTOBUFS ####
|
#### PROTOBUFS ####
|
||||||
|
|||||||
4
src/experiments/l4-sys/InstructionFilter.cc
Normal file
4
src/experiments/l4-sys/InstructionFilter.cc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#include "InstructionFilter.hpp"
|
||||||
|
|
||||||
|
// for more complex filters yet to come
|
||||||
|
|
||||||
56
src/experiments/l4-sys/InstructionFilter.hpp
Normal file
56
src/experiments/l4-sys/InstructionFilter.hpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#ifndef __L4SYS_INSTRUCTIONFILTER_HPP__
|
||||||
|
#define __L4SYS_INSTRUCTIONFILTER_HPP__
|
||||||
|
|
||||||
|
#include "sal/SALConfig.hpp"
|
||||||
|
#include "cpu/instr.h"
|
||||||
|
|
||||||
|
using namespace fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class InstructionFilter
|
||||||
|
*
|
||||||
|
* \brief Filters instructions
|
||||||
|
*
|
||||||
|
* This class is an interface that can be used to
|
||||||
|
* implement instruction filter classes that can
|
||||||
|
* be used to decide if an instruction should be
|
||||||
|
* included in the fault injection experiment.
|
||||||
|
*/
|
||||||
|
class InstructionFilter {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Decides if the given instruction at the given program location
|
||||||
|
* is valid for fault injection
|
||||||
|
* @param ip the instruction pointer of the instruction
|
||||||
|
* @param instr the instruction in its coded binary representation
|
||||||
|
* @returns \c true if the instruction should be included, \c false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool isValidInstr(address_t ip, char const *instr) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class RangeInstructionFilter
|
||||||
|
*
|
||||||
|
* Permits an instruction if its instruction pointer lies within a certain range
|
||||||
|
*/
|
||||||
|
class RangeInstructionFilter : public InstructionFilter {
|
||||||
|
public:
|
||||||
|
RangeInstructionFilter(address_t begin_addr, address_t end_addr)
|
||||||
|
: beginAddress(begin_addr), endAddress(end_addr)
|
||||||
|
{}
|
||||||
|
~RangeInstructionFilter() {}
|
||||||
|
/**
|
||||||
|
* check if the instruction pointer of an instruction lies within a certain range
|
||||||
|
* @param ip the instruction pointer to check
|
||||||
|
* @param instr this parameter is ignored
|
||||||
|
* @returns \c true if the instruction lies within the predefined range,
|
||||||
|
* \c false otherwise
|
||||||
|
*/
|
||||||
|
bool isValidInstr(address_t ip, char const *instr) const
|
||||||
|
{ return (beginAddress < ip && ip < endAddress); }
|
||||||
|
private:
|
||||||
|
address_t beginAddress; //<! the beginning of the address range
|
||||||
|
address_t endAddress; //<! the end of the address range
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __L4SYS_INSTRUCTIONFILTER_HPP__ */
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#ifndef __UDIS86_HPP__
|
#ifndef __L4SYS_UDIS86_HPP__
|
||||||
#define __UDIS86_HPP__
|
#define __L4SYS_UDIS86_HPP__
|
||||||
|
|
||||||
#include <udis86.h>
|
#include <udis86.h>
|
||||||
#include "sal/bochs/BochsController.hpp"
|
#include "sal/bochs/BochsController.hpp"
|
||||||
@ -87,4 +87,4 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __UDIS86_HPP__
|
#endif // __L4SYS_UDIS86_HPP__
|
||||||
|
|||||||
@ -299,7 +299,7 @@ size_t const aluInstructionsSize = sizeof(aluInstructions);
|
|||||||
/**
|
/**
|
||||||
* \class BochsALUInstructions
|
* \class BochsALUInstructions
|
||||||
*
|
*
|
||||||
* \brfief This class handles Bochs ALU instructions.
|
* \brief This class handles Bochs ALU instructions.
|
||||||
*
|
*
|
||||||
* This class analyses a given bxInstruction_c object:
|
* This class analyses a given bxInstruction_c object:
|
||||||
* if it belongs to the instructions listed in
|
* if it belongs to the instructions listed in
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "experiment.hpp"
|
#include "experiment.hpp"
|
||||||
#include "experimentInfo.hpp"
|
#include "experimentInfo.hpp"
|
||||||
#include "UDIS86.hpp"
|
#include "UDIS86.hpp"
|
||||||
|
#include "InstructionFilter.hpp"
|
||||||
#include "aluinstr.hpp"
|
#include "aluinstr.hpp"
|
||||||
#include "campaign.hpp"
|
#include "campaign.hpp"
|
||||||
|
|
||||||
@ -32,16 +33,9 @@ using namespace fail;
|
|||||||
save, and restore. Enable these in the configuration.
|
save, and restore. Enable these in the configuration.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct __trace_instr_type {
|
|
||||||
fail::address_t trigger_addr;
|
|
||||||
unsigned bp_counter;
|
|
||||||
} trace_instr;
|
|
||||||
|
|
||||||
string output;
|
string output;
|
||||||
#if 0
|
#ifdef L4SYS_FILTER_INSTRUCTIONS
|
||||||
//disabled (see "STEP 2" below)
|
TraceVector instr_list;
|
||||||
vector<trace_instr> instr_list;
|
|
||||||
vector<trace_instr> alu_instr_list;
|
|
||||||
#endif
|
#endif
|
||||||
string golden_run;
|
string golden_run;
|
||||||
|
|
||||||
@ -131,17 +125,6 @@ void L4SysExperiment::logInjection(Logger &log,
|
|||||||
<< ")" << " bit " << bit_offset << endl;
|
<< ")" << " bit " << bit_offset << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void L4SysExperiment::readFromFileToVector(std::ifstream &file,
|
|
||||||
std::vector<trace_instr> &instr_list) {
|
|
||||||
file >> hex;
|
|
||||||
while (!file.eof()) {
|
|
||||||
trace_instr curr_instr;
|
|
||||||
file.read(reinterpret_cast<char*>(&curr_instr), sizeof(trace_instr));
|
|
||||||
instr_list.push_back(curr_instr);
|
|
||||||
}
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void L4SysExperiment::singleStep() {
|
void L4SysExperiment::singleStep() {
|
||||||
BPSingleListener singlestepping_event(ANY_ADDR, L4SYS_ADDRESS_SPACE);
|
BPSingleListener singlestepping_event(ANY_ADDR, L4SYS_ADDRESS_SPACE);
|
||||||
simulator.addListener(&singlestepping_event);
|
simulator.addListener(&singlestepping_event);
|
||||||
@ -195,6 +178,45 @@ bool L4SysExperiment::run() {
|
|||||||
<< simulator.getRegisterManager().getInstructionPointer()
|
<< simulator.getRegisterManager().getInstructionPointer()
|
||||||
<< endl;
|
<< endl;
|
||||||
|
|
||||||
|
#ifdef L4SYS_FILTER_INSTRUCTIONS
|
||||||
|
ofstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::out | ios::binary);
|
||||||
|
bp.setWatchInstructionPointer(ANY_ADDR);
|
||||||
|
|
||||||
|
size_t count = 0, accepted = 0;
|
||||||
|
map<address_t, unsigned> times_called_map;
|
||||||
|
InstructionFilter *instrFilter = NULL;
|
||||||
|
#if defined(L4SYS_ADDRESS_LBOUND) && defined(L4SYS_ADDRESS_UBOUND)
|
||||||
|
instrFilter = new RangeInstructionFilter(L4SYS_ADDRESS_LBOUND, L4SYS_ADDRESS_UBOUND);
|
||||||
|
#endif
|
||||||
|
while (bp.getTriggerInstructionPointer() != L4SYS_FUNC_EXIT) {
|
||||||
|
simulator.addListenerAndResume(&bp);
|
||||||
|
count++;
|
||||||
|
//short sanity check
|
||||||
|
address_t curr_addr = bp.getTriggerInstructionPointer();
|
||||||
|
assert(
|
||||||
|
curr_addr == simulator.getRegisterManager().getInstructionPointer());
|
||||||
|
|
||||||
|
unsigned times_called = times_called_map[curr_addr];
|
||||||
|
times_called++;
|
||||||
|
times_called_map[curr_addr] = times_called;
|
||||||
|
|
||||||
|
// now check if we want to add the instruction for fault injection
|
||||||
|
if (instrFilter != NULL &&
|
||||||
|
instrFilter->isValidInstr(curr_addr, simulator.getCurrentInstruction())) {
|
||||||
|
accepted++;
|
||||||
|
TraceInstr new_instr;
|
||||||
|
new_instr.trigger_addr = curr_addr;
|
||||||
|
new_instr.bp_counter = times_called;
|
||||||
|
|
||||||
|
instr_list_file.write(reinterpret_cast<char*>(&new_instr), sizeof(TraceInstr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete instrFilter;
|
||||||
|
log << "saving instructions triggered during normal execution" << endl;
|
||||||
|
instr_list_file.close();
|
||||||
|
log << "test function calculation position reached after "
|
||||||
|
<< dec << count << " instructions; " << accepted << " accepted" << endl;
|
||||||
|
#else
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int ul = 0, kernel = 0;
|
int ul = 0, kernel = 0;
|
||||||
bp.setWatchInstructionPointer(ANY_ADDR);
|
bp.setWatchInstructionPointer(ANY_ADDR);
|
||||||
@ -211,6 +233,8 @@ bool L4SysExperiment::run() {
|
|||||||
log << "test function calculation position reached after "
|
log << "test function calculation position reached after "
|
||||||
<< dec << count << " instructions; "
|
<< dec << count << " instructions; "
|
||||||
<< "ul: " << ul << ", kernel: " << kernel << endl;
|
<< "ul: " << ul << ", kernel: " << kernel << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
#elif PREPARATION_STEP == 3
|
#elif PREPARATION_STEP == 3
|
||||||
// STEP 3: determine the output of a "golden run"
|
// STEP 3: determine the output of a "golden run"
|
||||||
log << "restoring state" << endl;
|
log << "restoring state" << endl;
|
||||||
@ -239,68 +263,6 @@ bool L4SysExperiment::run() {
|
|||||||
log << "saving output generated during normal execution" << endl;
|
log << "saving output generated during normal execution" << endl;
|
||||||
golden_run_file.close();
|
golden_run_file.close();
|
||||||
|
|
||||||
#if 0
|
|
||||||
// the files currently get too big.
|
|
||||||
/* I do not really have a clever idea to solve this.
|
|
||||||
* You would probably need some kind of loop detection,
|
|
||||||
* but for the moment, I have to focus on different issues.
|
|
||||||
*/
|
|
||||||
if (stat(L4SYS_INSTRUCTION_LIST, &teststruct) == -1 ||
|
|
||||||
stat(L4SYS_ALU_INSTRUCTIONS, &teststruct) == -1) {
|
|
||||||
log << "restoring state" << endl;
|
|
||||||
simulator.restore(L4SYS_STATE_FOLDER);
|
|
||||||
log << "EIP = " << hex
|
|
||||||
<< simulator.getRegisterManager().getInstructionPointer()
|
|
||||||
<< endl;
|
|
||||||
|
|
||||||
// make sure the timer interrupt doesn't disturb us
|
|
||||||
simulator.addSuppressedInterrupt(0);
|
|
||||||
|
|
||||||
ofstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::out | ios::binary);
|
|
||||||
ofstream alu_instr_file(L4SYS_ALU_INSTRUCTIONS, ios::out | ios::binary);
|
|
||||||
bp.setWatchInstructionPointer(ANY_ADDR);
|
|
||||||
|
|
||||||
map<address_t, unsigned> times_called_map;
|
|
||||||
while (bp.getTriggerInstructionPointer() != L4SYS_FUNC_EXIT) {
|
|
||||||
simulator.addListenerAndResume(&bp);
|
|
||||||
//short sanity check
|
|
||||||
address_t curr_addr = bp.getTriggerInstructionPointer();
|
|
||||||
assert(
|
|
||||||
curr_addr == simulator.getRegisterManager().getInstructionPointer());
|
|
||||||
|
|
||||||
unsigned times_called = times_called_map[curr_addr];
|
|
||||||
times_called++;
|
|
||||||
times_called_map[curr_addr] = times_called;
|
|
||||||
|
|
||||||
trace_instr new_instr;
|
|
||||||
new_instr.trigger_addr = curr_addr;
|
|
||||||
new_instr.bp_counter = times_called;
|
|
||||||
instr_list.push_back(new_instr);
|
|
||||||
|
|
||||||
instr_list_file.write(reinterpret_cast<char*>(&new_instr), sizeof(trace_instr));
|
|
||||||
|
|
||||||
// ALU instructions
|
|
||||||
|
|
||||||
// decode the instruction
|
|
||||||
bxInstruction_c instr;
|
|
||||||
fetchInstruction(simulator.getCPUContext(), calculateInstructionAddress(), &instr);
|
|
||||||
// add it to a second list if it is an ALU instruction
|
|
||||||
if (isALUInstruction(instr.getIaOpcode())) {
|
|
||||||
alu_instr_list.push_back(new_instr);
|
|
||||||
alu_instr_file.write(reinterpret_cast<char*>(&new_instr), sizeof(trace_instr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log << "saving instructions triggered during normal execution" << endl;
|
|
||||||
alu_instr_file.close();
|
|
||||||
instr_list_file.close();
|
|
||||||
} else {
|
|
||||||
ifstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::in | ios::binary);
|
|
||||||
ifstream alu_instr_file(L4SYS_ALU_INSTRUCTIONS, ios::in | ios::binary);
|
|
||||||
readFromFileToVector(instr_list_file, instr_list);
|
|
||||||
readFromFileToVector(alu_instr_file, alu_instr_list);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif PREPARATION_STEP == 0
|
#elif PREPARATION_STEP == 0
|
||||||
// LAST STEP: The actual experiment.
|
// LAST STEP: The actual experiment.
|
||||||
struct stat teststruct;
|
struct stat teststruct;
|
||||||
@ -322,6 +284,21 @@ bool L4SysExperiment::run() {
|
|||||||
|
|
||||||
golden_run_file.close();
|
golden_run_file.close();
|
||||||
|
|
||||||
|
#ifdef L4SYS_FILTER_INSTRUCTIONS
|
||||||
|
ifstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::in | ios::binary);
|
||||||
|
|
||||||
|
if (!instr_list_file.good()) {
|
||||||
|
log << "Missing instruction trace" << endl;
|
||||||
|
simulator.terminate(21);
|
||||||
|
}
|
||||||
|
while (!instr_list_file.eof()) {
|
||||||
|
TraceInstr curr_instr;
|
||||||
|
instr_list_file.read(reinterpret_cast<char*>(&curr_instr), sizeof(TraceInstr));
|
||||||
|
instr_list.push_back(curr_instr);
|
||||||
|
}
|
||||||
|
instr_list_file.close();
|
||||||
|
#endif
|
||||||
|
|
||||||
//the generated output probably has a similar length
|
//the generated output probably has a similar length
|
||||||
output.reserve(teststruct.st_size);
|
output.reserve(teststruct.st_size);
|
||||||
|
|
||||||
@ -340,8 +317,13 @@ bool L4SysExperiment::run() {
|
|||||||
int bit_offset = param.msg.bit_offset();
|
int bit_offset = param.msg.bit_offset();
|
||||||
int exp_type = param.msg.exp_type();
|
int exp_type = param.msg.exp_type();
|
||||||
|
|
||||||
|
#ifdef L4SYS_FILTER_INSTRUCTIONS
|
||||||
|
bp.setWatchInstructionPointer(instr_list[instr_offset].trigger_addr);
|
||||||
|
bp.setCounter(instr_list[instr_offset].bp_counter);
|
||||||
|
#else
|
||||||
bp.setWatchInstructionPointer(ANY_ADDR);
|
bp.setWatchInstructionPointer(ANY_ADDR);
|
||||||
bp.setCounter(instr_offset + 1);
|
bp.setCounter(instr_offset);
|
||||||
|
#endif
|
||||||
simulator.addListener(&bp);
|
simulator.addListener(&bp);
|
||||||
//and log the output
|
//and log the output
|
||||||
waitIOOrOther(true);
|
waitIOOrOther(true);
|
||||||
@ -351,8 +333,8 @@ bool L4SysExperiment::run() {
|
|||||||
simulator.getRegisterManager().getInstructionPointer();
|
simulator.getRegisterManager().getInstructionPointer();
|
||||||
param.msg.set_injection_ip(injection_ip);
|
param.msg.set_injection_ip(injection_ip);
|
||||||
|
|
||||||
#if 0
|
#ifdef L4SYS_FILTER_INSTRUCTIONS
|
||||||
// temporarily out of order (see above)
|
// only works if we filter instructions
|
||||||
// sanity check (only works if we're working with an instruction trace)
|
// sanity check (only works if we're working with an instruction trace)
|
||||||
if (injection_ip != instr_list[instr_offset].trigger_addr) {
|
if (injection_ip != instr_list[instr_offset].trigger_addr) {
|
||||||
stringstream ss;
|
stringstream ss;
|
||||||
|
|||||||
@ -9,6 +9,21 @@
|
|||||||
|
|
||||||
class L4SysExperimentData;
|
class L4SysExperimentData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data type containing an instruction trace entry.
|
||||||
|
*/
|
||||||
|
typedef struct TraceInstrType {
|
||||||
|
fail::address_t trigger_addr; //!< the instruction pointer of the observed instruction
|
||||||
|
/**
|
||||||
|
* counts how often this instruction has been called
|
||||||
|
* if you want to call exactly this instruction, e.g. in a loop,
|
||||||
|
* you need to ignore the breakpoint \c bp_counter - 1 times
|
||||||
|
*/
|
||||||
|
unsigned bp_counter;
|
||||||
|
} TraceInstr;
|
||||||
|
|
||||||
|
typedef std::vector<TraceInstr> TraceVector;
|
||||||
|
|
||||||
class L4SysExperiment : public fail::ExperimentFlow {
|
class L4SysExperiment : public fail::ExperimentFlow {
|
||||||
fail::JobClient m_jc;
|
fail::JobClient m_jc;
|
||||||
public:
|
public:
|
||||||
@ -56,10 +71,6 @@ private:
|
|||||||
* @param param The experiment parameter object to log data from
|
* @param param The experiment parameter object to log data from
|
||||||
*/
|
*/
|
||||||
void logInjection(fail::Logger &log, const L4SysExperimentData ¶m);
|
void logInjection(fail::Logger &log, const L4SysExperimentData ¶m);
|
||||||
/**
|
|
||||||
* May be obsolete. Not supplying doc until I am sure whether I need to
|
|
||||||
*/
|
|
||||||
void readFromFileToVector(std::ifstream &file, std::vector<struct __trace_instr_type> &instr_list);
|
|
||||||
/**
|
/**
|
||||||
* Proceeds by one single instruction.
|
* Proceeds by one single instruction.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#ifndef __EXPERIMENT_INFO_HPP__
|
#ifndef __L4SYS_EXPERIMENT_INFO_HPP__
|
||||||
#define __EXPERIMENT_INFO_HPP__
|
#define __L4SYS_EXPERIMENT_INFO_HPP__
|
||||||
|
|
||||||
// the maximum number of bytes in a Bochs instruction
|
// the maximum number of bytes in a Bochs instruction
|
||||||
#define MAX_INSTR_BYTES 15
|
#define MAX_INSTR_BYTES 15
|
||||||
@ -24,4 +24,4 @@
|
|||||||
// >0 - next step to execute
|
// >0 - next step to execute
|
||||||
#define PREPARATION_STEP 0
|
#define PREPARATION_STEP 0
|
||||||
|
|
||||||
#endif // __EXPERIMENT_INFO_HPP__
|
#endif // __L4SYS_EXPERIMENT_INFO_HPP__
|
||||||
|
|||||||
Reference in New Issue
Block a user