Merge branch 'failpanda'

Conflicts:
	src/core/comm/DatabaseCampaignMessage.proto.in
	src/core/cpn/CMakeLists.txt
	src/core/cpn/DatabaseCampaign.cc
	src/core/sal/ConcreteCPU.hpp
	src/core/sal/SALConfig.hpp
	src/core/util/CMakeLists.txt

Change-Id: Id86b93d0e3ea4d9963fcc88605eec0603575ec83
This commit is contained in:
Horst Schirmeier
2014-06-03 12:24:38 +02:00
1230 changed files with 579380 additions and 28 deletions

View File

@ -7,15 +7,31 @@ set(SRCS
## Setup desired protobuf descriptions HERE ##
set(PROTOS
FailControlMessage.proto
DatabaseCampaignMessage.proto
${CMAKE_CURRENT_BINARY_DIR}/DatabaseCampaignMessage.proto
TracePlugin.proto
)
## Set concrete implementation of InjectionPointMessage
# TODO: Define separate symbol, so it can also be used in other build types
if(CONFIG_INJECTIONPOINT_HOPS)
set(PROTOS ${PROTOS} InjectionPointHopsMessage.proto)
set(CONCRETE_INJECTION_POINT InjectionPointHopsMessage.proto)
else(CONFIG_INJECTIONPOINT_HOPS)
set(PROTOS ${PROTOS} InjectionPointStepsMessage.proto)
set(CONCRETE_INJECTION_POINT InjectionPointStepsMessage.proto)
endif(CONFIG_INJECTIONPOINT_HOPS)
# Configure concrete protobuf message to be included by campaign message
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DatabaseCampaignMessage.proto.in
${CMAKE_CURRENT_BINARY_DIR}/DatabaseCampaignMessage.proto)
#### PROTOBUFS ####
find_package(Protobuf REQUIRED)
include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# Let protobuf compiler find defined file (DatabaseCampaignMessage) in binary tree
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${PROTOS})
add_library(fail-comm ${SRCS} ${PROTO_SRCS} ${PROTO_HDRS})

View File

@ -4,14 +4,21 @@ extend google.protobuf.FieldOptions {
optional bool sql_ignore = 32383 [ default = false];
}
import "@CONCRETE_INJECTION_POINT@";
message DatabaseCampaignMessage {
required uint32 pilot_id = 1 [(sql_primary_key) = true];
required uint32 variant_id = 2 [(sql_ignore) = true];
required uint32 fspmethod_id = 3 [(sql_ignore) = true];
// ToDo: injection_instr can be deleted if all experiments switched to
// using generic InjectionPointMessage
required uint32 injection_instr = 4 [(sql_ignore) = true];
optional uint32 injection_instr_absolute = 5 [(sql_ignore) = true];
required uint32 data_address = 6 [(sql_ignore) = true];
required uint32 data_width = 7 [(sql_ignore) = true];
required string variant = 8 [(sql_ignore) = true];
required string benchmark = 9 [(sql_ignore) = true];
}
required InjectionPointMessage injection_point = 10 [(sql_ignore) = true];
}

View File

@ -0,0 +1,28 @@
message InjectionPointMessage {
// Costs of the hop chain on the PandaBoard
// ToDo: Could be eliminated, but it is nice for evaluation
optional uint32 costs = 3;
// If checkpoint must be used for this hop chain, id is set properly
optional uint32 checkpoint_id = 1;
// If we need to know the target dynamic instruction offset,
// here it is
optional uint32 target_trace_position = 4;
// Repeated groups can't be defined as non-empty, so a manual
// non-empty check is required at usage
// As we assume hops to always watch addresses of length 1, we
// don't encode the length in here
repeated group Hops = 2 {
required uint64 address = 1;
enum AccessType {
EXECUTE = 1;
READ = 2;
WRITE = 3;
}
required AccessType accesstype = 2;
}
}

View File

@ -0,0 +1,3 @@
message InjectionPointMessage {
required uint32 injection_instr = 1;
}

View File

