Important bugfix: passing the instruction cache entry pointer
does not account for arrays of instructions provided by one virtual instruction trace cache entry -> passing the current instruction directly. ALUInstr not yet completely tested. git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1704 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
@ -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, bxICacheEntry_c *pEntry)
|
||||
static inline void defineCPULoopJoinPoint(BX_CPU_C* pThis, bxInstruction_c *pInstr)
|
||||
{
|
||||
/* nothing to do here */
|
||||
}
|
||||
@ -166,7 +166,7 @@ void BX_CPU_C::cpu_loop(Bit32u max_instr_count)
|
||||
*
|
||||
*/
|
||||
|
||||
defineCPULoopJoinPoint(BX_CPU_THIS, entry);
|
||||
defineCPULoopJoinPoint(BX_CPU_THIS, i);
|
||||
|
||||
/****************************************************************/
|
||||
// instruction decoding completed -> continue with execution
|
||||
|
||||
@ -19,7 +19,7 @@ bx_bool interrupt_injection_request = false;
|
||||
|
||||
BochsController::BochsController()
|
||||
: SimulatorController(new BochsRegisterManager(), new BochsMemoryManager()),
|
||||
m_CPUContext(NULL), m_CacheEntry(NULL)
|
||||
m_CPUContext(NULL), m_CurrentInstruction(NULL)
|
||||
{
|
||||
// -------------------------------------
|
||||
// Add the general purpose register:
|
||||
@ -116,12 +116,12 @@ void BochsController::onBreakpoint(address_t instrPtr, address_t address_space)
|
||||
// implementation.
|
||||
}
|
||||
|
||||
void BochsController::updateBPEventInfo(BX_CPU_C *context, bxICacheEntry_c *cacheEntry)
|
||||
void BochsController::updateBPEventInfo(BX_CPU_C *context, bxInstruction_c *instr)
|
||||
{
|
||||
assert(context != NULL && "FATAL ERROR: Bochs internal member was NULL (not expected)!");
|
||||
assert(cacheEntry != NULL && "FATAL ERROR: Bochs internal member was NULL (not expected)!");
|
||||
assert(instr != NULL && "FATAL ERROR: Bochs internal member was NULL (not expected)!");
|
||||
m_CPUContext = context;
|
||||
m_CacheEntry = cacheEntry;
|
||||
m_CurrentInstruction = instr;
|
||||
}
|
||||
|
||||
void BochsController::onIOPort(unsigned char data, unsigned port, bool out) {
|
||||
@ -229,7 +229,7 @@ void BochsController::onTimerTrigger(void* thisPtr)
|
||||
const std::string& BochsController::getMnemonic() const
|
||||
{
|
||||
static std::string str;
|
||||
bxInstruction_c* pInstr = getICacheEntry()->i;
|
||||
bxInstruction_c* pInstr = getCurrentInstruction();
|
||||
assert(pInstr != NULL && "FATAL ERROR: Bochs internal member was NULL (not expected)!");
|
||||
const char* pszName = get_bx_opcode_name(pInstr->getIaOpcode());
|
||||
if (pszName != NULL)
|
||||
|
||||
@ -31,7 +31,7 @@ class BochsController : public SimulatorController {
|
||||
private:
|
||||
ExperimentFlow* m_CurrFlow; //!< Stores the current flow for save/restore-operations
|
||||
BX_CPU_C *m_CPUContext; //!< Additional information that is passed on occurence of a BPEvent
|
||||
bxICacheEntry_c *m_CacheEntry; //!< dito.
|
||||
bxInstruction_c *m_CurrentInstruction; //!< dito.
|
||||
#ifdef DEBUG
|
||||
unsigned m_Regularity; //! regularity of instruction ptr output
|
||||
unsigned m_Counter; //! current instr-ptr counter
|
||||
@ -145,7 +145,7 @@ public:
|
||||
* Retrieves the current Bochs instruction cache entry
|
||||
* @returns a pointer to a bxICacheEntry_c object
|
||||
*/
|
||||
inline bxICacheEntry_c *getICacheEntry() const { return m_CacheEntry; }
|
||||
inline bxInstruction_c *getCurrentInstruction() const { return m_CurrentInstruction; }
|
||||
/**
|
||||
* Retrieves the current CPU context
|
||||
* @return a pointer to a \c BX_CPU_C object
|
||||
@ -157,7 +157,7 @@ public:
|
||||
* @param context the CPU context object ptr (Bochs internal=
|
||||
* @param cacheEntry the Bochs internal CPU cache entry ptr
|
||||
*/
|
||||
void updateBPEventInfo(BX_CPU_C *context, bxICacheEntry_c *cacheEntry);
|
||||
void updateBPEventInfo(BX_CPU_C *context, bxInstruction_c *instr);
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
@ -20,10 +20,10 @@ aspect Breakpoints {
|
||||
// BX_CPU(0) otherwise
|
||||
BX_CPU_C* pThis = *(tjp->arg<0>());
|
||||
// Points to the *current* bxInstruction-object
|
||||
bxICacheEntry_c* pEntry = *(tjp->arg<1>());
|
||||
bxInstruction_c* pInstr = *(tjp->arg<1>());
|
||||
|
||||
// Report this event to the Bochs controller:
|
||||
fail::simulator.updateBPEventInfo(pThis, pEntry);
|
||||
fail::simulator.updateBPEventInfo(pThis, pInstr);
|
||||
fail::simulator.onBreakpoint(pThis->get_instruction_pointer(), pThis->cr3);
|
||||
// Note: get_bx_opcode_name(pInstr->getIaOpcode()) retrieves the mnemonics.
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ set(MY_PROTOS
|
||||
|
||||
set(MY_CAMPAIGN_SRCS
|
||||
aluinstr.hpp
|
||||
aluinstr.cc
|
||||
experiment.hpp
|
||||
experiment.cc
|
||||
campaign.hpp
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
using namespace fail;
|
||||
|
||||
Udis86::Udis86(const unsigned char *instr, size_t size, address_t ip) {
|
||||
Udis86::Udis86(unsigned char const *instr, size_t size, address_t ip) {
|
||||
// initialise the buffer
|
||||
udis_instr_size = size;
|
||||
udis_instr = static_cast<unsigned char*>(malloc(udis_instr_size));
|
||||
|
||||
@ -20,13 +20,13 @@ private:
|
||||
unsigned char *udis_instr; //<! the instruction buffer for UDIs86
|
||||
size_t udis_instr_size; //<! the size of the instruction buffer
|
||||
public:
|
||||
Udis86(const unsigned char *instr, size_t size, fail::address_t ip);
|
||||
Udis86(unsigned char const *instr, size_t size, fail::address_t ip);
|
||||
~Udis86();
|
||||
/**
|
||||
* retrieves the private ud structure of udis86
|
||||
* @returns a reference pointer to a ud_t variable
|
||||
*/
|
||||
inline const ud_t &getCurrentState() const { return ud_obj; }
|
||||
inline ud_t const &getCurrentState() const { return ud_obj; }
|
||||
/**
|
||||
* Tries to decode the next instruction from the given buffer.
|
||||
* @returns \c true if a new instruction could be retrieved, \c false if the object has expired
|
||||
|
||||
@ -1,39 +1,34 @@
|
||||
#ifndef __L4SYS_ALUINSTR_HPP__
|
||||
#define __L4SYS_ALUINSTR_HPP__
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Forward declaration of the Bochs instruction decode table.
|
||||
* This is necessary because, inconveniently, it is not declared in a header file.
|
||||
*/
|
||||
#include "cpu/fetchdecode.h"
|
||||
static const BxOpcodeInfo_t *BxOpcodeInfo32;
|
||||
#endif
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
#include "cpu/instr.h"
|
||||
|
||||
/**
|
||||
* Trying to order X86 ALU instructions.
|
||||
* Each instruction class contains instructions
|
||||
* of roughly equal length and operands, so that
|
||||
* all the bxInstruction_c structures residing within
|
||||
* one class contain the same member fields.
|
||||
* one class contain the same member fields (except for
|
||||
* b1, rm and the execute pointers).
|
||||
*/
|
||||
enum X86AluClass {
|
||||
ALU_UNDEF = 0,
|
||||
ALU_GENERIC,
|
||||
ALU_RM8,
|
||||
ALU_RM16,
|
||||
ALU_RM32,
|
||||
ALU_REG,
|
||||
ALU_IMM8_REG,
|
||||
ALU_IMM16_REG,
|
||||
ALU_IMM32_REG,
|
||||
ALU_IMM8,
|
||||
ALU_IMM16,
|
||||
ALU_IMM32,
|
||||
ALU_IMM8_RM8,
|
||||
ALU_IMM8_RM16,
|
||||
ALU_IMM8_RM32,
|
||||
ALU_IMM16_RM16,
|
||||
ALU_IMM32_RM32,
|
||||
ALU_REG_RM8,
|
||||
ALU_REG_RM16,
|
||||
ALU_REG_RM32
|
||||
ALU_IMM32_RM32
|
||||
};
|
||||
|
||||
/**
|
||||
@ -48,28 +43,32 @@ struct BochsALUInstr {
|
||||
*/
|
||||
Bit16u bochs_operation;
|
||||
/**
|
||||
* the x86 opcode (known as b1 in bxInstruction_c)
|
||||
* the x86 opcode, as stored by Bochs (known as b1 in bxInstruction_c)
|
||||
*/
|
||||
Bit8u opcode;
|
||||
/**
|
||||
* the reg part of the modr/m field (known as "nnn" in bxInstruction_c)
|
||||
* it is used to
|
||||
* a) further subdivide the functionality of a given opcode
|
||||
* b) specify a register the instruction is supposed to use
|
||||
* In this class, a value of 8 or higher marks this field unused.
|
||||
* a) further subdivide the functionality of a given opcode (reg < REG_COUNT)
|
||||
* b) specify a register the instruction is supposed to use (reg = REG_COUNT)
|
||||
* In this class, a value greater than REG_COUNT marks this field unused.
|
||||
*/
|
||||
Bit8u reg;
|
||||
/**
|
||||
* the register offset of the instruction byte of this instruction
|
||||
* Some x86 instructions, like INC register, add a register offset
|
||||
* to their opcode. This offset is stored as "rm" in bxInstruction_c.
|
||||
* In this class, a value of 8 or higher marks this field unused.
|
||||
* In this class, a value greater than REG_COUNT marks this field unused.
|
||||
*/
|
||||
Bit8u opcodeRegisterOffset;
|
||||
/**
|
||||
* the ALU class this instruction belongs to
|
||||
*/
|
||||
X86AluClass aluClass;
|
||||
/**
|
||||
* the count of registers
|
||||
*/
|
||||
static const unsigned REG_COUNT = 8;
|
||||
};
|
||||
|
||||
|
||||
@ -86,43 +85,54 @@ const BochsALUInstr aluInstructions [] = {
|
||||
/* --- /// UNARY OPERATIONS \\\ --- */
|
||||
|
||||
// 8-bit
|
||||
{ BX_IA_INC_Eb, 0xFE, 0, 8, ALU_RM8},
|
||||
{ BX_IA_DEC_Eb, 0xFE, 1, 8, ALU_RM8},
|
||||
{ BX_IA_NOT_Eb, 0xF6, 2, 8, ALU_RM8},
|
||||
{ BX_IA_NEG_Eb, 0xF6, 3, 8, ALU_RM8},
|
||||
{ BX_IA_INC_Eb, 0xFE, 0, BochsALUInstr::REG_COUNT + 1, ALU_RM8},
|
||||
{ BX_IA_DEC_Eb, 0xFE, 1, BochsALUInstr::REG_COUNT + 1, ALU_RM8},
|
||||
{ BX_IA_NOT_Eb, 0xF6, 2, BochsALUInstr::REG_COUNT + 1, ALU_RM8},
|
||||
{ BX_IA_NEG_Eb, 0xF6, 3, BochsALUInstr::REG_COUNT + 1, ALU_RM8},
|
||||
|
||||
// 16-bit
|
||||
{ BX_IA_INC_Ew, 0xFF, 0, 8, ALU_RM16},
|
||||
{ BX_IA_DEC_Ew, 0xFF, 1, 8, ALU_RM16},
|
||||
{ BX_IA_NOT_Ew, 0xF7, 2, 8, ALU_RM16},
|
||||
{ BX_IA_NEG_Ew, 0xF7, 3, 8, ALU_RM16},
|
||||
{ BX_IA_INC_Ew, 0xFF, 0, BochsALUInstr::REG_COUNT + 1, ALU_RM16},
|
||||
{ BX_IA_DEC_Ew, 0xFF, 1, BochsALUInstr::REG_COUNT + 1, ALU_RM16},
|
||||
{ BX_IA_NOT_Ew, 0xF7, 2, BochsALUInstr::REG_COUNT + 1, ALU_RM16},
|
||||
{ BX_IA_NEG_Ew, 0xF7, 3, BochsALUInstr::REG_COUNT + 1, ALU_RM16},
|
||||
|
||||
// 32-bit
|
||||
{ BX_IA_INC_Ed, 0xFF, 0, 8, ALU_RM32},
|
||||
{ BX_IA_DEC_Ed, 0xFF, 1, 8, ALU_RM32},
|
||||
{ BX_IA_NOT_Ed, 0xF7, 2, 8, ALU_RM32},
|
||||
{ BX_IA_NEG_Ed, 0xF7, 3, 8, ALU_RM32},
|
||||
{ BX_IA_INC_Ed, 0xFF, 0, BochsALUInstr::REG_COUNT + 1, ALU_RM32},
|
||||
{ BX_IA_DEC_Ed, 0xFF, 1, BochsALUInstr::REG_COUNT + 1, ALU_RM32},
|
||||
{ BX_IA_NOT_Ed, 0xF7, 2, BochsALUInstr::REG_COUNT + 1, ALU_RM32},
|
||||
{ BX_IA_NEG_Ed, 0xF7, 3, BochsALUInstr::REG_COUNT + 1, ALU_RM32},
|
||||
|
||||
// register
|
||||
{ BX_IA_INC_RX, 0x40, 8, 7, ALU_REG},
|
||||
{ BX_IA_DEC_RX, 0x48, 8, 7, ALU_REG},
|
||||
{ BX_IA_INC_ERX, 0x40, 8, 7, ALU_REG},
|
||||
{ BX_IA_DEC_ERX, 0x48, 8, 7, ALU_REG},
|
||||
{ BX_IA_INC_RX, 0x40, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT, ALU_GENERIC},
|
||||
{ BX_IA_DEC_RX, 0x48, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT, ALU_GENERIC},
|
||||
{ BX_IA_INC_ERX, 0x40, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT, ALU_GENERIC},
|
||||
{ BX_IA_DEC_ERX, 0x48, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT, ALU_GENERIC},
|
||||
|
||||
/* --- \\\ UNARY OPERATIONS /// --- */
|
||||
|
||||
/* --- /// BCD ADJUSTMENT \\\ --- */
|
||||
|
||||
{ BX_IA_DAA, 0x27, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_GENERIC},
|
||||
{ BX_IA_DAS, 0x2F, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_GENERIC},
|
||||
{ BX_IA_AAA, 0x37, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_GENERIC},
|
||||
{ BX_IA_AAS, 0x3F, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_GENERIC},
|
||||
{ BX_IA_AAM, 0xD4, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM8 },
|
||||
{ BX_IA_AAD, 0xD5, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM8 },
|
||||
|
||||
/* --- \\\ BCD ADJUSTMENT /// --- */
|
||||
|
||||
/* --- /// SHIFT OPERATIONS \\\ --- */
|
||||
|
||||
// a macro to reduce copy-paste overhead
|
||||
#define SHIFTOPS(OPCODE, WD, CLASS) \
|
||||
{ BX_IA_RCL_E##WD, OPCODE, 2, 8, CLASS }, \
|
||||
{ BX_IA_RCR_E##WD, OPCODE, 3, 8, CLASS }, \
|
||||
{ BX_IA_ROL_E##WD, OPCODE, 0, 8, CLASS }, \
|
||||
{ BX_IA_ROR_E##WD, OPCODE, 1, 8, CLASS }, \
|
||||
{ BX_IA_SHL_E##WD, OPCODE, 4, 8, CLASS }, \
|
||||
{ BX_IA_SAR_E##WD, OPCODE, 7, 8, CLASS }, \
|
||||
{ BX_IA_SHL_E##WD, OPCODE, 6, 8, CLASS }, \
|
||||
{ BX_IA_SHR_E##WD, OPCODE, 5, 8, CLASS }
|
||||
{ BX_IA_RCL_E##WD, OPCODE, 2, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_RCR_E##WD, OPCODE, 3, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_ROL_E##WD, OPCODE, 0, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_ROR_E##WD, OPCODE, 1, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_SHL_E##WD, OPCODE, 4, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_SAR_E##WD, OPCODE, 7, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_SHL_E##WD, OPCODE, 6, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_SHR_E##WD, OPCODE, 5, BochsALUInstr::REG_COUNT + 1, CLASS }
|
||||
|
||||
// first shifting by one bit
|
||||
SHIFTOPS(0xD0, b, ALU_RM8),
|
||||
@ -130,24 +140,35 @@ const BochsALUInstr aluInstructions [] = {
|
||||
SHIFTOPS(0xD1, d, ALU_RM32),
|
||||
|
||||
// then shifting by CL bits
|
||||
SHIFTOPS(0xD2, b, ALU_REG_RM8),
|
||||
SHIFTOPS(0xD3, w, ALU_REG_RM16),
|
||||
SHIFTOPS(0xD3, d, ALU_REG_RM32),
|
||||
SHIFTOPS(0xD2, b, ALU_RM8),
|
||||
SHIFTOPS(0xD3, w, ALU_RM16),
|
||||
SHIFTOPS(0xD3, d, ALU_RM32),
|
||||
|
||||
// then shifting by a number of bits given via an immediate value
|
||||
SHIFTOPS(0xC0, b, ALU_IMM8_RM8),
|
||||
SHIFTOPS(0xC1, w, ALU_IMM8_RM16),
|
||||
SHIFTOPS(0xC1, d, ALU_IMM8_RM32),
|
||||
|
||||
#undef SHIFTOPS
|
||||
// SHLD / SHRD (Note: Bochs Opcode; normally 0x0F...)
|
||||
{ BX_IA_SHLD_EwGw, 0xA4, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_IMM8_RM16 },
|
||||
{ BX_IA_SHLD_EdGd, 0xA4, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_IMM8_RM32 },
|
||||
{ BX_IA_SHLD_EwGw, 0xA5, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM16 },
|
||||
{ BX_IA_SHLD_EdGd, 0xA5, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM32 },
|
||||
{ BX_IA_SHRD_EwGw, 0xAC, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_IMM8_RM16 },
|
||||
{ BX_IA_SHRD_EdGd, 0xAC, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_IMM8_RM32 },
|
||||
{ BX_IA_SHRD_EwGw, 0xAD, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM16 },
|
||||
{ BX_IA_SHRD_EdGd, 0xAD, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM32 },
|
||||
|
||||
/* --- \\\ SHIFT OPERATIONS /// --- */
|
||||
|
||||
/* --- /// BINARY OPERATIONS \\\ --- */
|
||||
|
||||
// register ax, immediate
|
||||
#define BINOPS(IACODE, OPCODE8, OPCODE16) \
|
||||
{ BX_IA_##IACODE##_ALIb, OPCODE8, 8, 8, ALU_IMM8_REG }, \
|
||||
{ BX_IA_##IACODE##_AXIw, OPCODE16, 8, 8, ALU_IMM16_REG }, \
|
||||
{ BX_IA_##IACODE##_EAXId, OPCODE16, 8, 8, ALU_IMM32_REG }
|
||||
{ BX_IA_##IACODE##_ALIb, OPCODE8, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM8 }, \
|
||||
{ BX_IA_##IACODE##_AXIw, OPCODE16, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM16 }, \
|
||||
{ BX_IA_##IACODE##_EAXId, OPCODE16, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM32 }
|
||||
|
||||
BINOPS(ADC, 0x14, 0x15),
|
||||
BINOPS(ADD, 0x04, 0x05),
|
||||
@ -161,27 +182,28 @@ const BochsALUInstr aluInstructions [] = {
|
||||
|
||||
// r/m, immediate
|
||||
#define BINOPS(OPCODE, WDE, WDI, CLASS) \
|
||||
{ BX_IA_ADC_E##WDE##I##WDI, OPCODE, 2, 8, CLASS }, \
|
||||
{ BX_IA_ADD_E##WDE##I##WDI, OPCODE, 0, 8, CLASS }, \
|
||||
{ BX_IA_AND_E##WDE##I##WDI, OPCODE, 4, 8, CLASS }, \
|
||||
{ BX_IA_CMP_E##WDE##I##WDI, OPCODE, 7, 8, CLASS }, \
|
||||
{ BX_IA_OR_E##WDE##I##WDI, OPCODE, 1, 8, CLASS }, \
|
||||
{ BX_IA_SBB_E##WDE##I##WDI, OPCODE, 3, 8, CLASS }, \
|
||||
{ BX_IA_SUB_E##WDE##I##WDI, OPCODE, 5, 8, CLASS }, \
|
||||
{ BX_IA_XOR_E##WDE##I##WDI, OPCODE, 6, 8, CLASS }
|
||||
{ BX_IA_ADC_E##WDE##I##WDI, OPCODE, 2, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_ADD_E##WDE##I##WDI, OPCODE, 0, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_AND_E##WDE##I##WDI, OPCODE, 4, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_CMP_E##WDE##I##WDI, OPCODE, 7, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_OR_E##WDE##I##WDI, OPCODE, 1, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_SBB_E##WDE##I##WDI, OPCODE, 3, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_SUB_E##WDE##I##WDI, OPCODE, 5, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||
{ BX_IA_XOR_E##WDE##I##WDI, OPCODE, 6, BochsALUInstr::REG_COUNT + 1, CLASS }
|
||||
|
||||
BINOPS(0x80, b, b, ALU_IMM8_RM8),
|
||||
BINOPS(0x81, w, w, ALU_IMM16_RM16),
|
||||
BINOPS(0x81, d, d, ALU_IMM32_RM32),
|
||||
BINOPS(0x82, b, b, ALU_IMM8_RM8),
|
||||
BINOPS(0x83, w, w, ALU_IMM8_RM16),
|
||||
BINOPS(0x83, d, d, ALU_IMM8_RM32),
|
||||
#undef BINOPS
|
||||
|
||||
// r/m, arbitrary register
|
||||
#define BINOPS(IACODE, OPCODE8, OPCODE16) \
|
||||
{ BX_IA_##IACODE##_EbGb, OPCODE8, 7, 8, ALU_REG_RM8 }, \
|
||||
{ BX_IA_##IACODE##_EwGw, OPCODE16, 7, 8, ALU_REG_RM16 }, \
|
||||
{ BX_IA_##IACODE##_EdGd, OPCODE16, 7, 8, ALU_REG_RM32 }
|
||||
{ BX_IA_##IACODE##_EbGb, OPCODE8, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM8 }, \
|
||||
{ BX_IA_##IACODE##_EwGw, OPCODE16, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM16 }, \
|
||||
{ BX_IA_##IACODE##_EdGd, OPCODE16, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM32 }
|
||||
|
||||
BINOPS(ADC, 0x10, 0x11),
|
||||
BINOPS(ADD, 0x00, 0x01),
|
||||
@ -195,21 +217,83 @@ const BochsALUInstr aluInstructions [] = {
|
||||
|
||||
// arbitrary register, r/m
|
||||
#define BINOPS(IACODE, OPCODE8, OPCODE16) \
|
||||
{ BX_IA_##IACODE##_GbEb, OPCODE8, 7, 8, ALU_REG_RM8 }, \
|
||||
{ BX_IA_##IACODE##_GwEw, OPCODE16, 7, 8, ALU_REG_RM16 }, \
|
||||
{ BX_IA_##IACODE##_GdEd, OPCODE16, 7, 8, ALU_REG_RM32 }
|
||||
{ BX_IA_##IACODE##_GbEb, OPCODE8, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM8 }, \
|
||||
{ BX_IA_##IACODE##_GwEw, OPCODE16, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM16 }, \
|
||||
{ BX_IA_##IACODE##_GdEd, OPCODE16, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM32 }
|
||||
|
||||
BINOPS(ADC, 0x12, 0x13),
|
||||
BINOPS(ADD, 0x02, 0x03),
|
||||
BINOPS(AND, 0x22, 0x23),
|
||||
BINOPS(CMP, 0x3a, 0x3b),
|
||||
BINOPS(OR, 0x0a, 0x0b),
|
||||
BINOPS(SBB, 0x1a, 0x1b),
|
||||
BINOPS(SUB, 0x2a, 0x2b),
|
||||
BINOPS(CMP, 0x3A, 0x3B),
|
||||
BINOPS(OR, 0x0A, 0x0B),
|
||||
BINOPS(SBB, 0x1A, 0x1B),
|
||||
BINOPS(SUB, 0x2A, 0x2B),
|
||||
BINOPS(XOR, 0x32, 0x33),
|
||||
#undef BINOPS
|
||||
|
||||
// TEST instruction
|
||||
{ BX_IA_TEST_ALIb, 0xA8, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM8},
|
||||
{ BX_IA_TEST_AXIw, 0xA9, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM16},
|
||||
{ BX_IA_TEST_EAXId, 0xA9, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM32},
|
||||
{ BX_IA_TEST_EbIb, 0xF6, 0, BochsALUInstr::REG_COUNT + 1, ALU_IMM8_RM8 },
|
||||
{ BX_IA_TEST_EbIb, 0xF6, 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM8_RM8 },
|
||||
{ BX_IA_TEST_EwIw, 0xF7, 0, BochsALUInstr::REG_COUNT + 1, ALU_IMM16_RM16 },
|
||||
{ BX_IA_TEST_EwIw, 0xF7, 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM16_RM16 },
|
||||
{ BX_IA_TEST_EdId, 0xF7, 0, BochsALUInstr::REG_COUNT + 1, ALU_IMM32_RM32 },
|
||||
{ BX_IA_TEST_EdId, 0xF7, 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM32_RM32 },
|
||||
{ BX_IA_TEST_EbGb, 0x84, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM8},
|
||||
{ BX_IA_TEST_EwGw, 0x85, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM16},
|
||||
{ BX_IA_TEST_EdGd, 0x85, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM32},
|
||||
|
||||
// MUL and DIV
|
||||
#define BINOPS(IACODE, OPCODE8, OPCODE16, REG) \
|
||||
{ BX_IA_##IACODE##_ALEb, OPCODE8, REG, BochsALUInstr::REG_COUNT + 1, ALU_IMM8 }, \
|
||||
{ BX_IA_##IACODE##_AXEw, OPCODE16, REG, BochsALUInstr::REG_COUNT + 1, ALU_IMM16 }, \
|
||||
{ BX_IA_##IACODE##_EAXEd, OPCODE16, REG, BochsALUInstr::REG_COUNT + 1, ALU_IMM32 }
|
||||
BINOPS(MUL, 0xF6, 0xF7, 4),
|
||||
BINOPS(IMUL, 0xF6, 0xF7, 5),
|
||||
BINOPS(DIV, 0xF6, 0xF7, 6),
|
||||
BINOPS(IDIV, 0xF6, 0xF7, 7),
|
||||
#undef BINOPS
|
||||
{ BX_IA_IMUL_GwEwIw, 0x69, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_IMM16_RM16 },
|
||||
{ BX_IA_IMUL_GwEwIw, 0x69, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_IMM32_RM32 },
|
||||
{ BX_IA_IMUL_GwEwIw, 0x6B, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_IMM8_RM16 },
|
||||
{ BX_IA_IMUL_GwEwIw, 0x6B, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_IMM8_RM32 },
|
||||
// two-byte opcode, see above
|
||||
{ BX_IA_IMUL_GwEw, 0xAF, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM16},
|
||||
{ BX_IA_IMUL_GdEd, 0xAF, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM32},
|
||||
|
||||
/* --- \\\ BINARY OPERATIONS /// --- */
|
||||
};
|
||||
|
||||
const size_t aluInstructionsSize = sizeof(aluInstructions);
|
||||
|
||||
class BochsALUInstructions {
|
||||
public:
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef std::vector<BochsALUInstr> InstrList;
|
||||
typedef std::map<X86AluClass, InstrList> EquivClassMap;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
BochsALUInstructions(const BochsALUInstr *initial_array, size_t array_size);
|
||||
~BochsALUInstructions() { free(allInstr); }
|
||||
bool isALUInstruction(const bxInstruction_c *src);
|
||||
bxInstruction_c randomEquivalent() const;
|
||||
protected:
|
||||
void bochsInstrToInstrStruct(const bxInstruction_c *src, BochsALUInstr *dest) const;
|
||||
private:
|
||||
BochsALUInstr *allInstr;
|
||||
BochsALUInstr lastInstr;
|
||||
const bxInstruction_c *lastOrigInstr;
|
||||
size_t allInstrSize;
|
||||
EquivClassMap equivalenceClasses;
|
||||
void buildEquivalenceClasses();
|
||||
#ifdef DEBUG
|
||||
void printNestedMap();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // __L4SYS_ALUINSTR_HPP__
|
||||
|
||||
@ -11,16 +11,16 @@ using namespace std;
|
||||
using namespace fail;
|
||||
|
||||
char const * const results_csv = "l4sys.csv";
|
||||
const char *l4sys_output_result_strings[] = { "Unknown", "Done", "Timeout", "Trap", "Interrupt", "Wrong output", "Error" };
|
||||
const char *l4sys_output_experiment_strings[] = { "Unknown", "GPR Flip", "RAT Flip", "Instr Flip", "ALU Instr Flip" };
|
||||
char const *l4sys_output_result_strings[] = { "Unknown", "Done", "Incomplete", "Timeout", "Wrong output", "Error" };
|
||||
char const *l4sys_output_experiment_strings[] = { "Unknown", "GPR Flip", "RAT Flip", "Instr Flip", "ALU Instr Flip" };
|
||||
char const *l4sys_output_register_strings[] = { "Unknown", "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI" };
|
||||
|
||||
#define OUTPUT_CASE(OUTPUT) case L4SysProtoMsg::OUTPUT: return l4sys_output_result_strings[L4SysProtoMsg::OUTPUT];
|
||||
std::string L4SysCampaign::output_result(L4SysProtoMsg_ResultType res) {
|
||||
switch (res) {
|
||||
OUTPUT_CASE(DONE);
|
||||
OUTPUT_CASE(INCOMPLETE);
|
||||
OUTPUT_CASE(TIMEOUT);
|
||||
OUTPUT_CASE(TRAP);
|
||||
OUTPUT_CASE(INTR);
|
||||
OUTPUT_CASE(WRONG);
|
||||
OUTPUT_CASE(UNKNOWN);
|
||||
default:
|
||||
@ -61,9 +61,23 @@ bool L4SysCampaign::run() {
|
||||
|
||||
int count = 0;
|
||||
srand(time(NULL));
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
L4SysExperimentData *d = new L4SysExperimentData;
|
||||
d->msg.set_exp_type(d->msg.ALUINSTR);
|
||||
// modify for a random instruction
|
||||
int instr_offset = rand() % L4SYS_NUMINSTR;
|
||||
d->msg.set_instr_offset(instr_offset);
|
||||
// this value is not required for this experiment, so set it to an arbitrary value
|
||||
d->msg.set_bit_offset(0);
|
||||
|
||||
campaignmanager.addParam(d);
|
||||
++count;
|
||||
}
|
||||
#if 0
|
||||
for (int i = 0; i < 25; ++i) {
|
||||
L4SysExperimentData *d = new L4SysExperimentData;
|
||||
d->msg.set_exp_type(d->msg.IDCFLIP);
|
||||
d->msg.set_exp_type(d->msg.GPRFLIP);
|
||||
d->msg.set_register_offset(d->msg.EBX);
|
||||
// modify for a random instruction
|
||||
int instr_offset = rand() % L4SYS_NUMINSTR;
|
||||
d->msg.set_instr_offset(instr_offset);
|
||||
@ -74,7 +88,6 @@ bool L4SysCampaign::run() {
|
||||
campaignmanager.addParam(d);
|
||||
++count;
|
||||
}
|
||||
#if 0
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
L4SysExperimentData *d = new L4SysExperimentData;
|
||||
d->msg.set_exp_type(d->msg.RATFLIP);
|
||||
@ -108,13 +121,17 @@ bool L4SysCampaign::run() {
|
||||
L4SysExperimentData *res;
|
||||
int rescount = 0;
|
||||
results
|
||||
<< "exp_type,injection_ip,instr_offset,injection_bit,resulttype,resultdata,output,details"
|
||||
<< "exp_type,injection_ip,register,instr_offset,injection_bit,resulttype,resultdata,output,details"
|
||||
<< endl;
|
||||
while ((res = static_cast<L4SysExperimentData *>(campaignmanager.getDone()))) {
|
||||
rescount++;
|
||||
|
||||
results << output_experiment(res->msg.exp_type()) << "," << hex << res->msg.injection_ip() << "," << dec
|
||||
<< res->msg.instr_offset() << "," << res->msg.bit_offset()
|
||||
results << output_experiment(res->msg.exp_type()) << "," << hex << res->msg.injection_ip() << dec << ",";
|
||||
if (res->msg.has_register_offset())
|
||||
results << res->msg.register_offset();
|
||||
else
|
||||
results << "None";
|
||||
results << "," << res->msg.instr_offset() << "," << res->msg.bit_offset()
|
||||
<< "," << output_result(res->msg.resulttype()) << ","
|
||||
<< res->msg.resultdata();
|
||||
if (res->msg.has_output())
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include "experiment.hpp"
|
||||
#include "experimentInfo.hpp"
|
||||
#include "UDIS86.hpp"
|
||||
#include "aluinstr.hpp"
|
||||
#include "campaign.hpp"
|
||||
|
||||
#include "sal/SALConfig.hpp"
|
||||
@ -26,9 +27,8 @@ using namespace fail;
|
||||
// Check if configuration dependencies are satisfied:
|
||||
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \
|
||||
!defined(CONFIG_SR_SAVE) || \
|
||||
!defined(CONFIG_EVENT_TRAP) || !defined(CONFIG_EVENT_IOPORT) || \
|
||||
!defined(CONFIG_EVENT_INTERRUPT)
|
||||
#error This experiment needs: breakpoints, suppressed-interrupts, traps, I/O port and interrupt events, \
|
||||
!defined(CONFIG_EVENT_IOPORT)
|
||||
#error This experiment needs: breakpoints and I/O port events, \
|
||||
save, and restore. Enable these in the configuration.
|
||||
#endif
|
||||
|
||||
@ -149,6 +149,26 @@ void L4SysExperiment::singleStep() {
|
||||
simulator.removeListener(&singlestepping_event);
|
||||
}
|
||||
|
||||
void L4SysExperiment::injectInstruction(bxInstruction_c *oldInstr, bxInstruction_c *newInstr) {
|
||||
// backup the current and insert the faulty instruction
|
||||
bxInstruction_c backupInstr;
|
||||
memcpy(&backupInstr, oldInstr, sizeof(bxInstruction_c));
|
||||
memcpy(oldInstr, newInstr, sizeof(bxInstruction_c));
|
||||
|
||||
// execute the faulty instruction, then return
|
||||
singleStep();
|
||||
|
||||
//restore the old instruction
|
||||
memcpy(oldInstr, &backupInstr, sizeof(bxInstruction_c));
|
||||
}
|
||||
|
||||
unsigned L4SysExperiment::calculateTimeout() {
|
||||
// [instr] / [instr / s] = [s]
|
||||
unsigned seconds = L4SYS_NUMINSTR / L4SYS_BOCHS_IPS;
|
||||
// 1.1 (+10 percent) * 1000 ms/s * [s]
|
||||
return 1100 * seconds;
|
||||
}
|
||||
|
||||
bool L4SysExperiment::run() {
|
||||
Logger log("L4Sys", false);
|
||||
BPSingleListener bp(0, L4SYS_ADDRESS_SPACE);
|
||||
@ -194,7 +214,6 @@ bool L4SysExperiment::run() {
|
||||
|
||||
ofstream golden_run_file(L4SYS_CORRECT_OUTPUT);
|
||||
bp.setWatchInstructionPointer(L4SYS_FUNC_EXIT);
|
||||
bp.setCounter(L4SYS_ITERATION_COUNT);
|
||||
simulator.addListener(&bp);
|
||||
BaseListener* ev = waitIOOrOther(true);
|
||||
if (ev == &bp) {
|
||||
@ -279,19 +298,23 @@ bool L4SysExperiment::run() {
|
||||
struct stat teststruct;
|
||||
if (stat(L4SYS_STATE_FOLDER, &teststruct) == -1 || stat(L4SYS_CORRECT_OUTPUT, &teststruct) == -1) {
|
||||
log << "Important data missing - call \"prepare\" first." << endl;
|
||||
simulator.terminate(1);
|
||||
simulator.terminate(10);
|
||||
}
|
||||
ifstream golden_run_file(L4SYS_CORRECT_OUTPUT);
|
||||
ifstream golden_run_file(L4SYS_CORRECT_OUTPUT);
|
||||
|
||||
golden_run.reserve(teststruct.st_size);
|
||||
if(!golden_run_file.good()) {
|
||||
log << "Could not open file " << L4SYS_CORRECT_OUTPUT << endl;
|
||||
simulator.terminate(20);
|
||||
}
|
||||
golden_run.reserve(teststruct.st_size);
|
||||
|
||||
golden_run.assign((istreambuf_iterator<char>(golden_run_file)),
|
||||
istreambuf_iterator<char>());
|
||||
golden_run.assign((istreambuf_iterator<char>(golden_run_file)),
|
||||
istreambuf_iterator<char>());
|
||||
|
||||
golden_run_file.close();
|
||||
golden_run_file.close();
|
||||
|
||||
//the generated output probably has a similar length
|
||||
output.reserve(teststruct.st_size);
|
||||
//the generated output probably has a similar length
|
||||
output.reserve(teststruct.st_size);
|
||||
|
||||
log << "restoring state" << endl;
|
||||
simulator.restore(L4SYS_STATE_FOLDER);
|
||||
@ -339,11 +362,23 @@ bool L4SysExperiment::run() {
|
||||
|
||||
// inject
|
||||
if (exp_type == param.msg.GPRFLIP) {
|
||||
if(!param.msg.has_register_offset()) {
|
||||
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 << "Sent package did not contain the injection location (register offset)" << endl;
|
||||
param.msg.set_details(ss.str());
|
||||
simulator.terminate(30);
|
||||
}
|
||||
int reg_offset = param.msg.register_offset();
|
||||
RegisterManager& rm = simulator.getRegisterManager();
|
||||
Register *ebx = rm.getRegister(RID_EBX);
|
||||
regdata_t data = ebx->getData();
|
||||
Register *reg_target = rm.getRegister(reg_offset - 1);
|
||||
regdata_t data = reg_target->getData();
|
||||
regdata_t newdata = data ^ (1 << bit_offset);
|
||||
ebx->setData(newdata);
|
||||
reg_target->setData(newdata);
|
||||
|
||||
// do the logging in case everything worked out
|
||||
logInjection(log, param);
|
||||
@ -353,8 +388,8 @@ bool L4SysExperiment::run() {
|
||||
// this is a twisted one
|
||||
|
||||
// initial definitions
|
||||
bxICacheEntry_c *cache_entry = simulator.getICacheEntry();
|
||||
unsigned length_in_bits = cache_entry->i->ilen() << 3;
|
||||
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
|
||||
unsigned length_in_bits = currInstr->ilen() << 3;
|
||||
|
||||
// get the instruction in plain text in inject the error there
|
||||
// Note: we need to fetch some extra bytes into the array
|
||||
@ -383,22 +418,13 @@ bool L4SysExperiment::run() {
|
||||
&bochs_instr);
|
||||
|
||||
// inject it
|
||||
// backup the current and insert the faulty instruction
|
||||
bxInstruction_c old_instr;
|
||||
memcpy(&old_instr, cache_entry->i, sizeof(bxInstruction_c));
|
||||
memcpy(cache_entry->i, &bochs_instr, sizeof(bxInstruction_c));
|
||||
|
||||
// execute the faulty instruction, then return
|
||||
singleStep();
|
||||
|
||||
//restore the old instruction
|
||||
memcpy(cache_entry->i, &old_instr, sizeof(bxInstruction_c));
|
||||
injectInstruction(currInstr, &bochs_instr);
|
||||
|
||||
// do the logging
|
||||
logInjection(log, param);
|
||||
} else if (exp_type == param.msg.RATFLIP) {
|
||||
bxICacheEntry_c *cache_entry = simulator.getCPUContext()->getICacheEntry();
|
||||
Udis86 udis(calculateInstructionAddress(), cache_entry->i->ilen(), injection_ip);
|
||||
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
|
||||
Udis86 udis(calculateInstructionAddress(), currInstr->ilen(), injection_ip);
|
||||
if (udis.fetchNextInstruction()) {
|
||||
ud_t _ud = udis.getCurrentState();
|
||||
|
||||
@ -493,28 +519,50 @@ bool L4SysExperiment::run() {
|
||||
// restore the actual value of the register
|
||||
// in reality, it would never have been overwritten
|
||||
rm.getRegister(bochs_reg)->setData(data);
|
||||
|
||||
// and log the injection
|
||||
logInjection(log, param);
|
||||
}
|
||||
|
||||
}
|
||||
} else if (exp_type == param.msg.ALUINSTR) {
|
||||
BochsALUInstructions aluInstrObject(aluInstructions, aluInstructionsSize);
|
||||
// find the closest ALU instruction after the current IP
|
||||
|
||||
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
|
||||
while(!aluInstrObject.isALUInstruction(currInstr)) {
|
||||
singleStep();
|
||||
currInstr = simulator.getCurrentInstruction();
|
||||
}
|
||||
// now exchange it with a random equivalent
|
||||
bxInstruction_c newInstr = aluInstrObject.randomEquivalent();
|
||||
if(!memcmp(&newInstr, currInstr, sizeof(bxInstruction_c))) {
|
||||
// something went wrong - exit experiment
|
||||
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 << "Did not hit an ALU instruction - correct the source code please!" << endl;
|
||||
param.msg.set_details(ss.str());
|
||||
simulator.terminate(40);
|
||||
}
|
||||
// inject it
|
||||
injectInstruction(currInstr, &newInstr);
|
||||
|
||||
// do the logging
|
||||
logInjection(log, param);
|
||||
}
|
||||
|
||||
// aftermath
|
||||
BPSingleListener ev_done(L4SYS_FUNC_EXIT, L4SYS_ADDRESS_SPACE);
|
||||
ev_done.setCounter(L4SYS_ITERATION_COUNT);
|
||||
simulator.addListener(&ev_done);
|
||||
const unsigned instr_run = L4SYS_ITERATION_COUNT * L4SYS_NUMINSTR;
|
||||
BPSingleListener ev_timeout(ANY_ADDR, L4SYS_ADDRESS_SPACE);
|
||||
ev_timeout.setCounter(instr_run + 3000);
|
||||
BPSingleListener ev_incomplete(ANY_ADDR, L4SYS_ADDRESS_SPACE);
|
||||
ev_incomplete.setCounter(static_cast<unsigned>(L4SYS_NUMINSTR * 1.1));
|
||||
simulator.addListener(&ev_incomplete);
|
||||
TimerListener ev_timeout(calculateTimeout());
|
||||
simulator.addListener(&ev_timeout);
|
||||
TrapListener ev_trap(ANY_TRAP);
|
||||
//one trap for each 150 instructions justifies an exception
|
||||
ev_trap.setCounter(instr_run / 150);
|
||||
simulator.addListener(&ev_trap);
|
||||
InterruptListener ev_intr(ANY_INTERRUPT);
|
||||
//one interrupt for each 100 instructions justifies an exception (timeout mostly)
|
||||
ev_intr.setCounter(instr_run / 100);
|
||||
simulator.addListener(&ev_intr);
|
||||
|
||||
//do not discard output recorded so far
|
||||
BaseListener *ev = waitIOOrOther(false);
|
||||
@ -533,25 +581,18 @@ bool L4SysExperiment::run() {
|
||||
param.msg.set_resulttype(param.msg.WRONG);
|
||||
param.msg.set_output(sanitised(output.c_str()));
|
||||
}
|
||||
} else if (ev == &ev_incomplete) {
|
||||
log << dec << "Result INCOMPLETE" << endl;
|
||||
param.msg.set_resulttype(param.msg.INCOMPLETE);
|
||||
param.msg.set_resultdata(
|
||||
simulator.getRegisterManager().getInstructionPointer());
|
||||
param.msg.set_output(sanitised(output.c_str()));
|
||||
} else if (ev == &ev_timeout) {
|
||||
log << dec << "Result TIMEOUT" << endl;
|
||||
log << hex << "Result TIMEOUT; Last INT #:" << 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);
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
#include "efw/ExperimentFlow.hpp"
|
||||
#include "efw/JobClient.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include "aluinstr.hpp"
|
||||
|
||||
class L4SysExperimentData;
|
||||
|
||||
@ -65,6 +64,16 @@ private:
|
||||
* Proceeds by one single instruction.
|
||||
*/
|
||||
void singleStep();
|
||||
/**
|
||||
* Injects a new instruction into the Bochs instruction stream and restores the previous one
|
||||
* @param oldInstr address of the instruction to be replaced
|
||||
* @param newInstr address of the instruction to replace it with
|
||||
*/
|
||||
void injectInstruction(bxInstruction_c *oldInstr, bxInstruction_c *newInstr);
|
||||
/**
|
||||
* Calculate the timeout of the current workload in milliseconds.
|
||||
*/
|
||||
unsigned calculateTimeout();
|
||||
};
|
||||
|
||||
#endif // __L4SYS_EXPERIMENT_HPP__
|
||||
|
||||
@ -4,14 +4,13 @@
|
||||
// the maximum number of bytes in a Bochs instruction
|
||||
#define MAX_INSTR_BYTES 15
|
||||
|
||||
// the bounds of the program
|
||||
// the bounds of the program (space, instructions and time)
|
||||
#define L4SYS_ADDRESS_SPACE 0x203d000
|
||||
#define L4SYS_FUNC_ENTRY 0x10025ca
|
||||
#define L4SYS_FUNC_EXIT 0x1002810
|
||||
#define L4SYS_NUMINSTR 83084798
|
||||
// kernel: 3599694, userland: 79485104
|
||||
|
||||
#define L4SYS_ITERATION_COUNT 1
|
||||
// kernel: 16300287, userland: 210785625
|
||||
#define L4SYS_NUMINSTR 227085912
|
||||
#define L4SYS_BOCHS_IPS 5000000
|
||||
|
||||
// several file names used
|
||||
#define L4SYS_STATE_FOLDER "l4sys.state"
|
||||
@ -23,6 +22,6 @@
|
||||
#define HEADLESS_EXPERIMENT
|
||||
// 0 - preparation complete
|
||||
// >0 - next step to execute
|
||||
#define PREPARATION_STEP 3
|
||||
#define PREPARATION_STEP 0
|
||||
|
||||
#endif // __EXPERIMENT_INFO_HPP__
|
||||
|
||||
@ -11,24 +11,36 @@ message L4SysProtoMsg {
|
||||
required int32 instr_offset = 2;
|
||||
required int32 bit_offset = 3;
|
||||
|
||||
// registers
|
||||
enum RegisterType {
|
||||
EAX = 1;
|
||||
ECX = 2;
|
||||
EDX = 3;
|
||||
EBX = 4;
|
||||
ESP = 5;
|
||||
EBP = 6;
|
||||
ESI = 7;
|
||||
EDI = 8;
|
||||
}
|
||||
optional RegisterType register_offset = 4;
|
||||
|
||||
// results
|
||||
// make these optional to reduce overhead for server->client communication
|
||||
enum ResultType {
|
||||
DONE = 1;
|
||||
TIMEOUT = 2;
|
||||
TRAP = 3;
|
||||
INTR = 4;
|
||||
WRONG = 5;
|
||||
UNKNOWN = 6;
|
||||
INCOMPLETE = 2;
|
||||
TIMEOUT = 3;
|
||||
WRONG = 4;
|
||||
UNKNOWN = 5;
|
||||
}
|
||||
// instruction pointer where injection was done
|
||||
optional uint32 injection_ip = 4;
|
||||
optional uint32 injection_ip = 5;
|
||||
// result type, see above
|
||||
optional ResultType resulttype = 5;
|
||||
optional ResultType resulttype = 6;
|
||||
// result data, depending on resulttype (see source code)
|
||||
optional uint32 resultdata = 6;
|
||||
optional uint32 resultdata = 7;
|
||||
// generated output
|
||||
optional string output = 7;
|
||||
optional string output = 8;
|
||||
// optional textual description of what happened
|
||||
optional string details = 8;
|
||||
optional string details = 9;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user