another directory rename: failstar -> fail

"failstar" sounds like a name for a cruise liner from the 80s.  As "*" isn't a
desirable part of directory names, just name the whole thing "fail/", the core
parts being stored in "fail/core/".

Additionally fixing two build system dependency issues:
 - missing jobserver -> protomessages dependency
 - broken bochs -> fail dependency (add_custom_target DEPENDS only allows plain
   file dependencies ... cmake for the win)


git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@956 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
hsc
2012-03-08 19:43:02 +00:00
commit b70b6fb43a
921 changed files with 473161 additions and 0 deletions

View File

@ -0,0 +1,24 @@
#ifndef __BOCHS_CONFIG_HPP__
#define __BOCHS_CONFIG_HPP__
#include "../../../bochs/bochs.h"
#include "../../../bochs/config.h"
// Type definitions and configuration settings for
// the Bochs simulator.
namespace sal
{
typedef bx_address guest_address_t; //!< the guest memory address type
typedef Bit8u* host_address_t; //!< the host memory address type
#if BX_SUPPORT_X86_64
typedef Bit64u register_data_t; //!< register data type (64 bit)
#else
typedef Bit32u register_data_t; //!< register data type (32 bit)
#endif
};
#endif /* __BOCHS_CONFIG_HPP__ */

View File

@ -0,0 +1,106 @@
#ifndef __BOCHS_CONTROLLER_HPP__
#define __BOCHS_CONTROLLER_HPP__
#define DEBUG
#include <string>
#include <cassert>
#include <iostream>
#include <iomanip>
#include <string.h>
#include <stdlib.h>
#include "failbochs.hpp"
#include "../SimulatorController.hpp"
#include "../../controller/Event.hpp"
#include "../../../bochs/bochs.h"
#include "../../../bochs/cpu/cpu.h"
#include "../../../bochs/config.h"
using namespace std;
namespace fi { class ExperimentFlow; }
/// Simulator Abstraction Layer namespace
namespace sal
{
/**
* \class BochsController
* Bochs-specific implementation of a SimulatorController.
*/
class BochsController : public SimulatorController
{
private:
/**
* stores the current flow for save/restore-operations
*/
fi::ExperimentFlow* m_CurrFlow;
#ifdef DEBUG
unsigned m_Regularity;
unsigned m_Counter;
std::ostream* m_pDest;
#endif
public:
// Initialize the controller.
BochsController();
~BochsController();
/* ********************************************************************
* Standard Event Handler API (SEH-API):
* ********************************************************************/
/**
* Instruction pointer modification handler. This method is called (from
* the CPULoop aspect) every time when the Bochs-internal IP changes.
* @param instrPtr
*/
void onInstrPtrChanged(address_t instrPtr);
/* ********************************************************************
* Simulator Controller & Access API (SCA-API):
* ********************************************************************/
/**
* Save simulator state.
* @param path Location to store state information
*/
void save(const string& path);
/**
* Save finished: Callback from Simulator
*/
void saveDone();
/**
* Restore simulator state. Clears all Events.
* @param path Location to previously saved state information
*/
void restore(const string& path);
/**
* Restore finished: Callback from Simulator
*/
void restoreDone();
/**
* Reboot simulator. Clears all Events.
*/
void reboot();
/**
* Reboot finished: Callback from Simulator
*/
void rebootDone();
/**
* Terminate simulator
* @param exCode Individual exit code
*/
void terminate(int exCode = EXIT_SUCCESS);
#ifdef DEBUG
/**
* Enables instruction pointer debugging output.
* @param regularity the output regularity; 1 to display every
* instruction pointer, 0 to disable
* @param dest specifies the output destition; defaults to \c std::cout
*/
void dbgEnableInstrPtrOutput(unsigned regularity, std::ostream* dest = &cout);
#endif
};
} // end-of-namespace: sal
#endif /* __BOCHS_CONTROLLER_HPP__ */

View File

@ -0,0 +1,115 @@
#ifndef __BOCHS_MEMORY_HPP__
#define __BOCHS_MEMORY_HPP__
#include "../Memory.hpp"
namespace sal
{
/**
* \class BochsMemoryManager
* Represents a concrete implemenation of the abstract
* MemoryManager to provide access to Bochs' memory pool.
*/
class BochsMemoryManager : public MemoryManager
{
public:
/**
* Constructs a new MemoryManager object and initializes
* it's attributes appropriately.
*/
BochsMemoryManager() : MemoryManager() { }
/**
* Retrieves the size of the available simulated memory.
* @return the size of the memory pool in bytes
*/
size_t getPoolSize() const
{
return (static_cast<size_t>(BX_MEM(0)->get_memory_len()));
}
/**
* Retrieves the starting address of the host memory. This is the
* first valid address in memory.
* @return the starting address
*/
host_address_t getStartAddr() const
{
return (0);
}
/**
* Retrieves the byte at address \a addr in the memory.
* @param addr The guest address where the byte is located.
* The address is expected to be valid.
* @return the byte at \a addr
*/
byte_t getByte(guest_address_t addr)
{
host_address_t haddr = guestToHost(addr);
assert(haddr != (host_address_t)ADDR_INV && "FATAL ERROR: Invalid guest address provided!");
return (static_cast<byte_t>(*reinterpret_cast<Bit8u*>(haddr)));
}
/**
* Retrieves \a cnt bytes at address \a addr in the memory.
* @param addr The guest address where the bytes are located.
* The address is expected to be valid.
* @param cnt The number of bytes to be retrieved. \a addr + \a cnt
* is expected to not exceed the memory limit.
* @param dest The destination buffer to write the bytes to
*/
void getBytes(guest_address_t addr, size_t cnt, std::vector<byte_t>& dest)
{
for(size_t i = 0; i < cnt; i++)
dest.push_back(getByte(addr+i));
}
/**
* Writes the byte \a data to memory.
* @param addr The guest address to write.
* The address is expected to be valid.
* @param data The new byte to write
*/
void setByte(guest_address_t addr, byte_t data)
{
host_address_t haddr = guestToHost(addr);
assert(haddr != (host_address_t)ADDR_INV &&
"FATAL ERROR: Invalid guest address provided!");
*reinterpret_cast<Bit8u*>(haddr) = data;
}
/**
* Writes the bytes \a data to memory. Consequently \c data.size()
* bytes will be written.
* @param addr The guest address to write.
* The address is expected to be valid.
* @param data The new bytes to write
*/
void setBytes(guest_address_t addr, const std::vector<byte_t>& data)
{
for(size_t i = 0; i < data.size(); i++)
setByte(addr+i, data[i]);
}
/**
* Transforms the guest address \a addr to a host address.
* @param addr The (logical) guest address to be transformed
* @return the transformed (host) address or \c ADDR_INV on errors
*/
host_address_t guestToHost(guest_address_t addr)
{
const unsigned SEGMENT_SELECTOR_IDX = 2; // always the code segment
const bx_address logicalAddr = static_cast<bx_address>(addr); // offset within the segment
// Get the linear address:
Bit32u linearAddr = BX_CPU(0)->get_laddr32(SEGMENT_SELECTOR_IDX/*seg*/, logicalAddr/*offset*/);
// Map the linear address to the physical address:
bx_phy_address physicalAddr;
bx_bool fValid = BX_CPU(0)->dbg_xlate_linear2phy(linearAddr, (bx_phy_address*)&physicalAddr);
// Determine the *host* address of the physical address:
Bit8u* hostAddr = BX_MEM(0)->getHostMemAddr(BX_CPU(0), physicalAddr, BX_READ);
// Now, hostAddr contains the "final" address
if(!fValid)
return ((host_address_t)ADDR_INV); // error
else
return (reinterpret_cast<host_address_t>(hostAddr)); // okay
}
};
}
#endif

