diff --git a/doc/class-diagram.dia b/doc/class-diagram.dia
index b0016d3e2202335c2875238167edcb7f5c85bc47..b355e80a34c5696aae1b4d0adc7ac0194a0a4548 100644
--- a/doc/class-diagram.dia
+++ b/doc/class-diagram.dia
@@ -1841,19 +1841,19 @@
     </dia:object>
     <dia:object type="UML - Class" version="0" id="O1">
       <dia:attribute name="obj_pos">
-        <dia:point val="20.3,55.05"/>
+        <dia:point val="13.75,58.55"/>
       </dia:attribute>
       <dia:attribute name="obj_bb">
-        <dia:rectangle val="20.25,55;43.565,73.7"/>
+        <dia:rectangle val="13.7,58.5;44.33,83.6"/>
       </dia:attribute>
       <dia:attribute name="elem_corner">
-        <dia:point val="20.3,55.05"/>
+        <dia:point val="13.75,58.55"/>
       </dia:attribute>
       <dia:attribute name="elem_width">
-        <dia:real val="23.215"/>
+        <dia:real val="30.530000000000001"/>
       </dia:attribute>
       <dia:attribute name="elem_height">
-        <dia:real val="18.600000000000005"/>
+        <dia:real val="25.000000000000007"/>
       </dia:attribute>
       <dia:attribute name="name">
         <dia:string>#BochsController#</dia:string>
@@ -2035,6 +2035,52 @@
             <dia:boolean val="false"/>
           </dia:attribute>
         </dia:composite>
+        <dia:composite type="umlattribute">
+          <dia:attribute name="name">
+            <dia:string>#m_CPUContext#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="type">
+            <dia:string>#BX_CPU_C*#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="value">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="comment">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="visibility">
+            <dia:enum val="1"/>
+          </dia:attribute>
+          <dia:attribute name="abstract">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="class_scope">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+        </dia:composite>
+        <dia:composite type="umlattribute">
+          <dia:attribute name="name">
+            <dia:string>#m_CacheEntry#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="type">
+            <dia:string>#bxICacheEntry_c*#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="value">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="comment">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="visibility">
+            <dia:enum val="1"/>
+          </dia:attribute>
+          <dia:attribute name="abstract">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="class_scope">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+        </dia:composite>
       </dia:attribute>
       <dia:attribute name="operations">
         <dia:composite type="umloperation">
@@ -2239,6 +2285,57 @@
                 <dia:enum val="1"/>
               </dia:attribute>
             </dia:composite>
+            <dia:composite type="umlparameter">
+              <dia:attribute name="name">
+                <dia:string>#address_space#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="type">
+                <dia:string>#address_t#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="value">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="comment">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="kind">
+                <dia:enum val="1"/>
+              </dia:attribute>
+            </dia:composite>
+            <dia:composite type="umlparameter">
+              <dia:attribute name="name">
+                <dia:string>#context#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="type">
+                <dia:string>#BX_CPU_C*#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="value">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="comment">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="kind">
+                <dia:enum val="1"/>
+              </dia:attribute>
+            </dia:composite>
+            <dia:composite type="umlparameter">
+              <dia:attribute name="name">
+                <dia:string>#cache_entry#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="type">
+                <dia:string>#bxICacheEntry_c*#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="value">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="comment">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="kind">
+                <dia:enum val="1"/>
+              </dia:attribute>
+            </dia:composite>
           </dia:attribute>
         </dia:composite>
         <dia:composite type="umloperation">
@@ -2732,6 +2829,148 @@
           </dia:attribute>
           <dia:attribute name="parameters"/>
         </dia:composite>
+        <dia:composite type="umloperation">
+          <dia:attribute name="name">
+            <dia:string>#onIOPortEvent#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="stereotype">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="type">
+            <dia:string>#void#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="visibility">
+            <dia:enum val="0"/>
+          </dia:attribute>
+          <dia:attribute name="comment">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="abstract">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="inheritance_type">
+            <dia:enum val="2"/>
+          </dia:attribute>
+          <dia:attribute name="query">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="class_scope">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="parameters">
+            <dia:composite type="umlparameter">
+              <dia:attribute name="name">
+                <dia:string>#data#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="type">
+                <dia:string>#unsigned char#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="value">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="comment">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="kind">
+                <dia:enum val="1"/>
+              </dia:attribute>
+            </dia:composite>
+            <dia:composite type="umlparameter">
+              <dia:attribute name="name">
+                <dia:string>#port#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="type">
+                <dia:string>#unsigned#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="value">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="comment">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="kind">
+                <dia:enum val="1"/>
+              </dia:attribute>
+            </dia:composite>
+            <dia:composite type="umlparameter">
+              <dia:attribute name="name">
+                <dia:string>#out#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="type">
+                <dia:string>#bool#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="value">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="comment">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="kind">
+                <dia:enum val="1"/>
+              </dia:attribute>
+            </dia:composite>
+          </dia:attribute>
+        </dia:composite>
+        <dia:composite type="umloperation">
+          <dia:attribute name="name">
+            <dia:string>#getICacheEntry#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="stereotype">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="type">
+            <dia:string>#bxICacheEntry_c*#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="visibility">
+            <dia:enum val="0"/>
+          </dia:attribute>
+          <dia:attribute name="comment">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="abstract">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="inheritance_type">
+            <dia:enum val="2"/>
+          </dia:attribute>
+          <dia:attribute name="query">
+            <dia:boolean val="true"/>
+          </dia:attribute>
+          <dia:attribute name="class_scope">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="parameters"/>
+        </dia:composite>
+        <dia:composite type="umloperation">
+          <dia:attribute name="name">
+            <dia:string>#getCPUContext#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="stereotype">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="type">
+            <dia:string>#BX_CPU_C*#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="visibility">
+            <dia:enum val="0"/>
+          </dia:attribute>
+          <dia:attribute name="comment">
+            <dia:string>##</dia:string>
+          </dia:attribute>
+          <dia:attribute name="abstract">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="inheritance_type">
+            <dia:enum val="2"/>
+          </dia:attribute>
+          <dia:attribute name="query">
+            <dia:boolean val="true"/>
+          </dia:attribute>
+          <dia:attribute name="class_scope">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="parameters"/>
+        </dia:composite>
       </dia:attribute>
       <dia:attribute name="template">
         <dia:boolean val="false"/>
@@ -2743,16 +2982,16 @@
         <dia:point val="32.55,48.5503"/>
       </dia:attribute>
       <dia:attribute name="obj_bb">
