vezs-example: update experiment for new VEZS lecture

Change-Id: Ifea2169ceb83135e6e53663d077f8f574539f512
This commit is contained in:
Christian Dietrich
2014-04-08 15:42:56 +02:00
parent 440cba706b
commit 1d42007168
8 changed files with 299 additions and 91 deletions

View File

@ -5,15 +5,15 @@ configure_file(../instantiate-experiment.ah.in
)
## Setup desired protobuf descriptions HERE ##
set(MY_PROTOS
# vezs-example.proto
set(MY_PROTOS
vezs.proto
)
set(MY_CAMPAIGN_SRCS
experiment.hpp
experiment.cc
#campaign.hpp
#campaign.cc
campaign.hpp
campaign.cc
)
#### PROTOBUFS ####
@ -21,7 +21,10 @@ find_package(Protobuf REQUIRED)
include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
#PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
find_package(MySQL REQUIRED)
include_directories(${MYSQL_INCLUDE_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library
add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS})
@ -30,6 +33,6 @@ target_link_libraries(fail-${EXPERIMENT_NAME} fail-comm)
target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY})
## This is the example's campaign server distributing experiment parameters
#add_executable(${EXPERIMENT_NAME}-server main.cc)
#target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY})
#install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)
add_executable(${EXPERIMENT_NAME}-server main.cc)
target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${MYSQL_LIBRARIES} -Wl,--end-group)
install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)

View File

@ -0,0 +1,20 @@
#include <iostream>
#include <fstream>
#include "campaign.hpp"
#include "experimentInfo.hpp"
#include "cpn/CampaignManager.hpp"
#include "util/Logger.hpp"
#include "util/ProtoStream.hpp"
#include "sal/SALConfig.hpp"
using namespace std;
using namespace fail;
using namespace google::protobuf;
void VEZSCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) {
VEZSExperimentData *data = new VEZSExperimentData;
data->msg.mutable_fsppilot()->CopyFrom(pilot);
campaignmanager.addParam(data);
}

View File

@ -0,0 +1,24 @@
#ifndef __KESOGCCAMPAIGN_HPP__
#define __KESOGCCAMPAIGN_HPP__
#include "cpn/DatabaseCampaign.hpp"
#include "comm/ExperimentData.hpp"
#include <google/protobuf/descriptor.h>
#include "vezs.pb.h"
class VEZSExperimentData : public fail::ExperimentData {
public:
VEZSProtoMsg msg;
VEZSExperimentData() : fail::ExperimentData(&msg) {}
};
class VEZSCampaign : public fail::DatabaseCampaign {
virtual const google::protobuf::Descriptor * cb_result_message()
{ return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("VEZSProtoMsg"); }
virtual void cb_send_pilot(DatabaseCampaignMessage pilot);
};
#endif // __KESOGCCAMPAIGN_HPP__

View File