View File

@ -0,0 +1,219 @@
#ifndef __BOCHS_REGISTER_HPP__
#define __BOCHS_REGISTER_HPP__
#include "../Register.hpp"
#include "../../../bochs/bochs.h"
#include <iostream>
namespace sal {
/**
* \class BochsRegister
* Bochs-specific implementation of x86 registers.
*/
class BochsRegister : public Register
{
protected:
regdata_t* m_pData;
public:
/**
* Constructs a new register object.
* @param id the global unique id
* @param width width of the register (8, 16, 32 or 64 bit should
* suffice)
* @param link pointer to bochs interal register memory
* @param t type of the register
*/
BochsRegister(unsigned int id, regwidth_t width, regdata_t* link, RegisterType t)
: Register(id, t, width), m_pData(link) { }
/**
* Retrieves the data of the register.
* @return the current register data
*/
regdata_t getData() { return (*m_pData); }
/**
* Sets the content of the register.
* @param data the new register data to be written
*/
virtual void setData(regdata_t data) { *m_pData = data; }
};
/**
* \class BxGPReg
* Bochs-specific implementation of x86 general purpose (GP) registers.
*/
class BxGPReg : public BochsRegister
{
public:
/**
* Constructs a new general purpose register.
* @param id the global unique id
* @param width width of the register (8, 16, 32 or 64 bit should
* suffice)
* @param link pointer to bochs interal register memory
*/
BxGPReg(unsigned int id, regwidth_t width, regdata_t* link)
: BochsRegister(id, width, link, RT_GP) { }
};
/**
* \enum GPRegisterId
* Symbolic identifier to access Bochs' general purpose register
* (within the corresponding GP set), e.g.
* \code
* // Print %eax register data:
* BochsController bc(...);
* cout << bc.getRegisterManager().getSetOfType(RT_GP)
* .getRegister(RID_EAX)->getData();
* \endcode
*/
enum GPRegisterId
{
#if BX_SUPPORT_X86_64 // 64 bit register id's:
RID_RAX = 0, RID_RCX, RID_RDX, RID_RBX, RID_RSP, RID_RBP, RID_RSI, RID_RDI,
RID_R8, RID_R9, RID_R10, RID_R11, RID_R12, RID_R13, RID_R14, RID_R15,
#else // 32 bit register id's:
RID_EAX = 0, RID_ECX, RID_EDX, RID_EBX, RID_ESP, RID_EBP, RID_ESI, RID_EDI,
#endif
RID_LAST_GP_ID
};
/**
* \enum PCRegisterId
* Symbolic identifier to access Bochs' program counter register.
*/
enum PCRegisterId { RID_PC = RID_LAST_GP_ID, RID_LAST_PC_ID };
/**
* \enum FlagsRegisterId
* Symbolic identifier to access Bochs' flags register.
*/
enum FlagsRegisterId { RID_FLAGS = RID_LAST_PC_ID };
/**
* \class BxPCReg
* Bochs-specific implementation of the x86 program counter register.
*/
class BxPCReg : public BochsRegister
{
public:
/**
* Constructs a new program counter register.
* @param id the global unique id
* @param width width of the register (8, 16, 32 or 64 bit should
* suffice)
* @param link pointer to bochs internal register memory
*/
BxPCReg(unsigned int id, regwidth_t width, regdata_t* link)
: BochsRegister(id, width, link, RT_PC) { }
};
/**
* \class BxFlagsReg
* Bochs-specific implementation of the FLAGS status register.
*/
class BxFlagsReg : public BochsRegister
{
public:
/**
* Constructs a new FLAGS status register. The refenced FLAGS are
* allocated as follows:
* --------------------------------------------------
* 31|30|29|28| 27|26|25|24| 23|22|21|20| 19|18|17|16
* ==|==|=====| ==|==|==|==| ==|==|==|==| ==|==|==|==
* 0| 0| 0| 0| 0| 0| 0| 0| 0| 0|ID|VP| VF|AC|VM|RF
*
* 15|14|13|12| 11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0
* ==|==|=====| ==|==|==|==| ==|==|==|==| ==|==|==|==
* 0|NT| IOPL| OF|DF|IF|TF| SF|ZF| 0|AF| 0|PF| 1|CF
* --------------------------------------------------
* @param id the global unique id
* @param link pointer to bochs internal register memory
*/
BxFlagsReg(unsigned int id, regdata_t* link)
: BochsRegister(id, 32, link, RT_ST) { }
/**
* Returns \c true if the corresponding flag is set, or \c false
* otherwise.
*/
bool getCarryFlag() const { return (BX_CPU(0)->get_CF()); }
bool getParityFlag() const { return (BX_CPU(0)->get_PF()); }
bool getZeroFlag() const { return (BX_CPU(0)->get_ZF()); }
bool getSignFlag() const { return (BX_CPU(0)->get_SF()); }
bool getOverflowFlag() const { return (BX_CPU(0)->get_OF()); }
/**
* Sets/resets various status FLAGS.
*/
void setCarryFlag(bool bit) { BX_CPU(0)->set_CF(bit); }
void setParityFlag(bool bit) { BX_CPU(0)->set_PF(bit); }
void setZeroFlag(bool bit) { BX_CPU(0)->set_ZF(bit); }
void setSignFlag(bool bit) { BX_CPU(0)->set_SF(bit); }
void setOverflowFlag(bool bit) { BX_CPU(0)->set_OF(bit); }
/**
* Sets the content of the status register.
* @param data the new register data to be written; note that only the
* 32 lower bits are used (bits 32-63 are ignored in 64 bit mode)
*/
void setData(regdata_t data)
{
#ifdef BX_SUPPORT_X86_64
// We are in 64 bit mode: Just assign the lower 32 bits!
(*m_pData) = ((*m_pData) & 0xFFFFFFFF00000000ULL) |
(data & 0xFFFFFFFFULL);
#else
*m_pData = data;
#endif
}
};
/**
* \class BochsRegister
* Bochs-specific implementation of the RegisterManager.
*/
class BochsRegisterManager : public RegisterManager
{
public:
/**
* Returns the current instruction pointer.
* @return the current eip
*/
address_t getInstructionPointer()
{
return (static_cast<address_t>(
getSetOfType(RT_PC)->first()->getData()
));
}
/**
* Retruns the top address of the stack.
* @return the starting address of the stack
*/
address_t getStackPointer()
{
#if BX_SUPPORT_X86_64
return (static_cast<address_t>(getRegister(RID_RSP)->getData()));
#else
return (static_cast<address_t>(getRegister(RID_ESP)->getData()));
#endif
}
/**
* Retrieves the base ptr (holding the address of the
* current stack frame).
* @return the base pointer
*/
address_t getBasePointer()
{
#if BX_SUPPORT_X86_64
return (static_cast<address_t>(getRegister(RID_RBP)->getData()));
#else
return (static_cast<address_t>(getRegister(RID_EBP)->getData()));
#endif
}
};
} // end-of-namespace: sal
#endif /* __BOCHS_REGISTER_HPP__ */