-        <dia:rectangle val="31.7,48.5003;33.4,55.0497"/>
+        <dia:rectangle val="28.965,48.5003;33.4,58.5496"/>
       </dia:attribute>
       <dia:attribute name="meta">
         <dia:composite type="dict"/>
       </dia:attribute>
       <dia:attribute name="orth_points">
         <dia:point val="32.55,48.5503"/>
-        <dia:point val="32.55,52.175"/>
-        <dia:point val="31.9075,52.175"/>
-        <dia:point val="31.9075,54.9997"/>
+        <dia:point val="32.55,53.9249"/>
+        <dia:point val="29.015,53.9249"/>
+        <dia:point val="29.015,58.4996"/>
       </dia:attribute>
       <dia:attribute name="orth_orient">
         <dia:enum val="1"/>
@@ -2776,7 +3015,7 @@
       </dia:attribute>
       <dia:connections>
         <dia:connection handle="0" to="O0" connection="88"/>
-        <dia:connection handle="1" to="O1" connection="48"/>
+        <dia:connection handle="1" to="O1" connection="58"/>
       </dia:connections>
     </dia:object>
     <dia:object type="UML - Class" version="0" id="O3">
diff --git a/doc/class-diagram.png b/doc/class-diagram.png
index 9c61864bddd8896f0241845572a457ea36dbd53b..17fdb5dc16c29ba3bb9b2cbf8e73a8fb99a577f8 100644
Binary files a/doc/class-diagram.png and b/doc/class-diagram.png differ
diff --git a/simulators/bochs/cpu/cpu.cc b/simulators/bochs/cpu/cpu.cc
index 2131687e5c3438262a55f247ab1f8999a5c752a3..65a10e69651d50edc1564368eab6822e287abadc 100644
--- a/simulators/bochs/cpu/cpu.cc
+++ b/simulators/bochs/cpu/cpu.cc
@@ -33,7 +33,7 @@
 
 // Just a dummy function to define a join-point. This function is
 // *just* called once within bx_cpu_c::cpu_loop(...).
-static inline void defineCPULoopJoinPoint(BX_CPU_C* pThis)
+static inline void defineCPULoopJoinPoint(BX_CPU_C* pThis, bxICacheEntry_c *pEntry)
 {
     /* nothing to do here */
 }
@@ -160,7 +160,7 @@ void BX_CPU_C::cpu_loop(Bit32u max_instr_count)
  * 
  */
 
-      defineCPULoopJoinPoint(BX_CPU_THIS);
+      defineCPULoopJoinPoint(BX_CPU_THIS, entry);
 
 /****************************************************************/
       // instruction decoding completed -> continue with execution
diff --git a/src/core/sal/bochs/BochsController.cc b/src/core/sal/bochs/BochsController.cc
index 46b6a14a9387cbbdd18fb946b30604a19baced67..13246e559dc996d929ecea5ec07680dba1f43768 100644
--- a/src/core/sal/bochs/BochsController.cc
+++ b/src/core/sal/bochs/BochsController.cc
@@ -19,7 +19,8 @@ bx_bool interrupt_injection_request = false;
 int     interrupt_to_fire           = -1;
 
 BochsController::BochsController()
-	: SimulatorController(new BochsRegisterManager(), new BochsMemoryManager())
+	: SimulatorController(new BochsRegisterManager(), new BochsMemoryManager()),
+	  m_CPUContext(NULL), m_CacheEntry(NULL)
 {
 	// -------------------------------------
 	// Add the general purpose register:
@@ -89,12 +90,15 @@ void BochsController::dbgEnableInstrPtrOutput(unsigned regularity, std::ostream*
 }
 #endif // DEBUG
 
-void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_space)
+void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_space,
+		BX_CPU_C *context, bxICacheEntry_c *cache_entry)
 {
 #ifdef DEBUG
 	if(m_Regularity != 0 && ++m_Counter % m_Regularity == 0)
 		(*m_pDest) << "0x" << std::hex << instrPtr;
 #endif
+	m_CPUContext = context;
+	m_CacheEntry = cache_entry;
 	bool do_fire = false;
 	// Check for active breakpoint-events:
 	bp_cache_t &buffer_cache = m_EvList.getBPBuffer();
@@ -117,31 +121,6 @@ void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_sp
 		m_EvList.fireActiveEvents();
 	// Note: SimulatorController::onBreakpointEvent will not be invoked in this
 	//       implementation.
-#if 0
-	//deprecated - this code is ugly
-	bool do_fire = false;
-	int i = 0;
-	BufferCache<BPEvent*> *buffer_cache = m_EvList.getBPBuffer();
-	while(i < buffer_cache->getCount()) {
-		BPEvent *pEvBreakpt = buffer_cache->get(i);
-		if(pEvBreakpt->isMatching(instrPtr, address_space)) {
-			pEvBreakpt->setTriggerInstructionPointer(instrPtr);
-
-			i = buffer_cache->makeActive(m_EvList, i);
-			assert(i >= 0 &&
-					   "FATAL ERROR: Could not erase BPEvent from cache");
-
-			// we now know we need to fire the active events - usually we do not have to
-			do_fire = true;
-			// "i" has already been set to the next element (by calling
-			// makeActive()):
-			continue; // -> skip loop  increment
-		}
-		i++;
-	}
-	if(do_fire)
-		m_EvList.fireActiveEvents();
-#endif
 }
 
 void BochsController::onIOPortEvent(unsigned char data, unsigned port, bool out) {
@@ -300,11 +279,13 @@ void BochsController::onEventTrigger(BaseEvent* pev)
 const std::string& BochsController::getMnemonic() const
 {
 	static std::string str;
+#if 0
 	bxICacheEntry_c* pEntry = BX_CPU(0)->getICacheEntry();
 	assert(pEntry != NULL && "FATAL ERROR: Bochs internal function returned NULL (not expected)!");
 	bxInstruction_c* pInstr = pEntry->i;
 	assert(pInstr != NULL && "FATAL ERROR: Bochs internal member was NULL (not expected)!");
-	const char* pszName = get_bx_opcode_name(pInstr->getIaOpcode());
+#endif
+	const char* pszName = get_bx_opcode_name(getICacheEntry()->i->getIaOpcode());
 	if (pszName != NULL)
 		str = pszName;
 	else
diff --git a/src/core/sal/bochs/BochsController.hpp b/src/core/sal/bochs/BochsController.hpp
index 1512fd54b6277db136e7ebf94d5222407787cf73..4338491021f24189495a4aab0ac2f1f4b7224206 100644
--- a/src/core/sal/bochs/BochsController.hpp
+++ b/src/core/sal/bochs/BochsController.hpp
@@ -81,7 +81,7 @@ public:
 	 * @param instrPtr the new instruction pointer
 	 * @param address_space the address space the CPU is currently in
 	 */
-	void onInstrPtrChanged(address_t instrPtr, address_t address_space);
+	void onInstrPtrChanged(address_t instrPtr, address_t address_space, BX_CPU_C *context, bxICacheEntry_c *cache_entry);
 	/**
 	 * I/O port communication handler. This method is called (from
 	 * the IOPortCom aspect) every time when Bochs performs a port I/O operation.
@@ -174,6 +174,19 @@ public:
 	 *         the returned string is empty
 	 */
 	const std::string& getMnemonic() const;
+	/**
+	 * Retrieves the current Bochs instruction cache entry
+	 * @returns a pointer to a bxICacheEntry_c object
+	 */
+	inline bxICacheEntry_c *getICacheEntry() const { return m_CacheEntry; }
+	/**
+	 * Retrieves the current CPU context
+	 * @return a pointer to a BX_CPU_C object
+	 */
+	inline BX_CPU_C *getCPUContext() const { return m_CPUContext; }
+private:
+	BX_CPU_C *m_CPUContext;
+	bxICacheEntry_c *m_CacheEntry;
 };
 
 } // end-of-namespace: fail
