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 a dummy function to define a join-point. This function is
|
||||||
// *just* called once within bx_cpu_c::cpu_loop(...).
|
// *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 */
|
/* 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
|
// instruction decoding completed -> continue with execution
|
||||||
|
|||||||
@ -19,7 +19,7 @@ bx_bool interrupt_injection_request = false;
|
|||||||
|
|
||||||
BochsController::BochsController()
|
BochsController::BochsController()
|
||||||
: SimulatorController(new BochsRegisterManager(), new BochsMemoryManager()),
|
: SimulatorController(new BochsRegisterManager(), new BochsMemoryManager()),
|
||||||
m_CPUContext(NULL), m_CacheEntry(NULL)
|
m_CPUContext(NULL), m_CurrentInstruction(NULL)
|
||||||
{
|
{
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
// Add the general purpose register:
|
// Add the general purpose register:
|
||||||
@ -116,12 +116,12 @@ void BochsController::onBreakpoint(address_t instrPtr, address_t address_space)
|
|||||||
// implementation.
|
// 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(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_CPUContext = context;
|
||||||
m_CacheEntry = cacheEntry;
|
m_CurrentInstruction = instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BochsController::onIOPort(unsigned char data, unsigned port, bool out) {
|
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
|
const std::string& BochsController::getMnemonic() const
|
||||||
{
|
{
|
||||||
static std::string str;
|
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)!");
|
assert(pInstr != NULL && "FATAL ERROR: Bochs internal member was NULL (not expected)!");
|
||||||
const char* pszName = get_bx_opcode_name(pInstr->getIaOpcode());
|
const char* pszName = get_bx_opcode_name(pInstr->getIaOpcode());
|
||||||
if (pszName != NULL)
|
if (pszName != NULL)
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class BochsController : public SimulatorController {
|
|||||||
private:
|
private:
|
||||||
ExperimentFlow* m_CurrFlow; //!< Stores the current flow for save/restore-operations
|
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
|
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
|
#ifdef DEBUG
|
||||||
unsigned m_Regularity; //! regularity of instruction ptr output
|
unsigned m_Regularity; //! regularity of instruction ptr output
|
||||||
unsigned m_Counter; //! current instr-ptr counter
|
unsigned m_Counter; //! current instr-ptr counter
|
||||||
@ -145,7 +145,7 @@ public:
|
|||||||
* Retrieves the current Bochs instruction cache entry
|
* Retrieves the current Bochs instruction cache entry
|
||||||
* @returns a pointer to a bxICacheEntry_c object
|
* @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
|
* Retrieves the current CPU context
|
||||||
* @return a pointer to a \c BX_CPU_C object
|
* @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 context the CPU context object ptr (Bochs internal=
|
||||||
* @param cacheEntry the Bochs internal CPU cache entry ptr
|
* @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
|
} // end-of-namespace: fail
|
||||||
|
|||||||
@ -20,10 +20,10 @@ aspect Breakpoints {
|
|||||||
// BX_CPU(0) otherwise
|
// BX_CPU(0) otherwise
|
||||||
BX_CPU_C* pThis = *(tjp->arg<0>());
|
BX_CPU_C* pThis = *(tjp->arg<0>());
|
||||||
// Points to the *current* bxInstruction-object
|
// 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:
|
// 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);
|
fail::simulator.onBreakpoint(pThis->get_instruction_pointer(), pThis->cr3);
|
||||||
// Note: get_bx_opcode_name(pInstr->getIaOpcode()) retrieves the mnemonics.
|
// Note: get_bx_opcode_name(pInstr->getIaOpcode()) retrieves the mnemonics.
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ set(MY_PROTOS
|
|||||||
|
|
||||||
set(MY_CAMPAIGN_SRCS
|
set(MY_CAMPAIGN_SRCS
|
||||||
aluinstr.hpp
|
aluinstr.hpp
|
||||||
|
aluinstr.cc
|
||||||
experiment.hpp
|
experiment.hpp
|
||||||
experiment.cc
|
experiment.cc
|
||||||
campaign.hpp
|
campaign.hpp
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using namespace fail;
|
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
|
// initialise the buffer
|
||||||
udis_instr_size = size;
|
udis_instr_size = size;
|
||||||
udis_instr = static_cast<unsigned char*>(malloc(udis_instr_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
|
unsigned char *udis_instr; //<! the instruction buffer for UDIs86
|
||||||
size_t udis_instr_size; //<! the size of the instruction buffer
|
size_t udis_instr_size; //<! the size of the instruction buffer
|
||||||
public:
|
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();
|
~Udis86();
|
||||||
/**
|
/**
|
||||||
* retrieves the private ud structure of udis86
|
* retrieves the private ud structure of udis86
|
||||||
* @returns a reference pointer to a ud_t variable
|
* @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.
|
* 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
|
* @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__
|
#ifndef __L4SYS_ALUINSTR_HPP__
|
||||||
#define __L4SYS_ALUINSTR_HPP__
|
#define __L4SYS_ALUINSTR_HPP__
|
||||||
|
|
||||||
#if 0
|
#include <map>
|
||||||
/**
|
#include <vector>
|
||||||
* Forward declaration of the Bochs instruction decode table.
|
#include <stdlib.h>
|
||||||
* This is necessary because, inconveniently, it is not declared in a header file.
|
#include "config.h"
|
||||||
*/
|
#include "cpu/instr.h"
|
||||||
#include "cpu/fetchdecode.h"
|
|
||||||
static const BxOpcodeInfo_t *BxOpcodeInfo32;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trying to order X86 ALU instructions.
|
* Trying to order X86 ALU instructions.
|
||||||
* Each instruction class contains instructions
|
* Each instruction class contains instructions
|
||||||
* of roughly equal length and operands, so that
|
* of roughly equal length and operands, so that
|
||||||
* all the bxInstruction_c structures residing within
|
* 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 {
|
enum X86AluClass {
|
||||||
ALU_UNDEF = 0,
|
ALU_UNDEF = 0,
|
||||||
|
ALU_GENERIC,
|
||||||
ALU_RM8,
|
ALU_RM8,
|
||||||
ALU_RM16,
|
ALU_RM16,
|
||||||
ALU_RM32,
|
ALU_RM32,
|
||||||
ALU_REG,
|
ALU_IMM8,
|
||||||
ALU_IMM8_REG,
|
ALU_IMM16,
|
||||||
ALU_IMM16_REG,
|
ALU_IMM32,
|
||||||
ALU_IMM32_REG,
|
|
||||||
ALU_IMM8_RM8,
|
ALU_IMM8_RM8,
|
||||||
ALU_IMM8_RM16,
|
ALU_IMM8_RM16,
|
||||||
ALU_IMM8_RM32,
|
ALU_IMM8_RM32,
|
||||||
ALU_IMM16_RM16,
|
ALU_IMM16_RM16,
|
||||||
ALU_IMM32_RM32,
|
ALU_IMM32_RM32
|
||||||
ALU_REG_RM8,
|
|
||||||
ALU_REG_RM16,
|
|
||||||
ALU_REG_RM32
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,28 +43,32 @@ struct BochsALUInstr {
|
|||||||
*/
|
*/
|
||||||
Bit16u bochs_operation;
|
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;
|
Bit8u opcode;
|
||||||
/**
|
/**
|
||||||
* the reg part of the modr/m field (known as "nnn" in bxInstruction_c)
|
* the reg part of the modr/m field (known as "nnn" in bxInstruction_c)
|
||||||
* it is used to
|
* it is used to
|
||||||
* a) further subdivide the functionality of a given opcode
|
* a) further subdivide the functionality of a given opcode (reg < REG_COUNT)
|
||||||
* b) specify a register the instruction is supposed to use
|
* b) specify a register the instruction is supposed to use (reg = REG_COUNT)
|
||||||
* 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 reg;
|
Bit8u reg;
|
||||||
/**
|
/**
|
||||||
* the register offset of the instruction byte of this instruction
|
* the register offset of the instruction byte of this instruction
|
||||||
* Some x86 instructions, like INC register, add a register offset
|
* Some x86 instructions, like INC register, add a register offset
|
||||||
* to their opcode. This offset is stored as "rm" in bxInstruction_c.
|
* 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;
|
Bit8u opcodeRegisterOffset;
|
||||||
/**
|
/**
|
||||||
* the ALU class this instruction belongs to
|
* the ALU class this instruction belongs to
|
||||||
*/
|
*/
|
||||||
X86AluClass aluClass;
|
X86AluClass aluClass;
|
||||||
|
/**
|
||||||
|
* the count of registers
|
||||||
|
*/
|
||||||
|
static const unsigned REG_COUNT = 8;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -86,43 +85,54 @@ const BochsALUInstr aluInstructions [] = {
|
|||||||
/* --- /// UNARY OPERATIONS \\\ --- */
|
/* --- /// UNARY OPERATIONS \\\ --- */
|
||||||
|
|
||||||
// 8-bit
|
// 8-bit
|
||||||
{ BX_IA_INC_Eb, 0xFE, 0, 8, ALU_RM8},
|
{ BX_IA_INC_Eb, 0xFE, 0, BochsALUInstr::REG_COUNT + 1, ALU_RM8},
|
||||||
{ BX_IA_DEC_Eb, 0xFE, 1, 8, ALU_RM8},
|
{ BX_IA_DEC_Eb, 0xFE, 1, BochsALUInstr::REG_COUNT + 1, ALU_RM8},
|
||||||
{ BX_IA_NOT_Eb, 0xF6, 2, 8, ALU_RM8},
|
{ BX_IA_NOT_Eb, 0xF6, 2, BochsALUInstr::REG_COUNT + 1, ALU_RM8},
|
||||||
{ BX_IA_NEG_Eb, 0xF6, 3, 8, ALU_RM8},
|
{ BX_IA_NEG_Eb, 0xF6, 3, BochsALUInstr::REG_COUNT + 1, ALU_RM8},
|
||||||
|
|
||||||
// 16-bit
|
// 16-bit
|
||||||
{ BX_IA_INC_Ew, 0xFF, 0, 8, ALU_RM16},
|
{ BX_IA_INC_Ew, 0xFF, 0, BochsALUInstr::REG_COUNT + 1, ALU_RM16},
|
||||||
{ BX_IA_DEC_Ew, 0xFF, 1, 8, ALU_RM16},
|
{ BX_IA_DEC_Ew, 0xFF, 1, BochsALUInstr::REG_COUNT + 1, ALU_RM16},
|
||||||
{ BX_IA_NOT_Ew, 0xF7, 2, 8, ALU_RM16},
|
{ BX_IA_NOT_Ew, 0xF7, 2, BochsALUInstr::REG_COUNT + 1, ALU_RM16},
|
||||||
{ BX_IA_NEG_Ew, 0xF7, 3, 8, ALU_RM16},
|
{ BX_IA_NEG_Ew, 0xF7, 3, BochsALUInstr::REG_COUNT + 1, ALU_RM16},
|
||||||
|
|
||||||
// 32-bit
|
// 32-bit
|
||||||
{ BX_IA_INC_Ed, 0xFF, 0, 8, ALU_RM32},
|
{ BX_IA_INC_Ed, 0xFF, 0, BochsALUInstr::REG_COUNT + 1, ALU_RM32},
|
||||||
{ BX_IA_DEC_Ed, 0xFF, 1, 8, ALU_RM32},
|
{ BX_IA_DEC_Ed, 0xFF, 1, BochsALUInstr::REG_COUNT + 1, ALU_RM32},
|
||||||
{ BX_IA_NOT_Ed, 0xF7, 2, 8, ALU_RM32},
|
{ BX_IA_NOT_Ed, 0xF7, 2, BochsALUInstr::REG_COUNT + 1, ALU_RM32},
|
||||||
{ BX_IA_NEG_Ed, 0xF7, 3, 8, ALU_RM32},
|
{ BX_IA_NEG_Ed, 0xF7, 3, BochsALUInstr::REG_COUNT + 1, ALU_RM32},
|
||||||
|
|
||||||
// register
|
// register
|
||||||
{ BX_IA_INC_RX, 0x40, 8, 7, ALU_REG},
|
{ BX_IA_INC_RX, 0x40, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT, ALU_GENERIC},
|
||||||
{ BX_IA_DEC_RX, 0x48, 8, 7, ALU_REG},
|
{ BX_IA_DEC_RX, 0x48, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT, ALU_GENERIC},
|
||||||
{ BX_IA_INC_ERX, 0x40, 8, 7, ALU_REG},
|
{ BX_IA_INC_ERX, 0x40, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT, ALU_GENERIC},
|
||||||
{ BX_IA_DEC_ERX, 0x48, 8, 7, ALU_REG},
|
{ BX_IA_DEC_ERX, 0x48, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT, ALU_GENERIC},
|
||||||
|
|
||||||
/* --- \\\ UNARY OPERATIONS /// --- */
|
/* --- \\\ 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 \\\ --- */
|
/* --- /// SHIFT OPERATIONS \\\ --- */
|
||||||
|
|
||||||
// a macro to reduce copy-paste overhead
|
// a macro to reduce copy-paste overhead
|
||||||
#define SHIFTOPS(OPCODE, WD, CLASS) \
|
#define SHIFTOPS(OPCODE, WD, CLASS) \
|
||||||
{ BX_IA_RCL_E##WD, OPCODE, 2, 8, CLASS }, \
|
{ BX_IA_RCL_E##WD, OPCODE, 2, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_RCR_E##WD, OPCODE, 3, 8, CLASS }, \
|
{ BX_IA_RCR_E##WD, OPCODE, 3, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_ROL_E##WD, OPCODE, 0, 8, CLASS }, \
|
{ BX_IA_ROL_E##WD, OPCODE, 0, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_ROR_E##WD, OPCODE, 1, 8, CLASS }, \
|
{ BX_IA_ROR_E##WD, OPCODE, 1, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_SHL_E##WD, OPCODE, 4, 8, CLASS }, \
|
{ BX_IA_SHL_E##WD, OPCODE, 4, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_SAR_E##WD, OPCODE, 7, 8, CLASS }, \
|
{ BX_IA_SAR_E##WD, OPCODE, 7, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_SHL_E##WD, OPCODE, 6, 8, CLASS }, \
|
{ BX_IA_SHL_E##WD, OPCODE, 6, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_SHR_E##WD, OPCODE, 5, 8, CLASS }
|
{ BX_IA_SHR_E##WD, OPCODE, 5, BochsALUInstr::REG_COUNT + 1, CLASS }
|
||||||
|
|
||||||
// first shifting by one bit
|
// first shifting by one bit
|
||||||
SHIFTOPS(0xD0, b, ALU_RM8),
|
SHIFTOPS(0xD0, b, ALU_RM8),
|
||||||
@ -130,24 +140,35 @@ const BochsALUInstr aluInstructions [] = {
|
|||||||
SHIFTOPS(0xD1, d, ALU_RM32),
|
SHIFTOPS(0xD1, d, ALU_RM32),
|
||||||
|
|
||||||
// then shifting by CL bits
|
// then shifting by CL bits
|
||||||
SHIFTOPS(0xD2, b, ALU_REG_RM8),
|
SHIFTOPS(0xD2, b, ALU_RM8),
|
||||||
SHIFTOPS(0xD3, w, ALU_REG_RM16),
|
SHIFTOPS(0xD3, w, ALU_RM16),
|
||||||
SHIFTOPS(0xD3, d, ALU_REG_RM32),
|
SHIFTOPS(0xD3, d, ALU_RM32),
|
||||||
|
|
||||||
// then shifting by a number of bits given via an immediate value
|
// then shifting by a number of bits given via an immediate value
|
||||||
SHIFTOPS(0xC0, b, ALU_IMM8_RM8),
|
SHIFTOPS(0xC0, b, ALU_IMM8_RM8),
|
||||||
SHIFTOPS(0xC1, w, ALU_IMM8_RM16),
|
SHIFTOPS(0xC1, w, ALU_IMM8_RM16),
|
||||||
SHIFTOPS(0xC1, d, ALU_IMM8_RM32),
|
SHIFTOPS(0xC1, d, ALU_IMM8_RM32),
|
||||||
|
|
||||||
#undef SHIFTOPS
|
#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 /// --- */
|
/* --- \\\ SHIFT OPERATIONS /// --- */
|
||||||
|
|
||||||
/* --- /// BINARY OPERATIONS \\\ --- */
|
/* --- /// BINARY OPERATIONS \\\ --- */
|
||||||
|
|
||||||
// register ax, immediate
|
// register ax, immediate
|
||||||
#define BINOPS(IACODE, OPCODE8, OPCODE16) \
|
#define BINOPS(IACODE, OPCODE8, OPCODE16) \
|
||||||
{ BX_IA_##IACODE##_ALIb, OPCODE8, 8, 8, ALU_IMM8_REG }, \
|
{ BX_IA_##IACODE##_ALIb, OPCODE8, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM8 }, \
|
||||||
{ BX_IA_##IACODE##_AXIw, OPCODE16, 8, 8, ALU_IMM16_REG }, \
|
{ BX_IA_##IACODE##_AXIw, OPCODE16, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM16 }, \
|
||||||
{ BX_IA_##IACODE##_EAXId, OPCODE16, 8, 8, ALU_IMM32_REG }
|
{ BX_IA_##IACODE##_EAXId, OPCODE16, BochsALUInstr::REG_COUNT + 1, BochsALUInstr::REG_COUNT + 1, ALU_IMM32 }
|
||||||
|
|
||||||
BINOPS(ADC, 0x14, 0x15),
|
BINOPS(ADC, 0x14, 0x15),
|
||||||
BINOPS(ADD, 0x04, 0x05),
|
BINOPS(ADD, 0x04, 0x05),
|
||||||
@ -161,27 +182,28 @@ const BochsALUInstr aluInstructions [] = {
|
|||||||
|
|
||||||
// r/m, immediate
|
// r/m, immediate
|
||||||
#define BINOPS(OPCODE, WDE, WDI, CLASS) \
|
#define BINOPS(OPCODE, WDE, WDI, CLASS) \
|
||||||
{ BX_IA_ADC_E##WDE##I##WDI, OPCODE, 2, 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, 8, CLASS }, \
|
{ BX_IA_ADD_E##WDE##I##WDI, OPCODE, 0, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_AND_E##WDE##I##WDI, OPCODE, 4, 8, CLASS }, \
|
{ BX_IA_AND_E##WDE##I##WDI, OPCODE, 4, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_CMP_E##WDE##I##WDI, OPCODE, 7, 8, CLASS }, \
|
{ BX_IA_CMP_E##WDE##I##WDI, OPCODE, 7, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_OR_E##WDE##I##WDI, OPCODE, 1, 8, CLASS }, \
|
{ BX_IA_OR_E##WDE##I##WDI, OPCODE, 1, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_SBB_E##WDE##I##WDI, OPCODE, 3, 8, CLASS }, \
|
{ BX_IA_SBB_E##WDE##I##WDI, OPCODE, 3, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_SUB_E##WDE##I##WDI, OPCODE, 5, 8, CLASS }, \
|
{ BX_IA_SUB_E##WDE##I##WDI, OPCODE, 5, BochsALUInstr::REG_COUNT + 1, CLASS }, \
|
||||||
{ BX_IA_XOR_E##WDE##I##WDI, OPCODE, 6, 8, CLASS }
|
{ BX_IA_XOR_E##WDE##I##WDI, OPCODE, 6, BochsALUInstr::REG_COUNT + 1, CLASS }
|
||||||
|
|
||||||
BINOPS(0x80, b, b, ALU_IMM8_RM8),
|
BINOPS(0x80, b, b, ALU_IMM8_RM8),
|
||||||
BINOPS(0x81, w, w, ALU_IMM16_RM16),
|
BINOPS(0x81, w, w, ALU_IMM16_RM16),
|
||||||
BINOPS(0x81, d, d, ALU_IMM32_RM32),
|
BINOPS(0x81, d, d, ALU_IMM32_RM32),
|
||||||
|
BINOPS(0x82, b, b, ALU_IMM8_RM8),
|
||||||
BINOPS(0x83, w, w, ALU_IMM8_RM16),
|
BINOPS(0x83, w, w, ALU_IMM8_RM16),
|
||||||
BINOPS(0x83, d, d, ALU_IMM8_RM32),
|
BINOPS(0x83, d, d, ALU_IMM8_RM32),
|
||||||
#undef BINOPS
|
#undef BINOPS
|
||||||
|
|
||||||
// r/m, arbitrary register
|
// r/m, arbitrary register
|
||||||
#define BINOPS(IACODE, OPCODE8, OPCODE16) \
|
#define BINOPS(IACODE, OPCODE8, OPCODE16) \
|
||||||
{ BX_IA_##IACODE##_EbGb, OPCODE8, 7, 8, ALU_REG_RM8 }, \
|
{ BX_IA_##IACODE##_EbGb, OPCODE8, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM8 }, \
|
||||||
{ BX_IA_##IACODE##_EwGw, OPCODE16, 7, 8, ALU_REG_RM16 }, \
|
{ BX_IA_##IACODE##_EwGw, OPCODE16, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM16 }, \
|
||||||
{ BX_IA_##IACODE##_EdGd, OPCODE16, 7, 8, ALU_REG_RM32 }
|
{ BX_IA_##IACODE##_EdGd, OPCODE16, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM32 }
|
||||||
|
|
||||||
BINOPS(ADC, 0x10, 0x11),
|
BINOPS(ADC, 0x10, 0x11),
|
||||||
BINOPS(ADD, 0x00, 0x01),
|
BINOPS(ADD, 0x00, 0x01),
|
||||||
@ -195,21 +217,83 @@ const BochsALUInstr aluInstructions [] = {
|
|||||||
|
|
||||||
// arbitrary register, r/m
|
// arbitrary register, r/m
|
||||||
#define BINOPS(IACODE, OPCODE8, OPCODE16) \
|
#define BINOPS(IACODE, OPCODE8, OPCODE16) \
|
||||||
{ BX_IA_##IACODE##_GbEb, OPCODE8, 7, 8, ALU_REG_RM8 }, \
|
{ BX_IA_##IACODE##_GbEb, OPCODE8, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM8 }, \
|
||||||
{ BX_IA_##IACODE##_GwEw, OPCODE16, 7, 8, ALU_REG_RM16 }, \
|
{ BX_IA_##IACODE##_GwEw, OPCODE16, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM16 }, \
|
||||||
{ BX_IA_##IACODE##_GdEd, OPCODE16, 7, 8, ALU_REG_RM32 }
|
{ BX_IA_##IACODE##_GdEd, OPCODE16, BochsALUInstr::REG_COUNT, BochsALUInstr::REG_COUNT + 1, ALU_RM32 }
|
||||||
|
|
||||||
BINOPS(ADC, 0x12, 0x13),
|
BINOPS(ADC, 0x12, 0x13),
|
||||||
BINOPS(ADD, 0x02, 0x03),
|
BINOPS(ADD, 0x02, 0x03),
|
||||||
BINOPS(AND, 0x22, 0x23),
|
BINOPS(AND, 0x22, 0x23),
|
||||||
BINOPS(CMP, 0x3a, 0x3b),
|
BINOPS(CMP, 0x3A, 0x3B),
|
||||||
BINOPS(OR, 0x0a, 0x0b),
|
BINOPS(OR, 0x0A, 0x0B),
|
||||||
BINOPS(SBB, 0x1a, 0x1b),
|
BINOPS(SBB, 0x1A, 0x1B),
|
||||||
BINOPS(SUB, 0x2a, 0x2b),
|
BINOPS(SUB, 0x2A, 0x2B),
|
||||||
BINOPS(XOR, 0x32, 0x33),
|
BINOPS(XOR, 0x32, 0x33),
|
||||||
#undef BINOPS
|
#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 /// --- */
|
/* --- \\\ 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__
|
#endif // __L4SYS_ALUINSTR_HPP__
|
||||||
|
|||||||
@ -11,16 +11,16 @@ using namespace std;
|
|||||||
using namespace fail;
|
using namespace fail;
|
||||||
|
|
||||||
char const * const results_csv = "l4sys.csv";
|
char const * const results_csv = "l4sys.csv";
|
||||||
const char *l4sys_output_result_strings[] = { "Unknown", "Done", "Timeout", "Trap", "Interrupt", "Wrong output", "Error" };
|
char const *l4sys_output_result_strings[] = { "Unknown", "Done", "Incomplete", "Timeout", "Wrong output", "Error" };
|
||||||
const char *l4sys_output_experiment_strings[] = { "Unknown", "GPR Flip", "RAT Flip", "Instr Flip", "ALU Instr Flip" };
|
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];
|
#define OUTPUT_CASE(OUTPUT) case L4SysProtoMsg::OUTPUT: return l4sys_output_result_strings[L4SysProtoMsg::OUTPUT];
|
||||||
std::string L4SysCampaign::output_result(L4SysProtoMsg_ResultType res) {
|
std::string L4SysCampaign::output_result(L4SysProtoMsg_ResultType res) {
|
||||||
switch (res) {
|
switch (res) {
|
||||||
OUTPUT_CASE(DONE);
|
OUTPUT_CASE(DONE);
|
||||||
|
OUTPUT_CASE(INCOMPLETE);
|
||||||
OUTPUT_CASE(TIMEOUT);
|
OUTPUT_CASE(TIMEOUT);
|
||||||
OUTPUT_CASE(TRAP);
|
|
||||||
OUTPUT_CASE(INTR);
|
|
||||||
OUTPUT_CASE(WRONG);
|
OUTPUT_CASE(WRONG);
|
||||||
OUTPUT_CASE(UNKNOWN);
|
OUTPUT_CASE(UNKNOWN);
|
||||||
default:
|
default:
|
||||||
@ -61,9 +61,23 @@ bool L4SysCampaign::run() {
|
|||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
srand(time(NULL));
|
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) {
|
for (int i = 0; i < 25; ++i) {
|
||||||
L4SysExperimentData *d = new L4SysExperimentData;
|
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
|
// modify for a random instruction
|
||||||
int instr_offset = rand() % L4SYS_NUMINSTR;
|
int instr_offset = rand() % L4SYS_NUMINSTR;
|
||||||
d->msg.set_instr_offset(instr_offset);
|
d->msg.set_instr_offset(instr_offset);
|
||||||
@ -74,7 +88,6 @@ bool L4SysCampaign::run() {
|
|||||||
campaignmanager.addParam(d);
|
campaignmanager.addParam(d);
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
for (int i = 0; i < 1000; ++i) {
|
for (int i = 0; i < 1000; ++i) {
|
||||||
L4SysExperimentData *d = new L4SysExperimentData;
|
L4SysExperimentData *d = new L4SysExperimentData;
|
||||||
d->msg.set_exp_type(d->msg.RATFLIP);
|
d->msg.set_exp_type(d->msg.RATFLIP);
|
||||||
@ -108,13 +121,17 @@ bool L4SysCampaign::run() {
|
|||||||
L4SysExperimentData *res;
|
L4SysExperimentData *res;
|
||||||
int rescount = 0;
|
int rescount = 0;
|
||||||
results
|
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;
|
<< endl;
|
||||||
while ((res = static_cast<L4SysExperimentData *>(campaignmanager.getDone()))) {
|
while ((res = static_cast<L4SysExperimentData *>(campaignmanager.getDone()))) {
|
||||||
rescount++;
|
rescount++;
|
||||||
|
|
||||||
results << output_experiment(res->msg.exp_type()) << "," << hex << res->msg.injection_ip() << "," << dec
|
results << output_experiment(res->msg.exp_type()) << "," << hex << res->msg.injection_ip() << dec << ",";
|
||||||
<< res->msg.instr_offset() << "," << res->msg.bit_offset()
|
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()) << ","
|
<< "," << output_result(res->msg.resulttype()) << ","
|
||||||
<< res->msg.resultdata();
|
<< res->msg.resultdata();
|
||||||
if (res->msg.has_output())
|
if (res->msg.has_output())
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "experiment.hpp"
|
#include "experiment.hpp"
|
||||||
#include "experimentInfo.hpp"
|
#include "experimentInfo.hpp"
|
||||||
#include "UDIS86.hpp"
|
#include "UDIS86.hpp"
|
||||||
|
#include "aluinstr.hpp"
|
||||||
#include "campaign.hpp"
|
#include "campaign.hpp"
|
||||||
|
|
||||||
#include "sal/SALConfig.hpp"
|
#include "sal/SALConfig.hpp"
|
||||||
@ -26,9 +27,8 @@ using namespace fail;
|
|||||||
// Check if configuration dependencies are satisfied:
|
// Check if configuration dependencies are satisfied:
|
||||||
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \
|
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \
|
||||||
!defined(CONFIG_SR_SAVE) || \
|
!defined(CONFIG_SR_SAVE) || \
|
||||||
!defined(CONFIG_EVENT_TRAP) || !defined(CONFIG_EVENT_IOPORT) || \
|
!defined(CONFIG_EVENT_IOPORT)
|
||||||
!defined(CONFIG_EVENT_INTERRUPT)
|
#error This experiment needs: breakpoints and I/O port events, \
|
||||||
#error This experiment needs: breakpoints, suppressed-interrupts, traps, I/O port and interrupt events, \
|
|
||||||
save, and restore. Enable these in the configuration.
|
save, and restore. Enable these in the configuration.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -149,6 +149,26 @@ void L4SysExperiment::singleStep() {
|
|||||||
simulator.removeListener(&singlestepping_event);
|
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() {
|
bool L4SysExperiment::run() {
|
||||||
Logger log("L4Sys", false);
|
Logger log("L4Sys", false);
|
||||||
BPSingleListener bp(0, L4SYS_ADDRESS_SPACE);
|
BPSingleListener bp(0, L4SYS_ADDRESS_SPACE);
|
||||||
@ -194,7 +214,6 @@ bool L4SysExperiment::run() {
|
|||||||
|
|
||||||
ofstream golden_run_file(L4SYS_CORRECT_OUTPUT);
|
ofstream golden_run_file(L4SYS_CORRECT_OUTPUT);
|
||||||
bp.setWatchInstructionPointer(L4SYS_FUNC_EXIT);
|
bp.setWatchInstructionPointer(L4SYS_FUNC_EXIT);
|
||||||
bp.setCounter(L4SYS_ITERATION_COUNT);
|
|
||||||
simulator.addListener(&bp);
|
simulator.addListener(&bp);
|
||||||
BaseListener* ev = waitIOOrOther(true);
|
BaseListener* ev = waitIOOrOther(true);
|
||||||
if (ev == &bp) {
|
if (ev == &bp) {
|
||||||
@ -279,19 +298,23 @@ bool L4SysExperiment::run() {
|
|||||||
struct stat teststruct;
|
struct stat teststruct;
|
||||||
if (stat(L4SYS_STATE_FOLDER, &teststruct) == -1 || stat(L4SYS_CORRECT_OUTPUT, &teststruct) == -1) {
|
if (stat(L4SYS_STATE_FOLDER, &teststruct) == -1 || stat(L4SYS_CORRECT_OUTPUT, &teststruct) == -1) {
|
||||||
log << "Important data missing - call \"prepare\" first." << endl;
|
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)),
|
golden_run.assign((istreambuf_iterator<char>(golden_run_file)),
|
||||||
istreambuf_iterator<char>());
|
istreambuf_iterator<char>());
|
||||||
|
|
||||||
golden_run_file.close();
|
golden_run_file.close();
|
||||||
|
|
||||||
//the generated output probably has a similar length
|
//the generated output probably has a similar length
|
||||||
output.reserve(teststruct.st_size);
|
output.reserve(teststruct.st_size);
|
||||||
|
|
||||||
log << "restoring state" << endl;
|
log << "restoring state" << endl;
|
||||||
simulator.restore(L4SYS_STATE_FOLDER);
|
simulator.restore(L4SYS_STATE_FOLDER);
|
||||||
@ -339,11 +362,23 @@ bool L4SysExperiment::run() {
|
|||||||
|
|
||||||
// inject
|
// inject
|
||||||
if (exp_type == param.msg.GPRFLIP) {
|
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();
|
RegisterManager& rm = simulator.getRegisterManager();
|
||||||
Register *ebx = rm.getRegister(RID_EBX);
|
Register *reg_target = rm.getRegister(reg_offset - 1);
|
||||||
regdata_t data = ebx->getData();
|
regdata_t data = reg_target->getData();
|
||||||
regdata_t newdata = data ^ (1 << bit_offset);
|
regdata_t newdata = data ^ (1 << bit_offset);
|
||||||
ebx->setData(newdata);
|
reg_target->setData(newdata);
|
||||||
|
|
||||||
// do the logging in case everything worked out
|
// do the logging in case everything worked out
|
||||||
logInjection(log, param);
|
logInjection(log, param);
|
||||||
@ -353,8 +388,8 @@ bool L4SysExperiment::run() {
|
|||||||
// this is a twisted one
|
// this is a twisted one
|
||||||
|
|
||||||
// initial definitions
|
// initial definitions
|
||||||
bxICacheEntry_c *cache_entry = simulator.getICacheEntry();
|
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
|
||||||
unsigned length_in_bits = cache_entry->i->ilen() << 3;
|
unsigned length_in_bits = currInstr->ilen() << 3;
|
||||||
|
|
||||||
// get the instruction in plain text in inject the error there
|
// get the instruction in plain text in inject the error there
|
||||||
// Note: we need to fetch some extra bytes into the array
|
// Note: we need to fetch some extra bytes into the array
|
||||||
@ -383,22 +418,13 @@ bool L4SysExperiment::run() {
|
|||||||
&bochs_instr);
|
&bochs_instr);
|
||||||
|
|
||||||
// inject it
|
// inject it
|
||||||
// backup the current and insert the faulty instruction
|
injectInstruction(currInstr, &bochs_instr);
|
||||||
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));
|
|
||||||
|
|
||||||
// do the logging
|
// do the logging
|
||||||
logInjection(log, param);
|
logInjection(log, param);
|
||||||
} else if (exp_type == param.msg.RATFLIP) {
|
} else if (exp_type == param.msg.RATFLIP) {
|
||||||
bxICacheEntry_c *cache_entry = simulator.getCPUContext()->getICacheEntry();
|
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
|
||||||
Udis86 udis(calculateInstructionAddress(), cache_entry->i->ilen(), injection_ip);
|
Udis86 udis(calculateInstructionAddress(), currInstr->ilen(), injection_ip);
|
||||||
if (udis.fetchNextInstruction()) {
|
if (udis.fetchNextInstruction()) {
|
||||||
ud_t _ud = udis.getCurrentState();
|
ud_t _ud = udis.getCurrentState();
|
||||||
|
|
||||||
@ -493,28 +519,50 @@ bool L4SysExperiment::run() {
|
|||||||
// restore the actual value of the register
|
// restore the actual value of the register
|
||||||
// in reality, it would never have been overwritten
|
// in reality, it would never have been overwritten
|
||||||
rm.getRegister(bochs_reg)->setData(data);
|
rm.getRegister(bochs_reg)->setData(data);
|
||||||
|
|
||||||
|
// and log the injection
|
||||||
|
logInjection(log, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if (exp_type == param.msg.ALUINSTR) {
|
} 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
|
// aftermath
|
||||||
BPSingleListener ev_done(L4SYS_FUNC_EXIT, L4SYS_ADDRESS_SPACE);
|
BPSingleListener ev_done(L4SYS_FUNC_EXIT, L4SYS_ADDRESS_SPACE);
|
||||||
ev_done.setCounter(L4SYS_ITERATION_COUNT);
|
|
||||||
simulator.addListener(&ev_done);
|
simulator.addListener(&ev_done);
|
||||||
const unsigned instr_run = L4SYS_ITERATION_COUNT * L4SYS_NUMINSTR;
|
BPSingleListener ev_incomplete(ANY_ADDR, L4SYS_ADDRESS_SPACE);
|
||||||
BPSingleListener ev_timeout(ANY_ADDR, L4SYS_ADDRESS_SPACE);
|
ev_incomplete.setCounter(static_cast<unsigned>(L4SYS_NUMINSTR * 1.1));
|
||||||
ev_timeout.setCounter(instr_run + 3000);
|
simulator.addListener(&ev_incomplete);
|
||||||
|
TimerListener ev_timeout(calculateTimeout());
|
||||||
simulator.addListener(&ev_timeout);
|
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
|
//do not discard output recorded so far
|
||||||
BaseListener *ev = waitIOOrOther(false);
|
BaseListener *ev = waitIOOrOther(false);
|
||||||
@ -533,25 +581,18 @@ bool L4SysExperiment::run() {
|
|||||||
param.msg.set_resulttype(param.msg.WRONG);
|
param.msg.set_resulttype(param.msg.WRONG);
|
||||||
param.msg.set_output(sanitised(output.c_str()));
|
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) {
|
} 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_resulttype(param.msg.TIMEOUT);
|
||||||
param.msg.set_resultdata(
|
param.msg.set_resultdata(
|
||||||
simulator.getRegisterManager().getInstructionPointer());
|
simulator.getRegisterManager().getInstructionPointer());
|
||||||
param.msg.set_output(sanitised(output.c_str()));
|
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 {
|
} else {
|
||||||
log << dec << "Result WTF?" << endl;
|
log << dec << "Result WTF?" << endl;
|
||||||
param.msg.set_resulttype(param.msg.UNKNOWN);
|
param.msg.set_resulttype(param.msg.UNKNOWN);
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
#include "efw/ExperimentFlow.hpp"
|
#include "efw/ExperimentFlow.hpp"
|
||||||
#include "efw/JobClient.hpp"
|
#include "efw/JobClient.hpp"
|
||||||
#include "util/Logger.hpp"
|
#include "util/Logger.hpp"
|
||||||
#include "aluinstr.hpp"
|
|
||||||
|
|
||||||
class L4SysExperimentData;
|
class L4SysExperimentData;
|
||||||
|
|
||||||
@ -65,6 +64,16 @@ private:
|
|||||||
* Proceeds by one single instruction.
|
* Proceeds by one single instruction.
|
||||||
*/
|
*/
|
||||||
void singleStep();
|
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__
|
#endif // __L4SYS_EXPERIMENT_HPP__
|
||||||
|
|||||||
@ -4,14 +4,13 @@
|
|||||||
// the maximum number of bytes in a Bochs instruction
|
// the maximum number of bytes in a Bochs instruction
|
||||||
#define MAX_INSTR_BYTES 15
|
#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_ADDRESS_SPACE 0x203d000
|
||||||
#define L4SYS_FUNC_ENTRY 0x10025ca
|
#define L4SYS_FUNC_ENTRY 0x10025ca
|
||||||
#define L4SYS_FUNC_EXIT 0x1002810
|
#define L4SYS_FUNC_EXIT 0x1002810
|
||||||
#define L4SYS_NUMINSTR 83084798
|
// kernel: 16300287, userland: 210785625
|
||||||
// kernel: 3599694, userland: 79485104
|
#define L4SYS_NUMINSTR 227085912
|
||||||
|
#define L4SYS_BOCHS_IPS 5000000
|
||||||
#define L4SYS_ITERATION_COUNT 1
|
|
||||||
|
|
||||||
// several file names used
|
// several file names used
|
||||||
#define L4SYS_STATE_FOLDER "l4sys.state"
|
#define L4SYS_STATE_FOLDER "l4sys.state"
|
||||||
@ -23,6 +22,6 @@
|
|||||||
#define HEADLESS_EXPERIMENT
|
#define HEADLESS_EXPERIMENT
|
||||||
// 0 - preparation complete
|
// 0 - preparation complete
|
||||||
// >0 - next step to execute
|
// >0 - next step to execute
|
||||||
#define PREPARATION_STEP 3
|
#define PREPARATION_STEP 0
|
||||||
|
|
||||||
#endif // __EXPERIMENT_INFO_HPP__
|
#endif // __EXPERIMENT_INFO_HPP__
|
||||||
|
|||||||
@ -11,24 +11,36 @@ message L4SysProtoMsg {
|
|||||||
required int32 instr_offset = 2;
|
required int32 instr_offset = 2;
|
||||||
required int32 bit_offset = 3;
|
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
|
// results
|
||||||
// make these optional to reduce overhead for server->client communication
|
// make these optional to reduce overhead for server->client communication
|
||||||
enum ResultType {
|
enum ResultType {
|
||||||
DONE = 1;
|
DONE = 1;
|
||||||
TIMEOUT = 2;
|
INCOMPLETE = 2;
|
||||||
TRAP = 3;
|
TIMEOUT = 3;
|
||||||
INTR = 4;
|
WRONG = 4;
|
||||||
WRONG = 5;
|
UNKNOWN = 5;
|
||||||
UNKNOWN = 6;
|
|
||||||
}
|
}
|
||||||
// instruction pointer where injection was done
|
// instruction pointer where injection was done
|
||||||
optional uint32 injection_ip = 4;
|
optional uint32 injection_ip = 5;
|
||||||
// result type, see above
|
// result type, see above
|
||||||
optional ResultType resulttype = 5;
|
optional ResultType resulttype = 6;
|
||||||
// result data, depending on resulttype (see source code)
|
// result data, depending on resulttype (see source code)
|
||||||
optional uint32 resultdata = 6;
|
optional uint32 resultdata = 7;
|
||||||
// generated output
|
// generated output
|
||||||
optional string output = 7;
|
optional string output = 8;
|
||||||
// optional textual description of what happened
|
// optional textual description of what happened
|
||||||
optional string details = 8;
|
optional string details = 9;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user