35
core/SAL/bochs/CPULoop.ah Normal file
View File

@ -0,0 +1,35 @@
#ifndef __CPU_LOOP_AH__
#define __CPU_LOOP_AH__
#include "../../AspectConfig.hpp"
#if CONFIG_EVENT_CPULOOP == 1
#include "../../../bochs/bochs.h" // for "BX_CPU_C"
#include "../../../bochs/cpu/cpu.h" // for "bxInstruction_c"
#include "../SALInst.hpp"
aspect CPULoop
{
pointcut cpuLoop() = "void defineCPULoopJoinPoint(...)";
//
// Event source: "instruction pointer"
//
advice execution (cpuLoop()) : after ()
{
// Points to the cpu class: "this" if BX_USE_CPU_SMF == 0,
// BX_CPU(0) otherwise
BX_CPU_C* pThis = *(tjp->arg<0>());
// Points to the *current* bxInstruction-object
bxInstruction_c* pInstr = *(tjp->arg<1>());
// report this event to the Bochs controller:
sal::simulator.onInstrPtrChanged(pThis->get_instruction_pointer());
// Note: get_bx_opcode_name(pInstr->getIaOpcode()) retrieves the mnemonics.
}
};
#endif // CONFIG_EVENT_CPULOOP
#endif /* __CPU_LOOP_AH__ */

View File

@ -0,0 +1,179 @@
#include "BochsController.hpp"
#include "BochsMemory.hpp"
#include "BochsRegister.hpp"
#include "../Register.hpp"
namespace sal
{
bx_bool restore_bochs_request = false;
bx_bool save_bochs_request = false;
bx_bool reboot_bochs_request = false;
std::string sr_path = "";
BochsController::BochsController()
: SimulatorController(new BochsRegisterManager(), new BochsMemoryManager())
{
// -------------------------------------
// Add the general purpose register:
#if BX_SUPPORT_X86_64
// -- 64 bit register --
const string names[] = { "RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI",
"RDI", "R8", "R9", "R10", "R11", "R12", "R13",
"R14", "R15" };
for(unsigned short i = 0; i < 16; i++)
{
BxGPReg* pReg = new BxGPReg(i, 64, &(BX_CPU(0)->gen_reg[i].rrx));
pReg->setName(names[i]);
m_Regs->add(pReg);
}
#else
// -- 32 bit register --
const string names[] = { "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI",
"EDI" };
for(unsigned short i = 0; i < 8; i++)
{
BxGPReg* pReg = new BxGPReg(i, 32, &(BX_CPU(0)->gen_reg[i].dword.erx));
pReg->setName(names[i]);
m_Regs->add(pReg);
}
#endif // BX_SUPPORT_X86_64
#ifdef DEBUG
m_Regularity = 0; // disabled
m_Counter = 0;
m_pDest = NULL;
#endif
// -------------------------------------
// Add the Program counter register:
#if BX_SUPPORT_X86_64
BxPCReg* pPCReg = new BxPCReg(RID_PC, 64, &(BX_CPU(0)->gen_reg[BX_64BIT_REG_RIP].rrx));
pPCReg->setName("RIP");
#else
BxPCReg* pPCReg = new BxPCReg(RID_PC, 32, &(BX_CPU(0)->gen_reg[BX_32BIT_REG_EIP].dword.erx));
pFlagReg->setName("EIP");
#endif // BX_SUPPORT_X86_64
// -------------------------------------
// Add the Status register (x86 cpu FLAGS):
BxFlagsReg* pFlagReg = new BxFlagsReg(RID_FLAGS, reinterpret_cast<regdata_t*>(&(BX_CPU(0)->eflags)));
// Note: "eflags" is (always) of type Bit32u which matches the regdata_t only in
// case of the 32 bit version (id est !BX_SUPPORT_X86_64). Therefor we need
// to ensure to assign only 32 bit to the Bochs internal register variable
// (see SAL/bochs/BochsRegister.hpp, setData) if we are in 64 bit mode.
pFlagReg->setName("FLAGS");
m_Regs->add(pFlagReg);
m_Regs->add(pPCReg);
}
BochsController::~BochsController()
{
for(RegisterManager::iterator it = m_Regs->begin(); it != m_Regs->end(); it++)
delete (*it); // free the memory, allocated in the constructor
m_Regs->clear();
delete m_Regs;
delete m_Mem;
}
#ifdef DEBUG
void BochsController::dbgEnableInstrPtrOutput(unsigned regularity, std::ostream* dest)
{
m_Regularity = regularity;
m_pDest = dest;
m_Counter = 0;
}
#endif // DEBUG
void BochsController::onInstrPtrChanged(address_t instrPtr)
{
#ifdef DEBUG
if(m_Regularity != 0 && ++m_Counter % m_Regularity == 0)
(*m_pDest) << "0x" << std::hex << instrPtr;
#endif
// Check for active breakpoint-events:
fi::EventList::iterator it = m_EvList.begin();
while(it != m_EvList.end())
{
// FIXME: Performance verbessern (dazu muss entsprechend auch die Speicherung
// in EventList(.cc|.hpp) angepasst bzw. verbessert werden).
fi::BPEvent* pEvBreakpt = dynamic_cast<fi::BPEvent*>(*it);
if(pEvBreakpt && (instrPtr == pEvBreakpt->getWatchInstructionPointer() ||
pEvBreakpt->getWatchInstructionPointer() == fi::ANY_ADDR))
{
pEvBreakpt->setTriggerInstructionPointer(instrPtr);
it = m_EvList.makeActive(it);
// "it" has already been set to the next element (by calling
// makeActive()):
continue; // -> skip iterator increment
}
fi::BPRangeEvent* pEvRange = dynamic_cast<fi::BPRangeEvent*>(*it);
if(pEvRange && pEvRange->isMatching(instrPtr))
{
pEvBreakpt->setTriggerInstructionPointer(instrPtr);
it = m_EvList.makeActive(it);
continue; // dito.
}
it++;
}
m_EvList.fireActiveEvents();
// Note: SimulatorController::onBreakpointEvent will not be invoked in this
// implementation.
}
void BochsController::save(const string& path)
{
int stat;
stat = mkdir(path.c_str(), 0777);
if(!(stat == 0 || errno == EEXIST))
std::cout << "[FAIL] Can not create target-directory to save!" << std::endl;
// TODO: (Non-)Verbose-Mode? Maybe better: use return value to indicate failure?
save_bochs_request = true;
sr_path = path;
m_CurrFlow = m_Flows.getCurrent();
m_Flows.resume();
}
void BochsController::saveDone()
{
save_bochs_request = false;
m_Flows.toggle(m_CurrFlow);
}
void BochsController::restore(const string& path)
{
clearEvents();
restore_bochs_request = true;
sr_path = path;
m_CurrFlow = m_Flows.getCurrent();
m_Flows.resume();
}
void BochsController::restoreDone()
{
restore_bochs_request = false;
m_Flows.toggle(m_CurrFlow);
}
void BochsController::reboot()
{
clearEvents();
reboot_bochs_request = true;
m_CurrFlow = m_Flows.getCurrent();
m_Flows.resume();
}
void BochsController::rebootDone()
{
reboot_bochs_request = false;
m_Flows.toggle(m_CurrFlow);
}
void BochsController::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?
exit(exCode);
}
} // end-of-namespace: sal

