Additionally passing the current Bochs CPU context and instruction cache entry to BochsController (enables detailed instruction analysis and modification)

git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1361 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
unzner
2012-06-15 16:39:14 +00:00
parent 33772f750e
commit bff60aeae3
12 changed files with 702 additions and 251 deletions

View File

@ -3,13 +3,11 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "util/Logger.hpp"
#include "experiment.hpp"
#include "experimentInfo.hpp"
#include "campaign.hpp"
#include "sal/SALConfig.hpp"
#include "sal/SALInst.hpp"
@ -33,43 +31,31 @@ using namespace fail;
#endif
typedef struct __trace_instr_type {
address_t trigger_addr;
fail::address_t trigger_addr;
unsigned bp_counter;
} trace_instr;
ostream& operator<<(ostream& out, const trace_instr &val) {
out << val.trigger_addr << "," << val.bp_counter;
return out;
}
istream& operator>>(istream& in, trace_instr &val) {
in >> val.trigger_addr;
//skip the comma
in.ignore(1);
in >> val.bp_counter;
return in;
}
char const * const state_folder = "l4sys.state";
char const * const instr_list_fn = "ip.list";
char const * const golden_run_fn = "golden.out";
address_t const aspace = 0x01e00000;
string output;
#if 0
//disabled (see "STEP 2" below)
vector<trace_instr> instr_list;
vector<trace_instr> alu_instr_list;
#endif
string golden_run;
//the program needs to run 5 times without a fault
const unsigned times_run = 5;
string L4SysExperiment::sanitised(string in_str) {
string L4SysExperiment::sanitised(const string &in_str) {
string result;
result.reserve(in_str.size());
for (string::iterator it = in_str.begin(); it != in_str.end(); it++) {
unsigned char_value = static_cast<unsigned>(*it);
if (char_value < 0x20 || char_value > 0x7E) {
int in_str_size = in_str.size();
result.reserve(in_str_size);
for (int idx = 0; idx < in_str_size; idx++) {
char cur_char = in_str[idx];
unsigned cur_char_value = static_cast<unsigned>(cur_char);
if (cur_char_value < 0x20 || cur_char_value > 0x7E) {
char str_nr[5];
sprintf(str_nr, "\\%03o", char_value);
sprintf(str_nr, "\\%03o", cur_char_value);
result += str_nr;
} else {
result += *it;
result += cur_char;
}
}
return result;
@ -93,15 +79,119 @@ BaseEvent* L4SysExperiment::waitIOOrOther(bool clear_output) {
return ev;
}
Bit32u L4SysExperiment::eipBiased() {
BX_CPU_C *cpu_context = simulator.getCPUContext();
Bit32u EIP = cpu_context->gen_reg[BX_32BIT_REG_EIP].dword.erx;
return EIP + cpu_context->eipPageBias;
}
const Bit8u *L4SysExperiment::calculateInstructionAddress() {
// pasted in from various nested Bochs functions and macros - I hope
// they will not change too soon (as do the Bochs developers, probably)
BX_CPU_C *cpu_context = simulator.getCPUContext();
const Bit8u *result = cpu_context->eipFetchPtr + eipBiased();
return result;
}
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
#endif
ret = instance->fetchDecode32(instr, iStorage, remainingInPage);
if (ret < 0) {
// handle instrumentation callback inside boundaryFetch
instance->boundaryFetch(instr, remainingInPage, iStorage);
return 0;
}
return 1;
}
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();
int bit_offset = param.msg.bit_offset();
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;
}
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;
}
}
void L4SysExperiment::readFromFileToVector(std::ifstream &file, std::vector<trace_instr> &instr_list)
{
file >> hex;
while (!file.eof()) {
trace_instr curr_instr;
file.read(reinterpret_cast<char*>(&curr_instr), sizeof(trace_instr));
instr_list.push_back(curr_instr);
}
file.close();
}
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));
memcpy(dest, src, sizeof(bxInstruction_c));
// execute the faulty instruction, then return
BPSingleEvent singlestepping_event(ANY_ADDR, L4SYS_ADDRESS_SPACE);
simulator.addEvent(&singlestepping_event);
waitIOOrOther(false);
simulator.removeEvent(&singlestepping_event);
//restore the old instruction
memcpy(dest, &old_instr, sizeof(bxInstruction_c));
}
bool L4SysExperiment::run() {
Logger log("L4Sys", false);
BPSingleEvent bp(0, aspace);
BPSingleEvent bp(0, L4SYS_ADDRESS_SPACE);
log << "startup" << endl;
struct stat teststruct;
// STEP 1: run until interesting function starts, and save state
if (stat(state_folder, &teststruct) == -1) {
if (stat(L4SYS_STATE_FOLDER, &teststruct) == -1) {
bp.setWatchInstructionPointer(L4SYS_FUNC_ENTRY);
simulator.addEventAndWait(&bp);
@ -109,13 +199,19 @@ bool L4SysExperiment::run() {
log << "EIP = " << hex << bp.getTriggerInstructionPointer() << " or "
<< simulator.getRegisterManager().getInstructionPointer()
<< endl;
simulator.save(state_folder);
simulator.save(L4SYS_STATE_FOLDER);
}
// STEP 2: determine instructions executed
if (stat(instr_list_fn, &teststruct) == -1) {
#if 0
// the files currently get too big.
/* I do not really have a clever idea to solve this.
* You would probably need some kind of loop detection,
* but for the moment, I have to focus on different issues.
*/
if (stat(L4SYS_INSTRUCTION_LIST, &teststruct) == -1 || stat(L4SYS_ALU_INSTRUCTIONS, &teststruct) == -1) {
log << "restoring state" << endl;
simulator.restore(state_folder);
simulator.restore(L4SYS_STATE_FOLDER);
log << "EIP = " << hex
<< simulator.getRegisterManager().getInstructionPointer()
<< endl;
@ -123,8 +219,8 @@ bool L4SysExperiment::run() {
// make sure the timer interrupt doesn't disturb us
simulator.addSuppressedInterrupt(32);
ofstream instr_list_file(instr_list_fn);
instr_list_file << hex;
ofstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::out | ios::binary);
ofstream alu_instr_file(L4SYS_ALU_INSTRUCTIONS, ios::out | ios::binary);
bp.setWatchInstructionPointer(ANY_ADDR);
map<address_t, unsigned> times_called_map;
@ -144,25 +240,34 @@ bool L4SysExperiment::run() {
new_instr.bp_counter = times_called;
instr_list.push_back(new_instr);
instr_list_file << new_instr << endl;
instr_list_file.write(reinterpret_cast<char*>(&new_instr), sizeof(trace_instr));
// ALU instructions
// decode the instruction
bxInstruction_c instr;
fetchInstruction(simulator.getCPUContext(), calculateInstructionAddress(), &instr);
// add it to a second list if it is an ALU instruction
if(isALUInstruction(instr.getIaOpcode())) {
alu_instr_list.push_back(new_instr);
alu_instr_file.write(reinterpret_cast<char*>(&new_instr), sizeof(trace_instr));
}
}
log << "saving instructions triggered during normal execution" << endl;
alu_instr_file.close();
instr_list_file.close();
} else {
ifstream instr_list_file(instr_list_fn);
instr_list_file >> hex;
while (!instr_list_file.eof()) {
trace_instr curr_instr;
instr_list_file >> curr_instr;
instr_list.push_back(curr_instr);
}
instr_list_file.close();
ifstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::in | ios::binary);
ifstream alu_instr_file(L4SYS_ALU_INSTRUCTIONS, ios::in | ios::binary);
readFromFileToVector(instr_list_file, instr_list);
readFromFileToVector(alu_instr_file, alu_instr_list);
}
#endif
// STEP 3: determine the output of a "golden run"
if (stat(golden_run_fn, &teststruct) == -1) {
if (stat(L4SYS_CORRECT_OUTPUT, &teststruct) == -1) {
log << "restoring state" << endl;
simulator.restore(state_folder);
simulator.restore(L4SYS_STATE_FOLDER);
log << "EIP = " << hex
<< simulator.getRegisterManager().getInstructionPointer()
<< endl;
@ -170,9 +275,9 @@ bool L4SysExperiment::run() {
// make sure the timer interrupt doesn't disturb us
simulator.addSuppressedInterrupt(32);
ofstream golden_run_file(golden_run_fn);
ofstream golden_run_file(L4SYS_CORRECT_OUTPUT);
bp.setWatchInstructionPointer(L4SYS_FUNC_EXIT);
bp.setCounter(times_run);
bp.setCounter(L4SYS_ITERATION_COUNT);
simulator.addEvent(&bp);
BaseEvent* ev = waitIOOrOther(true);
if (ev == &bp) {
@ -191,13 +296,9 @@ bool L4SysExperiment::run() {
log << "saving output generated during normal execution" << endl;
golden_run_file.close();
} else {
ifstream golden_run_file(golden_run_fn);
ifstream golden_run_file(L4SYS_CORRECT_OUTPUT);
//shamelessly copied from http://stackoverflow.com/questions/2602013/:
golden_run_file.seekg(0, ios::end);
size_t flen = golden_run_file.tellg();
golden_run.reserve(flen);
golden_run_file.seekg(0, ios::beg);
golden_run.reserve(teststruct.st_size);
golden_run.assign((istreambuf_iterator<char>(golden_run_file)),
istreambuf_iterator<char>());
@ -205,130 +306,177 @@ bool L4SysExperiment::run() {
golden_run_file.close();
//the generated output probably has a similar length
output.reserve(flen);
output.reserve(teststruct.st_size);
}
// STEP 4: The actual experiment.
while (1) {
log << "restoring state" << endl;
simulator.restore(state_folder);
log << "restoring state" << endl;
simulator.restore(L4SYS_STATE_FOLDER);
log << "asking job server for experiment parameters" << endl;
L4SysExperimentData param;
if (!m_jc.getParam(param)) {
log << "Dying." << endl;
// communicate that we were told to die
simulator.terminate(1);
}
int id = param.getWorkloadID();
int instr_offset = param.msg.instr_offset();
int bit_offset = param.msg.bit_offset();
log << "job " << id << " instr " << instr_offset << " bit "
<< bit_offset << endl;
log << "asking job server for experiment parameters" << endl;
L4SysExperimentData param;
if (!m_jc.getParam(param)) {
log << "Dying." << endl;
// communicate that we were told to die
simulator.terminate(1);
}
bp.setWatchInstructionPointer(instr_list[instr_offset].trigger_addr);
bp.setCounter(instr_list[instr_offset].bp_counter);
simulator.addEvent(&bp);
//and log the output
waitIOOrOther(true);
int instr_offset = param.msg.instr_offset();
int bit_offset = param.msg.bit_offset();
int exp_type = param.msg.exp_type();
// inject
RegisterManager& rm = simulator.getRegisterManager();
Register *ebx = rm.getRegister(RID_CBX);
regdata_t data = ebx->getData();
regdata_t newdata = data ^ (1 << bit_offset);
ebx->setData(newdata);
// note at what IP we did it
address_t injection_ip =
simulator.getRegisterManager().getInstructionPointer();
param.msg.set_injection_ip(injection_ip);
log << "inject @ ip " << injection_ip << " (offset " << dec
<< instr_offset << ")" << " bit " << bit_offset << ": 0x" << hex
<< ((int) data) << " -> 0x" << ((int) newdata) << endl;
bp.setWatchInstructionPointer(ANY_ADDR);
bp.setCounter(instr_offset);
simulator.addEvent(&bp);
//and log the output
waitIOOrOther(true);
// sanity check (only works if we're working with an instruction trace)
if (injection_ip != instr_list[instr_offset].trigger_addr) {
stringstream ss;
ss << "SANITY CHECK FAILED: " << injection_ip << " != "
<< instr_list[instr_offset].trigger_addr << endl;
log << ss.str();
param.msg.set_resulttype(param.msg.UNKNOWN);
param.msg.set_resultdata(injection_ip);
param.msg.set_details(ss.str());
// note at what IP we will do the injection
address_t injection_ip =
simulator.getRegisterManager().getInstructionPointer();
param.msg.set_injection_ip(injection_ip);
simulator.clearEvents();
m_jc.sendResult(param);
simulator.terminate(20);
}
// aftermath
BPSingleEvent ev_done(L4SYS_FUNC_EXIT, aspace);
ev_done.setCounter(times_run);
simulator.addEvent(&ev_done);
const unsigned instr_run = times_run * L4SYS_NUMINSTR;
BPSingleEvent ev_timeout(ANY_ADDR, aspace);
ev_timeout.setCounter(instr_run + 3000);
simulator.addEvent(&ev_timeout);
TrapEvent ev_trap(ANY_TRAP);
simulator.addEvent(&ev_trap);
InterruptEvent ev_intr(ANY_INTERRUPT);
//ten times as many interrupts as instructions justify an exception
ev_intr.setCounter(instr_run * 10);
simulator.addEvent(&ev_intr);
//do not discard output recorded so far
BaseEvent *ev = waitIOOrOther(false);
/* copying a string object that contains control sequences
* unfortunately does not work with the library I am using,
* which is why output is passed on as C string and
* the string compare is done on C strings
*/
if (ev == &ev_done) {
if (strcmp(output.c_str(), golden_run.c_str()) == 0) {
log << dec << "Result DONE" << endl;
param.msg.set_resulttype(param.msg.DONE);
} else {
log << dec << "Result WRONG" << endl;
param.msg.set_resulttype(param.msg.WRONG);
param.msg.set_output(sanitised(output.c_str()));
}
} else if (ev == &ev_timeout) {
log << dec << "Result TIMEOUT" << 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);
param.msg.set_resultdata(
simulator.getRegisterManager().getInstructionPointer());
param.msg.set_output(sanitised(output.c_str()));
stringstream ss;
ss << "eventid " << ev << " EIP "
<< simulator.getRegisterManager().getInstructionPointer()
<< endl;
param.msg.set_details(ss.str());
}
#if 0
// temporarily out of order (see above)
// sanity check (only works if we're working with an instruction trace)
if (injection_ip != instr_list[instr_offset].trigger_addr) {
stringstream ss;
ss << "SANITY CHECK FAILED: " << injection_ip << " != "
<< instr_list[instr_offset].trigger_addr << endl;
log << ss.str();
param.msg.set_resulttype(param.msg.UNKNOWN);
param.msg.set_resultdata(injection_ip);
param.msg.set_details(ss.str());
simulator.clearEvents();
m_jc.sendResult(param);
simulator.terminate(20);
}
#endif
// inject
if (exp_type == param.msg.GPRFLIP) {
RegisterManager& rm = simulator.getRegisterManager();
Register *ebx = rm.getRegister(RID_EBX);
regdata_t data = ebx->getData();
regdata_t newdata = data ^ (1 << bit_offset);
ebx->setData(newdata);
// 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) {
// this is a twisted one
// initial definitions
bxICacheEntry_c *cache_entry = simulator.getICacheEntry();
unsigned length_in_bits = cache_entry->i->ilen() << 3;
// get the instruction in plain text in inject the error there
// Note: we need to fetch some extra bytes into the array
// in case the faulty instruction is interpreted to be longer
// than the original one
Bit8u curr_instr_plain[MAX_INSTR_BYTES];
const Bit8u *addr = calculateInstructionAddress();
memcpy(curr_instr_plain, addr, MAX_INSTR_BYTES);
// CampaignManager has no idea of the instruction length
// (neither do we), therefore this small adaption
bit_offset %= length_in_bits;
param.msg.set_bit_offset(bit_offset);
// do some access calculation
int byte_index = bit_offset >> 3;
Bit8u bit_index = bit_offset & 7;
// apply the fault
curr_instr_plain[byte_index] ^= 1 << bit_index;
// decode the instruction
bxInstruction_c bochs_instr;
memset(&bochs_instr, 0, sizeof(bxInstruction_c));
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) {
bxICacheEntry_c *cache_entry = simulator.getICacheEntry();
}
// aftermath
BPSingleEvent ev_done(L4SYS_FUNC_EXIT, L4SYS_ADDRESS_SPACE);
ev_done.setCounter(L4SYS_ITERATION_COUNT);
simulator.addEvent(&ev_done);
const unsigned instr_run = L4SYS_ITERATION_COUNT * L4SYS_NUMINSTR;
BPSingleEvent ev_timeout(ANY_ADDR, L4SYS_ADDRESS_SPACE);
ev_timeout.setCounter(instr_run + 3000);
simulator.addEvent(&ev_timeout);
TrapEvent ev_trap(ANY_TRAP);
//one trap for each 150 instructions justifies an exception
ev_trap.setCounter(instr_run / 150);
simulator.addEvent(&ev_trap);
InterruptEvent ev_intr(ANY_INTERRUPT);
//one interrupt for each 100 instructions justifies an exception (timeout mostly)
ev_intr.setCounter(instr_run / 100);
simulator.addEvent(&ev_intr);
//do not discard output recorded so far
BaseEvent *ev = waitIOOrOther(false);
/* copying a string object that contains control sequences
* unfortunately does not work with the library I am using,
* which is why output is passed on as C string and
* the string compare is done on C strings
*/
if (ev == &ev_done) {
if (strcmp(output.c_str(), golden_run.c_str()) == 0) {
log << dec << "Result DONE" << endl;
param.msg.set_resulttype(param.msg.DONE);
} else {
log << dec << "Result WRONG" << endl;
param.msg.set_resulttype(param.msg.WRONG);
param.msg.set_output(sanitised(output.c_str()));
}
} else if (ev == &ev_timeout) {
log << dec << "Result TIMEOUT" << 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);
param.msg.set_resultdata(
simulator.getRegisterManager().getInstructionPointer());
param.msg.set_output(sanitised(output.c_str()));
stringstream ss;
ss << "eventid " << ev << " EIP "
<< simulator.getRegisterManager().getInstructionPointer()
<< endl;
param.msg.set_details(ss.str());
}
simulator.clearEvents();
m_jc.sendResult(param);
#ifdef HEADLESS_EXPERIMENT
simulator.terminate(0);