From ebd62281c3fa5454f1ed4645cda4fe5ebd052433 Mon Sep 17 00:00:00 2001 From: unzner Date: Mon, 28 May 2012 09:23:27 +0000 Subject: [PATCH] The patch I announced on the mailing list regarding address space recognition. git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1275 8c4709b5-6ec9-48aa-a5cd-a96041d1645a --- core/SAL/SimulatorController.cc | 8 +- core/SAL/SimulatorController.hpp | 3 +- core/SAL/bochs/BochsController.cc | 12 +- core/SAL/bochs/BochsController.hpp | 3 +- core/SAL/bochs/Breakpoints.ah | 2 +- core/SAL/bochs/credits.ah | 1 + core/SAL/ovp/Controller.cc | 2 +- core/controller/Event.cc | 22 +- core/controller/Event.hpp | 112 +++++-- .../FaultCoverageExperiment/experiment.cc | 8 +- core/experiments/MHTestCampaign/experiment.cc | 4 +- core/experiments/TracingTest/experiment.cc | 4 +- .../attic/DataRetrievalExperiment.cc | 2 +- .../checksum-oostubs/experiment.cc | 10 +- core/experiments/coolchecksum/experiment.cc | 6 +- core/experiments/fireinterrupt/experiment.cc | 2 +- core/experiments/hscsimple/experiment.cc | 4 +- core/experiments/l4sys/CMakeLists.txt | 31 ++ core/experiments/l4sys/campaign.cc | 74 ++++ core/experiments/l4sys/campaign.hpp | 20 ++ core/experiments/l4sys/experiment.cc | 316 ++++++++++++++++++ core/experiments/l4sys/experiment.hpp | 17 + core/experiments/l4sys/experimentInfo.hpp | 11 + core/experiments/l4sys/l4sys.proto | 26 ++ core/experiments/l4sys/main.cc | 15 + core/experiments/weathermonitor/experiment.cc | 10 +- core/plugins/tracing/TracingPlugin.cc | 2 +- 27 files changed, 642 insertions(+), 85 deletions(-) create mode 100644 core/experiments/l4sys/CMakeLists.txt create mode 100644 core/experiments/l4sys/campaign.cc create mode 100644 core/experiments/l4sys/campaign.hpp create mode 100644 core/experiments/l4sys/experiment.cc create mode 100644 core/experiments/l4sys/experiment.hpp create mode 100644 core/experiments/l4sys/experimentInfo.hpp create mode 100644 core/experiments/l4sys/l4sys.proto create mode 100644 core/experiments/l4sys/main.cc diff --git a/core/SAL/SimulatorController.cc b/core/SAL/SimulatorController.cc index 1a38d648..5ea26e31 100644 --- a/core/SAL/SimulatorController.cc +++ b/core/SAL/SimulatorController.cc @@ -42,7 +42,7 @@ void SimulatorController::initExperiments() /* empty. */ } -void SimulatorController::onBreakpointEvent(address_t instrPtr) +void SimulatorController::onBreakpointEvent(address_t instrPtr, address_t address_space) { assert(false && "FIXME: SimulatorController::onBreakpointEvent() has not been tested before"); @@ -54,8 +54,8 @@ void SimulatorController::onBreakpointEvent(address_t instrPtr) while (it != m_EvList.end()) { fi::BaseEvent* pev = *it; - fi::BPEvent* pbp; fi::BPRangeEvent* pbpr; - if((pbp = dynamic_cast(pev)) && pbp->isMatching(instrPtr)) + fi::BPSingleEvent* pbp; fi::BPRangeEvent* pbpr; + if((pbp = dynamic_cast(pev)) && pbp->isMatching(instrPtr, address_space)) { pbp->setTriggerInstructionPointer(instrPtr); it = m_EvList.makeActive(it); @@ -64,7 +64,7 @@ void SimulatorController::onBreakpointEvent(address_t instrPtr) continue; // -> skip iterator increment } else if((pbpr = dynamic_cast(pev)) && - pbpr->isMatching(instrPtr)) + pbpr->isMatching(instrPtr, address_space)) { pbpr->setTriggerInstructionPointer(instrPtr); it = m_EvList.makeActive(it); diff --git a/core/SAL/SimulatorController.hpp b/core/SAL/SimulatorController.hpp index 7859e62a..188aa70d 100644 --- a/core/SAL/SimulatorController.hpp +++ b/core/SAL/SimulatorController.hpp @@ -81,8 +81,9 @@ class SimulatorController * Breakpoint event handler. This routine needs to be called in the * simulator specific backend each time a breakpoint event occurs. * @param instrPtr the instruction pointer of the breakpoint event + * @param address_space the address space it should occur in */ - void onBreakpointEvent(address_t instrPtr); + void onBreakpointEvent(address_t instrPtr, address_t address_space); /** * Memory access event handler (read/write). * @param addr the accessed memory address diff --git a/core/SAL/bochs/BochsController.cc b/core/SAL/bochs/BochsController.cc index 6f630d81..f72de3cd 100644 --- a/core/SAL/bochs/BochsController.cc +++ b/core/SAL/bochs/BochsController.cc @@ -87,7 +87,7 @@ void BochsController::dbgEnableInstrPtrOutput(unsigned regularity, std::ostream* } #endif // DEBUG -void BochsController::onInstrPtrChanged(address_t instrPtr) +void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_space) { #ifdef DEBUG if(m_Regularity != 0 && ++m_Counter % m_Regularity == 0) @@ -99,8 +99,7 @@ void BochsController::onInstrPtrChanged(address_t instrPtr) { // FIXME: Maybe we need to improve the performance of this check. fi::BPEvent* pEvBreakpt = dynamic_cast(*it); - if(pEvBreakpt && (instrPtr == pEvBreakpt->getWatchInstructionPointer() || - pEvBreakpt->getWatchInstructionPointer() == fi::ANY_ADDR)) + if(pEvBreakpt && pEvBreakpt->isMatching(instrPtr, address_space)) { pEvBreakpt->setTriggerInstructionPointer(instrPtr); it = m_EvList.makeActive(it); @@ -108,13 +107,6 @@ void BochsController::onInstrPtrChanged(address_t instrPtr) // makeActive()): continue; // -> skip iterator increment } - fi::BPRangeEvent* pEvRange = dynamic_cast(*it); - if(pEvRange && pEvRange->isMatching(instrPtr)) - { - pEvRange->setTriggerInstructionPointer(instrPtr); - it = m_EvList.makeActive(it); - continue; // dito. - } it++; } m_EvList.fireActiveEvents(); diff --git a/core/SAL/bochs/BochsController.hpp b/core/SAL/bochs/BochsController.hpp index 7ab90b34..94b73356 100644 --- a/core/SAL/bochs/BochsController.hpp +++ b/core/SAL/bochs/BochsController.hpp @@ -86,8 +86,9 @@ class BochsController : public SimulatorController * Instruction pointer modification handler. This method is called (from * the Breakpoints aspect) every time when the Bochs-internal IP changes. * @param instrPtr the new instruction pointer + * @param address_space */ - void onInstrPtrChanged(address_t instrPtr); + void onInstrPtrChanged(address_t instrPtr, address_t address_space); /** * This method is called when an experiment flow adds a new event by * calling \c simulator.addEvent(pev) or \c simulator.addEventAndWait(pev). diff --git a/core/SAL/bochs/Breakpoints.ah b/core/SAL/bochs/Breakpoints.ah index 4127884b..ea281ba5 100644 --- a/core/SAL/bochs/Breakpoints.ah +++ b/core/SAL/bochs/Breakpoints.ah @@ -25,7 +25,7 @@ aspect Breakpoints //bxInstruction_c* pInstr = *(tjp->arg<1>()); // report this event to the Bochs controller: - sal::simulator.onInstrPtrChanged(pThis->get_instruction_pointer()); + sal::simulator.onInstrPtrChanged(pThis->get_instruction_pointer(), pThis->cr3); // Note: get_bx_opcode_name(pInstr->getIaOpcode()) retrieves the mnemonics. } }; diff --git a/core/SAL/bochs/credits.ah b/core/SAL/bochs/credits.ah index 3f2c7a9a..3c4c9a79 100644 --- a/core/SAL/bochs/credits.ah +++ b/core/SAL/bochs/credits.ah @@ -2,6 +2,7 @@ #define __CREDITS_AH__ #include +#include aspect credits { bool first; diff --git a/core/SAL/ovp/Controller.cc b/core/SAL/ovp/Controller.cc index 7813dd44..fae8b94b 100644 --- a/core/SAL/ovp/Controller.cc +++ b/core/SAL/ovp/Controller.cc @@ -83,7 +83,7 @@ void OVPController::onInstrPtrChanged(address_t instrPtr) { // FIXME: Performance verbessern (dazu muss entsprechend auch die Speicherung // in EventList(.cc|.hpp) angepasst bzw. verbessert werden). - fi::BPEvent* pEvBreakpt = dynamic_cast(*it); + fi::BPSingleEvent* pEvBreakpt = dynamic_cast(*it); if(pEvBreakpt && (instrPtr == pEvBreakpt->getWatchInstructionPointer() || pEvBreakpt->getWatchInstructionPointer() == fi::ANY_ADDR)) { diff --git a/core/controller/Event.cc b/core/controller/Event.cc index cfb29771..727388d1 100644 --- a/core/controller/Event.cc +++ b/core/controller/Event.cc @@ -52,25 +52,37 @@ bool MemAccessEvent::isMatching(sal::address_t addr, accessType_t accesstype) co return (true); } +bool BPEvent::aspaceIsMatching(sal::address_t aspace) const +{ + if (m_CR3 == ANY_ADDR || m_CR3 == aspace) + return true; + return false; +} + void BPRangeEvent::setWatchInstructionPointerRange(sal::address_t start, sal::address_t end) { m_WatchStartAddr = start; m_WatchEndAddr = end; } -bool BPRangeEvent::isMatching(sal::address_t addr) const +bool BPRangeEvent::isMatching(sal::address_t addr, sal::address_t aspace) const { + if (!aspaceIsMatching(aspace)) + return false; if ((m_WatchStartAddr != ANY_ADDR && addr < m_WatchStartAddr) || (m_WatchEndAddr != ANY_ADDR && addr > m_WatchEndAddr)) return false; return true; } -bool BPEvent::isMatching(sal::address_t addr) const +bool BPSingleEvent::isMatching(sal::address_t addr, sal::address_t aspace) const { - if(m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == addr) - return (true); - return (false); + if (aspaceIsMatching(aspace)) { + if (m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == addr) { + return true; + } + } + return false; } } // end-of-namespace: fi diff --git a/core/controller/Event.hpp b/core/controller/Event.hpp index 54201a10..fbefd9da 100644 --- a/core/controller/Event.hpp +++ b/core/controller/Event.hpp @@ -5,9 +5,10 @@ #include #include #include +#include #include "../SAL/SALConfig.hpp" - +#include namespace fi { class ExperimentFlow; @@ -100,39 +101,45 @@ class BaseEvent // /** - * \class BPEvent - * A Breakpoint event to observe specific instruction pointers. - * FIXME consider renaming to BPSingleEvent, introducing common BPEvent base class + * \class BEvent + * A Breakpoint event to observe instruction changes within a given address space. */ class BPEvent : virtual public BaseEvent { private: - sal::address_t m_WatchInstrPtr; + sal::address_t m_CR3; sal::address_t m_TriggerInstrPtr; public: /** - * Creates a new breakpoint event. - * @param ip the instruction pointer of the breakpoint. If the control - * flow reaches this address and its counter value is zero, the - * event will be triggered. \a eip can be set to the ANY_ADDR - * wildcard to allow arbitrary addresses. + * Creates a new breakpoint event. The range information is specific to + * the subclasses. + * @param address_space the address space to be oberserved, given as the + * content of a CR3 register. The event will not be triggered unless + * \a ip is part of the given address space. + * ANY_ADDR can be used as a placeholder to allow debugging + * in a random address space. */ - BPEvent(sal::address_t ip = 0) - : m_WatchInstrPtr(ip), m_TriggerInstrPtr(ANY_ADDR) { } + BPEvent(sal::address_t address_space = ANY_ADDR) + : m_CR3(address_space), m_TriggerInstrPtr(ANY_ADDR) + {} /** - * Returns the instruction pointer this event waits for. + * Returns the address space register of this event. */ - sal::address_t getWatchInstructionPointer() const - { return m_WatchInstrPtr; } + sal::address_t getCR3() const + { return m_CR3; } /** - * Sets the instruction pointer this event waits for. + * Sets the address space register for this event. */ - void setWatchInstructionPointer(sal::address_t iptr) - { m_WatchInstrPtr = iptr; } + void setCR3(sal::address_t iptr) + { m_CR3 = iptr; } + /** + * Checks whether a given address space is matching. + */ + bool aspaceIsMatching(sal::address_t address_space = ANY_ADDR) const; /** * Checks whether a given address is matching. */ - bool isMatching(sal::address_t addr) const; + virtual bool isMatching(sal::address_t addr = 0, sal::address_t address_space = ANY_ADDR) const = 0; /** * Returns the instruction pointer that triggered this event. */ @@ -146,11 +153,50 @@ class BPEvent : virtual public BaseEvent { m_TriggerInstrPtr = iptr; } }; +/** + * \class BPSingleEvent + * A Breakpoint event to observe specific instruction pointers. + */ +class BPSingleEvent : virtual public BPEvent +{ + private: + sal::address_t m_WatchInstrPtr; + public: + /** + * Creates a new breakpoint event. + * @param ip the instruction pointer of the breakpoint. If the control + * flow reaches this address and its counter value is zero, the + * event will be triggered. \a eip can be set to the ANY_ADDR + * wildcard to allow arbitrary addresses. + * @param address_space the address space to be oberserved, given as the + * content of a CR3 register. The event will not be triggered unless + * \a ip is part of the given address space. + * Here, too, ANY_ADDR is a placeholder to allow debugging + * in a random address space. + */ + BPSingleEvent(sal::address_t ip = 0, sal::address_t address_space = ANY_ADDR) + : BPEvent(address_space), m_WatchInstrPtr(ip) { } + /** + * Returns the instruction pointer this event waits for. + */ + sal::address_t getWatchInstructionPointer() const + { return m_WatchInstrPtr; } + /** + * Sets the instruction pointer this event waits for. + */ + void setWatchInstructionPointer(sal::address_t iptr) + { m_WatchInstrPtr = iptr; } + /** + * Checks whether a given address is matching. + */ + bool isMatching(sal::address_t addr, sal::address_t address_space) const; +}; + /** * \class BPRangeEvent * A event type to observe ranges of instruction pointers. */ -class BPRangeEvent : virtual public BaseEvent +class BPRangeEvent : virtual public BPEvent { private: sal::address_t m_WatchStartAddr; @@ -163,9 +209,14 @@ class BPRangeEvent : virtual public BaseEvent * ANY_ADDR denotes the lower respectively the upper end of the address * space. */ - BPRangeEvent(sal::address_t start = 0, sal::address_t end = 0) - : m_WatchStartAddr(start), m_WatchEndAddr(end), - m_TriggerInstrPtr(ANY_ADDR) { } + BPRangeEvent(sal::address_t start = 0, sal::address_t end = 0, sal::address_t address_space = ANY_ADDR) + : BPEvent(address_space), m_WatchStartAddr(start), m_WatchEndAddr(end) + { } + /** + * Returns the instruction pointer watch range of this event. + */ + std::pair getWatchInstructionPointerRange() const + { return std::make_pair(m_WatchStartAddr, m_WatchEndAddr); } /** * Sets the instruction pointer watch range. Both ends of the range * may be ANY_ADDR (cf. constructor). @@ -175,18 +226,7 @@ class BPRangeEvent : virtual public BaseEvent /** * Checks whether a given address is within the range. */ - bool isMatching(sal::address_t addr) const; - /** - * Returns the instruction pointer that triggered this event. - */ - sal::address_t getTriggerInstructionPointer() const - { return m_TriggerInstrPtr; } - /** - * Sets the instruction pointer that triggered this event. Should not - * be used by experiment code. - */ - void setTriggerInstructionPointer(sal::address_t iptr) - { m_TriggerInstrPtr = iptr; } + bool isMatching(sal::address_t addr, sal::address_t address_space) const; }; /** @@ -431,7 +471,7 @@ class GuestEvent : virtual public BaseEvent /** * Returns the data length, transmitted by the guest system. */ - unsigned getPort() const { return (m_Data); } + unsigned getPort() const { return (m_Port); } /** * Sets the data length which had been transmitted by the guest system. */ diff --git a/core/experiments/FaultCoverageExperiment/experiment.cc b/core/experiments/FaultCoverageExperiment/experiment.cc index 367c5626..55274ac4 100644 --- a/core/experiments/FaultCoverageExperiment/experiment.cc +++ b/core/experiments/FaultCoverageExperiment/experiment.cc @@ -39,7 +39,7 @@ bool FaultCoverageExperiment::run() // set breakpoint at start address of the function to be analyzed ("observed"); // wait until instruction pointer reaches that address cout << "[FaultCoverageExperiment] Setting up experiment. Allowing to start now." << endl; - BPEvent ev_func_start(INST_ADDR_FUNC_START); + BPSingleEvent ev_func_start(INST_ADDR_FUNC_START); simulator.addEvent(&ev_func_start); cout << "[FaultCoverageExperiment] Waiting for function start address..." << endl; @@ -72,14 +72,14 @@ bool FaultCoverageExperiment::run() cout << "done!" << endl; // breakpoint at function exit - BPEvent ev_func_end(INST_ADDR_FUNC_END); + BPSingleEvent ev_func_end(INST_ADDR_FUNC_END); simulator.addEvent(&ev_func_end); // no need to continue simulation if we want to // inject *now* if (instr > 0) { // breakpoint $instr instructions in the future - BPEvent ev_instr_reached(ANY_ADDR); + BPSingleEvent ev_instr_reached(ANY_ADDR); ev_instr_reached.setCounter(instr); simulator.addEvent(&ev_instr_reached); @@ -96,7 +96,7 @@ bool FaultCoverageExperiment::run() // catch traps and timeout TrapEvent ev_trap; // any traps simulator.addEvent(&ev_trap); - BPEvent ev_timeout(ANY_ADDR); + BPSingleEvent ev_timeout(ANY_ADDR); ev_timeout.setCounter(1000); simulator.addEvent(&ev_timeout); diff --git a/core/experiments/MHTestCampaign/experiment.cc b/core/experiments/MHTestCampaign/experiment.cc index 4ee84f5d..957c51fc 100644 --- a/core/experiments/MHTestCampaign/experiment.cc +++ b/core/experiments/MHTestCampaign/experiment.cc @@ -11,7 +11,7 @@ bool MHTestExperiment::run() cout << "[MHTestExperiment] Let's go" << endl; #if 0 - fi::BPEvent mainbp(0x00003c34); + fi::BPSingleEvent mainbp(0x00003c34); sal::simulator.addEventAndWait(&mainbp); cout << "[MHTestExperiment] breakpoint reached, saving" << endl; sal::simulator.save("hello.main"); @@ -22,7 +22,7 @@ bool MHTestExperiment::run() int num = par.msg.input(); cout << "[MHExperiment] stepping " << num << " instructions" << endl; if (num > 0) { - fi::BPEvent nextbp(fi::ANY_ADDR); + fi::BPSingleEvent nextbp(fi::ANY_ADDR); nextbp.setCounter(num); sal::simulator.addEventAndWait(&nextbp); } diff --git a/core/experiments/TracingTest/experiment.cc b/core/experiments/TracingTest/experiment.cc index 6ce9df60..39081798 100644 --- a/core/experiments/TracingTest/experiment.cc +++ b/core/experiments/TracingTest/experiment.cc @@ -21,7 +21,7 @@ bool TracingTest::run() #if 1 // STEP 1: run until interesting function starts, and save state - BPEvent breakpoint(0x00101658); + BPSingleEvent breakpoint(0x00101658); simulator.addEventAndWait(&breakpoint); cout << "[TracingTest] main() reached, saving" << endl; @@ -40,7 +40,7 @@ bool TracingTest::run() simulator.addFlow(&tp); cout << "[TracingTest] tracing 1000000 instructions" << endl; - BPEvent timeout(fi::ANY_ADDR); + BPSingleEvent timeout(fi::ANY_ADDR); timeout.setCounter(1000000); simulator.addEvent(&timeout); diff --git a/core/experiments/attic/DataRetrievalExperiment.cc b/core/experiments/attic/DataRetrievalExperiment.cc index 5dfb397d..f2624256 100644 --- a/core/experiments/attic/DataRetrievalExperiment.cc +++ b/core/experiments/attic/DataRetrievalExperiment.cc @@ -16,7 +16,7 @@ bool DataRetrievalExperiment::run() cout << "[getExperimentDataExperiment] Experiment start." << endl; // Breakpoint address for Memtest86: - fi::BPEvent mainbp(MEMTEST86_BREAKPOINT); + fi::BPSingleEvent mainbp(MEMTEST86_BREAKPOINT); sal::simulator.addEventAndWait(&mainbp); cout << "[getExperimentDataExperiment] Breakpoint reached." << endl; diff --git a/core/experiments/checksum-oostubs/experiment.cc b/core/experiments/checksum-oostubs/experiment.cc index bf206120..bec38882 100644 --- a/core/experiments/checksum-oostubs/experiment.cc +++ b/core/experiments/checksum-oostubs/experiment.cc @@ -27,7 +27,7 @@ bool ChecksumOOStuBSExperiment::run() { char const *statename = "checksum-oostubs.state"; Logger log("Checksum-OOStuBS", false); - fi::BPEvent bp; + fi::BPSingleEvent bp; log << "startup" << endl; @@ -75,7 +75,7 @@ bool ChecksumOOStuBSExperiment::run() bp.setWatchInstructionPointer(fi::ANY_ADDR); bp.setCounter(OOSTUBS_NUMINSTR); sal::simulator.addEvent(&bp); - fi::BPEvent func_finish(OOSTUBS_FUNC_FINISH); + fi::BPSingleEvent func_finish(OOSTUBS_FUNC_FINISH); sal::simulator.addEvent(&func_finish); if (sal::simulator.waitAny() == &func_finish) { @@ -145,7 +145,7 @@ bool ChecksumOOStuBSExperiment::run() job.close(); // reaching finish() could happen before OR after FI - fi::BPEvent func_finish(OOSTUBS_FUNC_FINISH); + fi::BPSingleEvent func_finish(OOSTUBS_FUNC_FINISH); sal::simulator.addEvent(&func_finish); bool finish_reached = false; @@ -208,10 +208,10 @@ bool ChecksumOOStuBSExperiment::run() fi::TrapEvent ev_trap(fi::ANY_TRAP); sal::simulator.addEvent(&ev_trap); // OOStuBS' way to terminally halt (CLI+HLT) - fi::BPEvent ev_halt(OOSTUBS_FUNC_CPU_HALT); + fi::BPSingleEvent ev_halt(OOSTUBS_FUNC_CPU_HALT); sal::simulator.addEvent(&ev_halt); // remaining instructions until "normal" ending - fi::BPEvent ev_done(fi::ANY_ADDR); + fi::BPSingleEvent ev_done(fi::ANY_ADDR); ev_done.setCounter(OOSTUBS_NUMINSTR + OOSTUBS_RECOVERYINSTR - instr_offset); sal::simulator.addEvent(&ev_done); diff --git a/core/experiments/coolchecksum/experiment.cc b/core/experiments/coolchecksum/experiment.cc index 20aceafb..62d063f4 100644 --- a/core/experiments/coolchecksum/experiment.cc +++ b/core/experiments/coolchecksum/experiment.cc @@ -31,7 +31,7 @@ using std::endl; bool CoolChecksumExperiment::run() { Logger log("CoolChecksum", false); - fi::BPEvent bp; + fi::BPSingleEvent bp; log << "startup" << endl; @@ -156,9 +156,9 @@ bool CoolChecksumExperiment::run() } // aftermath - fi::BPEvent ev_done(COOL_ECC_CALCDONE); + fi::BPSingleEvent ev_done(COOL_ECC_CALCDONE); sal::simulator.addEvent(&ev_done); - fi::BPEvent ev_timeout(fi::ANY_ADDR); + fi::BPSingleEvent ev_timeout(fi::ANY_ADDR); ev_timeout.setCounter(COOL_ECC_NUMINSTR + 3000); sal::simulator.addEvent(&ev_timeout); fi::TrapEvent ev_trap(fi::ANY_TRAP); diff --git a/core/experiments/fireinterrupt/experiment.cc b/core/experiments/fireinterrupt/experiment.cc index 76bdaed9..18265228 100644 --- a/core/experiments/fireinterrupt/experiment.cc +++ b/core/experiments/fireinterrupt/experiment.cc @@ -31,7 +31,7 @@ bool fireinterruptExperiment::run() while(1){ int j = 0; for(j=0 ; j<=100 ; j++){ - fi::BPEvent mainbp(0x1045f5); + fi::BPSingleEvent mainbp(0x1045f5); sal::simulator.addEventAndWait(&mainbp); } sal::simulator.fireInterrupt(1); diff --git a/core/experiments/hscsimple/experiment.cc b/core/experiments/hscsimple/experiment.cc index 753c1ae3..0ff52192 100644 --- a/core/experiments/hscsimple/experiment.cc +++ b/core/experiments/hscsimple/experiment.cc @@ -24,7 +24,7 @@ bool hscsimpleExperiment::run() // do funny things here... #if 1 // STEP 1 - fi::BPEvent mainbp(0x00003c34); + fi::BPSingleEvent mainbp(0x00003c34); sal::simulator.addEventAndWait(&mainbp); log << "breakpoint reached, saving" << endl; sal::simulator.save("hello.state"); @@ -35,7 +35,7 @@ bool hscsimpleExperiment::run() log << "restored!" << endl; log << "waiting for last square() instruction" << endl; - fi::BPEvent breakpoint(0x3c9e); // square(x) ret instruction + fi::BPSingleEvent breakpoint(0x3c9e); // square(x) ret instruction sal::simulator.addEventAndWait(&breakpoint); log << "injecting hellish fault" << endl; // RID_CAX is the RAX register in 64 bit mode and EAX in 32 bit mode: diff --git a/core/experiments/l4sys/CMakeLists.txt b/core/experiments/l4sys/CMakeLists.txt new file mode 100644 index 00000000..0f51411f --- /dev/null +++ b/core/experiments/l4sys/CMakeLists.txt @@ -0,0 +1,31 @@ +set(EXPERIMENT_NAME l4sys) +set(EXPERIMENT_TYPE L4SysExperiment) +configure_file(../instantiate-experiment.ah.in + ${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY +) + +## Setup desired protobuf descriptions HERE ## +set(MY_PROTOS + l4sys.proto +) + +set(MY_CAMPAIGN_SRCS + experiment.hpp + experiment.cc + campaign.hpp + campaign.cc +) + +#### PROTOBUFS #### +find_package(Protobuf REQUIRED) +include_directories(${PROTOBUF_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS}) + +## Build library +add_library(${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS}) + +## This is the example's campaign server distributing experiment parameters +add_executable(${EXPERIMENT_NAME}-server main.cc) +target_link_libraries(${EXPERIMENT_NAME}-server ${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY}) diff --git a/core/experiments/l4sys/campaign.cc b/core/experiments/l4sys/campaign.cc new file mode 100644 index 00000000..03379995 --- /dev/null +++ b/core/experiments/l4sys/campaign.cc @@ -0,0 +1,74 @@ +#include + +#include "campaign.hpp" +#include "experimentInfo.hpp" +#include "controller/CampaignManager.hpp" +#include "util/Logger.hpp" +#include "SAL/SALConfig.hpp" + +using namespace fi; +using std::endl; + +char const * const results_csv = "l4sys.csv"; + +bool L4SysCampaign::run() +{ + Logger log("L4SysCampaign"); + +#if 0 + ifstream test(results_csv); + if (test.is_open()) { + log << results_csv << " already exists" << endl; + return false; + } +#endif + ofstream results(results_csv); + if (!results.is_open()) { + log << "failed to open " << results_csv << endl; + return false; + } + + 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 < COOL_ECC_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); + + fi::campaignmanager.addParam(d); + ++count; + } + } + fi::campaignmanager.noMoreParameters(); + log << "done enqueueing parameter sets (" << count << ")." << endl; + + // collect results + L4SysExperimentData *res; + int rescount = 0; + results << "injection_ip,instr_offset,injection_bit,resulttype,resultdata,output,details" << endl; + while ((res = static_cast(fi::campaignmanager.getDone()))) { + rescount++; + + results << std::hex + << res->msg.injection_ip() << "," + << std::dec << res->msg.instr_offset() << "," + << res->msg.bit_offset() << "," + << res->msg.resulttype() << "," + << res->msg.resultdata(); + if(res->msg.has_output()) + results << "," << res->msg.output(); + if(res->msg.has_details()) + results << "," << res->msg.details(); + results << endl; + delete res; + } + + log << "done. sent " << count << " received " << rescount << endl; + results.close(); + + return true; +} diff --git a/core/experiments/l4sys/campaign.hpp b/core/experiments/l4sys/campaign.hpp new file mode 100644 index 00000000..f4757477 --- /dev/null +++ b/core/experiments/l4sys/campaign.hpp @@ -0,0 +1,20 @@ +#ifndef __COOLCAMPAIGN_HPP__ +#define __COOLCAMPAIGN_HPP__ + +#include "controller/Campaign.hpp" +#include "controller/ExperimentData.hpp" +#include "l4sys.pb.h" + +class L4SysExperimentData : public fi::ExperimentData { +public: + L4SysProtoMsg msg; + L4SysExperimentData() : fi::ExperimentData(&msg) {} +}; + + +class L4SysCampaign : public fi::Campaign { +public: + virtual bool run(); +}; + +#endif diff --git a/core/experiments/l4sys/experiment.cc b/core/experiments/l4sys/experiment.cc new file mode 100644 index 00000000..1b565207 --- /dev/null +++ b/core/experiments/l4sys/experiment.cc @@ -0,0 +1,316 @@ +#include +#include +#include +#include +#include + +#include "util/Logger.hpp" + +#include "experiment.hpp" +#include "experimentInfo.hpp" +#include "campaign.hpp" + +#include "SAL/SALConfig.hpp" +#include "SAL/SALInst.hpp" +#include "SAL/Memory.hpp" +#include "SAL/bochs/BochsRegister.hpp" +#include "controller/Event.hpp" +#include "config/AspectConfig.hpp" + +#include "l4sys.pb.h" + +using std::endl; + +// Check if configuration dependencies are satisfied: +#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \ + !defined(CONFIG_SR_SAVE) || !defined(CONFIG_SUPPRESS_INTERRUPTS) || \ + !defined(CONFIG_EVENT_TRAP) || !defined(CONFIG_EVENT_GUESTSYS) || \ + !defined(CONFIG_EVENT_INTERRUPT) +#error This experiment needs: breakpoints, suppressed-interrupts, traps, guest system and interrupt events, \ + save, and restore. Enable these in the configuration. +#endif + +char const * const state_folder = "l4sys.state"; +char const * const instr_list_fn = "ip.list"; +char const * const golden_run_fn = "golden.out"; +sal::address_t const aspace = 0x1fd44000; +std::string output; +std::vector instr_list; +std::string golden_run; +//the program needs to run 5 times without a fault +const unsigned times_run = 5; + +std::string L4SysExperiment::sanitised(std::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(*it); + if (char_value < 0x20 || char_value > 0x7E) { + char str_nr[5]; + sprintf(str_nr, "\\%03o", char_value); + result += str_nr; + } else { + result += *it; + } + } + return result; +} + +fi::BaseEvent* L4SysExperiment::waitGuestOrOther(bool clear_output) { + fi::GuestEvent ev_guest; + fi::BaseEvent* ev = NULL; + if (clear_output) + output.clear(); + while (true) { + sal::simulator.addEvent(&ev_guest); + ev = sal::simulator.waitAny(); + sal::simulator.removeEvent(&ev_guest); + if (ev == &ev_guest) { + output += ev_guest.getData(); + } else { + break; + } + } + return ev; +} + +bool L4SysExperiment::run() { + Logger log("L4Sys", false); + fi::BPSingleEvent bp(0, aspace); + + log << "startup" << endl; + + //FIXME: this is a race condition: + //only one L4SysExperiment instance should execute this block + //at a time + + struct stat teststruct; + // STEP 1: run until interesting function starts, and save state + if (stat(state_folder, &teststruct) == -1) { + bp.setWatchInstructionPointer(COOL_ECC_FUNC_ENTRY); + sal::simulator.addEventAndWait(&bp); + + log << "test function entry reached, saving state" << endl; + log << "EIP = " << std::hex << bp.getTriggerInstructionPointer() + << " or " + << sal::simulator.getRegisterManager().getInstructionPointer() + << endl; + sal::simulator.save(state_folder); + } + + // STEP 2: determine instructions executed + if (stat(instr_list_fn, &teststruct) == -1) { + log << "restoring state" << endl; + sal::simulator.restore(state_folder); + log << "EIP = " << std::hex + << sal::simulator.getRegisterManager().getInstructionPointer() + << endl; + + // make sure the timer interrupt doesn't disturb us + sal::simulator.addSuppressedInterrupt(32); + + std::ofstream instr_list_file(instr_list_fn); + instr_list_file << std::hex; + bp.setWatchInstructionPointer(fi::ANY_ADDR); + while (bp.getTriggerInstructionPointer() != COOL_ECC_CALCDONE) { + sal::simulator.addEventAndWait(&bp); + //short sanity check + sal::address_t curr_instr = bp.getTriggerInstructionPointer(); + assert( + curr_instr == sal::simulator.getRegisterManager().getInstructionPointer()); + instr_list.push_back(curr_instr); + instr_list_file << curr_instr << endl; + } + log << "saving instructions triggered during normal execution" << endl; + instr_list_file.close(); + } else { + std::ifstream instr_list_file(instr_list_fn); + instr_list_file >> std::hex; + while (!instr_list_file.eof()) { + sal::address_t curr_instr; + instr_list_file >> curr_instr; + instr_list.push_back(curr_instr); + } + instr_list_file.close(); + } + + // STEP 3: determine the output of a "golden run" + if (stat(golden_run_fn, &teststruct) == -1) { + log << "restoring state" << endl; + sal::simulator.restore(state_folder); + log << "EIP = " << std::hex + << sal::simulator.getRegisterManager().getInstructionPointer() + << endl; + + // make sure the timer interrupt doesn't disturb us + sal::simulator.addSuppressedInterrupt(32); + + std::ofstream golden_run_file(golden_run_fn); + bp.setWatchInstructionPointer(COOL_ECC_CALCDONE); + bp.setCounter(times_run); + sal::simulator.addEvent(&bp); + fi::BaseEvent* ev = waitGuestOrOther(true); + if (ev == &bp) { + golden_run.assign(output.c_str()); + golden_run_file << output.c_str(); + log << "Output successfully logged!" << endl; + } else { + log + << "Obviously, there is some trouble with the events registered - aborting simulation!" + << endl; + golden_run_file.close(); + sal::simulator.terminate(10); + } + sal::simulator.clearEvents(); + bp.setCounter(1); + log << "saving output generated during normal execution" << endl; + golden_run_file.close(); + } else { + std::ifstream golden_run_file(golden_run_fn); + + //shamelessly copied from http://stackoverflow.com/questions/2602013/: + golden_run_file.seekg(0, std::ios::end); + size_t flen = golden_run_file.tellg(); + golden_run.reserve(flen); + golden_run_file.seekg(0, std::ios::beg); + + golden_run.assign((std::istreambuf_iterator(golden_run_file)), + std::istreambuf_iterator()); + + golden_run_file.close(); + + //the generated output probably has a similar length + output.reserve(flen); + } + + //end of critical section + + // STEP 4: The actual experiment. + for (int i = 0; i < COOL_ECC_NUMINSTR; i++) { + log << "restoring state" << endl; + sal::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 + sal::simulator.terminate(1); // "return (false);" ? + } + 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]); + sal::simulator.addEvent(&bp); + //and log the output + waitGuestOrOther(true); + + // inject + sal::RegisterManager& rm = sal::simulator.getRegisterManager(); + sal::Register *ebx = rm.getRegister(sal::RID_EBX); + sal::regdata_t data = ebx->getData(); + sal::regdata_t newdata = data ^ (1 << bit_offset); + ebx->setData(newdata); + // note at what IP we did it + sal::address_t injection_ip = + sal::simulator.getRegisterManager().getInstructionPointer(); + param.msg.set_injection_ip(injection_ip); + log << "inject @ ip " << injection_ip << " (offset " << std::dec + << instr_offset << ")" << " bit " << bit_offset << ": 0x" + << std::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]) { + std::stringstream ss; + ss << "SANITY CHECK FAILED: " << injection_ip << " != " + << instr_list[instr_offset] << endl; + log << ss.str(); + param.msg.set_resulttype(param.msg.UNKNOWN); + param.msg.set_resultdata(injection_ip); + param.msg.set_details(ss.str()); + + sal::simulator.clearEvents(); + m_jc.sendResult(param); + continue; + } + + // aftermath + fi::BPSingleEvent ev_done(COOL_ECC_CALCDONE, aspace); + ev_done.setCounter(times_run); + sal::simulator.addEvent(&ev_done); + const unsigned instr_run = times_run * COOL_ECC_NUMINSTR; + fi::BPSingleEvent ev_timeout(fi::ANY_ADDR, aspace); + ev_timeout.setCounter(instr_run + 3000); + sal::simulator.addEvent(&ev_timeout); + fi::TrapEvent ev_trap(fi::ANY_TRAP); + sal::simulator.addEvent(&ev_trap); + fi::InterruptEvent ev_intr(fi::ANY_INTERRUPT); + //ten times as many interrupts as instructions justify an exception + ev_intr.setCounter(instr_run * 10); + sal::simulator.addEvent(&ev_intr); + + //do not discard output recorded so far + fi::BaseEvent *ev = waitGuestOrOther(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 << std::dec << "Result DONE" << endl; + param.msg.set_resulttype(param.msg.CALCDONE); + } else { + log << std::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 << std::dec << "Result TIMEOUT" << endl; + param.msg.set_resulttype(param.msg.TIMEOUT); + param.msg.set_resultdata( + sal::simulator.getRegisterManager().getInstructionPointer()); + param.msg.set_output(sanitised(output.c_str())); + } else if (ev == &ev_trap) { + log << std::dec << "Result TRAP #" << ev_trap.getTriggerNumber() + << endl; + param.msg.set_resulttype(param.msg.TRAP); + param.msg.set_resultdata( + sal::simulator.getRegisterManager().getInstructionPointer()); + param.msg.set_output(sanitised(output.c_str())); + } else if (ev == &ev_intr) { + log << std::hex << "Result INT FLOOD; Last INT #:" + << ev_intr.getTriggerNumber() << endl; + param.msg.set_resulttype(param.msg.INTR); + param.msg.set_resultdata( + sal::simulator.getRegisterManager().getInstructionPointer()); + param.msg.set_output(sanitised(output.c_str())); + } else { + log << std::dec << "Result WTF?" << endl; + param.msg.set_resulttype(param.msg.UNKNOWN); + param.msg.set_resultdata( + sal::simulator.getRegisterManager().getInstructionPointer()); + param.msg.set_output(sanitised(output.c_str())); + + std::stringstream ss; + ss << "eventid " << ev << " EIP " + << sal::simulator.getRegisterManager().getInstructionPointer() + << endl; + param.msg.set_details(ss.str()); + } + + sal::simulator.clearEvents(); + m_jc.sendResult(param); + } + +#ifdef HEADLESS_EXPERIMENT + sal::simulator.terminate(0); +#endif +// experiment successfully conducted + return true; +} diff --git a/core/experiments/l4sys/experiment.hpp b/core/experiments/l4sys/experiment.hpp new file mode 100644 index 00000000..6a8ea8aa --- /dev/null +++ b/core/experiments/l4sys/experiment.hpp @@ -0,0 +1,17 @@ +#ifndef __COOLEXPERIMENT_HPP__ +#define __COOLEXPERIMENT_HPP__ + +#include "controller/ExperimentFlow.hpp" +#include "jobserver/JobClient.hpp" + +class L4SysExperiment : public fi::ExperimentFlow { + fi::JobClient m_jc; +public: + L4SysExperiment() : m_jc("localhost") {} + bool run(); +private: + std::string sanitised(std::string in_str); + fi::BaseEvent* waitGuestOrOther(bool clear_output); +}; + +#endif diff --git a/core/experiments/l4sys/experimentInfo.hpp b/core/experiments/l4sys/experimentInfo.hpp new file mode 100644 index 00000000..ac012734 --- /dev/null +++ b/core/experiments/l4sys/experimentInfo.hpp @@ -0,0 +1,11 @@ +#ifndef __EXPERIMENT_INFO_HPP__ +#define __EXPERIMENT_INFO_HPP__ + +// FIXME autogenerate this + +#define COOL_ECC_FUNC_ENTRY 0x1007cd0 +#define COOL_ECC_CALCDONE 0x1007d3a +#define COOL_ECC_NUMINSTR 3166 +#define HEADLESS_EXPERIMENT + +#endif diff --git a/core/experiments/l4sys/l4sys.proto b/core/experiments/l4sys/l4sys.proto new file mode 100644 index 00000000..dc56f376 --- /dev/null +++ b/core/experiments/l4sys/l4sys.proto @@ -0,0 +1,26 @@ +message L4SysProtoMsg { + // parameters + required int32 instr_offset = 1; + required int32 bit_offset = 2; + + // results + // make these optional to reduce overhead for server->client communication + enum ResultType { + CALCDONE = 1; + TIMEOUT = 2; + TRAP = 3; + INTR = 4; + WRONG = 5; + UNKNOWN = 6; + } + // instruction pointer where injection was done + optional uint32 injection_ip = 3; + // result type, see above + optional ResultType resulttype = 4; + // result data, depending on resulttype (see source code) + optional uint32 resultdata = 5; + // generated output + optional string output = 6; + // optional textual description of what happened + optional string details = 7; +} diff --git a/core/experiments/l4sys/main.cc b/core/experiments/l4sys/main.cc new file mode 100644 index 00000000..0f65b3a3 --- /dev/null +++ b/core/experiments/l4sys/main.cc @@ -0,0 +1,15 @@ +#include +#include + +#include "controller/CampaignManager.hpp" +#include "experiments/l4sys/campaign.hpp" + +int main(int argc, char **argv) +{ + L4SysCampaign c; + if (fi::campaignmanager.runCampaign(&c)) { + return 0; + } else { + return 1; + } +} diff --git a/core/experiments/weathermonitor/experiment.cc b/core/experiments/weathermonitor/experiment.cc index a245b23c..724c64fb 100644 --- a/core/experiments/weathermonitor/experiment.cc +++ b/core/experiments/weathermonitor/experiment.cc @@ -29,7 +29,7 @@ bool WeathermonitorExperiment::run() { char const *statename = "bochs.state"; Logger log("Weathermonitor", false); - fi::BPEvent bp; + fi::BPSingleEvent bp; log << "startup" << endl; @@ -78,7 +78,7 @@ bool WeathermonitorExperiment::run() bp.setWatchInstructionPointer(WEATHER_FUNC_WAIT_END); bp.setCounter(WEATHER_NUMITER_TRACING); sal::simulator.addEvent(&bp); - fi::BPEvent ev_count(fi::ANY_ADDR); + fi::BPSingleEvent ev_count(fi::ANY_ADDR); sal::simulator.addEvent(&ev_count); // count instructions @@ -168,14 +168,14 @@ bool WeathermonitorExperiment::run() */ // this marks THE END - fi::BPEvent ev_end(fi::ANY_ADDR); + fi::BPSingleEvent ev_end(fi::ANY_ADDR); ev_end.setCounter(WEATHER_NUMINSTR_TRACING + WEATHER_NUMINSTR_AFTER); sal::simulator.addEvent(&ev_end); // count loop iterations by counting wait_begin() calls // FIXME would be nice to have a callback API for this as this needs to // be done "in parallel" - fi::BPEvent ev_wait_begin(WEATHER_FUNC_WAIT_BEGIN); + fi::BPSingleEvent ev_wait_begin(WEATHER_FUNC_WAIT_BEGIN); sal::simulator.addEvent(&ev_wait_begin); int count_loop_iter_before = 0; @@ -242,7 +242,7 @@ bool WeathermonitorExperiment::run() sal::simulator.addEvent(&ev_below_text); sal::simulator.addEvent(&ev_beyond_text); // error detected - fi::BPEvent ev_detected(WEATHER_FUNC_VPTR_PANIC); + fi::BPSingleEvent ev_detected(WEATHER_FUNC_VPTR_PANIC); sal::simulator.addEvent(&ev_detected); #if LOCAL && 0 diff --git a/core/plugins/tracing/TracingPlugin.cc b/core/plugins/tracing/TracingPlugin.cc index e9c7cc97..eff96fa8 100644 --- a/core/plugins/tracing/TracingPlugin.cc +++ b/core/plugins/tracing/TracingPlugin.cc @@ -13,7 +13,7 @@ using namespace sal; bool TracingPlugin::run() { MemAccessEvent ev_mem(ANY_ADDR); - BPEvent ev_step(ANY_ADDR); + BPSingleEvent ev_step(ANY_ADDR); BaseEvent *ev; if (m_iponly || !m_memonly) {