diff --git a/src/core/sal/bochs/Breakpoints.ah b/src/core/sal/bochs/Breakpoints.ah
index 42c004580152571d1f4b7a55e4462d42d190c561..9aa683fde137995e6c9f36afb5b0c50fbebc67a3 100644
--- a/src/core/sal/bochs/Breakpoints.ah
+++ b/src/core/sal/bochs/Breakpoints.ah
@@ -19,10 +19,10 @@ aspect Breakpoints {
 		// BX_CPU(0) otherwise
 		BX_CPU_C* pThis = *(tjp->arg<0>());
 		// Points to the *current* bxInstruction-object
-		//bxInstruction_c* pInstr = *(tjp->arg<1>());
+		bxICacheEntry_c* pEntry = *(tjp->arg<1>());
 
 		// report this event to the Bochs controller:
-		fail::simulator.onInstrPtrChanged(pThis->get_instruction_pointer(), pThis->cr3);
+		fail::simulator.onInstrPtrChanged(pThis->get_instruction_pointer(), pThis->cr3, pThis, pEntry);
 		// Note: get_bx_opcode_name(pInstr->getIaOpcode()) retrieves the mnemonics.
 	}
 };
diff --git a/src/experiments/l4-sys/campaign.cc b/src/experiments/l4-sys/campaign.cc
index 61e50e8908cbef2a23b322c75d38a6fddd4bbc3e..2128cdef8ea12895f9030e7fbcef790f748fe731 100644
--- a/src/experiments/l4-sys/campaign.cc
+++ b/src/experiments/l4-sys/campaign.cc
@@ -11,9 +11,24 @@ using namespace std;
 using namespace fail;
 
 char const * const results_csv = "l4sys.csv";
+const char *l4sys_output_strings[] = { "Unknown", "Done", "Timeout", "Trap", "Interrupt", "Wrong output", "Error" };
 