View File

@ -0,0 +1,37 @@
#ifndef __GUESTSYS_COM_AH__
#define __GUESTSYS_COM_AH__
#include "../../AspectConfig.hpp"
#if CONFIG_EVENT_GUESTSYS == 1
#include "../../../bochs/bochs.h"
#include "../../../bochs/cpu/cpu.h"
#include "../SALInst.hpp"
#include "bochs_helpers.hpp"
// Fixed "port number" for "Guest system >> Bochs" communication
#define BOCHS_COM_PORT 0x378
aspect GuestSysCom
{
pointcut outInstructions() = "% ...::bx_cpu_c::OUT_DX%(...)";
advice execution (outInstructions()) : after ()
{
//
// Event source: "guest system"
//
unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number
unsigned rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data
if (rDX == BOCHS_COM_PORT) {
sal::simulator.onGuestSystemEvent((char)rAL, rDX);
}
}
};
#endif // CONFIG_EVENT_GUESTSYS
#endif /* __GUESTSYS_COM_AH__ */

View File

@ -0,0 +1,40 @@
#ifndef __INTERRUPT_AH__
#define __INTERRUPT_AH__
#include "../../AspectConfig.hpp"
#if CONFIG_EVENT_INTERRUPT == 1
#include "../../../bochs/bochs.h"
#include "../../../bochs/cpu/cpu.h"
#include "../SALInst.hpp"
aspect Interrupt
{
// cpu/exception.cc
pointcut interrupt_method() = "void bx_cpu_c::interrupt(...)";
advice execution (interrupt_method()) : before ()
{
// There are six different type-arguments for the interrupt-method
// in cpu.h (lines 3867-3872):
// - BX_EXTERNAL_INTERRUPT = 0,
// - BX_NMI = 2,
// - BX_HARDWARE_EXCEPTION = 3,
// - BX_SOFTWARE_INTERRUPT = 4,
// - BX_PRIVILEGED_SOFTWARE_INTERRUPT = 5,
// - BX_SOFTWARE_EXCEPTION = 6
// Only the first and the second types are relevant for this aspect.
unsigned vector = *(tjp->arg<0>());
unsigned type = *(tjp->arg<1>());
if(type == BX_EXTERNAL_INTERRUPT)
sal::simulator.onInterruptEvent(vector, false);
else if(type == BX_NMI)
sal::simulator.onInterruptEvent(vector, true);
}
};
#endif // CONFIG_EVENT_INTERRUPT
#endif /* __INTERRUPT_AH__ */

View File

@ -0,0 +1,28 @@
#ifndef __INTERRUPT_SUPPRESSION_AH__
#define __INTERRUPT_SUPPRESSION_AH__
#include "../../AspectConfig.hpp"
#if CONFIG_SUPPRESS_INTERRUPTS == 1
#include "../../../bochs/bochs.h"
#include "../../../bochs/cpu/cpu.h"
#include "../SALInst.hpp"
aspect Interrupt_FI
{
pointcut interrupt_method() = "void bx_cpu_c::interrupt(...)";
advice execution (interrupt_method()) : around ()
{
unsigned type = *(tjp->arg<1>());
if(!sal::simulator.isSuppressedInterrupt(type)){
tjp->proceed();
}
}
};
#endif // CONFIG_SUPPRESS_INTERRUPTS
#endif /* __INTERRUPT_SUPPRESSION_AH__ */

139
core/SAL/bochs/Jump.ah Normal file
View File

