- introduced improved logging in RATFlip

- adapted the manual
- centralised output conversion


git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1988 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
unzner
2012-12-24 12:55:20 +00:00
parent 5b07b4d312
commit 2547021e5d
13 changed files with 120 additions and 172 deletions

View File

@ -20,6 +20,8 @@ set(MY_CAMPAIGN_SRCS
UDIS86.cc
InstructionFilter.hpp
InstructionFilter.cc
conversion.hpp
conversion.cc
)
#### PROTOBUFS ####

View File

@ -1,16 +0,0 @@
62c62
< if (m_Data.getAddressSpace() == ANY_ADDR || m_Data.getAddressSpace() == address_space)
---
> if (m_Data.getAddressSpace() == ANY_ADDR || m_Data.getAddressSpace() == address_space) {
63a64
> }
86c87,91
< if (m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == pEv->getTriggerInstructionPointer())
---
> if (m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == pEv->getTriggerInstructionPointer()) {
> address_t address_space = pEv->getAddressSpace();
> if (address_space) {
> fprintf(stderr, "Got a match; address space: 0x%x\n", address_space);
> }
87a93
> }

View File

@ -3,6 +3,7 @@
#include "campaign.hpp"
#include "experimentInfo.hpp"
#include "conversion.hpp"
#include "cpn/CampaignManager.hpp"
#include "util/Logger.hpp"
#include "sal/SALConfig.hpp"
@ -11,10 +12,8 @@ using namespace std;
using namespace fail;
char const * const results_csv = "l4sys.csv";
char const *l4sys_output_result_strings[] = { "Unknown", "No effect", "Incomplete execution", "Crash", "Silent data corruption", "Error" };
char const *l4sys_output_experiment_strings[] = { "Unknown", "GPR Flip", "RAT Flip", "IDC Flip", "ALU Instr Flip" };
char const *l4sys_output_register_strings[] = { "Unknown", "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI" };
#if 0
#define OUTPUT_CASE(OUTPUT) case L4SysProtoMsg::OUTPUT: return l4sys_output_result_strings[L4SysProtoMsg::OUTPUT];
std::string L4SysCampaign::output_result(L4SysProtoMsg_ResultType res) {
switch (res) {
@ -56,6 +55,11 @@ std::string L4SysCampaign::output_register(L4SysProtoMsg_RegisterType res) {
}
}
#undef OUTPUT_CASE
#endif
extern L4SysConversion l4sysResultConversion;
extern L4SysConversion l4sysExperimentConversion;
extern L4SysConversion l4sysRegisterConversion;
bool L4SysCampaign::run() {
Logger log("L4SysCampaign");
@ -77,6 +81,7 @@ bool L4SysCampaign::run() {
int count = 0;
srand(time(NULL));
#if 0
for (int i = 0; i < 20000; ++i) {
L4SysExperimentData *d = new L4SysExperimentData;
d->msg.set_exp_type(d->msg.GPRFLIP);
@ -119,7 +124,8 @@ bool L4SysCampaign::run() {
campaignmanager.addParam(d);
++count;
}
for (int i = 0; i < 20000; ++i) {
#endif
for (int i = 0; i < 5000; ++i) {
L4SysExperimentData *d = new L4SysExperimentData;
d->msg.set_exp_type(d->msg.RATFLIP);
// modify for a random instruction
@ -144,13 +150,15 @@ bool L4SysCampaign::run() {
while ((res = static_cast<L4SysExperimentData *>(campaignmanager.getDone()))) {
rescount++;
results << output_experiment(res->msg.exp_type()) << "," << hex << res->msg.injection_ip() << dec << ",";
results << l4sysExperimentConversion.output(res->msg.exp_type())
<< "," << hex << res->msg.injection_ip() << dec << ",";
if (res->msg.has_register_offset())
results << output_register(res->msg.register_offset());
results << l4sysRegisterConversion.output(res->msg.register_offset());
else
results << "None";
results << "," << res->msg.instr_offset() << "," << res->msg.bit_offset()
<< "," << output_result(res->msg.resulttype()) << ","
<< ","
<< l4sysResultConversion.output(res->msg.resulttype()) << ","
<< res->msg.resultdata();
if (res->msg.has_output())
results << "," << res->msg.output();

View File

@ -14,10 +14,6 @@ public:
class L4SysCampaign : public fail::Campaign {
public:
virtual bool run();
private:
std::string output_result(L4SysProtoMsg_ResultType res);
std::string output_experiment(L4SysProtoMsg_ExperimentType res);
std::string output_register(L4SysProtoMsg_RegisterType res);
};
#endif // __L4SYS_CAMPAIGN_HPP__

View File

@ -0,0 +1,16 @@
#include "conversion.hpp"
char const *l4sys_output_result_strings[] = { "Unknown", "No effect", "Incomplete execution", "Crash", "Silent data corruption", "Error" };
char const *l4sys_output_experiment_strings[] = { "Unknown", "GPR Flip", "RAT Flip", "IDC Flip", "ALU Instr Flip" };
char const *l4sys_output_register_strings[] = { "Unknown", "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI" };
L4SysConversion l4sysResultConversion(
l4sys_output_result_strings,
sizeof(l4sys_output_result_strings));
L4SysConversion l4sysExperimentConversion(
l4sys_output_experiment_strings,
sizeof(l4sys_output_experiment_strings));
L4SysConversion l4sysRegisterConversion(
l4sys_output_register_strings,
sizeof(l4sys_output_register_strings));

View File

@ -0,0 +1,25 @@
#ifndef __L4SYS_CONVERSION_HPP__
#define __L4SYS_CONVERSION_HPP__
#include "l4sys.pb.h"
class L4SysConversion {
public:
L4SysConversion(char const **strings, size_t array_size)
: m_Strings(strings)
{
m_ElementCount = array_size / sizeof(char*);
}
char const * output(unsigned int res) {
if (res == 0 || res >= m_ElementCount) {
return m_Strings[0];
} else {
return m_Strings[res];
}
}
private:
char const **m_Strings;
size_t m_ElementCount;
};
#endif // __L4SYS_CONVERSION_HPP__

View File

@ -12,6 +12,7 @@
#include "InstructionFilter.hpp"
#include "aluinstr.hpp"
#include "campaign.hpp"
#include "conversion.hpp"
#include "sal/SALConfig.hpp"
#include "sal/SALInst.hpp"
@ -35,6 +36,7 @@ using namespace fail;
string output;
string golden_run;
extern L4SysConversion l4sysRegisterConversion;
string L4SysExperiment::sanitised(const string &in_str) {
string result;
@ -191,6 +193,17 @@ void L4SysExperiment::terminate(int reason) {
simulator.terminate(reason);
}
void L4SysExperiment::terminateWithError(string details, int reason) {
param->msg.set_resulttype(param->msg.UNKNOWN);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
param->msg.set_details(details);
m_jc.sendResult(*param);
terminate(reason);
}
bool L4SysExperiment::run() {
BPSingleListener bp(0, L4SYS_ADDRESS_SPACE);
srand(time(NULL));
@ -203,9 +216,11 @@ bool L4SysExperiment::run() {
simulator.addListenerAndResume(&bp);
log << "test function entry reached, saving state" << endl;
log << "EIP = " << hex << bp.getTriggerInstructionPointer() << " or "
log << "EIP: expected " << hex << bp.getTriggerInstructionPointer()
<< " and actually got "
<< simulator.getCPU(0).getInstructionPointer()
<< endl;
log << "check the source code if the two instruction pointers are not equal" << endl;
simulator.save(L4SYS_STATE_FOLDER);
#elif PREPARATION_STEP == 2
// STEP 2: determine instructions executed
@ -375,28 +390,16 @@ bool L4SysExperiment::run() {
ss << "SANITY CHECK FAILED: " << injection_ip << " != "
<< curr_instr.trigger_addr;
log << ss.str() << endl;
param->msg.set_resulttype(param->msg.UNKNOWN);
param->msg.set_resultdata(injection_ip);
param->msg.set_details(ss.str());
m_jc.sendResult(*param);
terminate(20);
terminateWithError(ss.str(), 20);
}
#endif
// inject
if (exp_type == param->msg.GPRFLIP) {
if (!param->msg.has_register_offset()) {
param->msg.set_resulttype(param->msg.UNKNOWN);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
stringstream ss;
ss << "Sent package did not contain the injection location (register offset)";
param->msg.set_details(ss.str());
m_jc.sendResult(*param);
terminate(30);
terminateWithError(
"Sent package did not contain the injection location (register offset)",
30);
}
int reg_offset = param->msg.register_offset();
ConcreteCPU& cpu = simulator.getCPU(0);
@ -448,11 +451,6 @@ bool L4SysExperiment::run() {
// do the logging
logInjection();
} else if (exp_type == param->msg.RATFLIP) {
/*
TODO: provide information on the affected register
in param->msg.register and on its destination in
param->msg.details
*/
ud_type_t which = UD_NONE;
unsigned rnd = 0;
Udis86 udis(injection_ip);
@ -460,16 +458,8 @@ bool L4SysExperiment::run() {
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
udis.setInputBuffer(calculateInstructionAddress(), currInstr->ilen());
if (!udis.fetchNextInstruction()) {
param->msg.set_resulttype(param->msg.UNKNOWN);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
stringstream ss;
ss << "Could not decode instruction using UDIS86";
param->msg.set_details(ss.str());
m_jc.sendResult(*param);
terminate(32);
terminateWithError(
"Could not decode instruction using UDIS86", 32);
}
ud_t _ud = udis.getCurrentState();
@ -522,16 +512,11 @@ bool L4SysExperiment::run() {
simulator.getCPU(0).getInstructionPointer() != L4SYS_FUNC_EXIT);
if (simulator.getCPU(0).getInstructionPointer() == L4SYS_FUNC_EXIT) {
param->msg.set_resulttype(param->msg.UNKNOWN);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
stringstream ss;
ss << "Reached the end of the experiment without finding an appropriate instruction";
param->msg.set_details(ss.str());
m_jc.sendResult(*param);
terminate(33);
ss << "Reached the end of the experiment ";
ss << "without finding an appropriate instruction";
terminateWithError(ss.str(), 33);
}
// store the real injection point
@ -542,7 +527,8 @@ bool L4SysExperiment::run() {
// some declarations
GPRegisterId bochs_reg = Udis86::udisGPRToFailBochsGPR(which);
int exchg_reg = -1;
param->msg.set_register_offset(
static_cast<L4SysProtoMsg_RegisterType>(bochs_reg + 1));
ConcreteCPU &cpu = simulator.getCPU(0);
Register *bochsRegister = cpu.getRegister(bochs_reg);
Register *exchangeRegister = NULL;
@ -551,10 +537,11 @@ bool L4SysExperiment::run() {
// (ten percent chance)
if (rand() % 10 == 0) {
// assure exchange of registers
exchg_reg = rand() % 7;
unsigned int exchg_reg = rand() % 7;
if (exchg_reg == bochs_reg)
exchg_reg++;
exchangeRegister = cpu.getRegister(exchg_reg);
param->msg.set_details(l4sysRegisterConversion.output(exchg_reg + 1));
}
// prepare the fault
@ -562,7 +549,7 @@ bool L4SysExperiment::run() {
if (rnd > 0) {
//input register - do the fault injection here
regdata_t newdata = 0;
if (exchangeRegister >= 0) {
if (exchangeRegister != NULL) {
// the data is taken from a process register chosen before
newdata = cpu.getRegisterContent(exchangeRegister);
} else {
@ -578,7 +565,7 @@ bool L4SysExperiment::run() {
// restore the register if we are still in the thread
if (rnd == 0) {
// output register - do the fault injection here
if (exchangeRegister >= 0) {
if (exchangeRegister != NULL) {
// write the result into the wrong local register
regdata_t newdata = cpu.getRegisterContent(bochsRegister);
cpu.setRegisterContent(exchangeRegister, newdata);
@ -604,16 +591,11 @@ bool L4SysExperiment::run() {
}
if (simulator.getCPU(0).getInstructionPointer() == L4SYS_FUNC_EXIT) {
param->msg.set_resulttype(param->msg.UNKNOWN);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
stringstream ss;
ss << "Reached the end of the experiment without finding an appropriate instruction";
param->msg.set_details(ss.str());
m_jc.sendResult(*param);
terminate(33);
ss << "Reached the end of the experiment ";
ss << "without finding an appropriate instruction";
terminateWithError(ss.str(), 34);
}
// store the real injection point
@ -625,16 +607,9 @@ bool L4SysExperiment::run() {
aluInstrObject.randomEquivalent(newInstr, details);
if (memcmp(&newInstr, currInstr, sizeof(bxInstruction_c)) == 0) {
// something went wrong - exit experiment
param->msg.set_resulttype(param->msg.UNKNOWN);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
ostringstream oss;
oss << "Did not hit an ALU instruction - correct the source code please!";
param->msg.set_details(oss.str());
m_jc.sendResult(*param);
terminate(40);
terminateWithError(
"Did not hit an ALU instruction - correct the source code please!",
40);
}
// record information on the new instruction
param->msg.set_details(details);
@ -688,15 +663,9 @@ bool L4SysExperiment::run() {
param->msg.set_output(sanitised(output.c_str()));
} else {
log << "Result WTF?" << endl;
param->msg.set_resulttype(param->msg.UNKNOWN);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
stringstream ss;
ss << "eventid " << ev << " EIP "
<< simulator.getCPU(0).getInstructionPointer();
param->msg.set_details(ss.str());
ss << "eventid " << ev;
terminateWithError(ss.str(), 50);
}
m_jc.sendResult(*param);

View File

@ -1,23 +0,0 @@
195c195
< BPSingleListener bp(0, L4SYS_ADDRESS_SPACE);
---
> BPSingleListener bp(0, ANY_ADDR);
202,209c202,210
< bp.setWatchInstructionPointer(L4SYS_FUNC_ENTRY);
< simulator.addListenerAndResume(&bp);
<
< log << "test function entry reached, saving state" << endl;
< log << "EIP = " << hex << bp.getTriggerInstructionPointer() << " or "
< << simulator.getRegisterManager().getInstructionPointer()
< << endl;
< simulator.save(L4SYS_STATE_FOLDER);
---
> for (int i = 0; i < 500; i++) {
> bp.setWatchInstructionPointer(L4SYS_FUNC_ENTRY);
> simulator.addListenerAndResume(&bp);
> log << "test function entry reached" << endl;
> log << "EIP = " << hex << bp.getTriggerInstructionPointer() << " or "
> << simulator.getRegisterManager().getInstructionPointer()
> << endl;
> simulator.removeListener(&bp);
> }

View File

@ -102,6 +102,10 @@ private:
* Calculate the timeout of the current workload in milliseconds.
*/
unsigned calculateTimeout(unsigned instr_left);
/**
* Send back the experiment parameter set with a description of the error.
*/
void terminateWithError(std::string details, int reason);
};
#endif // __L4SYS_EXPERIMENT_HPP__

View File

@ -5,11 +5,11 @@
#define MAX_INSTR_BYTES 15
// the bounds of the program (space, instructions and time)
#define L4SYS_ADDRESS_SPACE 0x203d000
#define L4SYS_ADDRESS_SPACE 0x1fe0000
#define L4SYS_FUNC_ENTRY 0x10025ca
#define L4SYS_FUNC_EXIT 0x1002810
// kernel: 3597806, userland: 79484908
#define L4SYS_NUMINSTR 83082714
// kernel: 2377547, userland: 79405472
#define L4SYS_NUMINSTR 81783019
#define L4SYS_BOCHS_IPS 5000000
// several file names used

View File

@ -12,17 +12,17 @@ message L4SysProtoMsg {
required int32 bit_offset = 3;
// registers
enum RegisterType {
EAX = 1;
ECX = 2;
EDX = 3;
EBX = 4;
ESP = 5;
EBP = 6;
ESI = 7;
EDI = 8;
}
optional RegisterType register_offset = 4;
enum RegisterType {
EAX = 1;
ECX = 2;
EDX = 3;
EBX = 4;
ESP = 5;
EBP = 6;
ESI = 7;
EDI = 8;
}
optional RegisterType register_offset = 4;
// results
// make these optional to reduce overhead for server->client communication

Binary file not shown.

View File

@ -81,8 +81,8 @@ you may set \verb+L4SYS_ADDRESS_SPACE+ to \verb+ANY_ADDR+. Keep in mind that in
that case, your instruction addresses must be unique among all those
executed in the system, which in general is not the case.
Basically, there are two ways to find out the identifier of a certain
address space in Fail*: You can look up the value in
To find out the value of the address space identifier, you will have to
look up the value in
the emulator using a debugger. In the case of Bochs, you may want to
study
\href{http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html}{this page},
@ -90,38 +90,8 @@ and, according to its instructions,
dump the content of the CR3 control register at the
beginning of your program.
You can also utilise the Fail* framework, which is easier and more reliable,
but as there is no real reason to include this ``feature'' in the framework,
in order to do so, you need to patch it. Namely,
\texttt{src/core/sal/Listener.cc} and
\texttt{src/experiments/l4-sys/experiment.cc}
need to be modified using the two patch files supplied alongside with this
manual in the current directory.
You should check the patch files for their release date and content:
In case the framework's
event handling structure has changed, the line numbers in
\texttt{Listener.cc} are incorrect,
and you need to apply the patch manually.
As soon as you have applied the patch, set \verb+PREPARATION_STEP+
to \texttt{1} in \texttt{experimentInfo.hpp} and recompile the framework.
Now start the experiment client (\texttt{fail-client}) in your
emulator directory, and
it will show you which address space is active whenever a
breakpoint triggers.
Ideally, you still have a graphical interface enabled to
monitor your system's progress and check if the breakpoints
are triggered at the right points in time.
When your program has reached the function entry point,
note the address space and exit the program simply by pressing Ctrl+C.
\subsection{Step 1: Save the initial state of the machine}
If you have modified the Fail* framework in Step 0,
you should now restore the original framework
data using \texttt{svn revert}.
Make sure \verb+PREPARATION_STEP+ is still set to \texttt{1}, and
you have set \verb+L4SYS_ADDRESS_SPACE+ accordingly.
Now recompile and execute the framework code again, this time with the graphical
@ -297,10 +267,7 @@ the campaign server, from left to right.
\section{Known bugs}
At the moment, RATFlip does not provide enough information
to reconstruct the injected fault
(see also the \texttt{TODO} in \texttt{experiment.cc}).
Also, if you need support for more than one processor,
If you need support for more than one processor,
you will have to extend the code accordingly:
at the moment, when in doubt, it uses the first CPU.