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:
@ -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})
|
||||
|
||||
@ -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];
|
||||
}
|
||||
28
src/core/comm/InjectionPointHopsMessage.proto
Normal file
28
src/core/comm/InjectionPointHopsMessage.proto
Normal 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;
|
||||
}
|
||||
}
|
||||
3
src/core/comm/InjectionPointStepsMessage.proto
Normal file
3
src/core/comm/InjectionPointStepsMessage.proto
Normal file
@ -0,0 +1,3 @@
|
||||
message InjectionPointMessage {
|
||||
required uint32 injection_instr = 1;
|
||||
}
|
||||
@ -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)")
|
||||
|
||||
@ -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
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#cmakedefine BUILD_GEM5
|
||||
#cmakedefine BUILD_QEMU
|
||||
#cmakedefine BUILD_T32
|
||||
#cmakedefine BUILD_PANDA
|
||||
#cmakedefine T32_MOCK_API
|
||||
|
||||
#cmakedefine BUILD_X86
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
119
src/core/cpn/InjectionPoint.hpp
Normal file
119
src/core/cpn/InjectionPoint.hpp
Normal 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_ */
|
||||
110
src/core/cpn/InjectionPointHops.cc
Normal file
110
src/core/cpn/InjectionPointHops.cc
Normal 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 */
|
||||
10
src/core/cpn/InjectionPointSteps.cc
Normal file
10
src/core/cpn/InjectionPointSteps.cc
Normal 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 */
|
||||
@ -9,7 +9,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_ARM
|
||||
#include "arm/ARMArchitecture.hpp"
|
||||
#include "arm/ArmArchitecture.hpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
21
src/core/sal/panda/PandaArmCPU.cc
Normal file
21
src/core/sal/panda/PandaArmCPU.cc
Normal 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
|
||||
73
src/core/sal/panda/PandaArmCPU.hpp
Normal file
73
src/core/sal/panda/PandaArmCPU.hpp
Normal 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__
|
||||
50
src/core/sal/panda/PandaBreakpoints.ah
Normal file
50
src/core/sal/panda/PandaBreakpoints.ah
Normal 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__
|
||||
19
src/core/sal/panda/PandaConfig.hpp
Normal file
19
src/core/sal/panda/PandaConfig.hpp
Normal 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__
|
||||
97
src/core/sal/panda/PandaController.cc
Normal file
97
src/core/sal/panda/PandaController.cc
Normal 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
|
||||
77
src/core/sal/panda/PandaController.hpp
Normal file
77
src/core/sal/panda/PandaController.hpp
Normal 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__
|
||||
11
src/core/sal/panda/PandaListener.cc
Normal file
11
src/core/sal/panda/PandaListener.cc
Normal file
@ -0,0 +1,11 @@
|
||||
#include "PandaListener.hpp"
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
void onTimerTrigger(void* thisPtr)
|
||||
{
|
||||
simulator.onTimerTrigger(thisPtr);
|
||||
}
|
||||
|
||||
} // end-of-namespace: fail
|
||||
13
src/core/sal/panda/PandaListener.hpp
Normal file
13
src/core/sal/panda/PandaListener.hpp
Normal 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__
|
||||
129
src/core/sal/panda/PandaMemory.hpp
Normal file
129
src/core/sal/panda/PandaMemory.hpp
Normal 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__
|
||||
52
src/core/sal/panda/PandaTimer.ah
Normal file
52
src/core/sal/panda/PandaTimer.ah
Normal 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__
|
||||
67
src/core/sal/panda/PandaWatchpoints.ah
Normal file
67
src/core/sal/panda/PandaWatchpoints.ah
Normal 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__
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
10
src/core/util/smarthops/CMakeLists.txt
Normal file
10
src/core/util/smarthops/CMakeLists.txt
Normal 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)
|
||||
260
src/core/util/smarthops/SmartHops.cc
Normal file
260
src/core/util/smarthops/SmartHops.cc
Normal 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
|
||||
90
src/core/util/smarthops/SmartHops.hpp
Normal file
90
src/core/util/smarthops/SmartHops.hpp
Normal 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
|
||||
|
||||
106
src/core/util/smarthops/TraceReader.cc
Normal file
106
src/core/util/smarthops/TraceReader.cc
Normal 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
|
||||
60
src/core/util/smarthops/TraceReader.hpp
Normal file
60
src/core/util/smarthops/TraceReader.hpp
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
36
src/experiments/lra-simple-panda/CMakeLists.txt
Normal file
36
src/experiments/lra-simple-panda/CMakeLists.txt
Normal 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)
|
||||
19
src/experiments/lra-simple-panda/campaign.cc
Normal file
19
src/experiments/lra-simple-panda/campaign.cc
Normal 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);
|
||||
}
|
||||
26
src/experiments/lra-simple-panda/campaign.hpp
Normal file
26
src/experiments/lra-simple-panda/campaign.hpp
Normal 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__
|
||||
372
src/experiments/lra-simple-panda/experiment.cc
Normal file
372
src/experiments/lra-simple-panda/experiment.cc
Normal 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;
|
||||
}
|
||||
20
src/experiments/lra-simple-panda/experiment.hpp
Normal file
20
src/experiments/lra-simple-panda/experiment.hpp
Normal 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__
|
||||
11
src/experiments/lra-simple-panda/experimentInfo.hpp
Normal file
11
src/experiments/lra-simple-panda/experimentInfo.hpp
Normal 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
|
||||
29
src/experiments/lra-simple-panda/lra_simple.proto
Normal file
29
src/experiments/lra-simple-panda/lra_simple.proto
Normal 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;
|
||||
}
|
||||
}
|
||||
21
src/experiments/lra-simple-panda/main.cc
Normal file
21
src/experiments/lra-simple-panda/main.cc
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user