@ -0,0 +1,139 @@
#ifndef __JUMP_AH__
#define __JUMP_AH__
#include "../../AspectConfig.hpp"
#if CONFIG_EVENT_JUMP == 1
#include <iostream>
#include <cstdlib>
#include <string>
#include <ctime>
#include "../../../bochs/bochs.h"
#include "../SALInst.hpp"
using namespace std;
aspect Jump
{
// Note: Have a look at the Bochs-Code (cpu/cpu.h) and the Intel
// Architecture Software Developer's Manual - Instruction Set Reference
// p. 3-329 (PDF p. 369) for further information:
// http://www.intel.com/design/intarch/manuals/243191.htm
// Default conditional-jump instructions: they are evaluating the FLAGS,
// defined in ctrl_xfer[16 | 32 | 64].cc, Postfix: 16-Bit: w, 32-Bit: d, 64-Bit: q
pointcut defJumpInstructions() =
"% ...::bx_cpu_c::JO_J%(...)" ||
"% ...::bx_cpu_c::JNO_J%(...)" ||
"% ...::bx_cpu_c::JB_J%(...)" ||
"% ...::bx_cpu_c::JNB_J%(...)" ||
"% ...::bx_cpu_c::JZ_J%(...)" ||
"% ...::bx_cpu_c::JNZ_J%(...)" ||
"% ...::bx_cpu_c::JBE_J%(...)" ||
"% ...::bx_cpu_c::JNBE_J%(...)" ||
"% ...::bx_cpu_c::JS_J%(...)" ||
"% ...::bx_cpu_c::JNS_J%(...)" ||
"% ...::bx_cpu_c::JP_J%(...)" ||
"% ...::bx_cpu_c::JNP_J%(...)" ||
"% ...::bx_cpu_c::JL_J%(...)" ||
"% ...::bx_cpu_c::JNL_J%(...)" ||
"% ...::bx_cpu_c::JLE_J%(...)" ||
"% ...::bx_cpu_c::JNLE_J%(...)";
// Special cases: they are evaluating the content of the CX-/ECX-/RCX-registers
// (NOT the FLAGS):
pointcut regJumpInstructions() =
"% ...::bx_cpu_c::JCXZ_Jb(...)" || // ctrl_xfer16.cc
"% ...::bx_cpu_c::JECXZ_Jb(...)" || // ctrl_xfer32.cc
"% ...::bx_cpu_c::JRCXZ_Jb(...)"; // ctrl_xfer64.cc
/* TODO: Loop-Instructions needed? Example: "LOOPNE16_Jb"
pointcut loopInstructions() = ...;
*/
/* TODO: Conditional-Data-Moves needed? Example: "CMOVZ_GwEwR"
pointcut dataMoveInstructions() = ...;
*/
advice execution (defJumpInstructions()) : around()
{
bxInstruction_c* pInstr = *(tjp->arg<0>()); // bxInstruction_c-object
sal::simulator.onJumpEvent(true, pInstr->getIaOpcode());
/*
JoinPoint::That* pThis = tjp->that();
if(pThis == NULL)
pThis = BX_CPU(0);
assert(pThis != NULL && "FATAL ERROR: tjp->that() returned null ptr! (Maybe called on a static instance?)");
// According to the Intel-Spec (p. 3-329f), the following flags are relevant:
bool fZeroFlag = pThis->get_ZF();
bool fCarryFlag = pThis->get_CF();
bool fSignFlag = pThis->get_SF();
bool fOverflowFlag = pThis->get_OF();
bool fParityFlag = pThis->get_PF();
//
// Step-1: Modify one or more of the fxxxFlag according to the error you want to inject
// (using pThis->set_XX(new_val))
// Step-2: Call tjp->proceed();
// Step-3: Eventually, unwind the changes of Step-1
//
// Example:
if(g_fEnableInjection) // event fired?
{
g_fEnableInjection = false;
// Obviously, this advice matches *all* jump-instructions so that it is not clear
// which flag have to be modified in order to invert the jump. For simplification,
// we will invert *all* flags. This avoids a few case differentiations.
cout << ">>> Manipulating jump-destination (inverted)... \"" << tjp->signature() << "\" ";
pThis->set_ZF(!fZeroFlag);
pThis->set_SF(!fSignFlag);
pThis->set_CF(!fCarryFlag);
pThis->set_OF(!fOverflowFlag);
pThis->set_PF(!fParityFlag);
tjp->proceed();
pThis->set_ZF(fZeroFlag);
pThis->set_SF(fSignFlag);
pThis->set_CF(fCarryFlag);
pThis->set_OF(fOverflowFlag);
pThis->set_PF(fParityFlag);
cout << "finished (jump taken)!" << endl;
}
else
*/
tjp->proceed();
}
advice execution (regJumpInstructions()) : around ()
{
bxInstruction_c* pInstr = *(tjp->arg<0>()); // bxInstruction_c-object
sal::simulator.onJumpEvent(false, pInstr->getIaOpcode());
/*
JoinPoint::That* pThis = tjp->that();
assert(pThis != NULL && "Unexpected: tjp->that() returned null ptr! (Maybe called on a static instance?)");
// Note: Direct access to the registers using the bochs-macros (defined in
// bochs.h) is not possibly due to the fact that they are using the this-ptr.
Bit16u CX = (Bit16u)(pThis->gen_reg[1].word.rx);
Bit32u ECX = (Bit32u)(pThis->gen_reg[1].dword.erx);
#if BX_SUPPORT_X86_64
Bit64u RCX = (Bit64u)(pThis->gen_reg[1].rrx);
#endif
//
// Step-1: Modify CX, ECX or RCX according to the error you want to inject
// Step-2: Call tjp->proceed();
// Step-3: Eventually, unwind the changes of Step-1
//
*/
tjp->proceed();
}
};
#endif // CONFIG_EVENT_JUMP
#endif /* __JUMP_AH__ */

View File

@ -0,0 +1,33 @@
#ifndef __JUMP_TO_PREVIOUS_CTX_AH__
#define __JUMP_TO_PREVIOUS_CTX_AH__
#include "../../AspectConfig.hpp"
#if 0
// #if CONFIG_SR_RESTORE == 1 || CONFIG_SR_REBOOT == 1
#include "bochs.h"
#include "../SALInst.hpp"
aspect jumpToPreviousCtx
{
pointcut end_reset_handler() = "void bx_gui_c::reset_handler(...)";
//|| "int bxmain()";
advice execution (end_reset_handler()) : after ()
{
if (sal::restore_bochs_request || sal::reboot_bochs_request )
{
sal::restore_bochs_request = false;
sal::reboot_bochs_request = false;
sal::simulator.toPreviousCtx();
}
}
};
#endif // CONFIG_SR_RESTORE == 1 || CONFIG_SR_REBOOT
#endif // __JUMP_TO_PREVIOUS_CTX_AH__