@ -1,3 +1,4 @@
#include <assert.h>
#include <iostream>
#include <fstream>
@ -8,87 +9,228 @@
#include <stdlib.h>
#include "experiment.hpp"
#include "experimentInfo.hpp"
#include "sal/SALConfig.hpp"
#include "sal/SALInst.hpp"
#include "sal/Memory.hpp"
#include "sal/Listener.hpp"
#include "sal/bochs/BochsListener.hpp"
#include <string>
#include <vector>
#include <set>
#include <algorithm>
#include "util/llvmdisassembler/LLVMtoFailTranslator.hpp"
#include "util/llvmdisassembler/LLVMtoFailBochs.hpp"
#include "campaign.hpp"
#include "vezs.pb.h"
#include "util/Disassembler.hpp"
using namespace std;
using namespace fail;
// Check if configuration dependencies are satisfied:
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE)
#error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration.
#endif
void VEZSExperiment::redecodeCurrentInstruction() {
/* Flush Instruction Caches and Prefetch queue */
BX_CPU_C *cpu_context = simulator.getCPUContext();
cpu_context->invalidate_prefetch_q();
cpu_context->iCache.flushICacheEntries();
guest_address_t pc = simulator.getCPU(0).getInstructionPointer();
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
cout << "REDECODE INSTRUCTION!" << endl;
Bit32u eipBiased = pc + cpu_context->eipPageBias;
Bit8u instr_plain[32];
MemoryManager& mm = simulator.getMemoryManager();
mm.getBytes(pc, 32, instr_plain);
unsigned remainingInPage = cpu_context->eipPageWindowSize - eipBiased;
int ret;
#if BX_SUPPORT_X86_64
if (cpu_context->cpu_mode == BX_MODE_LONG_64)
ret = cpu_context->fetchDecode64(instr_plain, currInstr, remainingInPage);
else
#endif
ret = cpu_context->fetchDecode32(instr_plain, currInstr, remainingInPage);
if (ret < 0) {
// handle instrumentation callback inside boundaryFetch
cpu_context->boundaryFetch(instr_plain, remainingInPage, currInstr);
}
}
unsigned VEZSExperiment::injectBitFlip(address_t data_address, unsigned data_width, unsigned bitpos){
MemoryManager& mm = simulator.getMemoryManager();
unsigned int value, injectedval;
value = mm.getByte(data_address);
injectedval = value ^ (1 << bitpos);
mm.setByte(data_address, injectedval);
cout << "INJECTION at: 0x" << hex << setw(2) << setfill('0') << data_address
<< " value: 0x" << setw(2) << setfill('0') << value << " -> 0x" << setw(2) << setfill('0') << injectedval << endl;
/* If it is the current instruction redecode it */
guest_address_t pc = simulator.getCPU(0).getInstructionPointer();
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
if (currInstr) {
unsigned length_in_bytes = currInstr->ilen();
if (pc <= data_address && data_address <= (pc + length_in_bytes)) {
redecodeCurrentInstruction();
}
}
return value;
}
void handleEvent(VEZSProtoMsg_Result& result, VEZSProtoMsg_Result_ResultType restype, const std::string &msg) {
cout << "Result details: " << msg << endl;
result.set_resulttype(restype);
result.set_details(msg);
}
bool VEZSExperiment::run()
{
//MemoryManager& mm = simulator.getMemoryManager();
// m_dis.init();
//******* Boot, and store state *******//
cout << "STARTING EXPERIMENT" << endl;
//m_elf.printDemangled();
m_log << "STARTING EXPERIMENT" << endl;
m_log << "Instruction Pointer: 0x" << hex << simulator.getCPU(0).getInstructionPointer() << endl;
// Test register access
Register* reg = simulator.getCPU(0).getRegister(RI_R1);
m_log << "Register R1: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
unsigned executed_jobs = 0;
reg = simulator.getCPU(0).getRegister(RI_R2);
m_log << "Register R2: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
// Setup exit points
const ElfSymbol &s_positive = m_elf.getSymbol("fail_marker_positive");
BPSingleListener l_positive(s_positive.getAddress());
const ElfSymbol &s_negative = m_elf.getSymbol("fail_marker_negative");
BPSingleListener l_negative(s_negative.getAddress());
const ElfSymbol &s_end = m_elf.getSymbol("fail_trace_stop");
BPSingleListener l_end(s_end.getAddress());
TrapListener l_trap(ANY_TRAP);
TimerListener l_timeout(500 * 1000); // 500 ms
assert(s_positive.isValid() || "fail_marker_positive not found");
assert(s_negative.isValid() || "fail_marker_negative not found");
assert(s_end.isValid() ||"fail_trace_stop not found");
// Test Listeners
address_t address = m_elf.getSymbol("incfoo").getAddress();
address &= ~1; // Cortex M3 Thumb Mode has the first bit set..
m_log << "incfoo() @ 0x" << std::hex << address << std::endl;
while (executed_jobs < 25 || m_jc->getNumberOfUndoneJobs() > 0) {
cout << "asking jobserver for parameters" << endl;
VEZSExperimentData param;
if(!m_jc->getParam(param)){
cout << "Dying." << endl; // We were told to die.
simulator.terminate(1);
}
address_t pfoo = m_elf.getSymbol("foo").getAddress();
//BPSingleListener bp(address);
//BPRangeListener bp(address-32, address + 32);
MemWriteListener l_foo( pfoo );
//MemAccessListener l_foo( 0x20002074 ); l_foo.setWatchWidth(0x4);
reg = simulator.getCPU(0).getRegister(RI_R4);
// Get input data from Jobserver
unsigned injection_instr = param.msg.fsppilot().injection_instr();
address_t data_address = param.msg.fsppilot().data_address();
unsigned data_width = param.msg.fsppilot().data_width();
//unsigned foo = 23;
for(int i = 0; i < 15; i++){
simulator.addListenerAndResume(&l_foo);
//if(i == 0) mm.setBytes(pfoo, 4, (void*)&foo);
m_log << " Breakpoint hit! @ 0x" << std::hex << simulator.getCPU(0).getInstructionPointer() << std::endl;
m_log << " Trigger PC: 0x" << std::hex << l_foo.getTriggerInstructionPointer() << std::endl;
//m_log << " Register R3: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
//mm.getBytes(pfoo, 4, (void*)&foo);
//m_log << " foo @ 0x"<< std::hex << pfoo << " = " << foo << std::endl;
}
for (int bit_offset = 0; bit_offset < 8; ++bit_offset) {
// 8 results in one job
VEZSProtoMsg_Result *result = param.msg.add_result();
result->set_bitoffset(bit_offset);
/*
BPRangeListener rbp(0xef, 0xff);
simulator.addListener(&rbp);
cout << "restoring state" << endl;
// Restore to the image, which starts at address(main)
simulator.restore("state");
executed_jobs ++;
MemAccessListener l_mem_w(0x1111, MemAccessEvent::MEM_WRITE);
l_mem_w.setWatchWidth(16);
simulator.addListener(&l_mem_w);
cout << "Trying to inject @ instr #" << dec << injection_instr << endl;
MemAccessListener l_mem_r(0x2222, MemAccessEvent::MEM_READ);
l_mem_r.setWatchWidth(16);
simulator.addListener(&l_mem_r);
MemAccessListener l_mem_rw(0x3333, MemAccessEvent::MEM_READWRITE);
l_mem_rw.setWatchWidth(16);
simulator.addListener(&l_mem_rw);
if (injection_instr > 0) {
simulator.clearListeners();
// XXX could be improved with intermediate states (reducing runtime until injection)
simulator.addListener(&l_end);
simulator.clearListeners();
// resume backend.
// simulator.resume();
BPSingleListener bp;
bp.setWatchInstructionPointer(ANY_ADDR);
// Fix offset by 1 error
bp.setCounter(injection_instr + 1);
simulator.addListener(&bp);
// Test Memory access
address_t targetaddress = 0x12345678;
MemoryManager& mm = simulator.getMemoryManager();
mm.setByte(targetaddress, 0x42);
mm.getByte(targetaddress);
bool inject = true;
while (1) {
fail::BaseListener * listener = simulator.resume();
// finish() before FI?
if (listener == &l_end) {
cout << "experiment reached finish() before FI" << endl;
handleEvent(*result, result->NOINJECTION, "time_marker reached before instr2");
inject = false;
break;
} else if (listener == &bp) {
break;
} else {
inject = false;
handleEvent(*result, result->NOINJECTION, "WTF");
break;
}
}
uint8_t tb[] = {0xab, 0xbb, 0xcc, 0xdd};
mm.setBytes(targetaddress, 4, tb);
*((uint32_t*)(tb)) = 0; // clear array.
// read back bytes
mm.getBytes(targetaddress, 4, tb);
// Next experiment
if (!inject)
continue;
}
address_t injection_instr_absolute = param.msg.fsppilot().injection_instr_absolute();
if (simulator.getCPU(0).getInstructionPointer() != injection_instr_absolute) {
cout << "Invalid Injection address EIP=0x"
<< std::hex << simulator.getCPU(0).getInstructionPointer()
<< " != 0x" << injection_instr_absolute << std::endl;
simulator.terminate(1);
}
*/
// Explicitly terminate, or the simulator will continue to run.
simulator.terminate();
/// INJECT BITFLIP:
result->set_original_value(injectBitFlip(data_address, data_width, bit_offset));
simulator.clearListeners();
simulator.addListener(&l_timeout);
simulator.addListener(&l_trap);
simulator.addListener(&l_positive);
simulator.addListener(&l_negative);
cout << "Resuming till the crash" << std::endl;
// resume and wait for results
fail::BaseListener* l = simulator.resume();
cout << "End of execution" << std::endl;
// Evaluate result
if(l == &l_positive) {
handleEvent(*result, result->POSITIVE_MARKER, "fail_marker_positive()");
} else if(l == &l_negative) {
handleEvent(*result, result->NEGATIVE_MARKER, "fail_marker_negative()");
} else if (l == &l_timeout) {
handleEvent(*result, result->TIMEOUT, "500ms");
} else if (l == &l_trap) {
stringstream sstr;
sstr << "trap #" << l_trap.getTriggerNumber();
handleEvent(*result, result->TRAP, sstr.str());
} else {
handleEvent(*result, result->UNKNOWN, "UNKNOWN event");
}
simulator.clearListeners();
}
m_jc->sendResult(param);
}
// Explicitly terminate, or the simulator will continue to run.
simulator.terminate();
}

