Some improvements on L4, and correcting a mistake made in revision 1361 (see mailing list).

git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1377 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
unzner
2012-06-21 14:19:21 +00:00
parent aa838b3c5a
commit 58822b02f3
5 changed files with 257 additions and 73 deletions

View File

@ -97,7 +97,9 @@ void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_sp
if(m_Regularity != 0 && ++m_Counter % m_Regularity == 0)
(*m_pDest) << "0x" << std::hex << instrPtr;
#endif
assert(context != NULL && "FATAL ERROR: Bochs internal member was NULL (not expected)!");
m_CPUContext = context;
assert(cache_entry != NULL && "FATAL ERROR: Bochs internal member was NULL (not expected)!");
m_CacheEntry = cache_entry;
bool do_fire = false;
// Check for active breakpoint-events:
@ -228,13 +230,9 @@ void BochsController::onTimerTrigger(void* thisPtr)
const std::string& BochsController::getMnemonic() const
{
static std::string str;
#if 0
bxICacheEntry_c* pEntry = BX_CPU(0)->getICacheEntry();
assert(pEntry != NULL && "FATAL ERROR: Bochs internal function returned NULL (not expected)!");
bxInstruction_c* pInstr = pEntry->i;
bxInstruction_c* pInstr = getICacheEntry()->i;
assert(pInstr != NULL && "FATAL ERROR: Bochs internal member was NULL (not expected)!");
#endif
const char* pszName = get_bx_opcode_name(getICacheEntry()->i->getIaOpcode());
const char* pszName = get_bx_opcode_name(pInstr->getIaOpcode());
if (pszName != NULL)
str = pszName;
else

View File

@ -25,6 +25,7 @@ PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library
add_library(${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS})
target_link_libraries(${EXPERIMENT_NAME} udis86)
## This is the example's campaign server distributing experiment parameters
add_executable(${EXPERIMENT_NAME}-server main.cc)

View File

@ -50,7 +50,7 @@ bool L4SysCampaign::run() {
srand(time(NULL));
for (int i = 0; i < 3000; ++i) {
L4SysExperimentData *d = new L4SysExperimentData;
d->msg.set_exp_type(d->msg.IDCFLIP);
d->msg.set_exp_type(d->msg.RATFLIP);
d->msg.set_instr_offset(rand() % L4SYS_NUMINSTR);
// 15 bytes (120 bits) are the longest instruction Bochs still executes
int bit_offset = rand() % 120;

View File

@ -8,6 +8,7 @@
#include "experiment.hpp"
#include "experimentInfo.hpp"
#include "UDIS86.hpp"
#include "sal/SALConfig.hpp"
#include "sal/SALInst.hpp"
@ -93,28 +94,29 @@ const Bit8u *L4SysExperiment::calculateInstructionAddress() {
return result;
}
bx_bool L4SysExperiment::fetchInstruction(BX_CPU_C *instance, const Bit8u *instr, bxInstruction_c *iStorage)
{
unsigned remainingInPage = instance->eipPageWindowSize - eipBiased();
int ret;
bx_bool L4SysExperiment::fetchInstruction(BX_CPU_C *instance,
const Bit8u *instr, bxInstruction_c *iStorage) {
unsigned remainingInPage = instance->eipPageWindowSize - eipBiased();
int ret;
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
ret = instance->fetchDecode64(instr, iStorage, remainingInPage);
else
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
ret = instance->fetchDecode64(instr, iStorage, remainingInPage);
else
#endif
ret = instance->fetchDecode32(instr, iStorage, remainingInPage);
ret = instance->fetchDecode32(instr, iStorage, remainingInPage);
if (ret < 0) {
// handle instrumentation callback inside boundaryFetch
instance->boundaryFetch(instr, remainingInPage, iStorage);
return 0;
}
if (ret < 0) {
// handle instrumentation callback inside boundaryFetch
instance->boundaryFetch(instr, remainingInPage, iStorage);
return 0;
}
return 1;
return 1;
}
void L4SysExperiment::logInjection(Logger &log, const L4SysExperimentData &param) {
void L4SysExperiment::logInjection(Logger &log,
const L4SysExperimentData &param) {
// explicit type assignment necessary before sending over output stream
int id = param.getWorkloadID();
int instr_offset = param.msg.instr_offset();
@ -122,42 +124,124 @@ void L4SysExperiment::logInjection(Logger &log, const L4SysExperimentData &param
int exp_type = param.msg.exp_type();
address_t injection_ip = param.msg.injection_ip();
log << "job " << id << " exp_type " << exp_type << endl;
log << "inject @ ip " << injection_ip << " (offset " << dec
<< instr_offset << ")" << " bit " << bit_offset << endl;
log << "job " << id << " exp_type " << exp_type << endl;
log << "inject @ ip " << injection_ip << " (offset " << dec << instr_offset
<< ")" << " bit " << bit_offset << endl;
}
bool L4SysExperiment::isALUInstruction(unsigned opcode) {
switch(opcode) {
case BX_IA_INC_Eb: case BX_IA_INC_Ew: case BX_IA_INC_Ed: case BX_IA_INC_RX: case BX_IA_INC_ERX:
case BX_IA_DEC_Eb: case BX_IA_DEC_Ew: case BX_IA_DEC_Ed: case BX_IA_DEC_RX: case BX_IA_DEC_ERX:
case BX_IA_ADC_EbGb: case BX_IA_ADC_EdGd: case BX_IA_ADC_EwGw: case BX_IA_ADD_EbGb: case BX_IA_ADD_EdGd:
case BX_IA_ADD_EwGw: case BX_IA_AND_EbGb: case BX_IA_AND_EdGd: case BX_IA_AND_EwGw: case BX_IA_CMP_EbGb:
case BX_IA_CMP_EdGd: case BX_IA_CMP_EwGw: case BX_IA_OR_EbGb: case BX_IA_OR_EdGd: case BX_IA_OR_EwGw:
case BX_IA_SBB_EbGb: case BX_IA_SBB_EdGd: case BX_IA_SBB_EwGw: case BX_IA_SUB_EbGb: case BX_IA_SUB_EdGd:
case BX_IA_SUB_EwGw: case BX_IA_XOR_EbGb: case BX_IA_XOR_EdGd: case BX_IA_XOR_EwGw: case BX_IA_ADC_ALIb:
case BX_IA_ADC_AXIw: case BX_IA_ADC_EAXId: case BX_IA_ADD_EbIb: case BX_IA_OR_EbIb: case BX_IA_ADC_EbIb:
case BX_IA_SBB_EbIb: case BX_IA_AND_EbIb: case BX_IA_SUB_EbIb: case BX_IA_XOR_EbIb: case BX_IA_CMP_EbIb:
case BX_IA_ADD_EwIw: case BX_IA_OR_EwIw: case BX_IA_ADC_EwIw: case BX_IA_SBB_EwIw: case BX_IA_AND_EwIw:
case BX_IA_SUB_EwIw: case BX_IA_XOR_EwIw: case BX_IA_CMP_EwIw: case BX_IA_ADD_EdId: case BX_IA_OR_EdId:
case BX_IA_ADC_EdId: case BX_IA_SBB_EdId: case BX_IA_AND_EdId: case BX_IA_SUB_EdId: case BX_IA_XOR_EdId:
case BX_IA_CMP_EdId: case BX_IA_ADC_GbEb: case BX_IA_ADC_GwEw: case BX_IA_ADC_GdEd: case BX_IA_ADD_ALIb:
case BX_IA_ADD_AXIw: case BX_IA_ADD_EAXId: case BX_IA_ADD_GbEb: case BX_IA_ADD_GwEw: case BX_IA_ADD_GdEd:
case BX_IA_AND_ALIb: case BX_IA_AND_AXIw: case BX_IA_AND_EAXId: case BX_IA_AND_GbEb: case BX_IA_AND_GwEw:
case BX_IA_AND_GdEd: case BX_IA_ROL_Eb: case BX_IA_ROR_Eb: case BX_IA_RCL_Eb: case BX_IA_RCR_Eb:
case BX_IA_SHL_Eb: case BX_IA_SHR_Eb: case BX_IA_SAR_Eb: case BX_IA_ROL_Ew: case BX_IA_ROR_Ew:
case BX_IA_RCL_Ew: case BX_IA_RCR_Ew: case BX_IA_SHL_Ew: case BX_IA_SHR_Ew: case BX_IA_SAR_Ew:
case BX_IA_ROL_Ed: case BX_IA_ROR_Ed: case BX_IA_RCL_Ed: case BX_IA_RCR_Ed: case BX_IA_SHL_Ed:
case BX_IA_SHR_Ed: case BX_IA_SAR_Ed: case BX_IA_NOT_Eb: case BX_IA_NEG_Eb: case BX_IA_NOT_Ew:
case BX_IA_NEG_Ew: case BX_IA_NOT_Ed: case BX_IA_NEG_Ed:
return true;
default:
return false;
switch (opcode) {
case BX_IA_INC_Eb:
case BX_IA_INC_Ew:
case BX_IA_INC_Ed:
case BX_IA_INC_RX:
case BX_IA_INC_ERX:
case BX_IA_DEC_Eb:
case BX_IA_DEC_Ew:
case BX_IA_DEC_Ed:
case BX_IA_DEC_RX:
case BX_IA_DEC_ERX:
case BX_IA_ADC_EbGb:
case BX_IA_ADC_EdGd:
case BX_IA_ADC_EwGw:
case BX_IA_ADD_EbGb:
case BX_IA_ADD_EdGd:
case BX_IA_ADD_EwGw:
case BX_IA_AND_EbGb:
case BX_IA_AND_EdGd:
case BX_IA_AND_EwGw:
case BX_IA_CMP_EbGb:
case BX_IA_CMP_EdGd:
case BX_IA_CMP_EwGw:
case BX_IA_OR_EbGb:
case BX_IA_OR_EdGd:
case BX_IA_OR_EwGw:
case BX_IA_SBB_EbGb:
case BX_IA_SBB_EdGd:
case BX_IA_SBB_EwGw:
case BX_IA_SUB_EbGb:
case BX_IA_SUB_EdGd:
case BX_IA_SUB_EwGw:
case BX_IA_XOR_EbGb:
case BX_IA_XOR_EdGd:
case BX_IA_XOR_EwGw:
case BX_IA_ADC_ALIb:
case BX_IA_ADC_AXIw:
case BX_IA_ADC_EAXId:
case BX_IA_ADD_EbIb:
case BX_IA_OR_EbIb:
case BX_IA_ADC_EbIb:
case BX_IA_SBB_EbIb:
case BX_IA_AND_EbIb:
case BX_IA_SUB_EbIb:
case BX_IA_XOR_EbIb:
case BX_IA_CMP_EbIb:
case BX_IA_ADD_EwIw:
case BX_IA_OR_EwIw:
case BX_IA_ADC_EwIw:
case BX_IA_SBB_EwIw:
case BX_IA_AND_EwIw:
case BX_IA_SUB_EwIw:
case BX_IA_XOR_EwIw:
case BX_IA_CMP_EwIw:
case BX_IA_ADD_EdId:
case BX_IA_OR_EdId:
case BX_IA_ADC_EdId:
case BX_IA_SBB_EdId:
case BX_IA_AND_EdId:
case BX_IA_SUB_EdId:
case BX_IA_XOR_EdId:
case BX_IA_CMP_EdId:
case BX_IA_ADC_GbEb:
case BX_IA_ADC_GwEw:
case BX_IA_ADC_GdEd:
case BX_IA_ADD_ALIb:
case BX_IA_ADD_AXIw:
case BX_IA_ADD_EAXId:
case BX_IA_ADD_GbEb:
case BX_IA_ADD_GwEw:
case BX_IA_ADD_GdEd:
case BX_IA_AND_ALIb:
case BX_IA_AND_AXIw:
case BX_IA_AND_EAXId:
case BX_IA_AND_GbEb:
case BX_IA_AND_GwEw:
case BX_IA_AND_GdEd:
case BX_IA_ROL_Eb:
case BX_IA_ROR_Eb:
case BX_IA_RCL_Eb:
case BX_IA_RCR_Eb:
case BX_IA_SHL_Eb:
case BX_IA_SHR_Eb:
case BX_IA_SAR_Eb:
case BX_IA_ROL_Ew:
case BX_IA_ROR_Ew:
case BX_IA_RCL_Ew:
case BX_IA_RCR_Ew:
case BX_IA_SHL_Ew:
case BX_IA_SHR_Ew:
case BX_IA_SAR_Ew:
case BX_IA_ROL_Ed:
case BX_IA_ROR_Ed:
case BX_IA_RCL_Ed:
case BX_IA_RCR_Ed:
case BX_IA_SHL_Ed:
case BX_IA_SHR_Ed:
case BX_IA_SAR_Ed:
case BX_IA_NOT_Eb:
case BX_IA_NEG_Eb:
case BX_IA_NOT_Ew:
case BX_IA_NEG_Ew:
case BX_IA_NOT_Ed:
case BX_IA_NEG_Ed:
return true;
default:
return false;
}
}
void L4SysExperiment::readFromFileToVector(std::ifstream &file, std::vector<trace_instr> &instr_list)
{
void L4SysExperiment::readFromFileToVector(std::ifstream &file,
std::vector<trace_instr> &instr_list) {
file >> hex;
while (!file.eof()) {
trace_instr curr_instr;
@ -167,7 +251,8 @@ void L4SysExperiment::readFromFileToVector(std::ifstream &file, std::vector<trac
file.close();
}
void L4SysExperiment::changeBochsInstruction(bxInstruction_c *dest, bxInstruction_c *src) {
void L4SysExperiment::changeBochsInstruction(bxInstruction_c *dest,
bxInstruction_c *src) {
// backup the current and insert the faulty instruction
bxInstruction_c old_instr;
memcpy(&old_instr, dest, sizeof(bxInstruction_c));
@ -186,6 +271,7 @@ void L4SysExperiment::changeBochsInstruction(bxInstruction_c *dest, bxInstructio
bool L4SysExperiment::run() {
Logger log("L4Sys", false);
BPSingleEvent bp(0, L4SYS_ADDRESS_SPACE);
srand(time(NULL));
log << "startup" << endl;
@ -213,8 +299,8 @@ bool L4SysExperiment::run() {
log << "restoring state" << endl;
simulator.restore(L4SYS_STATE_FOLDER);
log << "EIP = " << hex
<< simulator.getRegisterManager().getInstructionPointer()
<< endl;
<< simulator.getRegisterManager().getInstructionPointer()
<< endl;
// make sure the timer interrupt doesn't disturb us
simulator.addSuppressedInterrupt(32);
@ -342,7 +428,7 @@ bool L4SysExperiment::run() {
if (injection_ip != instr_list[instr_offset].trigger_addr) {
stringstream ss;
ss << "SANITY CHECK FAILED: " << injection_ip << " != "
<< instr_list[instr_offset].trigger_addr << endl;
<< instr_list[instr_offset].trigger_addr << endl;
log << ss.str();
param.msg.set_resulttype(param.msg.UNKNOWN);
param.msg.set_resultdata(injection_ip);
@ -364,9 +450,9 @@ bool L4SysExperiment::run() {
// do the logging in case everything worked out
logInjection(log, param);
log << "register data: 0x" << hex
<< ((int) data) << " -> 0x" << ((int) newdata) << endl;
} else if(exp_type == param.msg.IDCFLIP) {
log << "register data: 0x" << hex << ((int) data) << " -> 0x"
<< ((int) newdata) << endl;
} else if (exp_type == param.msg.IDCFLIP) {
// this is a twisted one
// initial definitions
@ -396,16 +482,115 @@ bool L4SysExperiment::run() {
// decode the instruction
bxInstruction_c bochs_instr;
memset(&bochs_instr, 0, sizeof(bxInstruction_c));
fetchInstruction(simulator.getCPUContext(), curr_instr_plain, &bochs_instr);
fetchInstruction(simulator.getCPUContext(), curr_instr_plain,
&bochs_instr);
// inject it
changeBochsInstruction(cache_entry->i, &bochs_instr);
// do the logging
logInjection(log, param);
} else if(exp_type == param.msg.RATFLIP) {
} else if (exp_type == param.msg.RATFLIP) {
bxICacheEntry_c *cache_entry = simulator.getICacheEntry();
Udis86 udis(calculateInstructionAddress(), cache_entry->i->ilen());
if (udis.fetchNextInstruction()) {
ud_t _ud = udis.getCurrentState();
/* start Bjoern Doebel's code (slightly modified) */
/* ============================================== */
unsigned opcount = 0;
unsigned operands[4] = { ~0U, ~0U, ~0U, ~0U };
enum {
RAT_IDX_MASK = 0x0FF,
RAT_IDX_OFFSET = 0x100
};
for (unsigned i = 0; i < 3; ++i) {
/*
* Case 1: operand is a register
*/
if (_ud.operand[i].type == UD_OP_REG) {
operands[opcount++] = i;
} else if (_ud.operand[i].type == UD_OP_MEM) {
/*
* Case 2: operand is memory op.
*
* In this case, we may have 2 registers involved for the
* index-scale address calculation.
*/
if (_ud.operand[i].base != 0) // 0 if hard-wired mem operand
operands[opcount++] = i;
if (_ud.operand[i].index != 0)
operands[opcount++] = i + RAT_IDX_OFFSET;
}
}
ud_type_t which;
unsigned rnd = random() % opcount;
if (operands[rnd] > RAT_IDX_OFFSET) {
which = _ud.operand[operands[rnd] - RAT_IDX_OFFSET].index;
} else {
which = _ud.operand[operands[rnd]].base;
}
/* ============================================ */
/* end Bjoern Doebel's code (slightly modified) */
if (which != UD_NONE) {
// so we are able to flip the associated registers
// for details on the algorithm, see Bjoern Doebel's SWIFI/RATFlip class
// some declarations
GPRegisterId bochs_reg = Udis86::udisGPRToFailBochsGPR(which);
int exchg_reg = -1;
RegisterManager &rm = simulator.getRegisterManager();
// first, decide if the fault hits a register bound to this thread
// (ten percent chance)
if (rand() % 10) {
// assure exchange of registers
exchg_reg = rand() % 7;
if (exchg_reg == bochs_reg)
exchg_reg++;
}
// prepare the fault
regdata_t data = rm.getRegister(bochs_reg)->getData();
if (rnd > 0) {
//input register - do the fault injection here
regdata_t newdata = 0;
if(exchg_reg >= 0) {
newdata = rm.getRegister(exchg_reg)->getData();
} else {
newdata = rand();
}
rm.getRegister(bochs_reg)->setData(newdata);
}
// execute the instruction
BPSingleEvent execute_single_instr(ANY_INSTR, L4SYS_ADDRESS_SPACE);
simulator.addEvent(&execute_single_instr);
waitIOOrOther(false);
simulator.removeEvent(&execute_single_instr);
// restore
if (rnd > 0) {
// restore input register
rm.getRegister(bochs_reg)->setData(data);
} else if (rnd == 0) {
// output register - do the fault injection here
if(exchg_reg >= 0) {
// write the result into the wrong local register
regdata_t newdata = rm.getRegister(bochs_reg)->getData();
rm.getRegister(exchg_reg)->setData(newdata);
}
// restore the value of the actual output register
// in reality, it would never have been overwritten
rm.getRegister(bochs_reg)->setData(data);
}
}
}
}
// aftermath

View File

@ -1,15 +1,15 @@
message L4SysProtoMsg {
// experiment types
enum ExperimentType {
GPRFLIP = 10;
RATFLIP = 15;
IDCFLIP = 20;
ALUINSTR = 30;
GPRFLIP = 1;
RATFLIP = 2;
IDCFLIP = 3;
ALUINSTR = 4;
}
// parameters
required ExperimentType exp_type = 10;
required int32 instr_offset = 20;
required int32 bit_offset = 30;
required ExperimentType exp_type = 1;
required int32 instr_offset = 2;
required int32 bit_offset = 3;
// results
// make these optional to reduce overhead for server->client communication
@ -22,13 +22,13 @@ message L4SysProtoMsg {
UNKNOWN = 6;
}
// instruction pointer where injection was done
optional uint32 injection_ip = 40;
optional uint32 injection_ip = 4;
// result type, see above
optional ResultType resulttype = 50;
optional ResultType resulttype = 5;
// result data, depending on resulttype (see source code)
optional uint32 resultdata = 60;
optional uint32 resultdata = 6;
// generated output
optional string output = 70;
optional string output = 7;
// optional textual description of what happened
optional string details = 80;
optional string details = 8;
}