View File

@ -0,0 +1,100 @@
#ifndef __MEM_ACCESS_BIT_FLIP_AH__
#define __MEM_ACCESS_BIT_FLIP_AH__
#include "../../AspectConfig.hpp"
#if CONFIG_FI_MEM_ACCESS_BITFLIP == 1
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "bochs.h"
#include "../../controller/EventList.hpp"
#include "../../controller/Event.hpp"
using namespace std;
// FIXME this code doesn't make any sense for the read_virtual_% functions
// (the fault would need to be injected into their *return* value)
aspect MemAccessBitFlip
{
pointcut injection_methods()
= "% ...::bx_cpu_c::read_virtual_%(...)" || // -> access32/64.cc
/*
"% ...::bx_cpu_c::read_RMW_virtual_%(...)" || // -> access32.cc
"% ...::bx_cpu_c::system_read_%(...)" || // -> access.cc
"% ...::bx_cpu_c::v2h_read_byte(...)" || // -> access.cc
*/
"% ...::bx_cpu_c::write_virtual_%(...)"; // -> access32/64.cc
/*
"% ...::bx_cpu_c::write_RMW_virtual_%(...)" || // -> access32.cc
"% ...::bx_cpu_c::write_new_stack_%(...)" || // -> access32/64.cc
"% ...::bx_cpu_c::system_write_%(...)" || // -> access.cc
"% ...::bx_cpu_c::v2h_write_byte(...)"; // -> access.cc
*/
//
// Injects a bitflip each time the guest system requests to write/read
// data to/from RAM at the (hardcoded) addresses defined above:
//
// Event source: "memory write/read access"
//
advice execution (injection_methods()) : before ()
{
for(size_t i = 0; i < fi::evbuf.getEventCount(); i++) // check for active events
{
fi::SimpleBitFlip* pEv = dynamic_cast<fi::SimpleBitFlip*>(fi::evbuf.getEvent(i)); // FIXME: Performance verbessern
if(pEv && *(tjp->arg<1>())/*typed!*/ == pEv->getAddress())
{
cout << " " << tjp->signature() << endl;
// Get a pointer to the data that should be written to RAM
// *before* it is actually written:
Bit32u* pData = (Bit32u*)(tjp->arg(JoinPoint::ARGS-1));
// Flip bit at position pEv->getBitPos():
char* ptr = (char*)pData; // For simplification we're just looking at the
// first byte of the data
ptr[0] = (ptr[0]) ^ (pEv->getMask() << pEv->getBitPos());
cout << " >>> Bit flipped at index " << pEv->getBitPos()
<< " at address 0x" << hex << (*(tjp->arg<1>())) << "!" << endl;
fi::evbuf.fireEvent(pEv);
// Continue... (maybe more events to process)
}
}
}
/*
//
// Shows the mapping of a virtual address (within eCos) to a *host* address:
//
if(g_fEnableInjection) // event fired?
{
g_fEnableInjection = false;
const unsigned SEGMENT_SELECTOR_IDX = 2; // always the code segment (seg-base-addr should be zero)
const bx_address logicalAddr = MEM_ADDR_TO_INJECT; // offset within the segment ("local eCos address")
// Get the linear address:
Bit32u linearAddr = pThis->get_laddr32(SEGMENT_SELECTOR_IDX/ *seg* /, logicalAddr/ *offset* /);
// Map the linear address to the physical address:
bx_phy_address physicalAddr;
bx_bool fValid = pThis->dbg_xlate_linear2phy(linearAddr, (bx_phy_address*)&physicalAddr);
// Determine the *host* address of the physical address:
Bit8u* hostAddr = BX_MEM(0)->getHostMemAddr(pThis, physicalAddr, BX_READ);
// Now, hostAddr contains the "final" address where we are allowed to inject errors:
*(unsigned*)hostAddr = BAD_VALUE; // inject error
if(!fValid)
printf("[Error]: Could not map logical address to host address.\n");
else
printf("[Info]: Error injected at logical addr %p (host addr %p).\n", logicalAddr, hostAddr);
}
*/
};
#endif // CONFIG_FI_MEM_ACCESS_BITFLIP
#endif // __MEM_ACCESS_BIT_FLIP_AH__

146
core/SAL/bochs/MemEvents.ah Normal file
View File

