From 7ae8b6b09dcaae63a26e0742f4d863cf1df4cbc1 Mon Sep 17 00:00:00 2001 From: unzner Date: Tue, 30 Oct 2012 09:14:33 +0000 Subject: [PATCH] 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 --- src/experiments/l4-sys/CMakeLists.txt | 2 + src/experiments/l4-sys/InstructionFilter.cc | 4 + src/experiments/l4-sys/InstructionFilter.hpp | 56 +++++++ src/experiments/l4-sys/UDIS86.hpp | 6 +- src/experiments/l4-sys/aluinstr.hpp | 2 +- src/experiments/l4-sys/experiment.cc | 152 ++++++++----------- src/experiments/l4-sys/experiment.hpp | 19 ++- src/experiments/l4-sys/experimentInfo.hpp | 6 +- 8 files changed, 151 insertions(+), 96 deletions(-) create mode 100644 src/experiments/l4-sys/InstructionFilter.cc create mode 100644 src/experiments/l4-sys/InstructionFilter.hpp diff --git a/src/experiments/l4-sys/CMakeLists.txt b/src/experiments/l4-sys/CMakeLists.txt index 61112e19..0f1ba777 100644 --- a/src/experiments/l4-sys/CMakeLists.txt +++ b/src/experiments/l4-sys/CMakeLists.txt @@ -18,6 +18,8 @@ set(MY_CAMPAIGN_SRCS campaign.cc UDIS86.hpp UDIS86.cc + InstructionFilter.hpp + InstructionFilter.cc ) #### PROTOBUFS #### diff --git a/src/experiments/l4-sys/InstructionFilter.cc b/src/experiments/l4-sys/InstructionFilter.cc new file mode 100644 index 00000000..b3d339c3 --- /dev/null +++ b/src/experiments/l4-sys/InstructionFilter.cc @@ -0,0 +1,4 @@ +#include "InstructionFilter.hpp" + +// for more complex filters yet to come + diff --git a/src/experiments/l4-sys/InstructionFilter.hpp b/src/experiments/l4-sys/InstructionFilter.hpp new file mode 100644 index 00000000..fd8a20ea --- /dev/null +++ b/src/experiments/l4-sys/InstructionFilter.hpp @@ -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; // #include "sal/bochs/BochsController.hpp" @@ -87,4 +87,4 @@ public: } }; -#endif // __UDIS86_HPP__ +#endif // __L4SYS_UDIS86_HPP__ diff --git a/src/experiments/l4-sys/aluinstr.hpp b/src/experiments/l4-sys/aluinstr.hpp index fb89f572..a3b32a18 100644 --- a/src/experiments/l4-sys/aluinstr.hpp +++ b/src/experiments/l4-sys/aluinstr.hpp @@ -299,7 +299,7 @@ size_t const aluInstructionsSize = sizeof(aluInstructions); /** * \class BochsALUInstructions * - * \brfief This class handles Bochs ALU instructions. + * \brief This class handles Bochs ALU instructions. * * This class analyses a given bxInstruction_c object: * if it belongs to the instructions listed in diff --git a/src/experiments/l4-sys/experiment.cc b/src/experiments/l4-sys/experiment.cc index e3b4c57d..b42a54fb 100644 --- a/src/experiments/l4-sys/experiment.cc +++ b/src/experiments/l4-sys/experiment.cc @@ -9,6 +9,7 @@ #include "experiment.hpp" #include "experimentInfo.hpp" #include "UDIS86.hpp" +#include "InstructionFilter.hpp" #include "aluinstr.hpp" #include "campaign.hpp" @@ -32,16 +33,9 @@ using namespace fail; save, and restore. Enable these in the configuration. #endif -typedef struct __trace_instr_type { - fail::address_t trigger_addr; - unsigned bp_counter; -} trace_instr; - string output; -#if 0 -//disabled (see "STEP 2" below) -vector instr_list; -vector alu_instr_list; +#ifdef L4SYS_FILTER_INSTRUCTIONS +TraceVector instr_list; #endif string golden_run; @@ -131,17 +125,6 @@ void L4SysExperiment::logInjection(Logger &log, << ")" << " bit " << bit_offset << endl; } -void L4SysExperiment::readFromFileToVector(std::ifstream &file, - std::vector &instr_list) { - file >> hex; - while (!file.eof()) { - trace_instr curr_instr; - file.read(reinterpret_cast(&curr_instr), sizeof(trace_instr)); - instr_list.push_back(curr_instr); - } - file.close(); -} - void L4SysExperiment::singleStep() { BPSingleListener singlestepping_event(ANY_ADDR, L4SYS_ADDRESS_SPACE); simulator.addListener(&singlestepping_event); @@ -195,6 +178,45 @@ bool L4SysExperiment::run() { << simulator.getRegisterManager().getInstructionPointer() << 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 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(&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 ul = 0, kernel = 0; bp.setWatchInstructionPointer(ANY_ADDR); @@ -211,6 +233,8 @@ bool L4SysExperiment::run() { log << "test function calculation position reached after " << dec << count << " instructions; " << "ul: " << ul << ", kernel: " << kernel << endl; +#endif + #elif PREPARATION_STEP == 3 // STEP 3: determine the output of a "golden run" log << "restoring state" << endl; @@ -239,68 +263,6 @@ bool L4SysExperiment::run() { log << "saving output generated during normal execution" << endl; 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 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(&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(&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 // LAST STEP: The actual experiment. struct stat teststruct; @@ -322,6 +284,21 @@ bool L4SysExperiment::run() { 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(&curr_instr), sizeof(TraceInstr)); + instr_list.push_back(curr_instr); + } + instr_list_file.close(); +#endif + //the generated output probably has a similar length output.reserve(teststruct.st_size); @@ -340,8 +317,13 @@ bool L4SysExperiment::run() { int bit_offset = param.msg.bit_offset(); 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.setCounter(instr_offset + 1); + bp.setCounter(instr_offset); +#endif simulator.addListener(&bp); //and log the output waitIOOrOther(true); @@ -351,8 +333,8 @@ bool L4SysExperiment::run() { simulator.getRegisterManager().getInstructionPointer(); param.msg.set_injection_ip(injection_ip); -#if 0 - // temporarily out of order (see above) +#ifdef L4SYS_FILTER_INSTRUCTIONS + // only works if we filter instructions // sanity check (only works if we're working with an instruction trace) if (injection_ip != instr_list[instr_offset].trigger_addr) { stringstream ss; diff --git a/src/experiments/l4-sys/experiment.hpp b/src/experiments/l4-sys/experiment.hpp index 3c21be5a..6ff98eae 100644 --- a/src/experiments/l4-sys/experiment.hpp +++ b/src/experiments/l4-sys/experiment.hpp @@ -9,6 +9,21 @@ 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 TraceVector; + class L4SysExperiment : public fail::ExperimentFlow { fail::JobClient m_jc; public: @@ -56,10 +71,6 @@ private: * @param param The experiment parameter object to log data from */ 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 &instr_list); /** * Proceeds by one single instruction. */ diff --git a/src/experiments/l4-sys/experimentInfo.hpp b/src/experiments/l4-sys/experimentInfo.hpp index 63bf9c4e..b56fd4c3 100644 --- a/src/experiments/l4-sys/experimentInfo.hpp +++ b/src/experiments/l4-sys/experimentInfo.hpp @@ -1,5 +1,5 @@ -#ifndef __EXPERIMENT_INFO_HPP__ - #define __EXPERIMENT_INFO_HPP__ +#ifndef __L4SYS_EXPERIMENT_INFO_HPP__ + #define __L4SYS_EXPERIMENT_INFO_HPP__ // the maximum number of bytes in a Bochs instruction #define MAX_INSTR_BYTES 15 @@ -24,4 +24,4 @@ // >0 - next step to execute #define PREPARATION_STEP 0 -#endif // __EXPERIMENT_INFO_HPP__ +#endif // __L4SYS_EXPERIMENT_INFO_HPP__