diff --git a/CMakeLists.txt b/CMakeLists.txt index 918a7f9e..d45f5923 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,8 +66,10 @@ include_directories(${CMAKE_BINARY_DIR}/src/core) # FIXME: this should be in src/core/CMakeLists.txt but actually doesn't work ## Add CMakeLists from subdirectories: +add_subdirectory(tools) add_subdirectory(src) + #### Backend-related build system stuff include(bochs) include(gem5) diff --git a/configurations/t32_sim_m3.sh b/configurations/t32_sim_m3.sh index 8d4823d5..39c663cb 100755 --- a/configurations/t32_sim_m3.sh +++ b/configurations/t32_sim_m3.sh @@ -2,3 +2,7 @@ ## A cmake configuration call for a FailT32 Simulator variant cmake $(dirname $0)/.. -DBUILD_BOCHS:BOOL=OFF -DBUILD_X86:BOOL=OFF -DARCH_TOOL_PREFIX:STRING=arm-none-eabi- -DBUILD_T32:BOOL=ON -DBUILD_ARM:BOOL=ON -DCONFIG_BOCHS_NO_ABORT:BOOL=OFF -DCONFIG_EVENT_BREAKPOINTS:BOOL=ON -DCONFIG_EVENT_BREAKPOINTS_RANGE:BOOL=ON -DCONFIG_EVENT_MEMREAD:BOOL=ON -DCONFIG_EVENT_MEMWRITE:BOOL=ON -DEXPERIMENTS_ACTIVATED:STRING=vezs-example -DT32_ARCHITECTURE:STRING=armm3 -DT32_CPUNAME:STRING=STM32F103RG -DT32_SIMULATOR:BOOL=ON +echo "-------------" +echo "Test me with a recent CiAO version: Application armm3_test" +echo "Don't forget to: export FAIL_ELF_PATH=$CIAOBASE/kconf/config/lib/bin/armm3_test" + diff --git a/scripts/t32cmm/CMakeLists.txt b/scripts/t32cmm/CMakeLists.txt index 85d9c326..2678d094 100644 --- a/scripts/t32cmm/CMakeLists.txt +++ b/scripts/t32cmm/CMakeLists.txt @@ -4,8 +4,10 @@ if(EXISTS $ENV{T32SYS}) SET(T32_SYS $ENV{T32SYS}) message(STATUS "[Fail*] T32 base directory: T32SYS=${T32_SYS}") else() - message(FATAL_ERROR "Please set env variable T32SYS to a valid T32 installation base directory.") + SET(T32_SYS "/proj/i4ciao/tools/t32-20130226-qt") ## defaulting to I4 installation + #message(FATAL_ERROR "Please set env variable T32SYS to a valid T32 installation base directory.") endif() +message(STATUS "[Fail*] T32 base directory: T32SYS=${T32_SYS}") if(EXISTS $ENV{FAIL_ELF_PATH}) SET(T32_ELF_PATH $ENV{FAIL_ELF_PATH}) @@ -37,7 +39,7 @@ message(STATUS "[Fail*] T32 CPU name: ${T32_CPUNAME}") message(STATUS "[Fail*] T32 Executable: ${T32_EXE}") add_custom_target(runt32 - COMMAND T32CONFIG=${PROJECT_BINARY_DIR}/cmm/config.t32 ${T32_EXE} & + COMMAND T32CONFIG=${PROJECT_BINARY_DIR}/cmm/config.t32 T32SYS=${T32_SYS} ${T32_EXE} & WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/cmm" COMMENT "Starting Lauterbach." ) diff --git a/scripts/t32cmm/armm3/CMakeLists.txt b/scripts/t32cmm/armm3/CMakeLists.txt index 18eb0804..987950e4 100644 --- a/scripts/t32cmm/armm3/CMakeLists.txt +++ b/scripts/t32cmm/armm3/CMakeLists.txt @@ -1,18 +1,5 @@ ### Configure cmm Scripts for ARM Cortex-M3 -if(EXISTS $ENV{T32SYS}) - SET(T32_SYS $ENV{T32SYS}) -else() - message(FATAL_ERROR "Please set env variable T32SYS to valid T32 installation base directory.") -endif(EXISTS $ENV{T32SYS}) - -if(T32_SIMULATOR) - set(T32_OFF_FOR_SIM ";") -else() - set(T32_OFF_FOR_SIM " ") -endif() - - set(T32_EXE "${T32_EXE}/t32marm-qt" CACHE INTERNAL "") set(T32_CPUNAME STM32F103RG CACHE PATH "CPU name for SYSTEM.CPU call. (e.g. STM32F103RG)") configure_file(armm3cfg.cmm.in ${PROJECT_BINARY_DIR}/cmm/armm3cfg.cmm) diff --git a/src/core/util/CMakeLists.txt b/src/core/util/CMakeLists.txt index ef8190c5..4bc5f216 100644 --- a/src/core/util/CMakeLists.txt +++ b/src/core/util/CMakeLists.txt @@ -3,6 +3,8 @@ set(SRCS CommandLine.hpp ElfReader.cc ElfReader.hpp + Database.hpp + Database.cc Demangler.hpp Demangler.cc Disassembler.hpp diff --git a/src/core/util/CommandLine.hpp b/src/core/util/CommandLine.hpp index 9d4faaa0..507fe0b6 100644 --- a/src/core/util/CommandLine.hpp +++ b/src/core/util/CommandLine.hpp @@ -42,6 +42,11 @@ namespace fail { */ void collect_args(argument_count &, argument_value &); + /** + * Add a argument manually + */ + void add_args(char *value) { argv.push_back(value); } + /** * Add a option to the command line interface of the fail-client * diff --git a/src/core/util/Database.cc b/src/core/util/Database.cc new file mode 100644 index 00000000..eeb2ac83 --- /dev/null +++ b/src/core/util/Database.cc @@ -0,0 +1,143 @@ +#include +#include +#include "Database.hpp" +#include "util/CommandLine.hpp" +#include "util/Logger.hpp" +static fail::Logger log("Database", true); + +using namespace fail; + +Database::Database(const std::string &username, const std::string &host, const std::string &database) { + handle = mysql_init(0); + last_result = 0; + mysql_options(handle, MYSQL_READ_DEFAULT_FILE, "~/.my.cnf"); + if (!mysql_real_connect(handle, host.c_str(), + username.c_str(), + 0, database.c_str(), 0, 0, 0)) { + log << "cannot connect to MySQL server: " << mysql_error(handle) << std::endl; + exit(-1); + } + log << "opened MYSQL connection to " << username << "@" << host << "/" << database << std::endl; +} + +MYSQL_RES* Database::query(char const *query, bool get_result) +{ + if (mysql_query(handle, query)) { + std::cerr << "query '" << query << "' failed: " << mysql_error(handle) << std::endl; + return 0; + } + + if (get_result) { + if (last_result != 0) { + mysql_free_result(last_result); + last_result = 0; + } + MYSQL_RES *res = mysql_store_result(handle); + if (!res && mysql_errno(handle)) { + std::cerr << "mysql_store_result for query '" << query << "' failed: " << mysql_error(handle) << std::endl; + return 0; + } + last_result = res; + return res; + } + return (MYSQL_RES *) 1; // Invalid PTR!!! +} + + +my_ulonglong Database::affected_rows() +{ + return mysql_affected_rows(handle); +} + + +int Database::get_variant_id(const std::string &variant, const std::string &benchmark) +{ + query("CREATE TABLE IF NOT EXISTS variant (" + " id int(11) NOT NULL AUTO_INCREMENT," + " variant varchar(255) NOT NULL," + " benchmark varchar(255) NOT NULL," + " PRIMARY KEY (id)," + "UNIQUE KEY variant (variant,benchmark))"); + + int variant_id; + std::stringstream ss; + // FIXME SQL injection possible + ss << "SELECT id FROM variant WHERE variant = '" << variant << "' AND benchmark = '" << benchmark << "'"; + MYSQL_RES *variant_id_res = query(ss.str().c_str(), true); + ss.str(""); + if (mysql_num_rows(variant_id_res)) { + MYSQL_ROW row = mysql_fetch_row(variant_id_res); + variant_id = atoi(row[0]); + } else { + ss << "INSERT INTO variant (variant, benchmark) VALUES ('" << variant << "', '" << benchmark << "')"; + query(ss.str().c_str()); + variant_id = mysql_insert_id(handle); + } + return variant_id; +} + +int Database::get_fspmethod_id(const std::string &method) +{ + + query("CREATE TABLE IF NOT EXISTS fspmethod (" + " id int(11) NOT NULL AUTO_INCREMENT," + " method varchar(255) NOT NULL," + " PRIMARY KEY (id), UNIQUE KEY method (method))"); + + std::stringstream ss; + ss << "SELECT id FROM fspmethod WHERE method = '" << method << "'"; + MYSQL_RES *res = query(ss.str().c_str(), true); + ss.str(""); + + int id; + + if (mysql_num_rows(res)) { + MYSQL_ROW row = mysql_fetch_row(res); + id = atoi(row[0]); + } else { + ss << "INSERT INTO fspmethod (method) VALUES ('" << method << "')"; + query(ss.str().c_str()); + id = mysql_insert_id(handle); + } + + return id; +} + +static CommandLine::option_handle DATABASE, HOSTNAME, USERNAME; + +void Database::cmdline_setup() { + CommandLine &cmd = CommandLine::Inst(); + + DATABASE = cmd.addOption("d", "database", Arg::Required, + "-d/--database\t MYSQL Database (default: fail_demo)"); + HOSTNAME = cmd.addOption("H", "hostname", Arg::Required, + "-h/--hostname\t MYSQL Hostname (default: localhost)"); + USERNAME = cmd.addOption("u", "username", Arg::Required, + "-u/--username\t MYSQL Username (default: fail)"); +} + +Database * Database::cmdline_connect() { + std::string username, hostname, database; + + CommandLine &cmd = CommandLine::Inst(); + + if (cmd[USERNAME].count() > 0) + username = std::string(cmd[USERNAME].first()->arg); + else + username = "fail"; + + if (cmd[HOSTNAME].count() > 0) + hostname = std::string(cmd[HOSTNAME].first()->arg); + else + hostname = "localhost"; + + if (cmd[DATABASE].count() > 0) + database = std::string(cmd[DATABASE].first()->arg); + else + database = "fail_demo"; + + return new Database(username, hostname, database); +} + + + diff --git a/src/core/util/Database.hpp b/src/core/util/Database.hpp new file mode 100644 index 00000000..e11ed2a4 --- /dev/null +++ b/src/core/util/Database.hpp @@ -0,0 +1,32 @@ +#ifndef __UTIL_DATABASE_H__ +#define __UTIL_DATABASE_H__ + +#include +#include +#include + +namespace fail { +class Database { + MYSQL *handle; + MYSQL_RES *last_result; + +public: + Database(const std::string &username, const std::string &host, const std::string &database); + ~Database() { mysql_close(handle); } + + int get_variant_id(const std::string &variant, const std::string &benchmark); + int get_fspmethod_id(const std::string &method); + + + MYSQL * getHandle() const { return handle; } + MYSQL_RES *query(char const *query, bool get_result = false); + my_ulonglong affected_rows(); + + // Interface to the command line parser + static void cmdline_setup(); + static Database * cmdline_connect(); +}; + +} + +#endif diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 00000000..1c37bfb6 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,9 @@ +option(BUILD_IMPORT_TRACE "Build the trace import tool?" OFF) + +### Setup search paths for headers ## +include_directories(${CMAKE_CURRENT_BINARY_DIR}/../src/core) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src/core) + +if(BUILD_IMPORT_TRACE) + add_subdirectory(import-trace) +endif(BUILD_IMPORT_TRACE) diff --git a/tools/import-trace/BasicImporter.cc b/tools/import-trace/BasicImporter.cc new file mode 100644 index 00000000..1b8a8bfc --- /dev/null +++ b/tools/import-trace/BasicImporter.cc @@ -0,0 +1,75 @@ +#include +#include "util/Logger.hpp" +#include "BasicImporter.hpp" + +extern fail::Logger log; + +bool BasicImporter::create_database() { + std::string create_statement = "CREATE TABLE IF NOT EXISTS trace (" + " variant_id int(11) NOT NULL," + " instr1 int(10) unsigned NOT NULL," + " instr2 int(10) unsigned NOT NULL," + " instr2_absolute int(10) unsigned DEFAULT NULL," + " data_address int(10) unsigned NOT NULL," + " width tinyint(3) unsigned NOT NULL," + " accesstype enum('R','W') NOT NULL," + " PRIMARY KEY (variant_id,instr2,data_address)" + ") engine=MyISAM "; + return db->query(create_statement.c_str()); +} + +bool BasicImporter::add_trace_event(instruction_count_t begin, instruction_count_t end, + const Trace_Event &event, bool is_fake) { + + static MYSQL_STMT *stmt = 0; + if (!stmt) { + std::string sql("INSERT INTO trace (variant_id, instr1, instr2, instr2_absolute, data_address, width," + " accesstype)" + "VALUES (?,?,?,?, ?,?,?)"); + stmt = mysql_stmt_init(db->getHandle()); + if (mysql_stmt_prepare(stmt, sql.c_str(), sql.length())) { + log << "query '" << sql << "' failed: " << mysql_error(db->getHandle()) << std::endl; + return false; + } + } + + MYSQL_BIND bind[7]; + my_bool is_null = is_fake; + unsigned long accesstype_len = 1; + unsigned ip = event.ip(); + unsigned data_address = event.memaddr(); + unsigned width = event.width(); + char accesstype = event.accesstype() == event.READ ? 'R' : 'W'; + + memset(bind, 0, sizeof(bind)); + for (int i = 0; i < 7; ++i) { + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].is_unsigned = 1; + switch (i) { + case 0: bind[i].buffer = &m_variant_id; break; + case 1: bind[i].buffer = &begin; break; + case 2: bind[i].buffer = &end; break; + case 3: bind[i].buffer = &ip; + bind[i].is_null = &is_null; break; + case 4: bind[i].buffer = &data_address; break; + case 5: bind[i].buffer = &width; break; + case 6: bind[i].buffer = &accesstype; + bind[i].buffer_type = MYSQL_TYPE_STRING; + bind[i].buffer_length = accesstype_len; + bind[i].length = &accesstype_len; + break; + } + } + if (mysql_stmt_bind_param(stmt, bind)) { + log << "mysql_stmt_bind_param() failed: " << mysql_stmt_error(stmt) << std::endl; + return false; + } + if (mysql_stmt_execute(stmt)) { + log << "mysql_stmt_execute() failed: " << mysql_stmt_error(stmt) << std::endl; + log << "IP: " << std::hex<< event.ip() << std::endl; + return false; + } + return true; +} + + diff --git a/tools/import-trace/BasicImporter.hpp b/tools/import-trace/BasicImporter.hpp new file mode 100644 index 00000000..19efdbae --- /dev/null +++ b/tools/import-trace/BasicImporter.hpp @@ -0,0 +1,15 @@ +#ifndef __BASIC_IMPORTER_H__ +#define __BASIC_IMPORTER_H__ + +#include "Importer.hpp" + +class BasicImporter : public Importer { +public: + virtual bool create_database(); + bool add_trace_event(instruction_count_t begin, + instruction_count_t end, + const Trace_Event &event, + bool is_fake = false); +}; + +#endif diff --git a/tools/import-trace/CMakeLists.txt b/tools/import-trace/CMakeLists.txt new file mode 100644 index 00000000..bfa1e13d --- /dev/null +++ b/tools/import-trace/CMakeLists.txt @@ -0,0 +1,22 @@ +## Setup desired protobuf descriptions HERE ## +set(MY_PROTOS + ../../src/plugins/tracing/trace.proto +) + +set(SRCS + Importer.cc + BasicImporter.cc + DCiAOKernelImporter.cc +) + +#### PROTOBUFS #### +find_package(Protobuf REQUIRED) +include_directories(${PROTOBUF_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS}) + +## This is the example's campaign server distributing experiment parameters +add_executable(import-trace main.cc ${SRCS} ${PROTO_SRCS} ${PROTO_HDRS}) +target_link_libraries(import-trace ${PROTOBUF_LIBRARY} -lmysqlclient fail-util fail-sal) +install(TARGETS import-trace RUNTIME DESTINATION bin) diff --git a/tools/import-trace/DCiAOKernelImporter.cc b/tools/import-trace/DCiAOKernelImporter.cc new file mode 100644 index 00000000..43ebe03e --- /dev/null +++ b/tools/import-trace/DCiAOKernelImporter.cc @@ -0,0 +1,112 @@ +#include +#include + +#include "util/Logger.hpp" +extern fail::Logger log; + +using namespace fail; + +#include "DCiAOKernelImporter.hpp" + +bool DCiAOKernelImporter::inDynamicKernelMemory(fail::address_t addr) { + const std::string &name = m_elf->getSymbol(addr).getDemangledName(); + bool dynamic = name.find("os::data::dynamic", 0) != std::string::npos; + bool stack = name.find("_stack") != std::string::npos; + + return dynamic && !stack; +} + +bool DCiAOKernelImporter::copy_to_database(fail::ProtoIStream &ps) { + if (m_elf == 0) { + log << "Please give an ELF Binary as a parameter" << std::endl; + exit(-1); + } + + if (getEnterKernelAddress() == 0 || getLeaveKernelAddress() == 0) { + log << "Pleave give a valid CiAO Binary with kernel dependability options enabled" << std::endl; + exit(-1); + } + + unsigned row_count = 0; + + // instruction counter within trace + unsigned instr = 0; + unsigned instr_last_kernel_leave = 0; + + address_t enter_kernel_addr = getEnterKernelAddress(); + address_t leave_kernel_addr = getLeaveKernelAddress(); + + + Trace_Event ev; + + // Collect all memory addresses that + std::set already_written_addresses; + + bool in_kernel_space = false; + + while (ps.getNext(&ev)) { + // instruction events just get counted + if (!ev.has_memaddr()) { + // new instruction + instr++; + + if (ev.ip() == enter_kernel_addr) { + in_kernel_space = true; + } + + if (ev.ip() == leave_kernel_addr) { + instr_last_kernel_leave = instr; + in_kernel_space = false; + already_written_addresses.clear(); + } + continue; + } + + if (in_kernel_space && inDynamicKernelMemory(ev.memaddr())) { + if (ev.accesstype() == ev.WRITE) { + /* If a address is written in the protected kernel + space, we ignore it for further injections */ + address_t from = ev.memaddr(), to = ev.memaddr() + ev.width(); + // Iterate over all accessed bytes + for (address_t data_address = from; data_address < to; ++data_address) { + already_written_addresses.insert(data_address); + } + } else { + /* Read address was not written in this kernel section + -> Insert an trace event */ + address_t from = ev.memaddr(), to = ev.memaddr() + ev.width(); + // Iterate over all accessed bytes + for (address_t data_address = from; data_address < to; ++data_address) { + int instr1 = instr_last_kernel_leave; + int instr2 = instr; // the current instruction + + /* Was the byte already written in this kernel + space */ + if (already_written_addresses.find(data_address) + == already_written_addresses.end()) + continue; + + ev.set_memaddr(data_address); + ev.set_width(1); + + // we now have an interval-terminating R/W event to the memaddr + // we're currently looking at; the EC is defined by + // data_address [last_kernel_leave, read_instr] (instr_absolute) + if (!add_trace_event(instr1, instr2, ev)) { + log << "add_trace_event failed" << std::endl; + return false; + } + row_count ++; + if (row_count % 1000 == 0) { + log << "Imported " << row_count << " traces into the database" << std::endl; + } + } + } + } + + } + + log << "Inserted " << row_count << " traces into the database" << std::endl; + + return true; +} diff --git a/tools/import-trace/DCiAOKernelImporter.hpp b/tools/import-trace/DCiAOKernelImporter.hpp new file mode 100644 index 00000000..bfd3db17 --- /dev/null +++ b/tools/import-trace/DCiAOKernelImporter.hpp @@ -0,0 +1,32 @@ +#ifndef __DCIAO_KERNEL_IMPORTER_H__ +#define __DCIAO_KERNEL_IMPORTER_H__ + +#include "BasicImporter.hpp" + +/** \class DCiAOKernelImporter + * + * Strategy for importing traces into the MySQL Database, that cover + * only kernel space data address. A single trace is only added to the + * database, if it has the following form: + * + * - The memory access is after the kernel has passed the + * getEnterKernelAddress(), before it passes the + * getLeaveKernelAddress() again. Short: if the programm is in + * kernel space. + * - Only memory addresses that are located in the os::data::dynamic + * namespace + * - Only memory accesses to addresses that were not written in the + * current kernel space phase. + */ +class DCiAOKernelImporter : public BasicImporter { +protected: + fail::address_t getEnterKernelAddress() { return m_elf->getSymbol("os::dep::KernelStructs::correct").getAddress(); } + fail::address_t getLeaveKernelAddress() { return m_elf->getSymbol("os::dep::KernelStructs::calculate").getAddress(); } + bool inDynamicKernelMemory(fail::address_t addr); + +public: + virtual bool copy_to_database(fail::ProtoIStream &ps); +}; + + +#endif diff --git a/tools/import-trace/Importer.cc b/tools/import-trace/Importer.cc new file mode 100644 index 00000000..a5073617 --- /dev/null +++ b/tools/import-trace/Importer.cc @@ -0,0 +1,124 @@ +#include +#include +#include "Importer.hpp" +#include "util/Logger.hpp" + +using namespace fail; + +extern Logger log; + +void Importer::init(const std::string &variant, const std::string &benchmark, Database *db) { + this->db = db; + m_variant_id = db->get_variant_id(variant, benchmark); + log << "Importing to variant " << variant << "/" << benchmark + << " (ID: " << m_variant_id << ")" << std::endl; +} + +bool Importer::clear_database() { + std::stringstream ss; + ss << "DELETE FROM trace WHERE variant_id = " << m_variant_id; + + bool ret = db->query(ss.str().c_str()) == 0 ? false : true; + log << "delted " << db->affected_rows() << " rows from trace table" << std::endl; + return ret; +} + +bool Importer::copy_to_database(fail::ProtoIStream &ps) { + unsigned row_count = 0; + // map for keeping one "open" EC for every address + // (maps injection data address => equivalence class) + AddrLastaccessMap open_ecs; + + // instruction counter within trace + unsigned instr = 0; + + // "rightmost" instr where we did a FI experiment + unsigned instr_rightmost = 0; + + Trace_Event ev; + + while (ps.getNext(&ev)) { + // instruction events just get counted + if (!ev.has_memaddr()) { + // new instruction + instr++; + continue; + } + + address_t from = ev.memaddr(), to = ev.memaddr() + ev.width(); + // Iterate over all accessed bytes + for (address_t data_address = from; data_address < to; ++data_address) { + + int instr1 = open_ecs[data_address]; // defaults to 0 if nonexistent + int instr2 = instr; // the current instruction + + // skip zero-sized intervals: these can occur when an instruction + // accesses a memory location more than once (e.g., INC, CMPXCHG) + if (instr1 > instr2) { + continue; + } + + ev.set_width(1); + ev.set_memaddr(data_address); + + // we now have an interval-terminating R/W event to the memaddr + // we're currently looking at; the EC is defined by + // data_address [instr1, instr2] (instr_absolute) + if (!add_trace_event(instr1, instr2, ev)) { + log << "add_trace_event failed" << std::endl; + return false; + } + row_count ++; + if (row_count % 1000 == 0) { + log << "Imported " << row_count << " traces into the database" << std::endl; + } + + if (ev.accesstype() == ev.READ) { + // FIXME this is broken: we must abort after the rightmost R + // and must not allow Ws to find their way into the known + // results + instr_rightmost = instr2; + } + + // next interval must start at next instruction; the aforementioned + // skipping mechanism wouldn't work otherwise + //lastuse_it->second = instr2 + 1; + open_ecs[data_address] = instr2 + 1; + } + } + + log << "Inserted " << row_count << " traces into the database" << std::endl; + + // FIXME + // close all open intervals (right end of the fault-space) with fake trace event +// for (AddrLastaccessMap::iterator lastuse_it = open_ecs.begin(); +// lastuse_it != open_ecs.end(); ++lastuse_it) { +// address_t data_address = lastuse_it->first; +// int instr1 = lastuse_it->second; + +// #if 0 +// // Why -1? In most cases it does not make sense to inject before the +// // very last instruction, as we won't execute it anymore. This *only* +// // makes sense if we also inject into parts of the result vector. This +// // is not the case in this experiment, and with -1 we'll get a result +// // comparable to the non-pruned campaign. +// int instr2 = instr - 1; +// #else +// // EcosKernelTestCampaign only variant: fault space ends with the last FI experiment +// int instr2 = instr_rightmost; +// #endif +// // zero-sized? skip. +// if (instr1 > instr2) { +// continue; +// } + +// add_trace_event(variant_id, instr1, instr2, +// data_address, 1, 'W', 0, +// 0, 0, 0, 0, 0, true); +// } + +// fsp.fini(); + + return true; +} + diff --git a/tools/import-trace/Importer.hpp b/tools/import-trace/Importer.hpp new file mode 100644 index 00000000..a0eee0c1 --- /dev/null +++ b/tools/import-trace/Importer.hpp @@ -0,0 +1,36 @@ +#ifndef __IMPORTER_H__ +#define __IMPORTER_H__ + +#include +#include +#include "util/ProtoStream.hpp" +#include "util/ElfReader.hpp" +#include "sal/SALConfig.hpp" +#include "util/Database.hpp" +#include "trace.pb.h" + + +class Importer { +protected: + int m_variant_id; + fail::ElfReader *m_elf; + fail::Database *db; + +public: + typedef unsigned instruction_count_t; + + void init(const std::string &variant, const std::string &benchmark, fail::Database *db); + + virtual bool create_database() = 0; + virtual bool copy_to_database(fail::ProtoIStream &ps); + virtual bool clear_database(); + virtual bool add_trace_event(instruction_count_t begin, instruction_count_t end, + const Trace_Event &event, bool is_fake = false) = 0; + + void set_elf_file(fail::ElfReader *elf) {m_elf = elf;}; +protected: +private: + typedef std::map AddrLastaccessMap; +}; + +#endif diff --git a/tools/import-trace/main.cc b/tools/import-trace/main.cc new file mode 100644 index 00000000..53725863 --- /dev/null +++ b/tools/import-trace/main.cc @@ -0,0 +1,156 @@ +#include "util/optionparser/optionparser.h" +#include "util/optionparser/optionparser_ext.hpp" +#include "util/CommandLine.hpp" +#include "util/Database.hpp" +#include "util/ElfReader.hpp" +#include "util/gzstream/gzstream.h" +#include "util/Logger.hpp" +#include +#include + +#include "BasicImporter.hpp" +#include "DCiAOKernelImporter.hpp" + + +using namespace fail; +using std::cerr; +using std::endl; +using std::cout; + +Logger log("import-trace", true); + +ProtoIStream openProtoStream(std::string input_file) { + std::ifstream *gz_test_ptr = new std::ifstream(input_file.c_str()), &gz_test = *gz_test_ptr; + if (!gz_test) { + log << "couldn't open " << input_file << endl; + exit(-1); + } + unsigned char b1, b2; + gz_test >> b1 >> b2; + + if (b1 == 0x1f && b2 == 0x8b) { + igzstream *tracef = new igzstream(input_file.c_str()); + if (!tracef) { + log << "couldn't open " << input_file << endl; + exit(-1); + } + log << "opened file " << input_file << " in GZip mode" << endl; + delete gz_test_ptr; + ProtoIStream ps(tracef); + return ps; + } + + log << "opened file " << input_file << " in normal mode" << endl; + ProtoIStream ps(gz_test_ptr); + return ps; +} + +int main(int argc, char *argv[]) { + std::string trace_file, username, hostname, database, benchmark; + std::string variant, importer_args; + ElfReader *elf_file = 0; + + // Manually fill the command line option parser + CommandLine &cmd = CommandLine::Inst(); + for (int i = 1; i < argc; ++i) + cmd.add_args(argv[i]); + + CommandLine::option_handle IGNORE = cmd.addOption("", "", Arg::None, "USAGE: import-trace [options]"); + CommandLine::option_handle HELP = cmd.addOption("h", "help", Arg::None, "-h,--help\t Print usage and exit"); + CommandLine::option_handle TRACE_FILE = cmd.addOption("t", "trace-file", Arg::Required, + "-t/--trace-file\t File to save the execution trace to\n"); + + // setup the datbase command line options + Database::cmdline_setup(); + + CommandLine::option_handle VARIANT = cmd.addOption("v", "variant", Arg::Required, + "-v/--variant\t Variant label (default: \"none\")"); + CommandLine::option_handle BENCHMARK = cmd.addOption("b", "benchmark", Arg::Required, + "-b/--benchmark\t Benchmark label (default: \"none\")\n"); + CommandLine::option_handle IMPORTER = cmd.addOption("i", "importer", Arg::Required, + "-i/--importer\t Which import method to use (default: BasicImporter)"); + CommandLine::option_handle IMPORTER_ARGS = cmd.addOption("I", "importer-args", Arg::Required, + "-I/--importer-args\t Which import method to use (default: "")"); + CommandLine::option_handle ELF_FILE = cmd.addOption("e", "elf-file", Arg::Required, + "-e/--elf-file\t ELF File (default: UNSET)"); + + + if(!cmd.parse()) { + std::cerr << "Error parsing arguments." << std::endl; + exit(-1); + } + + Importer *importer; + + if (cmd[IMPORTER].count() > 0) { + std::string imp(cmd[IMPORTER].first()->arg); + if (imp == "BasicImporter") { + log << "Using BasicImporter" << endl; + importer = new BasicImporter(); + } else if (imp == "DCiAOKernelImporter") { + log << "Using DCiAOKernelImporter" << endl; + importer = new DCiAOKernelImporter(); + } else { + log << "Unkown import method: " << imp << endl; + exit(-1); + } + + } else { + log << "Using BasicImporter" << endl; + importer = new BasicImporter(); + } + + if (cmd[HELP]) { + cmd.printUsage(); + exit(0); + } + + if (cmd[TRACE_FILE].count() > 0) + trace_file = std::string(cmd[TRACE_FILE].first()->arg); + else + trace_file = "trace.pb"; + + ProtoIStream ps = openProtoStream(trace_file); + Database *db = Database::cmdline_connect(); + + if (cmd[VARIANT].count() > 0) + variant = std::string(cmd[VARIANT].first()->arg); + else + variant = "none"; + + if (cmd[BENCHMARK].count() > 0) + benchmark = std::string(cmd[BENCHMARK].first()->arg); + else + benchmark = "none"; + + if (cmd[IMPORTER_ARGS].count() > 0) + importer_args = std::string(cmd[IMPORTER_ARGS].first()->arg); + + if (cmd[ELF_FILE].count() > 0) { + elf_file = new ElfReader(cmd[ELF_FILE].first()->arg); + } + + + + importer->init(variant, benchmark, db); + importer->set_elf_file(elf_file); + + //////////////////////////////////////////////////////////////// + // Do the actual import + //////////////////////////////////////////////////////////////// + + if (!importer->create_database()) { + log << "create_database() failed" << endl; + exit(-1); + } + + if (!importer->clear_database()) { + log << "clear_database() failed" << endl; + exit(-1); + } + + if (!importer->copy_to_database(ps)) { + log << "copy_to_database() failed" << endl; + exit(-1); + } +}