@ -0,0 +1,146 @@
#ifndef __MEM_EVENTS_AH__
#define __MEM_EVENTS_AH__
#include <iostream>
#include "../../AspectConfig.hpp"
#if CONFIG_EVENT_MEMREAD == 1 || CONFIG_EVENT_MEMWRITE == 1
#include "../../../bochs/bochs.h"
#include "../../../bochs/cpu/cpu.h"
#include "../SALInst.hpp"
#include "bochs_helpers.hpp"
// FIXME we currently assume a "flat" memory model and ignore the segment
// parameter of all memory accesses
// TODO instruction fetch?
// TODO warn on uncovered memory accesses
aspect MemEvents
{
sal::address_t rmw_address;
pointcut write_methods() =
"% ...::bx_cpu_c::write_virtual_%(...)" && // -> access32/64.cc
// not an actual memory access:
!"% ...::bx_cpu_c::write_virtual_checks(...)";
pointcut write_methods_RMW() =
"% ...::bx_cpu_c::write_RMW_virtual_%(...)";
pointcut write_methods_new_stack() =
"% ...::bx_cpu_c::write_new_stack_%(...)" && // -> access32.cc
!"% ...::bx_cpu_c::write_new_stack_%_64(...)";
pointcut write_methods_new_stack_64() =
"% ...::bx_cpu_c::write_new_stack_%_64(...)"; // -> access64.cc
pointcut write_methods_system() =
"% ...::bx_cpu_c::system_write_%(...)"; // -> access.cc
// FIXME not covered:
/* "% ...::bx_cpu_c::v2h_write_byte(...)"; // -> access.cc */
pointcut read_methods() =
"% ...::bx_cpu_c::read_virtual_%(...)" &&
// sizeof() doesn't work here (see next pointcut)
!"% ...::bx_cpu_c::read_virtual_dqword_%(...)" && // -> access32/64.cc
// not an actual memory access:
!"% ...::bx_cpu_c::read_virtual_checks(...)";
pointcut read_methods_dqword() =
"% ...::bx_cpu_c::read_virtual_dqword_%(...)"; // -> access32/64.cc
pointcut read_methods_RMW() =
"% ...::bx_cpu_c::read_RMW_virtual_%(...)";
pointcut read_methods_system() =
"% ...::bx_cpu_c::system_read_%(...)"; // -> access.cc
// FIXME not covered:
/* "% ...::bx_cpu_c::v2h_read_byte(...)"; // -> access.cc */
//
// Fire a memory-write-event each time the guest system requests
// to write data to RAM:
//
// Event source: "memory write access"
//
#if CONFIG_EVENT_MEMWRITE == 1
advice execution (write_methods()) : after () {
sal::simulator.onMemoryAccessEvent(
*(tjp->arg<1>()), sizeof(*(tjp->arg<2>())), true,
getCPU(tjp->that())->prev_rip);
}
advice execution (write_methods_RMW()) : after () {
sal::simulator.onMemoryAccessEvent(
rmw_address, sizeof(*(tjp->arg<0>())), true,
getCPU(tjp->that())->prev_rip);
}
advice execution (write_methods_new_stack()) : after () {
std::cerr << "WOOOOOT write_methods_new_stack" << std::endl;
sal::simulator.onMemoryAccessEvent(
*(tjp->arg<1>()), sizeof(*(tjp->arg<3>())), true,
getCPU(tjp->that())->prev_rip);
}
advice execution (write_methods_new_stack_64()) : after () {
std::cerr << "WOOOOOT write_methods_new_stack_64" << std::endl;
sal::simulator.onMemoryAccessEvent(
*(tjp->arg<0>()), sizeof(*(tjp->arg<2>())), true,
getCPU(tjp->that())->prev_rip);
}
advice execution (write_methods_system()) : after () {
// We don't do anything here for now: This type of memory
// access is used when the hardware itself needs to access
// memory (e.g., to read vectors from the interrupt vector
// table).
/*
sal::simulator.onMemoryAccessEvent(
*(tjp->arg<0>()), sizeof(*(tjp->arg<1>())), true,
getCPU(tjp->that())->prev_rip);
*/
}
#endif
//
// Fire a memory-read-event each time the guest system requests
// to read data in RAM:
//
// Event source: "memory read access"
//
#if CONFIG_EVENT_MEMREAD == 1
advice execution (read_methods()) : before () {
sal::simulator.onMemoryAccessEvent(
*(tjp->arg<1>()), sizeof(*(tjp->result())), false,
getCPU(tjp->that())->prev_rip);
}
advice execution (read_methods_dqword()) : before () {
sal::simulator.onMemoryAccessEvent(
*(tjp->arg<1>()), 16, false,
getCPU(tjp->that())->prev_rip);
}
#endif
advice execution (read_methods_RMW()) : before () {
rmw_address = *(tjp->arg<1>());
#if CONFIG_EVENT_MEMREAD == 1
sal::simulator.onMemoryAccessEvent(
*(tjp->arg<1>()), sizeof(*(tjp->result())), false,
getCPU(tjp->that())->prev_rip);
#endif
}
#if CONFIG_EVENT_MEMREAD == 1
advice execution (read_methods_system()) : before () {
// We don't do anything here for now: This type of memory
// access is used when the hardware itself needs to access
// memory (e.g., to read vectors from the interrupt vector
// table).
/*
sal::simulator.onMemoryAccessEvent(
*(tjp->arg<0>()), sizeof(*(tjp->result())), false,
getCPU(tjp->that())->prev_rip);
*/
}
#endif
};
#endif // CONFIG_EVENT_MEMACCESS
#endif /* __MEM_EVENTS_AH__ */

27
core/SAL/bochs/Trap.ah Normal file
View File

@ -0,0 +1,27 @@
#ifndef __TRAP_AH__
#define __TRAP_AH__
#include "../../AspectConfig.hpp"
#if CONFIG_EVENT_TRAP == 1
#include "../../../bochs/bochs.h"
#include "../../../bochs/cpu/cpu.h"
#include "../SALInst.hpp"
aspect Trap
{
pointcut exception_method() = "void bx_cpu_c::exception(...)";
advice execution (exception_method()) : before ()
{
sal::simulator.onTrapEvent(*(tjp->arg<0>()));
// TODO: There are some different types of exceptions at cpu.h (line 265-281)
// Which kind of a trap are these types?
}
};
#endif // CONFIG_EVENT_TRAP
#endif /* __TRAP_AH__ */

View File

@ -0,0 +1,15 @@
#ifndef __BOCHS_HELPERS_HPP__
#define __BOCHS_HELPERS_HPP__
#include "../../../bochs/cpu/cpu.h"
static inline BX_CPU_C *getCPU(BX_CPU_C *that)
{
#if BX_USE_CPU_SMF == 0
return that;
#else
return BX_CPU_THIS;
#endif
}
#endif

27
core/SAL/bochs/credits.ah Normal file
View File

@ -0,0 +1,27 @@
#ifndef __CREDITS_AH__
#define __CREDITS_AH__
#include <string.h>
aspect credits {
bool first;
credits() : first(true) {}
advice call ("% bx_center_print(...)")
&& within ("void bx_print_header()")
&& args(file, line, maxwidth)
: around (FILE *file, const char *line, unsigned maxwidth) {
if (!first) {
tjp->proceed();
return;
}
// FIXME take version from global configuration
char buf[256] = "FailBochs 0.0.1, based on the ";
strncat(buf, line, 128);
first = false;
*(tjp->arg<1>()) = buf;
tjp->proceed();
}
};
#endif // __CREDITS_AH__

View File

@ -0,0 +1,19 @@
#ifndef __DISABLE_ADD_REMOVE_LOGFN_AH__
#define __DISABLE_ADD_REMOVE_LOGFN_AH__
/* Hack to prevent Bochs' logfunctions list (bochs.h) to overflow if the
* experiment restores simulator state more than ~1000 times.
*
* The "proper" fix would be to completely unregister all log functions before
* restore, i.e. to destroy all objects deriving from class logfunctions. We
* decided to simply ignore this tiny memory leak and to hack around the
* problem by disabling iofunctions::add/remove_logfn().
*/
aspect DisableLogfn {
pointcut add_remove_logfn() =
"void iofunctions::add_logfn(...)" ||
"void iofunctions::remove_logfn(...)";
advice execution (add_remove_logfn()) : around () {}
};
#endif /* __DISABLE_ADD_REMOVE_LOGFN_AH__ */

