- 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 UDIS86.cc
InstructionFilter.hpp InstructionFilter.hpp
InstructionFilter.cc InstructionFilter.cc
conversion.hpp
conversion.cc
) )
#### PROTOBUFS #### #### 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 "campaign.hpp"
#include "experimentInfo.hpp" #include "experimentInfo.hpp"
#include "conversion.hpp"
#include "cpn/CampaignManager.hpp" #include "cpn/CampaignManager.hpp"
#include "util/Logger.hpp" #include "util/Logger.hpp"
#include "sal/SALConfig.hpp" #include "sal/SALConfig.hpp"
@ -11,10 +12,8 @@ using namespace std;
using namespace fail; using namespace fail;
char const * const results_csv = "l4sys.csv"; 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]; #define OUTPUT_CASE(OUTPUT) case L4SysProtoMsg::OUTPUT: return l4sys_output_result_strings[L4SysProtoMsg::OUTPUT];
std::string L4SysCampaign::output_result(L4SysProtoMsg_ResultType res) { std::string L4SysCampaign::output_result(L4SysProtoMsg_ResultType res) {
switch (res) { switch (res) {
@ -56,6 +55,11 @@ std::string L4SysCampaign::output_register(L4SysProtoMsg_RegisterType res) {
} }
} }
#undef OUTPUT_CASE #undef OUTPUT_CASE
#endif
extern L4SysConversion l4sysResultConversion;
extern L4SysConversion l4sysExperimentConversion;
extern L4SysConversion l4sysRegisterConversion;
bool L4SysCampaign::run() { bool L4SysCampaign::run() {
Logger log("L4SysCampaign"); Logger log("L4SysCampaign");
@ -77,6 +81,7 @@ bool L4SysCampaign::run() {
int count = 0; int count = 0;
srand(time(NULL)); srand(time(NULL));
#if 0
for (int i = 0; i < 20000; ++i) { for (int i = 0; i < 20000; ++i) {
L4SysExperimentData *d = new L4SysExperimentData; L4SysExperimentData *d = new L4SysExperimentData;
d->msg.set_exp_type(d->msg.GPRFLIP); d->msg.set_exp_type(d->msg.GPRFLIP);
@ -119,7 +124,8 @@ bool L4SysCampaign::run() {
campaignmanager.addParam(d); campaignmanager.addParam(d);
++count; ++count;
} }
for (int i = 0; i < 20000; ++i) { #endif
for (int i = 0; i < 5000; ++i) {
L4SysExperimentData *d = new L4SysExperimentData; L4SysExperimentData *d = new L4SysExperimentData;
d->msg.set_exp_type(d->msg.RATFLIP); d->msg.set_exp_type(d->msg.RATFLIP);
// modify for a random instruction // modify for a random instruction
@ -144,13 +150,15 @@ bool L4SysCampaign::run() {
while ((res = static_cast<L4SysExperimentData *>(campaignmanager.getDone()))) { while ((res = static_cast<L4SysExperimentData *>(campaignmanager.getDone()))) {
rescount++; 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()) if (res->msg.has_register_offset())
results << output_register(res->msg.register_offset()); results << l4sysRegisterConversion.output(res->msg.register_offset());
else else
results << "None"; results << "None";
results << "," << res->msg.instr_offset() << "," << res->msg.bit_offset() results << "," << res->msg.instr_offset() << "," << res->msg.bit_offset()
<< "," << output_result(res->msg.resulttype()) << "," << ","
<< l4sysResultConversion.output(res->msg.resulttype()) << ","
<< res->msg.resultdata(); << res->msg.resultdata();
if (res->msg.has_output()) if (res->msg.has_output())
results << "," << res->msg.output(); results << "," << res->msg.output();

View File

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

View File

@ -5,11 +5,11 @@
#define MAX_INSTR_BYTES 15 #define MAX_INSTR_BYTES 15
// the bounds of the program (space, instructions and time) // 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_ENTRY 0x10025ca
#define L4SYS_FUNC_EXIT 0x1002810 #define L4SYS_FUNC_EXIT 0x1002810
// kernel: 3597806, userland: 79484908 // kernel: 2377547, userland: 79405472
#define L4SYS_NUMINSTR 83082714 #define L4SYS_NUMINSTR 81783019
#define L4SYS_BOCHS_IPS 5000000 #define L4SYS_BOCHS_IPS 5000000
// several file names used // several file names used

View File

@ -12,17 +12,17 @@ message L4SysProtoMsg {
required int32 bit_offset = 3; required int32 bit_offset = 3;
// registers // registers
enum RegisterType { enum RegisterType {
EAX = 1; EAX = 1;
ECX = 2; ECX = 2;
EDX = 3; EDX = 3;
EBX = 4; EBX = 4;
ESP = 5; ESP = 5;
EBP = 6; EBP = 6;
ESI = 7; ESI = 7;
EDI = 8; EDI = 8;
} }
optional RegisterType register_offset = 4; optional RegisterType register_offset = 4;
// results // results
// make these optional to reduce overhead for server->client communication // 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 that case, your instruction addresses must be unique among all those
executed in the system, which in general is not the case. executed in the system, which in general is not the case.
Basically, there are two ways to find out the identifier of a certain To find out the value of the address space identifier, you will have to
address space in Fail*: You can look up the value in look up the value in
the emulator using a debugger. In the case of Bochs, you may want to the emulator using a debugger. In the case of Bochs, you may want to
study study
\href{http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html}{this page}, \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 dump the content of the CR3 control register at the
beginning of your program. 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} \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 Make sure \verb+PREPARATION_STEP+ is still set to \texttt{1}, and
you have set \verb+L4SYS_ADDRESS_SPACE+ accordingly. you have set \verb+L4SYS_ADDRESS_SPACE+ accordingly.
Now recompile and execute the framework code again, this time with the graphical 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} \section{Known bugs}
At the moment, RATFlip does not provide enough information If you need support for more than one processor,
to reconstruct the injected fault
(see also the \texttt{TODO} in \texttt{experiment.cc}).
Also, if you need support for more than one processor,
you will have to extend the code accordingly: you will have to extend the code accordingly:
at the moment, when in doubt, it uses the first CPU. at the moment, when in doubt, it uses the first CPU.