View File

@ -9,14 +9,24 @@
#include "util/ElfReader.hpp"
class VEZSExperiment : public fail::ExperimentFlow {
fail::JobClient *m_jc;
fail::MemoryManager& m_mm;
fail::ElfReader m_elf;
fail::JobClient m_jc;
fail::Logger m_log;
fail::ElfReader m_elf;
unsigned injectBitFlip(fail::address_t data_address, unsigned data_width, unsigned bitpos);
void redecodeCurrentInstruction();
public:
VEZSExperiment() : m_log("VEZS-example", false) {};
bool run();
VEZSExperiment() : m_mm(fail::simulator.getMemoryManager()) {
char *server_host = getenv("FAIL_SERVER_HOST");
if(server_host != NULL){
this->m_jc = new fail::JobClient(std::string(server_host));
} else {
this->m_jc = new fail::JobClient();
}
};
bool run();
};
#endif // __CHECKSUM_OOSTUBS_EXPERIMENT_HPP__

View File

@ -1,24 +1,5 @@
#ifndef __EXPERIMENT_INFO_HPP__
#define __EXPERIMENT_INFO_HPP__
// FIXME autogenerate this
// the task function's entry address:
// nm -C ecc.elf|fgrep main
#define OOSTUBS_FUNC_ENTRY 0x001009d0
// empty function that is called explicitly when the experiment finished
// nm -C ecc.elf|fgrep "finished()"
#define OOSTUBS_FUNC_FINISH 0x001009d6
// function executing HLT with no chance for further progress (after panic())
// nm -C ecc.elf|fgrep cpu_halt
#define OOSTUBS_FUNC_CPU_HALT 0x001009f7
// nm -C ecc.elf | fgrep "_TEXT_"
#define OOSTUBS_TEXT_START 0x00100000
#define OOSTUBS_TEXT_END 0x00100a1b
#define OOSTUBS_NUMINSTR 5
#endif // __EXPERIMENT_INFO_HPP__

View File

@ -2,11 +2,16 @@
#include <cstdlib>
#include "cpn/CampaignManager.hpp"
#include "util/CommandLine.hpp"
#include "campaign.hpp"
int main(int argc, char **argv)
{
ChecksumOOStuBSCampaign c;
fail::CommandLine &cmd = fail::CommandLine::Inst();
for (int i = 1; i < argc; ++i)
cmd.add_args(argv[i]);
VEZSCampaign c;
if (fail::campaignmanager.runCampaign(&c)) {
return 0;
} else {

View File

@ -0,0 +1,23 @@
import "DatabaseCampaignMessage.proto";
message VEZSProtoMsg {
required DatabaseCampaignMessage fsppilot = 1;
repeated group Result = 2 {
// make these optional to reduce overhead for server->client communication
enum ResultType {
POSITIVE_MARKER = 1;
NEGATIVE_MARKER = 2;
NO_MARKER = 3;
TIMEOUT = 4;
TRAP = 5;
NOINJECTION = 6;
UNKNOWN = 7;
}
// result type, see above
required ResultType resulttype = 4;
required uint32 original_value = 5;
required uint32 bitoffset = 6 [(sql_primary_key) = true];
optional string details = 7;
}
}