View File

@ -0,0 +1,25 @@
#ifndef __DISABLE_KEYBOARD_INTERRUPT_AH__
#define __DISABLE_KEYBOARD_INTERRUPT_AH__
#include "../../AspectConfig.hpp"
#if CONFIG_DISABLE_KEYB_INTERRUPTS
#include "../../../bochs/iodev/keyboard.h"
aspect DisableKeybInt {
pointcut heyboard_interrupt() =
"void bx_keyb_c::timer_handler(...)";
advice execution (heyboard_interrupt()) : around () {
bx_keyb_c *class_ptr = (bx_keyb_c *) tjp->arg<0>();
unsigned retval;
retval=class_ptr->periodic(1);
}
};
#endif /* CONFIG_DISABLE_KEYB_INTERRUPTS */
#endif /* __DISABLE_KEYBOARD_INTERRUPT_AH__ */

View File

@ -0,0 +1,21 @@
#ifndef FAILBOCHS_H
#define FAILBOCHS_H
#include <string>
#include <string.h>
#include "config.h"
namespace sal{
//DanceOS Richard Hellwig
#ifdef DANCEOS_RESTORE
extern bx_bool restore_bochs_request;
extern bx_bool save_bochs_request;
extern bx_bool reboot_bochs_request;
extern std::string sr_path;
#endif
}
#endif //FAILBOCHS_H

View File

@ -0,0 +1,27 @@
#ifndef __FIRETIMER_AH__
#define __FIRETIMER_AH__
#include <iostream>
aspect fireTimer {
advice "bx_pc_system_c" : slice class {
public:
void fireTimer(Bit32u timerNum){
if(timerNum <= numTimers){
if(!timer[timerNum].active){
std::cout << "[FAIL] WARNING: The selected timer is actually NOT active!" << std::endl;
}
currCountdownPeriod = Bit64u(1);
timer[timerNum].timeToFire = Bit64u(currCountdownPeriod) + ticksTotal;
std::cout << "[FAIL] Timer " << timerNum <<" will fire now!" << std::endl;
}else{
std::cout << "[FAIL] There are actually only " << numTimers <<" allocated!" << std::endl;
}
}
};
};
#endif // __FIRETIMER_AH__

12
core/SAL/bochs/init.ah Normal file
View File

@ -0,0 +1,12 @@
#ifndef __BXINIT_AH__
#define __BXINIT_AH__
#include "../SALInst.hpp"
aspect BochsInit {
advice call("int bxmain()") : before () {
sal::simulator.startup();
}
};
#endif // __BXINIT_AH__

27
core/SAL/bochs/reboot.ah Normal file
View File

@ -0,0 +1,27 @@
#ifndef __REBOOT_AH__
#define __REBOOT_AH__
#include "../../AspectConfig.hpp"
#include "../SALInst.hpp"
#if CONFIG_SR_REBOOT == 1
#include "bochs.h"
aspect reboot {
pointcut cpuLoop() = "void defineCPULoopJoinPoint(...)";
advice execution (cpuLoop()) : after () {
if (!sal::reboot_bochs_request) {
return;
}
bx_gui_c::reset_handler();
std::cout << "[FAIL] Reboot finished" << std::endl;
sal::simulator.rebootDone();
}
};
#endif // CONFIG_SR_REBOOT
#endif // __REBOOT_AH__

23
core/SAL/bochs/restore.ah Normal file
View File

@ -0,0 +1,23 @@
#ifndef __RESTORE_AH__
#define __RESTORE_AH__
#include <iostream>
#include "../../AspectConfig.hpp"
#include "../SALInst.hpp"
#if CONFIG_SR_RESTORE == 1
#include "bochs.h"
aspect restore {
pointcut restoreState() = "void bx_sr_after_restore_state()";
advice execution (restoreState()) : after () {
std::cout << "[FAIL] Restore finished" << std::endl;
sal::simulator.restoreDone();
}
};
#endif // CONFIG_SR_RESTORE
#endif // __RESTORE_AH__

32
core/SAL/bochs/save.ah Normal file
View File

@ -0,0 +1,32 @@
#ifndef __SAVE_AH__
#define __SAVE_AH__
#include "../../AspectConfig.hpp"
#if CONFIG_SR_SAVE == 1
#include "bochs.h"
#include "../SALInst.hpp"
aspect save {
pointcut cpuLoop() = "void defineCPULoopJoinPoint(...)";
// make sure the "save" aspect comes *after* the breakpoint stuff: In
// an "after" advice this means it must get a *higher* precedence,
// therefore it's first in the order list.
advice execution (cpuLoop()) : order ("save", "CPULoop");
advice execution (cpuLoop()) : after () {
if (!sal::save_bochs_request) {
return;
}
assert(sal::sr_path.size() > 0 && "[FAIL] tried to save state without valid path");
SIM->save_state(sal::sr_path.c_str());
std::cout << "[FAIL] Save finished" << std::endl;
sal::simulator.saveDone();
}
};
#endif // CONFIG_SR_SAVE
#endif // _SAVE_AH__

54
core/SAL/bochs/stfu.ah Normal file
View File

@ -0,0 +1,54 @@
#ifndef __NONVERBOSE_AH__
#define __NONVERBOSE_AH__
#include "../../AspectConfig.hpp"
#if CONFIG_STFU == 1
#include "bochs.h"
// Doesn't work because AspectC++ doesn't deal properly with variadic parameter
// lists:
/*
aspect nonverbose {
// needed to suppress Bochs output *before* a state restore finished
// FIXME ac++ segfaults if we use call() instead of execution()
advice execution("% logfunctions::debug(...)")
|| execution("% logfunctions::info(...)")
|| execution("% logfunctions::pass(...)")
|| execution("% logfunctions::error(...)")
: around () {
}
};
*/
aspect nonverbose {
// needed to suppress Bochs output *before* a state restore finished
advice call("int logfunctions::get_default_action(int)")
: around () {
int action;
switch (*(tjp->arg<0>())) {
case LOGLEV_DEBUG:
case LOGLEV_PASS:
case LOGLEV_INFO:
action = ACT_IGNORE;
break;
case LOGLEV_ERROR:
action = ACT_REPORT;
break;
case LOGLEV_PANIC:
default:
action = ACT_FATAL;
}
*(tjp->result()) = action;
}
// no credits header
advice call("void bx_print_header()")
: around () {
}
};
#endif
#endif