@ -23,6 +23,7 @@ OPTION(CONFIG_DISABLE_KEYB_INTERRUPTS "Target backend: Suppress keyboard inter
OPTION(SERVER_PERFORMANCE_MEASURE "Performance measurement in job-server" OFF)
OPTION(CONFIG_FAST_BREAKPOINTS "Enable fast breakpoints (requires breakpoint events to be enabled)" OFF)
OPTION(CONFIG_FAST_WATCHPOINTS "Enable fast watchpoints (requires memory access events to be enabled)" OFF)
OPTION(CONFIG_INJECTIONPOINT_HOPS "Enable hop chain trace navigation to injection point" OFF)
SET(SERVER_COMM_HOSTNAME "localhost" CACHE STRING "Job-server hostname or IP")
SET(SERVER_COMM_TCP_PORT "1111" CACHE STRING "Job-server TCP port")
SET(SERVER_OUT_QUEUE_SIZE "0" CACHE STRING "Queue size for outbound jobs (0 = unlimited)")

View File

@ -19,6 +19,7 @@
// Performance options
#cmakedefine CONFIG_FAST_BREAKPOINTS
#cmakedefine CONFIG_FAST_WATCHPOINTS
#cmakedefine CONFIG_INJECTIONPOINT_HOPS
// Save/restore functionality
#cmakedefine CONFIG_SR_RESTORE

View File

@ -5,6 +5,7 @@
#cmakedefine BUILD_GEM5
#cmakedefine BUILD_QEMU
#cmakedefine BUILD_T32
#cmakedefine BUILD_PANDA
#cmakedefine T32_MOCK_API
#cmakedefine BUILD_X86

View File

@ -7,8 +7,21 @@ set(SRCS
find_package(MySQL REQUIRED)
include_directories(${MYSQL_INCLUDE_DIR})
# only compile concrete implementation of InjectionPoint
if(CONFIG_INJECTIONPOINT_HOPS)
set (SRCS ${SRCS} InjectionPointHops.cc)
else(CONFIG_INJECTIONPOINT_HOPS)
set (SRCS ${SRCS} InjectionPointSteps.cc)
endif(CONFIG_INJECTIONPOINT_HOPS)
add_library(fail-cpn ${SRCS})
target_link_libraries(fail-cpn fail-comm fail-util ${MYSQL_LIBRARIES})
# if hop-chains need to be calculated by the server, we
# the smarthopping module
if(CONFIG_INJECTIONPOINT_HOPS)
add_dependencies(fail-cpn fail-smarthops)
endif(CONFIG_INJECTIONPOINT_HOPS)
# make sure protobufs are generated before we include them
add_dependencies(fail-cpn fail-comm)

View File

@ -4,7 +4,7 @@
#include "util/Logger.hpp"
#include "util/Database.hpp"
#include "comm/ExperimentData.hpp"
#include "InjectionPoint.hpp"
#ifndef __puma
#include <boost/thread.hpp>
@ -131,10 +131,13 @@ bool DatabaseCampaign::run_variant(Database::Variant variant) {
/* Gather jobs */
int experiment_count;
std::stringstream ss;
std::string sql_select = "SELECT p.id, p.fspmethod_id, p.variant_id, p.injection_instr, p.injection_instr_absolute, p.data_address, p.data_width ";
std::string sql_select = "SELECT p.id, p.injection_instr, p.injection_instr_absolute, p.data_address, p.data_width, t.instr1, t.instr2 ";
ss << " FROM fsppilot p "
<< " WHERE p.fspmethod_id = " << fspmethod_id
<< " AND p.variant_id = " << variant.id;
<< " JOIN trace t"
<< " ON t.variant_id = p.variant_id AND t.data_address = p.data_address AND t.instr2 = p.instr2"
<< " WHERE p.fspmethod_id = " << fspmethod_id
<< " AND p.variant_id = " << variant.id
<< " ORDER BY t.instr1"; // Smart-Hopping needs this ordering
std::string sql_body = ss.str();
/* Get the number of unfinished experiments */
@ -148,6 +151,12 @@ bool DatabaseCampaign::run_variant(Database::Variant variant) {
log_send << "Found " << experiment_count << " jobs in database. ("
<< variant.variant << "/" << variant.benchmark << ")" << std::endl;
// abstraction of injection point:
// must not be initialized in loop, because hop chain calculator would lose
// state after loop pass and so for every hop chain it would have to begin
// calculating at trace instruction zero
ConcreteInjectionPoint ip;
unsigned expected_results = expected_number_of_results(variant.variant, variant.benchmark);
unsigned sent_pilots = 0, skipped_pilots = 0;
@ -158,20 +167,26 @@ bool DatabaseCampaign::run_variant(Database::Variant variant) {
continue;
}
unsigned injection_instr = strtoul(row[3], NULL, 10);
unsigned data_address = strtoul(row[5], NULL, 10);
unsigned data_width = strtoul(row[6], NULL, 10);
unsigned injection_instr = strtoul(row[1], NULL, 10);
unsigned data_address = strtoul(row[3], NULL, 10);
unsigned data_width = strtoul(row[4], NULL, 10);
unsigned instr1 = strtoul(row[5], NULL, 10);
unsigned instr2 = strtoul(row[6], NULL, 10);
DatabaseCampaignMessage pilot;
pilot.set_pilot_id(pilot_id);
pilot.set_fspmethod_id(fspmethod_id);
pilot.set_variant_id(variant.id);
// ToDo: Remove this, if all experiments work with abstract API (InjectionPoint)
pilot.set_injection_instr(injection_instr);
pilot.set_variant(variant.variant);
pilot.set_benchmark(variant.benchmark);
if (row[4]) {
unsigned injection_instr_absolute = strtoul(row[4], NULL, 10);
ip.parseFromInjectionInstr(instr1, instr2);
ip.addToCampaignMessage(pilot);
if (row[2]) {
unsigned injection_instr_absolute = strtoul(row[2], NULL, 10);
pilot.set_injection_instr_absolute(injection_instr_absolute);
}
pilot.set_data_address(data_address);

View File

@ -0,0 +1,119 @@
#ifndef INJECTIONPOINT_HPP_
#define INJECTIONPOINT_HPP_
#include "comm/DatabaseCampaignMessage.pb.h"
#include "util/Logger.hpp"
#include "config/FailConfig.hpp"
#include <vector>
namespace fail {
/**
* \class InjectionPointBase
*
* Interface for a generic InjectionPoint (e.g. trace instruction offset or
* hop chain) for use in the generic DatabaseCampaign. Every
* DataBaseCampaignMessage contains a concrete InjectionPoint.
*/
class InjectionPointBase {
protected:
InjectionPointMessage m_ip; // !< Protobuf message of concrete injection point, this class wraps
Logger m_log;
public:
InjectionPointBase() : m_log("InjectionPoint") {}
/**
* Parses generic representation from a injection instruction (trace offset).
* Used by server.
* @param inj_instr trace instruction offset to be parsed
*/
virtual void parseFromInjectionInstr(unsigned instr1, unsigned instr2) = 0;
/**
* Parses (extracts) generic representation from a DatabaseCampaignMessage.
* Used by client.
* @param pilot DatabaseCampaignMessage which contains a InjectionPoint
*/
void parseFromCampaignMessage(const DatabaseCampaignMessage &pilot) {m_ip.CopyFrom(pilot.injection_point());}
/**
* Adds generic representation to a DatabaseCampaignMessage
* @param pilot DatabaseCampaignMessage to which the generic protobuf representation will be added
*/
void addToCampaignMessage(DatabaseCampaignMessage &pilot) {pilot.mutable_injection_point()->CopyFrom(m_ip);}
/**
* Get a copy of the contained InjectionPointMessage
* @param ipm Generic InjectionPointMessage to which the content will be copied
*/
void copyInjectionPointMessage(InjectionPointMessage &ipm) {ipm.CopyFrom(m_ip);}
};
#ifdef CONFIG_INJECTIONPOINT_HOPS
#include "comm/InjectionPointHopsMessage.pb.h"
class SmartHops;
/**
* \class InjectionPointHops
*
* Concrete injection point which contains a hop chain to the target
* trace instruction.
*/
class InjectionPointHops : public InjectionPointBase {
private:
SmartHops *m_sa; // !< Hop calculator which generates the hop chain
// Boundaries must be signed to ensure, they can be initialized as outside of beginning
// of the trace (instr is -1).
long m_curr_instr1; // !< Lower end of instructions for which currently a hop chain is available
long m_curr_instr2; // !< Upper end of instructions for which currently a hop chain is available
bool m_initialized;
std::vector<InjectionPointMessage> m_results;
void init();
public:
InjectionPointHops() : InjectionPointBase(), m_sa(NULL), m_curr_instr1(-1),
m_curr_instr2(-1), m_initialized(false) {}
virtual ~InjectionPointHops();
/**
* Parses a hop chain from a injection instruction (trace offset).
* @param instr1 trace instruction offset of beginning of equivalence class
* @param instr2 trace instruction offset of ending of equivalence class
*/
virtual void parseFromInjectionInstr(unsigned instr1, unsigned instr2);
};
typedef InjectionPointHops ConcreteInjectionPoint;
#else
#include "comm/InjectionPointStepsMessage.pb.h"
/**
* \class InjectionPointSteps
*
* Concrete injection point which contains a trace instruction offset.
*/
class InjectionPointSteps : public InjectionPointBase {
public:
virtual ~InjectionPointSteps() {}
/**
* Parses a trace offset from a injection instruction (trace offset),
* so it effectively just stores the value in the protobuf message.
* @param instr1 trace instruction offset of beginning of equivalence class
* @param instr2 trace instruction offset of ending of equivalence class
*/
virtual void parseFromInjectionInstr(unsigned instr1, unsigned instr2);
};
typedef InjectionPointSteps ConcreteInjectionPoint;
#endif
} /* namespace fail */
#endif /* INJECTIONPOINT_HPP_ */

View File

@ -0,0 +1,110 @@
#include "InjectionPoint.hpp"
#include "util/smarthops/SmartHops.hpp"
#include <algorithm>
#include <limits>
namespace fail {
InjectionPointHops::~InjectionPointHops() {
if (m_initialized) {
delete m_sa;
}
}
void InjectionPointHops::init()
{
m_sa = new SmartHops();
char * elfpath = getenv("FAIL_TRACE_PATH");
if (elfpath == NULL) {
m_log << "FAIL_TRACE_PATH not set :(" << std::endl;
exit(-1);
} else {
m_sa->init((const char*) elfpath);
}
m_initialized = true;
}
/*
* if (!it->has_costs()) {
m_log << "FATAL ERROR: Costs must be delivered in order to calculate minimum costs" << endl;
}
*/
void InjectionPointHops::parseFromInjectionInstr(unsigned instr1, unsigned instr2) {
if (!m_initialized) {
init();
}
// clear results older than instr1, as the input needs to be sorted by instr1, these
// results won't be needed anymore
std::vector<InjectionPointMessage>::iterator it = m_results.begin(), delete_iterator = m_results.end();
for (; it != m_results.end(); it++) {
if (!it->has_target_trace_position()) {
m_log << "FATAL ERROR: Target trace offset must be delivered in order to calculate minimum costs" << std::endl;
m_log << m_results.size() << std::endl;
exit(0);
}
if (it->target_trace_position() < instr1) {
delete_iterator = it;
}
}
// Delete as chunk
if (delete_iterator != m_results.end()) {
m_results.erase(m_results.begin(), delete_iterator);
m_curr_instr1 = instr1;
}
// Calculate next needed results
while ((long)instr2 > m_curr_instr2) {
// if instr1 is bigger than nex instr2, we can skip instructions
// And current instr1 will be newly defined
unsigned new_curr_instr2;
if ((long)instr1 > m_curr_instr2) {
m_curr_instr1 = instr1;
new_curr_instr2 = instr1;
} else {
new_curr_instr2 = m_curr_instr2 + 1;
}
InjectionPointMessage m;
if (!m_sa->calculateFollowingHop(m, new_curr_instr2)) {
m_log << "FATAL ERROR: Trace does not contain enough instructions (no instruction with offset "
<< new_curr_instr2 << ")" << std::endl;
exit(-1);
}
m_results.push_back(m);
m_curr_instr2 = new_curr_instr2;
}
// Choose minimum
InjectionPointMessage *min_cost_msg;
uint32_t min_costs = std::numeric_limits<uint32_t>::max();
std::vector<InjectionPointMessage>::iterator search, search_end;
search = m_results.begin() + (instr1 - m_curr_instr1);
search_end = m_results.begin() + (instr2 - m_curr_instr1);
// Single-instruction eqivalence class
if (search == search_end) {
m_ip = *search;
} else {
for (;search != search_end; search++) {
if (!search->has_costs()) {
m_log << "FATAL ERROR: Costs must be delivered in order to calculate minimum costs" << std::endl;
exit(-1);
}
if (search->costs() < min_costs) {
min_cost_msg = &(*search);
min_costs = search->costs();
}
}
m_ip = *min_cost_msg;
}
}
} /* namespace fail */

View File

@ -0,0 +1,10 @@
#include "InjectionPoint.hpp"
namespace fail {
void InjectionPointSteps::parseFromInjectionInstr(unsigned instr1, unsigned instr2) {
// compute hops
m_ip.set_injection_instr(instr2);
}
} /* namespace fail */

View File

@ -9,7 +9,7 @@
#endif
#ifdef BUILD_ARM
#include "arm/ARMArchitecture.hpp"
#include "arm/ArmArchitecture.hpp"
#endif
#endif

View File

@ -57,34 +57,53 @@ elseif(BUILD_T32)
arm/ArmDisassembler.cc
)
endif(BUILD_ARM)
elseif(BUILD_PANDA)
include_directories(${PROJECT_SOURCE_DIR}/debuggers/openocd)
set(SRCS
CPU.cc
CPUState.cc
Listener.cc
ListenerManager.cc
SALConfig.cc
Register.cc
SimulatorController.cc
panda/PandaController.cc
panda/PandaArmCPU.cc
panda/PandaListener.cc
)
if(BUILD_ARM)
set(SRCS ${SRCS}
panda/PandaArmCPU.cc
)
endif(BUILD_ARM)
endif(BUILD_BOCHS)
if(BUILD_X86)
set(SRCS ${SRCS}
x86/X86Architecture.cc
)
set(ARCH_TOOL_PREFIX "" CACHE PATH "Setup prefix for binutils, e.g., arm-none-eabi- or tricore-, ..")
set(ARCH_TOOL_PREFIX "" CACHE PATH "Setup prefix for binutils, e.g., arm-none-eabi- or tricore-, ..")
elseif(BUILD_ARM)
set(SRCS ${SRCS}
arm/ArmArchitecture.cc
)
set(ARCH_TOOL_PREFIX "arm-none-eabi-" CACHE PATH "Setup prefix for binutils, e.g., arm-none-eabi- or tricore-, ..")
set(ARCH_TOOL_PREFIX "arm-none-eabi-" CACHE PATH "Setup prefix for binutils, e.g., arm-none-eabi- or tricore-, ..")
endif(BUILD_X86)
if(BUILD_GEM5)
message(STATUS "[${PROJECT_NAME}] Generating SConscript in ${CMAKE_CURRENT_BINARY_DIR}/gem5")
set(additional_libs "")
message(STATUS "[${PROJECT_NAME}] Generating SConscript in ${CMAKE_CURRENT_BINARY_DIR}/gem5")
set(additional_libs "")
foreach(exp ${EXPERIMENTS_ACTIVATED})
set(additional_libs "${additional_libs} '-lfail-${exp}',")
endforeach(exp)
foreach(exp ${EXPERIMENTS_ACTIVATED})
set(additional_libs "${additional_libs} '-lfail-${exp}',")
endforeach(exp)
foreach(plug ${PLUGINS_ACTIVATED})
set(additional_libs "${additional_libs} '-lfail-${plug}',")
endforeach(plug)
foreach(plug ${PLUGINS_ACTIVATED})
set(additional_libs "${additional_libs} '-lfail-${plug}',")
endforeach(plug)
set(GEM5_SAL_SRCS "'${CMAKE_CURRENT_SOURCE_DIR}/gem5/Gem5Wrapper.cc'")
configure_file(gem5/SConscript.in ${CMAKE_CURRENT_BINARY_DIR}/gem5/SConscript)
set(GEM5_SAL_SRCS "'${CMAKE_CURRENT_SOURCE_DIR}/gem5/Gem5Wrapper.cc'")
configure_file(gem5/SConscript.in ${CMAKE_CURRENT_BINARY_DIR}/gem5/SConscript)
endif(BUILD_GEM5)
# Don't include these sources if perf-stuff is disabled
# (reduces compiler overhead):

View File

@ -18,6 +18,9 @@
#else
#error Active config currently not supported!
#endif
#elif defined BUILD_PANDA
#include "panda/PandaConfig.hpp"
#include "panda/PandaArmCPU.hpp"
#else
#error SAL Config Target not defined
#endif

View File

@ -5,7 +5,8 @@ namespace fail {
// Flag initialization depends on the current selected simulator
// (For now, the initialization values are all the same):
#if defined BUILD_BOCHS || defined BUILD_GEM5 || \
defined BUILD_T32 || defined BUILD_QEMU
defined BUILD_T32 || defined BUILD_QEMU || \
defined BUILD_PANDA
const address_t ADDR_INV = static_cast<address_t> (0);
const address_t ANY_ADDR = static_cast<address_t> (-1);
const unsigned ANY_INSTR = static_cast<unsigned> (-1);

View File

@ -14,6 +14,8 @@
#include "qemu/QEMUConfig.hpp"
#elif defined BUILD_T32
#include "t32/T32Config.hpp"
#elif defined BUILD_PANDA
#include "panda/PandaConfig.hpp"
#else
#error SAL Config Target not defined
#endif

View File

@ -36,6 +36,14 @@ namespace fail {
typedef T32Controller ConcreteSimulatorController; //!< concrete simulator (type)
}
#elif defined BUILD_PANDA
#include "panda/PandaController.hpp"
namespace fail {
typedef PandaController ConcreteSimulatorController; //!< concrete simulator (type)
}
#else
#error SAL Instance not defined

View File

@ -0,0 +1,21 @@
#include "PandaArmCPU.hpp"
#include "openocd_wrapper.hpp"
namespace fail {
regdata_t PandaArmCPU::getRegisterContent(const Register* reg) const
{
regdata_t data;
oocdw_read_reg(reg->getId(), &data);
return data;
}
void PandaArmCPU::setRegisterContent(const Register* reg, regdata_t value)
{
oocdw_write_reg(reg->getId(), value);
}
} // end-of-namespace: fail

View File

@ -0,0 +1,73 @@
#ifndef __PANDA_ARM_CPU_HPP__
#define __PANDA_ARM_CPU_HPP__
#include "../arm/ArmArchitecture.hpp"
#include "../arm/ArmCPUState.hpp"
namespace fail {
/**
* \class PandaArmCPU
*
* \c PandaArmCPU is the concrete CPU implementation for the TI Pandaboard ES. It
* implements the CPU interfaces \c ArmArchitecture and \c ArmCPUState.
* \c ArmArchitecture refers to architectural information (e.g. register \a count)
* while \c ArmCPUState encapsulates the CPU state (e.g. register \a content).
*/
class PandaArmCPU : public ArmArchitecture, public ArmCPUState {
private:
unsigned int m_Id; //!< the unique ID of this CPU
public:
/**
* Creates a new gem5 CPU for ARM based targets.
* @param id the unique ID of the CPU to be created (the first CPU0 has ID 0)
* @param system the gem5 system object
*/
PandaArmCPU(unsigned int id) : m_Id(id) { }
virtual ~PandaArmCPU() {}
/**
* Retrieves the register content from the current Pandaboard CPU.
* @param reg the destination register whose content should be retrieved
* @return the content of register \c reg
*/
regdata_t getRegisterContent(const Register* reg) const;
/**
* Sets the register content for the \a current Pandaboard CPU.
* @param reg the (initialized) register object whose content should be set
* @param value the new content of the register \c reg
*/
void setRegisterContent(const Register* reg, regdata_t value);
/**
* Retrieves the current instruction pointer (IP aka program counter, PC for short)
* for the current CPU \c this.
* @return the current instruction ptr address
*/
address_t getInstructionPointer() const { return getRegisterContent(getRegister(RI_IP)); }
/**
* Retrieves the current stack pointer for the current CPU \c this.
* @return the current stack ptr address
*/
address_t getStackPointer() const { return getRegisterContent(getRegister(RI_SP)); }
/**
* Retrieves the link register (return address when a function returns) for
* the current CPU \c this. See
* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/ch02s08s01.html
* for further information.
* @return the current link register address
*/
address_t getLinkRegister() const { return getRegisterContent(getRegister(RI_LR)); }
address_t getDfarRegister() const { return getRegisterContent(getRegister(RI_DFAR)); }
/**
* Returns the ID of the current CPU.
* @return the unique ID of \c this CPU object
*/
unsigned int getId() const { return m_Id; }
};
typedef PandaArmCPU ConcreteCPU; //!< the concrete CPU type for Pandaboard (ARM)
} // end-of-namespace: fail
#endif // __PANDA_ARM_CPU_HPP__

View File

@ -0,0 +1,50 @@
#ifndef __PANDA_BREAKPOINTS_AH__
#define __PANDA_BREAKPOINTS_AH__
#include "config/FailConfig.hpp"
#include "config/VariantConfig.hpp"
#if defined(BUILD_PANDA) && defined(CONFIG_EVENT_BREAKPOINTS)
#include "../../../debuggers/openocd/openocd_wrapper.hpp"
aspect PandaBreakpoints
{
advice "fail::BPSingleListener" : slice class
{
public:
bool onAddition()
{
// Setup Breakpoint on Pandaboard
struct halt_condition hc;
if (m_WatchInstrPtr == ANY_ADDR) {
hc.type = HALT_TYPE_SINGLESTEP;
} else {
hc.type = HALT_TYPE_BP;
}
hc.address = m_WatchInstrPtr;
hc.addr_len = 4; // Thumb? => 2
oocdw_set_halt_condition(&hc);
return true;
}
void onDeletion()
{
// Delete Breakpoint on Pandaboard
struct halt_condition hc;
if (m_WatchInstrPtr == ANY_ADDR) {
hc.type = HALT_TYPE_SINGLESTEP;
} else {
hc.type = HALT_TYPE_BP;
}
hc.address = m_WatchInstrPtr;
hc.addr_len = 4; // Thumb? => 2
oocdw_delete_halt_condition(&hc);
}
};
};
#endif // BUILD_PANDA && CONFIG_EVENT_BREAKPOINTS
#endif // __PANDA_BREAKPOINTS_AH__

View File

@ -0,0 +1,19 @@
/**
* \file PandaConfig.hpp
* \brief Type definitions and configuration settings for
* the Pandaboard.
*/
#ifndef __PANDA_CONFIG_HPP__
#define __PANDA_CONFIG_HPP__
namespace fail {
typedef uint32_t host_address_t; //!< the host memory address type
typedef uint32_t guest_address_t; //!< the guest memory address type
typedef uint32_t register_data_t; //!< register data type (32 bit)
typedef int timer_t; //!< type of timer IDs
} // end-of-namespace: fail
#endif // __PANDA_CONFIG_HPP__

View File

@ -0,0 +1,97 @@
#include <sstream>
#include "PandaController.hpp"
#include "PandaMemory.hpp"
#include "../SALInst.hpp"
#include "../Listener.hpp"
#include "openocd_wrapper.hpp"
#if defined(CONFIG_FIRE_INTERRUPTS)
#error Firing interrupts not implemented for Pandaboard
#endif
#if defined(CONFIG_SR_RESTORE) || defined(CONFIG_SR_SAVE)
#error Save/Restore is not yet implemented for Pandaboard
#endif
#if defined(CONFIG_EVENT_IOPORT)
#error IoPort events not implemented for pandaboard
#endif
namespace fail {
PandaController::PandaController()
: SimulatorController(new PandaMemoryManager()), m_CurrFlow(NULL)
{
addCPU(new ConcreteCPU(0));
}
PandaController::~PandaController()
{
delete m_Mem;
std::vector<ConcreteCPU*>::iterator it = m_CPUs.begin();
while (it != m_CPUs.end()) {
delete *it;
it = m_CPUs.erase(it);
}
}
void PandaController::onTimerTrigger(void* thisPtr)
{
// FIXME: The timer logic can be modified to use only one timer in Bochs.
// (For now, this suffices.)
TimerListener* pli = static_cast<TimerListener*>(thisPtr);
// Check for a matching TimerListener. (In fact, we are only
// interessted in the iterator pointing at pli.)
ListenerManager::iterator it = std::find(simulator.m_LstList.begin(),
simulator.m_LstList.end(), pli);
// TODO: This has O(|m_LstList|) time complexity. We can further improve this
// by creating a method such that makeActive(pli) works as well,
// reducing the time complexity to O(1).
simulator.m_LstList.makeActive(it);
simulator.m_LstList.triggerActiveListeners();
}
bool PandaController::save(const std::string& path)
{
// TODO
return true;
}
void PandaController::restore(const std::string& path)
{
clearListeners();
// TODO
}
void PandaController::reboot()
{
clearListeners();
oocdw_reboot();
}
void PandaController::terminate(int exCode)
{
oocdw_finish(exCode);
/*
* Resume to let OpenOCD terminate properly
* This call does not return!
*/
m_Flows.resume();
}
simtime_t PandaController::getTimerTicks()
{
return oocdw_read_cycle_counter();
}
simtime_t PandaController::getTimerTicksPerSecond()
{
return 1200*1000*1000;
}
} // end-of-namespace: fail

View File

@ -0,0 +1,77 @@
#ifndef __PANDA_CONTROLLER_HPP__
#define __PANDA_CONTROLLER_HPP__
#include <string>
#include <cassert>
#include <iostream>
#include <iomanip>
#include <string.h>
#include "../SimulatorController.hpp"
namespace fail {
class ExperimentFlow;
struct target;
/**
* \class PandaController
* Pandaboard-specific implementation of a SimulatorController.
*/
class PandaController : public SimulatorController {
private:
ExperimentFlow* m_CurrFlow; //!< Stores the current flow for save/restore-operations
public:
/**
* Initialize the controller, i.e., add the number of simulated CPUs.
*/
PandaController();
~PandaController();
/* ********************************************************************
* Standard Listener Handler API:
* ********************************************************************/
/**
* Internal handler for TimerListeners. This method is called when a previously
* registered timer in openocd main loop triggers. It searches for the
* provided TimerListener object within the ListenerManager and fires
* such an event by calling * \c triggerActiveListeners().
* @param thisPtr a pointer to the TimerListener-object triggered.
*/
void onTimerTrigger(void *thisPtr);
/* ********************************************************************
* Simulator Controller & Access API:
* ********************************************************************/
/**
* Save simulator state.
* @param path Location to store state information
* @return \c true if the state has been successfully saved, \c false otherwise
*/
bool save(const std::string& path);
/**
* Restore simulator state. Clears all Listeners.
* @param path Location to previously saved state information
*/
void restore(const std::string& path);
/**
* Reboot simulator. Clears all Listeners.
*/
void reboot();
/**
* Fire an interrupt.
* @param irq Interrupt to be fired
*/
//void fireInterrupt(unsigned irq);
virtual simtime_t getTimerTicks();
virtual simtime_t getTimerTicksPerSecond();
// Overloading super method to terminate OpenOCD properly
void terminate(int exCode = EXIT_SUCCESS);
};
} // end-of-namespace: fail
#endif // __PANDA_CONTROLLER_HPP__

View File

@ -0,0 +1,11 @@
#include "PandaListener.hpp"
#include "../SALInst.hpp"
namespace fail {
void onTimerTrigger(void* thisPtr)
{
simulator.onTimerTrigger(thisPtr);
}
} // end-of-namespace: fail

View File

@ -0,0 +1,13 @@
#ifndef __PANDA_LISTENER_HPP__
#define __PANDA_LISTENER_HPP__
namespace fail {
/**
* Global internal handler for (Pandaboard) TimerListeners.
*/
void onTimerTrigger(void *thisPtr);
} // end-of-namespace: fail
#endif // __PANDA_LISTENER_HPP__

View File

@ -0,0 +1,129 @@
#ifndef __PANDA_MEMORY_HPP__
#define __PANDA_MEMORY_HPP__
#include "../Memory.hpp"
#include "openocd_wrapper.hpp"
namespace fail {
/**
* \class PandaMemoryManager
* Represents a concrete implemenation of the abstract
* MemoryManager to provide access to the memory pool
* of the pandaboard.
*/
class PandaMemoryManager : public MemoryManager {
public:
/**
* Constructs a new MemoryManager object and initializes
* it's attributes appropriately.
*/
PandaMemoryManager() : MemoryManager() { }
/**
* Retrieves the size of the available simulated memory.
* @return the size of the memory pool in bytes
*/
size_t getPoolSize() const
{
//ToDo (PORT): Get pool size from ELF file?
return 0xFFFFFFFF;
}
/**
* Retrieves the starting address of the host memory. This is the
* first valid address in memory.
* @return the starting address
*/
host_address_t getStartAddr() const
{
//ToDo Get Start address from ELF file!?
return 0;
}
/**
* Retrieves the byte at address \a addr in the memory.
* @param addr The guest address where the byte is located.
* The address is expected to be valid.
* @return the byte at \a addr
*/
byte_t getByte(guest_address_t addr)
{
// ToDo: Address translation
uint8_t buf;
oocdw_read_from_memory(addr, 1, 1, &buf);
return buf;
}
/**
* Retrieves \a cnt bytes at address \a addr from the memory.
* @param addr The guest address where the bytes are located.
* The address is expected to be valid.
* @param cnt The number of bytes to be retrieved. \a addr + \a cnt
* is expected to not exceed the memory limit.
* @param dest Pointer to destination buffer to copy the data to.
*/
void getBytes(guest_address_t addr, size_t cnt, void *dest)
{
// ToDo: Address translation
uint8_t *d = static_cast<uint8_t *>(dest);
// Write in 4-Byte chunks
// ToDo: Correct byte ordering?
if (cnt >= 4) {
oocdw_read_from_memory(addr, 4, cnt / 4, d);
}
if ((cnt % 4) != 0) {
oocdw_read_from_memory(addr + (cnt/4) * 4, 1, cnt % 4, d);
}
}
/**
* Writes the byte \a data to memory.
* @param addr The guest address to write.
* The address is expected to be valid.
* @param data The new byte to write
*/
void setByte(guest_address_t addr, byte_t data)
{
// ToDo: Address translation
oocdw_write_to_memory(addr, 1, 1, &data, true);
}
/**
* Copies data to memory.
* @param addr The guest address to write.
* The address is expected to be valid.
* @param cnt The number of bytes to be retrieved. \a addr + \a cnt
* is expected to not exceed the memory limit.
* @param src Pointer to data to be copied.
*/
void setBytes(guest_address_t addr, size_t cnt, void const *src)
{
// ToDo: Address translation
uint8_t const *s = static_cast<uint8_t const *>(src);
// Write in 4-Byte chunks
// ToDo: Correct byte ordering?
if (cnt >= 4) {
oocdw_write_to_memory(addr, 4, cnt / 4, s, true);
}
if ((cnt % 4) != 0) {
oocdw_write_to_memory(addr + (cnt/4) * 4, 1, cnt % 4, s, true);
}
}
};
} // end-of-namespace: fail
#endif // __PANDA_MEMORY_HPP__

View File

@ -0,0 +1,52 @@
#ifndef __PANDA_TIMER_AH__
#define __PANDA_TIMER_AH__
#include "config/VariantConfig.hpp"
#include "config/FailConfig.hpp"
#if defined(BUILD_PANDA)
#include "../../../debuggers/openocd/openocd_wrapper.hpp"
#include "PandaListener.hpp"
aspect PandaTimer {
advice "fail::TimerListener" : slice class {
public:
bool onAddition()
{
// Register the timer listener in the Bochs simulator:
timer_id_t id = m_registerTimer(this);
if (id == -1) {
setId(INVALID_TIMER);
return false; // unable to register the timer (error in Bochs' function call)
}
setId(id);
return true;
}
void onDeletion()
{
// Unregister the time listener:
m_unregisterTimer(this);
}
private:
timer_id_t m_registerTimer(TimerListener* pev)
{
assert(pev != NULL && "FATAL ERROR: TimerListener object ptr cannot be NULL!");
return static_cast<timer_id_t>(
oocdw_register_timer(pev, fail::onTimerTrigger,
pev->getTimeout() /*timeout in microseconds*/,
true /*start immediately*/, "Fail*: PandaController"/*name*/));
}
bool m_unregisterTimer(TimerListener* pev)
{
assert(pev != NULL && "FATAL ERROR: TimerListener object ptr cannot be NULL!");
oocdw_deactivate_timer(static_cast<unsigned>(pev->getId()));
return oocdw_unregisterTimer(static_cast<unsigned>(pev->getId()));
}
};
};
#endif // BUILD_PANDA && CONFIG_EVENT_BREAKPOINTS
#endif // __PANDA_LISTENER_AH__

View File

@ -0,0 +1,67 @@
#ifndef __PANDA_WATCHPOINTS_AH__
#define __PANDA_WATCHPOINTS_AH__
#include "config/FailConfig.hpp"
#include "config/VariantConfig.hpp"
#if defined(BUILD_PANDA) && defined(CONFIG_EVENT_MEMREAD) && defined(CONFIG_EVENT_MEMWRITE)
#include "../../../debuggers/openocd/openocd_wrapper.hpp"
aspect PandaWatchpoints
{
advice "fail::MemAccessListener" : slice class
{
int m_t32access;
public:
bool onAddition()
{
// Setup Watchpoint on Pandaboard (if it can't be realized as WP, MMU will be utilized)
struct halt_condition hc;
switch (m_WatchType) {
case MemAccessEvent::MEM_READ:
hc.type = HALT_TYPE_WP_READ; break;
case MemAccessEvent::MEM_WRITE:
hc.type = HALT_TYPE_WP_WRITE; break;
case MemAccessEvent::MEM_READWRITE:
hc.type = HALT_TYPE_WP_READWRITE; break;
default: return false;
}
hc.address = m_WatchAddr;
hc.addr_len = m_WatchWidth;
oocdw_set_halt_condition(&hc);
return true;
}
void onDeletion()
{
// Remove Watchpoint from Pandaboard (if it was realized by MMU, it will be reprogrammed)
struct halt_condition hc;
switch (m_WatchType) {
case MemAccessEvent::MEM_READ:
hc.type = HALT_TYPE_WP_READ; break;
case MemAccessEvent::MEM_WRITE:
hc.type = HALT_TYPE_WP_WRITE; break;
case MemAccessEvent::MEM_READWRITE:
hc.type = HALT_TYPE_WP_READWRITE; break;
default: return; // ToDo: Error handling
}
hc.address = m_WatchAddr;
hc.addr_len = m_WatchWidth;
// ToDo: Error handling
oocdw_delete_halt_condition(&hc);
}
};
};
#endif // BUILD_PANDA && CONFIG_EVENT_MEMREAD && CONFIG_EVENT_MEMWRITE
#endif // __PANDA_WATCHPOINTS_AH__

View File

@ -12,7 +12,6 @@
#include "WatchpointManagerSlice.ah" // slice class "WatchpointManagerSlice"
#include "WatchpointControllerSlice.ah" // slice class "WatchpointControllerSlice"
#include "../ListenerManager.hpp"
#include "../Listener.hpp"
#include "WatchpointBuffer.hpp"
#include "../SALInst.hpp"

View File

@ -70,15 +70,21 @@ else()
endif()
mark_as_advanced(FAIL_OBJDUMP)
# compile smarthops calculator if needed
if(CONFIG_INJECTIONPOINT_HOPS)
add_subdirectory(smarthops)
set(ADDITIONAL_LIBS fail-smarthops)
endif(CONFIG_INJECTIONPOINT_HOPS)
add_library(fail-util ${SRCS})
add_dependencies(fail-util fail-comm)
target_link_libraries(fail-util fail-comm ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${LibIberty_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBDWARF_LIBRARIES} ${LIBELF_LIBRARIES})
target_link_libraries(fail-util fail-comm ${ADDITIONAL_LIBS} ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${LibIberty_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBDWARF_LIBRARIES} ${LIBELF_LIBRARIES})
option(BUILD_LLVM_DISASSEMBLER "Build the LLVM-based disassembler (LLVM 3.3 preferred, for 3.1 and 3.2 read doc/how-to-build.txt)" OFF)
if (BUILD_LLVM_DISASSEMBLER)
add_subdirectory(llvmdisassembler)
endif (BUILD_LLVM_DISASSEMBLER)
### Tests
add_executable(memorymap-test testing/memorymap-test.cc)
target_link_libraries(memorymap-test fail-util)

View File

@ -0,0 +1,10 @@
set(SRCS
SmartHops.cc
SmartHops.hpp
TraceReader.cc
TraceReader.hpp
)
add_library(fail-smarthops ${SRCS})
# ToDo: Do we really need this dependency?
add_dependencies(fail-smarthops fail-comm)

View File

@ -0,0 +1,260 @@
#include "SmartHops.hpp"
#include <algorithm>
#include <limits>
#include <vector>
namespace fail {
#define COST_CHANGE 1
#define COST_NO_CHANGE 2
void SmartHops::init(const char *filename) {
m_trace_reader.openTraceFile(filename);
}
void SmartHops::convertToIPM(std::vector<result_tuple > &result, unsigned costs, InjectionPointMessage &ipm) {
ipm.Clear();
// If checkpoint at beginning of hop-chain, add its id to HopChain
std::vector<result_tuple >::iterator it_hop = result.begin();
if (it_hop != result.end() && it_hop->first.second == ACCESS_CHECKPOINT) {
ipm.set_checkpoint_id(it_hop->first.first);
it_hop++;
}
if (result.size() > 0 && result.back().first.second != ACCESS_CHECKPOINT) {
ipm.set_target_trace_position(result.back().second);
} else {
ipm.set_target_trace_position(0);
}
ipm.set_costs(costs);
for (; it_hop != result.end();
it_hop++) {
InjectionPointMessage_Hops *hop = ipm.add_hops();
hop->set_address(it_hop->first.first);
enum InjectionPointMessage_Hops_AccessType at;
switch (it_hop->first.second) {
case ACCESS_NONE:
at = InjectionPointMessage_Hops_AccessType_EXECUTE;
break;
case ACCESS_READ:
at = InjectionPointMessage_Hops_AccessType_READ;
break;
case ACCESS_WRITE:
at = InjectionPointMessage_Hops_AccessType_WRITE;
break;
case ACCESS_READORWRITE:
m_log << "ReadOrWrite memory access event not yet"
" covered" << std::endl;
exit(-1);
break;
case ACCESS_CHECKPOINT:
m_log << "Checkpoint not allowed after beginning of hop chain" << std::endl;
exit(-1);
}
hop->set_accesstype(at);
}
}
bool SmartHops::calculateFollowingHop(InjectionPointMessage &ip, unsigned instruction_offset) {
if (instruction_offset == 0) {
m_result.clear();
m_costs = 0;
convertToIPM(m_result, m_costs, ip);
return true;
}
while (m_trace_pos < instruction_offset) {
//m_log << "Calculating " << instruction_offset << std::endl;
if (!m_trace_reader.getNextTraceEvents(m_trace_pos, m_trace_events)) {
return false;
}
// Policy when multiple trace events: Choose the one with smallest last_pos
trace_event_tuple_t *best_te = NULL;
trace_pos_t last_pos = std::numeric_limits<trace_pos_t>::max();
bool hop_found = false;
bool checkpoint_forbidden = false;
for (std::vector<trace_event_tuple_t >::iterator it_te = m_trace_events.begin();
it_te != m_trace_events.end();
it_te++) {
// Don't use watchpoints?
if (!m_use_watchpoints && it_te->second != ACCESS_NONE) {
continue;
}
// Find last pos of current trace event
std::map<trace_event_tuple_t, trace_pos_t>::iterator it_lp = m_last_positions.find(*it_te);
// Not known? => Single hop, result calculation complete
if (it_lp == m_last_positions.end()) {
m_last_positions.insert(std::pair<trace_event_tuple_t, trace_pos_t>(*it_te, m_trace_pos));
// New instruction => single hop
if (!hop_found) {
m_result.clear();
m_result.push_back(result_tuple(*it_te, m_trace_pos));
m_costs = COST_CHANGE;
hop_found = true;
}
} else {
if (it_lp->second < last_pos) {
last_pos = it_lp->second;
best_te = (trace_event_tuple_t*)&(it_lp->first);
}
it_lp->second = m_trace_pos;
}
}
if (hop_found) {
continue;
}
// Deletion of unnecessary hops
/*
* |----------------|
* |pos bigger than |
* |last pos of new | --> delete -->-|
* |trace_event? | |
* |----------------| |
* ^ |
* | v
* A B A C <<< Last result
* ^ ^
* Reverse Reverse
* iterator iterator
* rit_pre_last rit_last
*
*/
std::vector<result_tuple >::reverse_iterator rit_pre_last, rit_last, end;
rit_last = m_result.rbegin();
rit_pre_last = m_result.rbegin();
rit_pre_last++;
while (rit_last != m_result.rend()) {
trace_pos_t left_pos;
// Policy switch:
// No weights => last pos <= pos of rit_pre_last
// Weights => last pos < pos of rit_pre_last
if ((rit_pre_last == m_result.rend())) {
// First node in hop list is Checkpoint? => Look at result before CP-Creation
if (rit_last->first.second == ACCESS_CHECKPOINT) {
rit_pre_last = (m_checkpoints[rit_last->first.first]).second.rbegin();
// This should never happen:
if (rit_pre_last == (m_checkpoints[rit_last->first.first]).second.rend()) {
break;
}
// Don't allow deletion of CP, if afterwards
// too few of the olf hops would be deleted.
// (past before to be deleted CP)
// Should not exceed vector boundaries, if
// g_rollback_thresh*2 < (g_cp_thresh - g_cost_cp)
if ((*(rit_pre_last + m_rollback_thresh)).second < last_pos) {
checkpoint_forbidden = true;
break;
}
} else {
break;
}
}
left_pos = rit_pre_last->second;
if ((!m_use_weights && !(last_pos <= left_pos))
|| (m_use_weights && !(last_pos < left_pos))) {
break;
}
// Hop a->b is not allowed if last pos of b is at a
// but a is not b
// e.g. instruction x with mem access at y
// a is WP y, and b is BP x
// OR a is BP x, and b is WP y but instruction
// at position a has also memory access at y
if (rit_pre_last != m_result.rend()) {
if ((last_pos == rit_pre_last->second) &&
rit_pre_last->first != *best_te) {
break;
}
}
// Right hop will be deleted
// => Recalculate costs
// If to be deleted hop is a checkpoint:
// There will be no past in the trace
// Reconfigure result and iterators
if (rit_last->first.second == ACCESS_CHECKPOINT) {
m_costs = m_checkpoints[rit_last->first.first].first;
m_result.clear();
std::vector<result_tuple > *tmp = &(m_checkpoints[rit_last->first.first].second);
m_result.insert(m_result.end(), tmp->begin(), tmp->end());
rit_last = m_result.rbegin();
rit_pre_last = m_result.rbegin();
rit_pre_last++;
// CP could be removed from m_checkpoints, but to do this
// m_checkpoints needs to be a map (CP-ID is implicit as vector index)
continue;
}
if (rit_pre_last->first == rit_last->first) {
m_costs -= COST_NO_CHANGE;
} else {
m_costs -= COST_CHANGE;
}
// Delete element described by rit_last
// Deletion of elements described by reverse iterator works like this
m_result.erase((rit_last+1).base());
rit_last = rit_pre_last;
rit_pre_last++;
}
// Add costs for new hop
if (*best_te == (m_result.back()).first) {
m_costs += COST_NO_CHANGE;
} else {
m_costs += COST_CHANGE;
}
// Check if Checkpoint needed
if (m_use_checkpoints && (m_costs > m_cp_thresh) && !checkpoint_forbidden) {
checkpoint_tuple_t new_cp(m_costs, std::vector<result_tuple >(m_result));
m_checkpoints.push_back(new_cp);
m_result.clear();
m_result.push_back(result_tuple(trace_event_tuple_t(m_next_cp_id++,
ACCESS_CHECKPOINT),
m_trace_pos));
m_costs = m_cost_cp;
} else {
// Add new hop
m_result.push_back(result_tuple(*best_te, m_trace_pos));
}
}
InjectionPointMessage ipm;
convertToIPM(m_result, m_costs, ip);
return true;
}
} // end of namespace

View File

@ -0,0 +1,90 @@
#ifndef SMART_ALGORITHM__HPP
#define SMART_ALGORITHM__HPP
#include <map>
#include <vector>
#include "TraceReader.hpp"
#include "comm/InjectionPointHopsMessage.pb.h"
#include "util/Logger.hpp"
namespace fail {
typedef std::pair<trace_event_tuple_t, trace_pos_t > result_tuple;
// COSTS NAVIGATIONAL RECORD
typedef std::pair<unsigned int, std::vector<result_tuple > > checkpoint_tuple_t;
/**
* \class SmartHops
*
* Calculator for (optimal) hop chains on the basis of a simple cost model.
* Currently hardcoded cost model for PandaBoard (horizontal hops cost
* twice as much as diagonal hops).
* Calculates stream based (only regarding the next trace event) and so
* it can only calculate for ascending trace instruction offsets.
*/
class SmartHops {
public:
// ToDo: If you want to use checkoints as additional hop-chain-element, you may switch
// m_use_checkpoints to true, but there will be additional changes needed for this to fully work.
// The sal must, for example, generate CPs at the given positions
SmartHops() : m_trace_pos(0), m_costs(0), m_next_cp_id(0), m_log("SmartHops", false), m_use_watchpoints(true),
m_use_weights(true), m_use_checkpoints(false), m_cp_thresh(0), m_cost_cp(0), m_rollback_thresh(0) {}
/**
* Initializes the used TraceReader with given trace file path
* @param filename Path to the trace file
*/
void init(const char *filename);
/**
* Initializes the used TraceReader with given trace file path
* @param filename Path to the trace file
* @returns \c true if calculation succeeded and \c false if it did not
*/
bool calculateFollowingHop(InjectionPointMessage &ip, unsigned instruction_offset);
private:
/**
* Converts internal representation of a hop chain to a
* InjectionPointMessage. The delivered InjectionPointMessage is
* cleared before parsing.
* @param result Internal representation of a hop chain
* @param costs Costs of the hop chain (extracted from cost model)
* @param ipm InjectionPointMessage to which the hop chain is parsed
*/
void convertToIPM(std::vector<result_tuple > &result, unsigned costs, InjectionPointMessage &ipm);
unsigned int m_trace_pos;
unsigned int m_costs;
TraceReader m_trace_reader;
unsigned int m_next_cp_id;
Logger m_log;
bool m_use_watchpoints;
bool m_use_weights;
bool m_use_checkpoints;
unsigned int m_cp_thresh;
unsigned int m_cost_cp;
// Must be smaller than ((COST_CP_THRESH - COST_CP) / 2)
// If too high: Costs per dynamic instruction will approach
// COST_CP_THRESH but number of CPs can be reduced drastically
unsigned int m_rollback_thresh;
std::map<trace_event_tuple_t, trace_pos_t> m_last_positions;
std::vector<checkpoint_tuple_t > m_checkpoints;
std::vector<trace_event_tuple_t > m_trace_events;
std::vector<result_tuple > m_result;
};
} // end of namespace
#endif // SMART_ALGORITHM__HPP

View File

@ -0,0 +1,106 @@
#include "TraceReader.hpp"
#include <iostream>
#include <fstream>
#include <string>
using std::endl;
using fail::ProtoIStream;
namespace fail {
TraceReader::~TraceReader()
{
delete ps;
delete normal_stream;
delete gz_stream;
}
std::istream& openStream(const char *input_file,
std::ifstream& normal_stream, igzstream& gz_stream, Logger &out_stream) {
normal_stream.open(input_file);
if (!normal_stream) {
out_stream << "FATAL ERROR: couldn't open " << input_file << endl;
exit(-1);
}
unsigned char b1, b2;
normal_stream >> b1 >> b2;
if (b1 == 0x1f && b2 == 0x8b) {
normal_stream.close();
gz_stream.open(input_file);
if (!gz_stream) {
out_stream << "couldn't open " << input_file << endl;
exit(-1);
}
return gz_stream;
}
normal_stream.seekg(0);
return normal_stream;
}
bool TraceReader::openTraceFile(const char *filename, unsigned int num_inst)
{
normal_stream = new std::ifstream();
gz_stream = new igzstream();
ps = new fail::ProtoIStream(&openStream(filename, *normal_stream, *gz_stream, m_log));
m_max_num_inst = num_inst;
return true;
}
bool TraceReader::getNextTraceEvents(trace_pos_t& trace_pos,
std::vector<trace_event_tuple_t >& trace_events)
{
// Stop after fixed number of instructions, if given as command line argument
if ((m_max_num_inst > 0) && (m_current_position > m_max_num_inst)) {
return false;
}
trace_pos = m_current_position;
// Delivered trace_events vector does not have to be
// empty, so it must be cleared
trace_events.clear();
if (m_current_position == 1) {
if (!ps->getNext(&ev)) {
return false;
}
ev_avail = true;
}
if (!ev_avail) {
return false;
}
trace_events.push_back(trace_event_tuple_t(ev.ip(), ACCESS_NONE));
ev_avail = false;
// read possible memory accesses and the next instruction
while (ps->getNext(&ev)) {
if (!ev.has_memaddr()) {
ev_avail = true;
break;
}
// Add a trace_event for every byte in memory access.
// This breaks down the calculations to multiple
// memory accesses of length 1. No more complexity
// is needed in hop calculations.
if (ev.has_width()) {
for (unsigned int i = 0; i < ev.width(); i++) {
trace_events.push_back(
trace_event_tuple_t(ev.memaddr() + i,
ev.accesstype() == ev.READ ? ACCESS_READ : ACCESS_WRITE));
}
}
}
m_current_position++;
return true;
}
} // end of namespace

View File

@ -0,0 +1,60 @@
#ifndef __TRACE_READER_HPP
#define __TRACE_READER_HPP
#include <vector>
#include <iostream>
#include "sal/SALConfig.hpp"
#include "../ProtoStream.hpp"
#include "comm/TracePlugin.pb.h"
#include "../gzstream/gzstream.h"
#include "util/Logger.hpp"
namespace fail {
typedef enum {
ACCESS_NONE,
ACCESS_READ,
ACCESS_WRITE,
ACCESS_READORWRITE, // some architectures can't distinguish read and write WPs in general (e.g. x86)
ACCESS_CHECKPOINT,
} mem_access_type_e;
typedef uint32_t trace_pos_t;
typedef std::pair<address_t, mem_access_type_e> trace_event_tuple_t;
class TraceReader {
public:
TraceReader() : m_current_position(1),
ps(0),
normal_stream(0),
gz_stream(0),
m_max_num_inst(0),
ev_avail(false),
m_log("TraceReader", false) {}
~TraceReader();
// Returns ACCESS_NONE in mem_access if current instruction does not access memory
bool getNextTraceEvents(trace_pos_t& trace_pos,
std::vector<trace_event_tuple_t >& trace_events);
bool openTraceFile(const char *filename, unsigned int num_inst = 0);
private:
unsigned int m_current_position;
ProtoIStream* ps;
std::ifstream *normal_stream;
igzstream *gz_stream;
unsigned int m_max_num_inst;
Trace_Event ev;
bool ev_avail;
Logger m_log;
};
} // end of namespace
#endif //__TRACE_HPP

View File

@ -21,6 +21,7 @@ find_package(Protobuf REQUIRED)
include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library

View File

@ -24,6 +24,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
find_package(MySQL REQUIRED)
include_directories(${MYSQL_INCLUDE_DIR})
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library

View File

@ -25,6 +25,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
find_package(MySQL REQUIRED)
include_directories(${MYSQL_INCLUDE_DIR})
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library

View File

@ -24,6 +24,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
find_package(MySQL REQUIRED)
include_directories(${MYSQL_INCLUDE_DIR})
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library

View File

@ -24,6 +24,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
find_package(MySQL REQUIRED)
include_directories(${MYSQL_INCLUDE_DIR})
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library

View File

@ -29,6 +29,7 @@ find_package(Protobuf REQUIRED)
include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library

View File

@ -0,0 +1,36 @@
set(EXPERIMENT_NAME lra-simple-panda)
set(EXPERIMENT_TYPE LRASimplePandaExperiment)
configure_file(../instantiate-experiment.ah.in
${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY
)
## Setup desired protobuf descriptions HERE ##
set(MY_PROTOS
lra_simple.proto
)
set(MY_CAMPAIGN_SRCS
experiment.hpp
experiment.cc
campaign.hpp
campaign.cc
)
#### PROTOBUFS ####
find_package(Protobuf REQUIRED)
include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library
add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS})
add_dependencies(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 -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-smarthops fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} -lmysqlclient -Wl,--end-group)
install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)

View File

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

View File

@ -0,0 +1,26 @@
#ifndef __LRA_CAMPAIGN_HPP__
#define __LRA_CAMPAIGN_HPP__
#include "cpn/DatabaseCampaign.hpp"
#include "comm/ExperimentData.hpp"
#include "lra_simple.pb.h"
#include "util/ElfReader.hpp"
#include <google/protobuf/descriptor.h>
class LraSimpleExperimentData : public fail::ExperimentData {
public:
LraSimpleProtoMsg msg;
LraSimpleExperimentData() : fail::ExperimentData(&msg) {}
};
class LraSimpleCampaign : public fail::DatabaseCampaign {
virtual const google::protobuf::Descriptor * cb_result_message()
{ return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("LraSimpleProtoMsg"); }
virtual void cb_send_pilot(DatabaseCampaignMessage pilot);
virtual int expected_number_of_results(std::string variant, std::string benchmark) {
return 1;
}
};
#endif // __LRA_CAMPAIGN_HPP__

View File

@ -0,0 +1,372 @@
#include "experiment.hpp"
#include "experimentInfo.hpp"
#include "sal/SALConfig.hpp"
#include "sal/SALInst.hpp"
#include "sal/Listener.hpp"
#include "sal/Register.hpp"
#include "sal/Memory.hpp"
#include "config/FailConfig.hpp"
#include "util/WallclockTimer.hpp"
#include "util/gzstream/gzstream.h"
#include "util/WallclockTimer.hpp"
#include "efw/JobClient.hpp"
#include "lra_simple.pb.h"
#include "campaign.hpp"
#include "config/FailConfig.hpp"
#include <fstream>
#include <unistd.h>
#include <math.h>
// you need to have the tracing plugin enabled for this
#include "../plugins/tracing/TracingPlugin.hpp"
using namespace std;
using namespace fail;
// Check if configuration dependencies are satisfied:
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_EVENT_MEMREAD) || !defined(CONFIG_EVENT_MEMWRITE) || !defined(CONFIG_EVENT_TRAP)
#error This experiment needs: breakpoints, watchpoints and traps. Enable them in the configuration.
#endif
#define PREPARATION 0
int32_t correct_result[100] = {
0, 6, 5, 1, 6, 2, 7, 3,
8, 4, 1, 6, 5, 9, 5, 3,
0, 6, 5, 3, 7, 1, 7, 2,
8, 3, 9, 4, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
};
// ToDo: Move this functionality to SimulatorController
bool LRASimplePandaExperiment::navigateToInjectionPoint(ConcreteInjectionPoint &ip) {
Logger log_nav("navigator", false);
#ifdef CONFIG_INJECTIONPOINT_HOPS
// Hop nav
InjectionPointMessage ipm;
ip.copyInjectionPointMessage(ipm);
if (ipm.has_checkpoint_id()) {
// ToDo: Load CP state!
log_nav << "FATAL ERROR: CPs not yet implemented!" << endl;
simulator.terminate(1);
}
log_nav << "Navigating to next instruction at navigational costs of " << ipm.costs() << endl;
log_nav << "Length of hop-chain: " << ipm.hops_size() << endl;
for (int i = 0; i < ipm.hops_size(); i++) {
InjectionPointMessage_Hops h = ipm.hops(i);
BaseListener *hop, *ev;
// Nav-fail-bp
BPSingleListener ev_func_end(elfReader->getSymbol("main").getEnd() - 4 - LRASP_MAIN_ENDOFFSET);
simulator.addListener(&ev_func_end);
if (h.accesstype() == h.EXECUTE) {
log_nav << "BP at " << hex << h.address() << dec << endl;
BPSingleListener bp (h.address());
hop = &bp;
ev = simulator.addListenerAndResume(&bp);
} else {
log_nav << "WP at " << hex << h.address() << dec << "Access: " <<
(h.accesstype() == h.READ ? "R" :"W")<< endl;
MemAccessListener ma (h.address(), h.accesstype() == h.READ ?
MemAccessEvent::MEM_READ : MemAccessEvent::MEM_WRITE);
hop = &ma;
ev = simulator.addListenerAndResume(&ma);
}
log_nav << "Halted" << endl;
if (ev == &ev_func_end) {
log_nav << "Navigational error..." << endl;
simulator.clearListeners();
return false;
} else {
simulator.removeListener(&ev_func_end);
}
if (ev != hop) {
log_nav << "FATAL ERROR: Unexpected event while navigating!" << endl;
simulator.terminate(1);
}
}
#else
// Step nav
InjectionPointMessage ipm;
ip.copyInjectionPointMessage(ipm);
log_nav << "Navigating to instruction " << ipm.injection_instr() << endl;
BPSingleListener step(ANY_ADDR);
step.setCounter(ipm.injection_instr());
simulator.addListenerAndResume(&step);
#endif
return true;
}
bool LRASimplePandaExperiment::run()
{
Logger logger("lra-simpla-panda", false);
logger << "Startup" << endl;
elfReader = new ElfReader();
fail::JobClient *jobClient = new JobClient();
#if PREPARATION == 1
logger << "Preparation mode" << endl;
// STEP 1: run until main starts, save state, record trace
BPSingleListener func_begin(elfReader->getSymbol("main").getStart());
simulator.addListenerAndResume(&func_begin);
logger << "test_func() reached, beginning trace recording" << endl;
TracingPlugin tp;
ogzstream of(LRASP_TRACE);
if (of.bad()) {
logger << "FATAL ERROR: Trace file could not be opened." << endl;
simulator.terminate();
return false;
}
tp.setOstream(&of);
// this must be done *after* configuring the plugin:
simulator.addFlow(&tp);
BPSingleListener func_end(elfReader->getSymbol("main").getEnd() - 4 - 28);
simulator.addListener(&func_end);
BPSingleListener step(ANY_ADDR);
WallclockTimer timer;
timer.startTimer();
// count instructions
long counter = 0;
while (true) {
BaseListener *l = simulator.addListenerAndResume(&step);
if (l == &func_end) {
break;
}
counter++;
if ((counter % 1000) == 0) {
timer.stopTimer();
logger << "Traced " << counter << " insturctions in " << timer << " seconds" << endl;
timer.reset();
timer.startTimer();
}
}
logger << "Traced " << counter << " insturctions in " << timer << " seconds" << endl << endl;
logger << "golden run took " << dec << counter << " instructions" << endl;
simulator.removeFlow(&tp);
of.flush();
// serialize trace to file
if (of.fail()) {
logger << "failed to write to trace file"<< std::endl;
return false;
}
of.close();
#else // PREPARATION
unsigned executed_jobs = 0;
while (true) {
logger << "asking jobserver for parameters. Undone: "<<jobClient->getNumberOfUndoneJobs() << endl;
LraSimpleExperimentData param;
if (!jobClient->getParam(param)) {
logger << "Dying." << endl; // We were told to die.
simulator.terminate(1);
}
logger << "New param" << param.msg.DebugString() << endl;
// 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();
ConcreteInjectionPoint ip;
ip.parseFromCampaignMessage(param.msg.fsppilot());
for (unsigned experiment_id = 0; experiment_id < LRASP_NUM_EXP_PER_PILOT; ++experiment_id) {
LraSimpleProtoMsg_Result *result = param.msg.add_result();
executed_jobs ++;
WallclockTimer timer;
timer.startTimer();
/********************
* INITIALIZATION *
********************/
logger << "rebooting device" << endl;
// Restore to the image, which starts at address(main)
simulator.reboot();
// In this case, no entry navigation is needed
// Otherwise we will have to navigate to the pre entry instruction!!!
BPSingleListener func_begin(elfReader->getSymbol("main").getStart());
simulator.addListenerAndResume(&func_begin);
timer.stopTimer();
result->set_time_init(float(timer));
timer.reset();
/****************
* NAVIGATION *
****************/
logger << "Fastforwarding to instr #" << injection_instr << endl;
timer.startTimer();
if (!navigateToInjectionPoint(ip)) {
continue;
}
timer.stopTimer();
result->set_time_nav(float(timer));
timer.reset();
/***************
* INJECTION *
***************/
// We do a 8-bit flip burst
// Alternatively for single-bit-flips:
// data ^= 1 << experiment_id;
logger << "Injection bitflips at address " << hex << data_address << dec << endl;
timer.startTimer();
byte_t data = simulator.getMemoryManager().getByte(data_address);
data = ~data;
simulator.getMemoryManager().setByte(data_address, data); // write back data to register
timer.stopTimer();
result->set_time_inject(float(timer));
timer.reset();
/***************
* AFTERMATH *
***************/
logger << "Aftermath: Checking for wrong mem access, traps, timeout, wrong result or success" << endl;
timer.startTimer();
// Setup MMU
/*
* As the false positive rate is very high, if we watch a
* page with actively used memory and because of the high
* costs for a false positive (in the magnitude of seconds),
* we don't want to watch those areas.
*
* We must not watch the following areas:
* - UART I/O Port at 0x48020014 => don't watch page 0x48020000
* - .text-, .bss- and .data-segment at 0x83000000 to 0x83411000 (exclusive)
* - Stack at 0xBFD00000 to 0xC0000000
*/
MemAccessListener ev_unauth_mem_acc_1(0x0);
ev_unauth_mem_acc_1.setWatchWidth(0x48020000);
simulator.addListener(&ev_unauth_mem_acc_1);
MemAccessListener ev_unauth_mem_acc_2(0x48021000);
ev_unauth_mem_acc_2.setWatchWidth(0x83000000 - 0x48021000);
simulator.addListener(&ev_unauth_mem_acc_2);
MemAccessListener ev_unauth_mem_acc_3(0x83411000);
ev_unauth_mem_acc_3.setWatchWidth(0xBFD00000 - 0x83411000);
simulator.addListener(&ev_unauth_mem_acc_3);
MemAccessListener ev_unauth_mem_acc_4(0xC0000000);
ev_unauth_mem_acc_4.setWatchWidth(0xFFFFFFFF - 0xC0000000);
simulator.addListener(&ev_unauth_mem_acc_4);
// Traps
TrapListener ev_trap(fail::ANY_TRAP, NULL);
simulator.addListener(&ev_trap);
// Timeout
TimerListener ev_timeout(LRASP_TIMEOUT);
simulator.addListener(&ev_timeout);
// Termination
BPSingleListener ev_func_end(elfReader->getSymbol("main").getEnd() - 4 - LRASP_MAIN_ENDOFFSET);
simulator.addListener(&ev_func_end);
logger << "waiting for function exit, trap or timeout(1 second)" << endl;
BaseListener* ev = simulator.resume();
if (ev == &ev_timeout) {
logger << "Timeout!" << endl;
result->set_resulttype(result->ERR_TIMEOUT);
} else if (ev == &ev_trap) {
logger << "Trap!" << endl;
result->set_resulttype(result->ERR_TRAP);
} else if (ev == &ev_unauth_mem_acc_1 ||
ev == &ev_unauth_mem_acc_2 ||
ev == &ev_unauth_mem_acc_3 ||
ev == &ev_unauth_mem_acc_4) {
result->set_resulttype(result->ERR_OUTSIDE_TEXT);
logger << hex << "Unauthorized memory access (" << ((((MemAccessListener*)ev)->getTriggerAccessType() == fail::MemAccessEvent::MEM_READ) ? "R" : "W") <<
") at instruction " << ((MemAccessListener*)ev)->getTriggerInstructionPointer() << " access address: " <<
((MemAccessListener*)ev)->getTriggerAddress() << dec << endl;
} else if (ev == &ev_func_end) {
logger << "Function terminated!" << endl;
int32_t results[elfReader->getSymbol("result").getSize()/sizeof(int32_t)];
simulator.getMemoryManager().getBytes(elfReader->getSymbol("result").getAddress(),
elfReader->getSymbol("result").getSize(),
(unsigned char*)results);
result->set_resulttype(result->OK);
for (unsigned i = 0; i < sizeof(results) / sizeof(*results); ++i) {
if (correct_result[i] != results[i]) {
result->set_resulttype(result->ERR_WRONG_RESULT);
break;
}
}
}
timer.stopTimer();
result->set_time_aftermath(float(timer));
result->set_experiment_number(executed_jobs);
simulator.clearListeners();
}
jobClient->sendResult(param);
logger << param.debugString();
}
logger << "jobClient.getNumberOfUndoneJobs() = " << jobClient->getNumberOfUndoneJobs() << "executed_jobs = " << executed_jobs << endl;
#endif // PREPARATION
delete elfReader;
delete jobClient;
simulator.terminate();
return true;
}

View File

@ -0,0 +1,20 @@
#ifndef __LRA_SIMPLE_PANDA_EXPERIMENT_HPP__
#define __LRA_SIMPLE_PANDA_EXPERIMENT_HPP__
#include "efw/ExperimentFlow.hpp"
#include "cpn/InjectionPoint.hpp"
#include "util/ElfReader.hpp"
using namespace fail;
class LRASimplePandaExperiment : public ExperimentFlow {
private:
fail::ElfReader *elfReader;
public:
LRASimplePandaExperiment() : ExperimentFlow() {}
bool run();
bool navigateToInjectionPoint(ConcreteInjectionPoint &ip);
// void navigateToInjectionPoint(ConcreteInjectionPoint &ip, std::ostream &log);
};
#endif // __LRA_SIMPLE_PANDA_EXPERIMENT_HPP__

View File

@ -0,0 +1,11 @@
#ifndef __LRA_SIMPLE_PANDA_EXPERIMENT_INFO_HPP__
#define __LRA_SIMPLE_PANDA_EXPERIMENT_INFO_HPP__
#define LRASP_TRACE "trace.tc"
#define LRASP_TIMEOUT 3000000 // 1500ms
#define LRASP_RESULT_ADDRESS 0x834106b0
#define LRASP_RESULTS_BYTES 1000
#define LRASP_MAIN_ENDOFFSET 28
#define LRASP_NUM_EXP_PER_PILOT 1
#endif

View File

@ -0,0 +1,29 @@
import "DatabaseCampaignMessage.proto";
message LraSimpleProtoMsg {
required DatabaseCampaignMessage fsppilot = 1;
repeated group Result = 2 {
enum ResultType {
OK = 1;
ERR_WRONG_RESULT = 2;
ERR_TRAP = 3;
ERR_TIMEOUT = 4;
ERR_OUTSIDE_TEXT = 5;
}
//required int32 bitoffset = 1 [(sql_primary_key) = true];
required uint32 experiment_number = 1 [(sql_primary_key) = true];
required ResultType resulttype = 2;
// Times for evaluation
required float time_init = 3;
required float time_nav = 4;
required float time_inject = 5;
required float time_aftermath = 6;
}
}

View File

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

View File

@ -24,6 +24,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
find_package(MySQL REQUIRED)
include_directories(${MYSQL_INCLUDE_DIR})
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library

View File

@ -22,6 +22,7 @@ find_package(Protobuf REQUIRED)
include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
## Build library