#include "SimulatorController.hpp" #include "SALInst.hpp" #include "Event.hpp" #include "Listener.hpp" #include "util/CommandLine.hpp" namespace fail { // External reference declared in SALInst.hpp ConcreteSimulatorController simulator; bool SimulatorController::addListener(BaseListener* li) { assert(li != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!"); // If addListener() was called from onTrigger(), there is no parent // to retrieve/assign. In this case, we simple expect the parent-member // to be valid ('as is'). (Otherwise, the current flow is retrieved by // calling CoroutineManager::getCurrent().) ExperimentFlow* pFlow = m_Flows.getCurrent(); if (pFlow == CoroutineManager::SIM_FLOW) pFlow = li->getParent(); m_LstList.add(li, pFlow); // Call the common postprocessing function: if (!li->onAddition()) { // If the return value signals "false"..., m_LstList.remove(li); // ...skip the addition return false; } return true; } BaseListener* SimulatorController::resume(void) { m_Flows.resume(); assert(m_LstList.getLastFired() != NULL && "FATAL ERROR: getLastFired() expected to be non-NULL!"); return m_LstList.getLastFired(); } void SimulatorController::startup(int& argc, char **& argv) { if (argv) { CommandLine::Inst().collect_args(argc, argv); } startup(); } void SimulatorController::startup() { // Some greetings to the user: std::cout << "[SimulatorController] Initializing..." << std::endl; // TODO: Log-Level? // Set FAIL* as initialized m_isInitialized = true; // Activate previously added experiments to allow initialization: initExperiments(); } void SimulatorController::initExperiments() { /* empty. */ } void SimulatorController::onBreakpoint(ConcreteCPU* cpu, address_t instrPtr, address_t address_space) { // Check for active breakpoint-events: ListenerManager::iterator it = m_LstList.begin(); BPEvent tmp(instrPtr, address_space, cpu); while (it != m_LstList.end()) { BaseListener* pLi = *it; BPListener* pBreakpt = dynamic_cast(pLi); if (pBreakpt != NULL && pBreakpt->isMatching(&tmp)) { pBreakpt->setTriggerCPU(cpu); pBreakpt->setTriggerInstructionPointer(instrPtr); it = m_LstList.makeActive(it); // "it" has already been set to the next element (by calling // makeActive()): continue; // -> skip iterator increment } it++; } m_LstList.triggerActiveListeners(); } void SimulatorController::onMemoryAccess(ConcreteCPU* cpu, address_t addr, size_t len, bool is_write, address_t instrPtr) { MemAccessEvent::access_type_t accesstype = is_write ? MemAccessEvent::MEM_WRITE : MemAccessEvent::MEM_READ; MemAccessEvent tmp(addr, len, instrPtr, accesstype, cpu); ListenerManager::iterator it = m_LstList.begin(); while (it != m_LstList.end()) { // check for active listeners BaseListener* pev = *it; MemAccessListener* ev = dynamic_cast(pev); // Is this a MemAccessListener? Correct access type? if (!ev || !ev->isMatching(&tmp)) { ++it; continue; // skip listener activation } ev->setTriggerAddress(addr); ev->setTriggerWidth(len); ev->setTriggerInstructionPointer(instrPtr); ev->setTriggerAccessType(accesstype); ev->setTriggerCPU(cpu); it = m_LstList.makeActive(it); } m_LstList.triggerActiveListeners(); } void SimulatorController::onInterrupt(ConcreteCPU* cpu, unsigned interruptNum, bool nmi) { ListenerManager::iterator it = m_LstList.begin(); InterruptEvent tmp(nmi, interruptNum, cpu); while (it != m_LstList.end()) { // check for active listeners BaseListener* pev = *it; InterruptListener* pie = dynamic_cast(pev); if (!pie || !pie->isMatching(&tmp)) { ++it; continue; // skip listener activation } pie->setTriggerNumber(interruptNum); pie->setNMI(nmi); pie->setTriggerCPU(cpu); it = m_LstList.makeActive(it); } m_LstList.triggerActiveListeners(); } void SimulatorController::onTrap(ConcreteCPU* cpu, unsigned trapNum) { TroubleEvent tmp(trapNum, cpu); ListenerManager::iterator it = m_LstList.begin(); while (it != m_LstList.end()) { // check for active listeners BaseListener* pev = *it; TrapListener* pte = dynamic_cast(pev); if (!pte || !pte->isMatching(&tmp)) { ++it; continue; // skip listener activation } pte->setTriggerNumber(trapNum); pte->setTriggerCPU(cpu); it = m_LstList.makeActive(it); } m_LstList.triggerActiveListeners(); } void SimulatorController::onGuestSystem(char data, unsigned port) { ListenerManager::iterator it = m_LstList.begin(); while (it != m_LstList.end()) { // check for active listeners BaseListener* pev = *it; GuestListener* pge = dynamic_cast(pev); if (pge != NULL) { pge->setData(data); pge->setPort(port); it = m_LstList.makeActive(it); continue; // dito. } ++it; } m_LstList.triggerActiveListeners(); } void SimulatorController::onJump(ConcreteCPU* cpu, bool flagTriggered, unsigned opcode) { ListenerManager::iterator it = m_LstList.begin(); while (it != m_LstList.end()) { // check for active listeners JumpListener* pje = dynamic_cast(*it); if (pje != NULL) { pje->setOpcode(opcode); pje->setFlagTriggered(flagTriggered); pje->setTriggerCPU(cpu); it = m_LstList.makeActive(it); continue; // dito. } ++it; } m_LstList.triggerActiveListeners(); } void SimulatorController::addCPU(ConcreteCPU* cpu) { assert(cpu != NULL && "FATAL ERROR: Argument (cpu) cannot be NULL!"); m_CPUs.push_back(cpu); } ConcreteCPU& SimulatorController::getCPU(size_t i) const { assert(i < m_CPUs.size() && "FATAL ERROR: Invalid index provided!"); return *m_CPUs[i]; } void SimulatorController::addFlow(ExperimentFlow* flow) { // Store the (flow,corohandle)-tuple internally and create its coroutine: m_Flows.create(flow); // let it run for the first time m_Flows.toggle(flow); } void SimulatorController::removeFlow(ExperimentFlow* flow) { // remove all remaining listeners of this flow clearListeners(flow); // remove coroutine m_Flows.remove(flow); } BaseListener* SimulatorController::addListenerAndResume(BaseListener* li) { addListener(li); return resume(); } void SimulatorController::terminate(int exCode) { // Attention: This could cause problems, e.g., because of non-closed sockets std::cout << "[FAIL] Exit called by experiment with exit code: " << exCode << std::endl; // TODO: (Non-)Verbose-Mode? Log-Level? m_Flows.setTerminated(); // we are about to terminate exit(exCode); } } // end-of-namespace: fail