-bool L4SysCampaign::run()
-{
+std::string L4SysCampaign::output_result(L4SysProtoMsg_ResultType res) {
+#define OUTPUT_CASE(OUTPUT) case L4SysProtoMsg::OUTPUT: return l4sys_output_strings[L4SysProtoMsg::OUTPUT];
+	switch (res) {
+	OUTPUT_CASE(DONE);
+	OUTPUT_CASE(TIMEOUT);
+	OUTPUT_CASE(TRAP);
+	OUTPUT_CASE(INTR);
+	OUTPUT_CASE(WRONG);
+	OUTPUT_CASE(UNKNOWN);
+	default:
+		return l4sys_output_strings[0];
+	}
+#undef OUTPUT_CASE
+}
+
+bool L4SysCampaign::run() {
 	Logger log("L4SysCampaign");
 
 #if 0
@@ -32,17 +47,17 @@ bool L4SysCampaign::run()
 	log << "startup" << endl;
 
 	int count = 0;
-	//iterate over one register
-	for (int bit_offset = 0; bit_offset < 1; ++bit_offset) {
-		for (int instr_offset = 0; instr_offset < L4SYS_NUMINSTR; ++instr_offset) {
-			L4SysExperimentData *d = new L4SysExperimentData;
-			d->msg.set_instr_offset(instr_offset);
-			d->msg.set_bit_offset(bit_offset);
-			d->msg.set_bit_offset(0);
-	  
-			campaignmanager.addParam(d);
-			++count;
-		}
+	srand(time(NULL));
+	for (int i = 0; i < 3000; ++i) {
+		L4SysExperimentData *d = new L4SysExperimentData;
+		d->msg.set_exp_type(d->msg.IDCFLIP);
+		d->msg.set_instr_offset(rand() % L4SYS_NUMINSTR);
+		// 15 bytes (120 bits) are the longest instruction Bochs still executes
+		int bit_offset = rand() % 120;
+		d->msg.set_bit_offset(bit_offset);
+
+		campaignmanager.addParam(d);
+		++count;
 	}
 	campaignmanager.noMoreParameters();
 	log << "done enqueueing parameter sets (" << count << ")." << endl;
@@ -50,19 +65,19 @@ bool L4SysCampaign::run()
 	// collect results
 	L4SysExperimentData *res;
 	int rescount = 0;
-	results << "injection_ip,instr_offset,injection_bit,resulttype,resultdata,output,details" << endl;
+	results
+			<< "injection_ip,instr_offset,injection_bit,resulttype,resultdata,output,details"
+			<< endl;
 	while ((res = static_cast<L4SysExperimentData *>(campaignmanager.getDone()))) {
 		rescount++;
 
-		results << hex
-		 << res->msg.injection_ip() << ","
-		 << dec << res->msg.instr_offset() << ","
-		 << res->msg.bit_offset() << ","
-		 << res->msg.resulttype() << ","
-		 << res->msg.resultdata();
-		if(res->msg.has_output())
+		results << hex << res->msg.injection_ip() << "," << dec
+				<< res->msg.instr_offset() << "," << res->msg.bit_offset()
+				<< "," << output_result(res->msg.resulttype()) << ","
+				<< res->msg.resultdata();
+		if (res->msg.has_output())
 			results << "," << res->msg.output();
-		if(res->msg.has_details())
+		if (res->msg.has_details())
 			results << "," << res->msg.details();
 		results << endl;
 		delete res;
diff --git a/src/experiments/l4-sys/campaign.hpp b/src/experiments/l4-sys/campaign.hpp
index cad4f060d916b92e64f91c5a1a900ab8dbb27b6c..f86a9d18c0d56a8f5b0765027da949b46a198e21 100644
--- a/src/experiments/l4-sys/campaign.hpp
+++ b/src/experiments/l4-sys/campaign.hpp
@@ -14,6 +14,8 @@ public:
 class L4SysCampaign : public fail::Campaign {
 public:
 	virtual bool run();
+private:
+	std::string output_result(L4SysProtoMsg_ResultType res);
 };
 
 #endif // __L4SYS_CAMPAIGN_HPP__
diff --git a/src/experiments/l4-sys/experiment.cc b/src/experiments/l4-sys/experiment.cc
index 620b30fac87058cdab83aed847d0d6170697b626..7b5960b3d6c5f383191fa9f39f1c48cae9e97546 100644
--- a/src/experiments/l4-sys/experiment.cc
+++ b/src/experiments/l4-sys/experiment.cc
@@ -3,13 +3,11 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include <string.h>
 
-#include "util/Logger.hpp"
-
 #include "experiment.hpp"
 #include "experimentInfo.hpp"
-#include "campaign.hpp"
 
 #include "sal/SALConfig.hpp"
 #include "sal/SALInst.hpp"
@@ -33,43 +31,31 @@ using namespace fail;
 #endif
 
 typedef struct __trace_instr_type {
-	address_t trigger_addr;
+	fail::address_t trigger_addr;
 	unsigned bp_counter;
 } trace_instr;
 
-ostream& operator<<(ostream& out, const trace_instr &val) {
-	out << val.trigger_addr << "," << val.bp_counter;
-	return out;
-}
-istream& operator>>(istream& in, trace_instr &val) {
-	in >> val.trigger_addr;
-	//skip the comma
-	in.ignore(1);
-	in >> val.bp_counter;
-	return in;
-}
-
-char const * const state_folder = "l4sys.state";
-char const * const instr_list_fn = "ip.list";
-char const * const golden_run_fn = "golden.out";
-address_t const aspace = 0x01e00000;
 string output;
+#if 0
+//disabled (see "STEP 2" below)
 vector<trace_instr> instr_list;
+vector<trace_instr> alu_instr_list;
+#endif
 string golden_run;
-//the program needs to run 5 times without a fault
-const unsigned times_run = 5;
 
-string L4SysExperiment::sanitised(string in_str) {
+string L4SysExperiment::sanitised(const string &in_str) {
 	string result;
-	result.reserve(in_str.size());
-	for (string::iterator it = in_str.begin(); it != in_str.end(); it++) {
-		unsigned char_value = static_cast<unsigned>(*it);
-		if (char_value < 0x20 || char_value > 0x7E) {
+	int in_str_size = in_str.size();
+	result.reserve(in_str_size);
+	for (int idx = 0; idx < in_str_size; idx++) {
+		char cur_char = in_str[idx];
+		unsigned cur_char_value = static_cast<unsigned>(cur_char);
+		if (cur_char_value < 0x20 || cur_char_value > 0x7E) {
 			char str_nr[5];
-			sprintf(str_nr, "\\%03o", char_value);
+			sprintf(str_nr, "\\%03o", cur_char_value);
 			result += str_nr;
 		} else {
-			result += *it;
+			result += cur_char;
 		}
 	}
 	return result;
@@ -93,15 +79,119 @@ BaseEvent* L4SysExperiment::waitIOOrOther(bool clear_output) {
 	return ev;
 }
 
+Bit32u L4SysExperiment::eipBiased() {
+	BX_CPU_C *cpu_context = simulator.getCPUContext();
+	Bit32u EIP = cpu_context->gen_reg[BX_32BIT_REG_EIP].dword.erx;
+	return EIP + cpu_context->eipPageBias;
+}
+
+const Bit8u *L4SysExperiment::calculateInstructionAddress() {
+	// pasted in from various nested Bochs functions and macros - I hope
+	// they will not change too soon (as do the Bochs developers, probably)
+	BX_CPU_C *cpu_context = simulator.getCPUContext();
+	const Bit8u *result = cpu_context->eipFetchPtr + eipBiased();
+	return result;
+}
+
+bx_bool L4SysExperiment::fetchInstruction(BX_CPU_C *instance, const Bit8u *instr, bxInstruction_c *iStorage)
+{
+  unsigned remainingInPage = instance->eipPageWindowSize - eipBiased();
+  int ret;
+
+#if BX_SUPPORT_X86_64
+  if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
+    ret = instance->fetchDecode64(instr, iStorage, remainingInPage);
+  else
+#endif
+    ret = instance->fetchDecode32(instr, iStorage, remainingInPage);
+
+  if (ret < 0) {
+    // handle instrumentation callback inside boundaryFetch
+    instance->boundaryFetch(instr, remainingInPage, iStorage);
+    return 0;
+  }
+
+  return 1;
+}
+
+void L4SysExperiment::logInjection(Logger &log, const L4SysExperimentData &param) {
+	// explicit type assignment necessary before sending over output stream
+	int id = param.getWorkloadID();
+	int instr_offset = param.msg.instr_offset();
+	int bit_offset = param.msg.bit_offset();
+	int exp_type = param.msg.exp_type();
+	address_t injection_ip = param.msg.injection_ip();
+
+	log << "job " << id << " exp_type " << exp_type	<< endl;
+	log << "inject @ ip " << injection_ip << " (offset " << dec
+			<< instr_offset << ")" << " bit " << bit_offset << endl;
+}
+
+bool L4SysExperiment::isALUInstruction(unsigned opcode) {
+	switch(opcode) {
+		case BX_IA_INC_Eb: case BX_IA_INC_Ew: case BX_IA_INC_Ed: case BX_IA_INC_RX: case BX_IA_INC_ERX:
+		case BX_IA_DEC_Eb: case BX_IA_DEC_Ew: case BX_IA_DEC_Ed: case BX_IA_DEC_RX: case BX_IA_DEC_ERX:
+		case BX_IA_ADC_EbGb: case BX_IA_ADC_EdGd: case BX_IA_ADC_EwGw: case BX_IA_ADD_EbGb: case BX_IA_ADD_EdGd:
+		case BX_IA_ADD_EwGw: case BX_IA_AND_EbGb: case BX_IA_AND_EdGd: case BX_IA_AND_EwGw: case BX_IA_CMP_EbGb:
+		case BX_IA_CMP_EdGd: case BX_IA_CMP_EwGw: case BX_IA_OR_EbGb: case BX_IA_OR_EdGd: case BX_IA_OR_EwGw:
+		case BX_IA_SBB_EbGb: case BX_IA_SBB_EdGd: case BX_IA_SBB_EwGw: case BX_IA_SUB_EbGb: case BX_IA_SUB_EdGd:
+		case BX_IA_SUB_EwGw: case BX_IA_XOR_EbGb: case BX_IA_XOR_EdGd: case BX_IA_XOR_EwGw: case BX_IA_ADC_ALIb:
+		case BX_IA_ADC_AXIw: case BX_IA_ADC_EAXId: case BX_IA_ADD_EbIb: case BX_IA_OR_EbIb: case BX_IA_ADC_EbIb:
+		case BX_IA_SBB_EbIb: case BX_IA_AND_EbIb: case BX_IA_SUB_EbIb: case BX_IA_XOR_EbIb: case BX_IA_CMP_EbIb:
+		case BX_IA_ADD_EwIw: case BX_IA_OR_EwIw: case BX_IA_ADC_EwIw: case BX_IA_SBB_EwIw: case BX_IA_AND_EwIw:
+		case BX_IA_SUB_EwIw: case BX_IA_XOR_EwIw: case BX_IA_CMP_EwIw: case BX_IA_ADD_EdId: case BX_IA_OR_EdId:
+		case BX_IA_ADC_EdId: case BX_IA_SBB_EdId: case BX_IA_AND_EdId: case BX_IA_SUB_EdId: case BX_IA_XOR_EdId:
+		case BX_IA_CMP_EdId: case BX_IA_ADC_GbEb: case BX_IA_ADC_GwEw: case BX_IA_ADC_GdEd: case BX_IA_ADD_ALIb:
+		case BX_IA_ADD_AXIw: case BX_IA_ADD_EAXId: case BX_IA_ADD_GbEb: case BX_IA_ADD_GwEw: case BX_IA_ADD_GdEd:
+		case BX_IA_AND_ALIb: case BX_IA_AND_AXIw: case BX_IA_AND_EAXId: case BX_IA_AND_GbEb: case BX_IA_AND_GwEw:
+		case BX_IA_AND_GdEd: case BX_IA_ROL_Eb: case BX_IA_ROR_Eb: case BX_IA_RCL_Eb: case BX_IA_RCR_Eb:
+		case BX_IA_SHL_Eb: case BX_IA_SHR_Eb: case BX_IA_SAR_Eb: case BX_IA_ROL_Ew: case BX_IA_ROR_Ew:
+		case BX_IA_RCL_Ew: case BX_IA_RCR_Ew: case BX_IA_SHL_Ew: case BX_IA_SHR_Ew: case BX_IA_SAR_Ew:
+		case BX_IA_ROL_Ed: case BX_IA_ROR_Ed: case BX_IA_RCL_Ed: case BX_IA_RCR_Ed: case BX_IA_SHL_Ed:
+		case BX_IA_SHR_Ed: case BX_IA_SAR_Ed: case BX_IA_NOT_Eb: case BX_IA_NEG_Eb: case BX_IA_NOT_Ew:
+		case BX_IA_NEG_Ew: case BX_IA_NOT_Ed: case BX_IA_NEG_Ed:
+			return true;
+		default:
+			return false;
+	}
+}
+
+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::changeBochsInstruction(bxInstruction_c *dest, bxInstruction_c *src) {
+	// backup the current and insert the faulty instruction
+	bxInstruction_c old_instr;
+	memcpy(&old_instr, dest, sizeof(bxInstruction_c));
+	memcpy(dest, src, sizeof(bxInstruction_c));
+
+	// execute the faulty instruction, then return
+	BPSingleEvent singlestepping_event(ANY_ADDR, L4SYS_ADDRESS_SPACE);
+	simulator.addEvent(&singlestepping_event);
+	waitIOOrOther(false);
+	simulator.removeEvent(&singlestepping_event);
+
+	//restore the old instruction
+	memcpy(dest, &old_instr, sizeof(bxInstruction_c));
+}
+
 bool L4SysExperiment::run() {
 	Logger log("L4Sys", false);
-	BPSingleEvent bp(0, aspace);
+	BPSingleEvent bp(0, L4SYS_ADDRESS_SPACE);
 
 	log << "startup" << endl;
 
 	struct stat teststruct;
 	// STEP 1: run until interesting function starts, and save state
-	if (stat(state_folder, &teststruct) == -1) {
+	if (stat(L4SYS_STATE_FOLDER, &teststruct) == -1) {
 		bp.setWatchInstructionPointer(L4SYS_FUNC_ENTRY);
 		simulator.addEventAndWait(&bp);
 
@@ -109,13 +199,19 @@ bool L4SysExperiment::run() {
 		log << "EIP = " << hex << bp.getTriggerInstructionPointer() << " or "
 				<< simulator.getRegisterManager().getInstructionPointer()
 				<< endl;
-		simulator.save(state_folder);
+		simulator.save(L4SYS_STATE_FOLDER);
 	}
 
 	// STEP 2: determine instructions executed
-	if (stat(instr_list_fn, &teststruct) == -1) {
+#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(state_folder);
+		simulator.restore(L4SYS_STATE_FOLDER);
 		log << "EIP = " << hex
 				<< simulator.getRegisterManager().getInstructionPointer()
 				<< endl;
@@ -123,8 +219,8 @@ bool L4SysExperiment::run() {
 		// make sure the timer interrupt doesn't disturb us
 		simulator.addSuppressedInterrupt(32);
 
-		ofstream instr_list_file(instr_list_fn);
-		instr_list_file << hex;
+		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;
@@ -144,25 +240,34 @@ bool L4SysExperiment::run() {
 			new_instr.bp_counter = times_called;
 			instr_list.push_back(new_instr);
 
-			instr_list_file << new_instr << endl;
+			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(instr_list_fn);
-		instr_list_file >> hex;
-		while (!instr_list_file.eof()) {
-			trace_instr curr_instr;
-			instr_list_file >> curr_instr;
-			instr_list.push_back(curr_instr);
-		}
-		instr_list_file.close();
+		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
 
 	// STEP 3: determine the output of a "golden run"
-	if (stat(golden_run_fn, &teststruct) == -1) {
+	if (stat(L4SYS_CORRECT_OUTPUT, &teststruct) == -1) {
 		log << "restoring state" << endl;
-		simulator.restore(state_folder);
+		simulator.restore(L4SYS_STATE_FOLDER);
 		log << "EIP = " << hex
 				<< simulator.getRegisterManager().getInstructionPointer()
 				<< endl;
@@ -170,9 +275,9 @@ bool L4SysExperiment::run() {
 		// make sure the timer interrupt doesn't disturb us
 		simulator.addSuppressedInterrupt(32);
 
-		ofstream golden_run_file(golden_run_fn);
+		ofstream golden_run_file(L4SYS_CORRECT_OUTPUT);
 		bp.setWatchInstructionPointer(L4SYS_FUNC_EXIT);
-		bp.setCounter(times_run);
+		bp.setCounter(L4SYS_ITERATION_COUNT);
 		simulator.addEvent(&bp);
 		BaseEvent* ev = waitIOOrOther(true);
 		if (ev == &bp) {
@@ -191,13 +296,9 @@ bool L4SysExperiment::run() {
 		log << "saving output generated during normal execution" << endl;
 		golden_run_file.close();
 	} else {
-		ifstream golden_run_file(golden_run_fn);
+		ifstream golden_run_file(L4SYS_CORRECT_OUTPUT);
 
-		//shamelessly copied from http://stackoverflow.com/questions/2602013/:
-		golden_run_file.seekg(0, ios::end);
-		size_t flen = golden_run_file.tellg();
-		golden_run.reserve(flen);
-		golden_run_file.seekg(0, ios::beg);
+		golden_run.reserve(teststruct.st_size);
 
 		golden_run.assign((istreambuf_iterator<char>(golden_run_file)),
 				istreambuf_iterator<char>());
@@ -205,131 +306,178 @@ bool L4SysExperiment::run() {
 		golden_run_file.close();
 
 		//the generated output probably has a similar length
-		output.reserve(flen);
+		output.reserve(teststruct.st_size);
 	}
 
 	// STEP 4: The actual experiment.
-	while (1) {
-		log << "restoring state" << endl;
-		simulator.restore(state_folder);
-
-		log << "asking job server for experiment parameters" << endl;
-		L4SysExperimentData param;
-		if (!m_jc.getParam(param)) {
-			log << "Dying." << endl;
-			// communicate that we were told to die
-			simulator.terminate(1);
-		}
-		int id = param.getWorkloadID();
-		int instr_offset = param.msg.instr_offset();
-		int bit_offset = param.msg.bit_offset();
-		log << "job " << id << " instr " << instr_offset << " bit "
-				<< bit_offset << endl;
-
-		bp.setWatchInstructionPointer(instr_list[instr_offset].trigger_addr);
-		bp.setCounter(instr_list[instr_offset].bp_counter);
-		simulator.addEvent(&bp);
-		//and log the output
-		waitIOOrOther(true);
+	log << "restoring state" << endl;
+	simulator.restore(L4SYS_STATE_FOLDER);
+
+	log << "asking job server for experiment parameters" << endl;
+	L4SysExperimentData param;
+	if (!m_jc.getParam(param)) {
+		log << "Dying." << endl;
+		// communicate that we were told to die
+		simulator.terminate(1);
+	}
+
+	int instr_offset = param.msg.instr_offset();
+	int bit_offset = param.msg.bit_offset();
+	int exp_type = param.msg.exp_type();
+
+	bp.setWatchInstructionPointer(ANY_ADDR);
+	bp.setCounter(instr_offset);
+	simulator.addEvent(&bp);
+	//and log the output
+	waitIOOrOther(true);
+
+	// note at what IP we will do the injection
+	address_t injection_ip =
+			simulator.getRegisterManager().getInstructionPointer();
+	param.msg.set_injection_ip(injection_ip);
+
+#if 0
+	// temporarily out of order (see above)
+	// sanity check (only works if we're working with an instruction trace)
+	if (injection_ip != instr_list[instr_offset].trigger_addr) {
+		stringstream ss;
+		ss << "SANITY CHECK FAILED: " << injection_ip << " != "
+				<< instr_list[instr_offset].trigger_addr << endl;
+		log << ss.str();
+		param.msg.set_resulttype(param.msg.UNKNOWN);
+		param.msg.set_resultdata(injection_ip);
+		param.msg.set_details(ss.str());
 
-		// inject
+		simulator.clearEvents();
+		m_jc.sendResult(param);
+		simulator.terminate(20);
+	}
+#endif
+
+	// inject
+	if (exp_type == param.msg.GPRFLIP) {
 		RegisterManager& rm = simulator.getRegisterManager();
-		Register *ebx = rm.getRegister(RID_CBX);
+		Register *ebx = rm.getRegister(RID_EBX);
 		regdata_t data = ebx->getData();
 		regdata_t newdata = data ^ (1 << bit_offset);
 		ebx->setData(newdata);
-		// note at what IP we did it
-		address_t injection_ip =
-				simulator.getRegisterManager().getInstructionPointer();
-		param.msg.set_injection_ip(injection_ip);
-		log << "inject @ ip " << injection_ip << " (offset " << dec
-				<< instr_offset << ")" << " bit " << bit_offset << ": 0x" << hex
-				<< ((int) data) << " -> 0x" << ((int) newdata) << endl;
-
-		// sanity check (only works if we're working with an instruction trace)
-		if (injection_ip != instr_list[instr_offset].trigger_addr) {
-			stringstream ss;
-			ss << "SANITY CHECK FAILED: " << injection_ip << " != "
-					<< instr_list[instr_offset].trigger_addr << endl;
-			log << ss.str();
-			param.msg.set_resulttype(param.msg.UNKNOWN);
-			param.msg.set_resultdata(injection_ip);
-			param.msg.set_details(ss.str());
-
-			simulator.clearEvents();
-			m_jc.sendResult(param);
-			simulator.terminate(20);
-		}
 
-		// aftermath
-		BPSingleEvent ev_done(L4SYS_FUNC_EXIT, aspace);
-		ev_done.setCounter(times_run);
-		simulator.addEvent(&ev_done);
-		const unsigned instr_run = times_run * L4SYS_NUMINSTR;
-		BPSingleEvent ev_timeout(ANY_ADDR, aspace);
-		ev_timeout.setCounter(instr_run + 3000);
-		simulator.addEvent(&ev_timeout);
-		TrapEvent ev_trap(ANY_TRAP);
-		simulator.addEvent(&ev_trap);
-		InterruptEvent ev_intr(ANY_INTERRUPT);
-		//ten times as many interrupts as instructions justify an exception
-		ev_intr.setCounter(instr_run * 10);
-		simulator.addEvent(&ev_intr);
-
-		//do not discard output recorded so far
-		BaseEvent *ev = waitIOOrOther(false);
-
-		/* copying a string object that contains control sequences
-		 * unfortunately does not work with the library I am using,
-		 * which is why output is passed on as C string and
-		 * the string compare is done on C strings
-		 */
-		if (ev == &ev_done) {
-			if (strcmp(output.c_str(), golden_run.c_str()) == 0) {
-				log << dec << "Result DONE" << endl;
-				param.msg.set_resulttype(param.msg.DONE);
-			} else {
-				log << dec << "Result WRONG" << endl;
-				param.msg.set_resulttype(param.msg.WRONG);
-				param.msg.set_output(sanitised(output.c_str()));
-			}
-		} else if (ev == &ev_timeout) {
-			log << dec << "Result TIMEOUT" << endl;
-			param.msg.set_resulttype(param.msg.TIMEOUT);
-			param.msg.set_resultdata(
-					simulator.getRegisterManager().getInstructionPointer());
-			param.msg.set_output(sanitised(output.c_str()));
-		} else if (ev == &ev_trap) {
-			log << dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl;
-			param.msg.set_resulttype(param.msg.TRAP);
-			param.msg.set_resultdata(
-					simulator.getRegisterManager().getInstructionPointer());
-			param.msg.set_output(sanitised(output.c_str()));
-		} else if (ev == &ev_intr) {
-			log << hex << "Result INT FLOOD; Last INT #:"
-					<< ev_intr.getTriggerNumber() << endl;
-			param.msg.set_resulttype(param.msg.INTR);
-			param.msg.set_resultdata(
-					simulator.getRegisterManager().getInstructionPointer());
-			param.msg.set_output(sanitised(output.c_str()));
+		// do the logging in case everything worked out
+		logInjection(log, param);
+		log << "register data: 0x" << hex
+					<< ((int) data) << " -> 0x" << ((int) newdata) << endl;
+	} else if(exp_type == param.msg.IDCFLIP) {
+		// this is a twisted one
+
+		// initial definitions
+		bxICacheEntry_c *cache_entry = simulator.getICacheEntry();
+		unsigned length_in_bits = cache_entry->i->ilen() << 3;
+
+		// get the instruction in plain text in inject the error there
+		// Note: we need to fetch some extra bytes into the array
+		// in case the faulty instruction is interpreted to be longer
+		// than the original one
+		Bit8u curr_instr_plain[MAX_INSTR_BYTES];
+		const Bit8u *addr = calculateInstructionAddress();
+		memcpy(curr_instr_plain, addr, MAX_INSTR_BYTES);
+
+		// CampaignManager has no idea of the instruction length
+		// (neither do we), therefore this small adaption
+		bit_offset %= length_in_bits;
+		param.msg.set_bit_offset(bit_offset);
+
+		// do some access calculation
+		int byte_index = bit_offset >> 3;
+		Bit8u bit_index = bit_offset & 7;
+
+		// apply the fault
+		curr_instr_plain[byte_index] ^= 1 << bit_index;
+
+		// decode the instruction
+		bxInstruction_c bochs_instr;
+		memset(&bochs_instr, 0, sizeof(bxInstruction_c));
+		fetchInstruction(simulator.getCPUContext(), curr_instr_plain, &bochs_instr);
+
+		// inject it
+		changeBochsInstruction(cache_entry->i, &bochs_instr);
+
+		// do the logging
+		logInjection(log, param);
+	} else if(exp_type == param.msg.RATFLIP) {
+		bxICacheEntry_c *cache_entry = simulator.getICacheEntry();
+
+	}
+
+	// aftermath
+	BPSingleEvent ev_done(L4SYS_FUNC_EXIT, L4SYS_ADDRESS_SPACE);
+	ev_done.setCounter(L4SYS_ITERATION_COUNT);
+	simulator.addEvent(&ev_done);
+	const unsigned instr_run = L4SYS_ITERATION_COUNT * L4SYS_NUMINSTR;
+	BPSingleEvent ev_timeout(ANY_ADDR, L4SYS_ADDRESS_SPACE);
+	ev_timeout.setCounter(instr_run + 3000);
+	simulator.addEvent(&ev_timeout);
+	TrapEvent ev_trap(ANY_TRAP);
+	//one trap for each 150 instructions justifies an exception
+	ev_trap.setCounter(instr_run / 150);
+	simulator.addEvent(&ev_trap);
+	InterruptEvent ev_intr(ANY_INTERRUPT);
+	//one interrupt for each 100 instructions justifies an exception (timeout mostly)
+	ev_intr.setCounter(instr_run / 100);
+	simulator.addEvent(&ev_intr);
+
+	//do not discard output recorded so far
+	BaseEvent *ev = waitIOOrOther(false);
+
+	/* copying a string object that contains control sequences
+	 * unfortunately does not work with the library I am using,
+	 * which is why output is passed on as C string and
+	 * the string compare is done on C strings
+	 */
+	if (ev == &ev_done) {
+		if (strcmp(output.c_str(), golden_run.c_str()) == 0) {
+			log << dec << "Result DONE" << endl;
+			param.msg.set_resulttype(param.msg.DONE);
 		} else {
-			log << dec << "Result WTF?" << endl;
-			param.msg.set_resulttype(param.msg.UNKNOWN);
-			param.msg.set_resultdata(
-					simulator.getRegisterManager().getInstructionPointer());
+			log << dec << "Result WRONG" << endl;
+			param.msg.set_resulttype(param.msg.WRONG);
 			param.msg.set_output(sanitised(output.c_str()));
-
-			stringstream ss;
-			ss << "eventid " << ev << " EIP "
-					<< simulator.getRegisterManager().getInstructionPointer()
-					<< endl;
-			param.msg.set_details(ss.str());
 		}
-
-		simulator.clearEvents();
-		m_jc.sendResult(param);
+	} else if (ev == &ev_timeout) {
+		log << dec << "Result TIMEOUT" << endl;
+		param.msg.set_resulttype(param.msg.TIMEOUT);
+		param.msg.set_resultdata(
+				simulator.getRegisterManager().getInstructionPointer());
+		param.msg.set_output(sanitised(output.c_str()));
+	} else if (ev == &ev_trap) {
+		log << dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl;
+		param.msg.set_resulttype(param.msg.TRAP);
+		param.msg.set_resultdata(
+				simulator.getRegisterManager().getInstructionPointer());
+		param.msg.set_output(sanitised(output.c_str()));
+	} else if (ev == &ev_intr) {
+		log << hex << "Result INT FLOOD; Last INT #:"
+				<< ev_intr.getTriggerNumber() << endl;
+		param.msg.set_resulttype(param.msg.INTR);
+		param.msg.set_resultdata(
+				simulator.getRegisterManager().getInstructionPointer());
+		param.msg.set_output(sanitised(output.c_str()));
+	} else {
+		log << dec << "Result WTF?" << endl;
+		param.msg.set_resulttype(param.msg.UNKNOWN);
+		param.msg.set_resultdata(
+				simulator.getRegisterManager().getInstructionPointer());
+		param.msg.set_output(sanitised(output.c_str()));
+
+		stringstream ss;
+		ss << "eventid " << ev << " EIP "
+				<< simulator.getRegisterManager().getInstructionPointer()
+				<< endl;
+		param.msg.set_details(ss.str());
 	}
 
+	simulator.clearEvents();
+	m_jc.sendResult(param);
+
 #ifdef HEADLESS_EXPERIMENT
 	simulator.terminate(0);
 #endif
diff --git a/src/experiments/l4-sys/experiment.hpp b/src/experiments/l4-sys/experiment.hpp
index 8522827b294457f29fbd23a156ac7bdac202b8c4..01347c1aa3906b7e1a563944572a0e6eee821ab6 100644
--- a/src/experiments/l4-sys/experiment.hpp
+++ b/src/experiments/l4-sys/experiment.hpp
@@ -5,6 +5,8 @@
 
 #include "efw/ExperimentFlow.hpp"
 #include "efw/JobClient.hpp"
+#include "campaign.hpp"
+#include "util/Logger.hpp"
 
 class L4SysExperiment : public fail::ExperimentFlow {
 	fail::JobClient m_jc;
@@ -12,12 +14,45 @@ public:
 	L4SysExperiment() : m_jc("localhost") {}
 	bool run();
 private:
-	// NOTE: It's good practise to use "const std::string&" as parameter type.
-	//       Additionaly, if you don't need the return value to be copied,
-	//       return a (const) reference to a class member or a static string-
-	//       object.
-	std::string sanitised(std::string in_str);
+	/**
+	 * Sanitises the output string of the serial device monitored.
+	 * @param a string containing special ASCII characters
+	 * @returns a byte-stuffed version of the given string
+	 */
+	std::string sanitised(const std::string &in_str);
+	/**
+	 * Waits for events and simultaneously logs output from the serial console
+	 * @param clear_output if true, the output logged so far is deleted, thus the buffer is reset (cleared)
+	 * @returns the event returned by waitAny, as long as it did not log output
+	 */
 	fail::BaseEvent* waitIOOrOther(bool clear_output);
+	/**
+	 * Calculates the address where Bochs will read the current instruction from.
+	 * This code is copied from various Bochs methods and should be reviewed as
+	 * soon as a new Bochs version is introduced.
+	 * @returns a pointer to the memory region containing the current Bochs instruction
+	 */
+	const Bit8u *calculateInstructionAddress();
+	/**
+	 * A function necessary for Bochs internal address translation
+	 * @returns a value for Bochs' eipBiased variable
+	 */
+	Bit32u eipBiased();
+	/**
+	 * Parses a raw instruction into a bxInstruction_c structure.
+	 * This simple version of the function is taken from Bochs
+	 * where it is currently disabled due to the TRACE_CACHE option,
+	 * and has been modified to fit the needs of instruction modification.
+	 * @param instance a pointer to the current Bochs CPU
+	 * @param instr a pointer to the address the instruction is fetched from
+	 * @param iStorage an outgoing value which contains the parsed instruction
+	 * @returns \a false if the instruction continued on the following page in memory
+	 */
+	bx_bool fetchInstruction(BX_CPU_C *instance, const Bit8u *instr, bxInstruction_c *iStorage);
+	void logInjection(fail::Logger &log, const L4SysExperimentData &param);
+	bool isALUInstruction(unsigned opcode);
+	void readFromFileToVector(std::ifstream &file, std::vector<struct __trace_instr_type> &instr_list);
+	void changeBochsInstruction(bxInstruction_c *dest, bxInstruction_c *src);
 };
 
 #endif // __L4SYS_EXPERIMENT_HPP__
diff --git a/src/experiments/l4-sys/experimentInfo.hpp b/src/experiments/l4-sys/experimentInfo.hpp
index 56f7573782816803b09fe76e8bc005116fff5998..abd84051564f20bff7eb1aad93f8a83f9939873a 100644
--- a/src/experiments/l4-sys/experimentInfo.hpp
+++ b/src/experiments/l4-sys/experimentInfo.hpp
@@ -1,15 +1,25 @@
 #ifndef __EXPERIMENT_INFO_HPP__
   #define __EXPERIMENT_INFO_HPP__
 
-//experiment types:
-#define GPRFLIP 10
-#define IDCFLIP 20
+// the maximum number of bytes in a Bochs instruction
+#define MAX_INSTR_BYTES 15
 
-#define L4SYS_FUNC_ENTRY		0x1007cd0
-#define L4SYS_FUNC_EXIT			0x1007d3a
-#define L4SYS_NUMINSTR			3184
+// the bounds of the program
+#define L4SYS_ADDRESS_SPACE		0x203d000
+#define L4SYS_FUNC_ENTRY		0x1000400
+#define L4SYS_FUNC_EXIT			0x10005b0
+#define L4SYS_NUMINSTR			56052772
+
+#define L4SYS_ITERATION_COUNT	1
+
+// several file names used
+#define L4SYS_STATE_FOLDER		"l4sys.state"
+#define L4SYS_INSTRUCTION_LIST	"ip.list"
+#define L4SYS_ALU_INSTRUCTIONS	"alu.list"
+#define L4SYS_CORRECT_OUTPUT	"golden.out"
+
+// flags
 #define HEADLESS_EXPERIMENT
-#define EXPERIMENT_TYPE			IDCFLIP
 //#define PREPARE_EXPERIMENT
 
 #endif // __EXPERIMENT_INFO_HPP__
diff --git a/src/experiments/l4-sys/l4sys.proto b/src/experiments/l4-sys/l4sys.proto
index f8d50bbcec2642d793a5ec10db955e5acc2b9699..b55971163cd1eb91d6732b83329c8448cb8da428 100644
--- a/src/experiments/l4-sys/l4sys.proto
+++ b/src/experiments/l4-sys/l4sys.proto
@@ -1,7 +1,15 @@
 message L4SysProtoMsg {
+	// experiment types
+	enum ExperimentType {
+		GPRFLIP = 10;
+		RATFLIP = 15;
+		IDCFLIP = 20;
+		ALUINSTR = 30;
+	}
 	// parameters
-	required int32 instr_offset = 1;
-	required int32 bit_offset = 2;
+	required ExperimentType exp_type = 10;
+	required int32 instr_offset = 20;
+	required int32 bit_offset = 30;
 
 	// results
 	// make these optional to reduce overhead for server->client communication
@@ -14,13 +22,13 @@ message L4SysProtoMsg {
 		UNKNOWN = 6;
 	}
 	// instruction pointer where injection was done
-	optional uint32 injection_ip = 3;
+	optional uint32 injection_ip = 40;
 	// result type, see above
-	optional ResultType resulttype = 4;
+	optional ResultType resulttype = 50;
 	// result data, depending on resulttype (see source code)
-	optional uint32 resultdata = 5;
+	optional uint32 resultdata = 60;
 	// generated output
-	optional string output = 6;
+	optional string output = 70;
 	// optional textual description of what happened
-	optional string details = 7;
+	optional string details = 80;
 }