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 ¶m) { + // 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 ¶m); + 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; }