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:
unzner
2012-10-01 17:51:34 +00:00
parent 1a9a72eaf4
commit fd102c01ea
13 changed files with 329 additions and 166 deletions

View File

@ -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)

View File

@ -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

View File

@ -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.
}

View File

@ -11,6 +11,7 @@ set(MY_PROTOS
set(MY_CAMPAIGN_SRCS
aluinstr.hpp
aluinstr.cc
experiment.hpp
experiment.cc
campaign.hpp

View File

@ -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));

View File

@ -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

View File

@ -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__

View File

@ -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())

View File

@ -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);

View File

@ -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__

View File

@ -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__

View File

@ -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;
}