tools/import-trace: new tool to import traces into MySQL database

The import tool does support the following import strategies:

- BasicImporter: generates def-use equivalence classes for read and
  write memory accesses
- DCiAOKernelImporter: generates equivalence classes for read access in
  the ciao kernel space.

Change-Id: I8960561d3e14dcf5dffa3ff7a59b61a5e8f7e719
This commit is contained in:
Christian Dietrich
2013-03-15 18:41:19 +01:00
parent 4e8098a636
commit e3c633c248
14 changed files with 765 additions and 0 deletions

View File

@ -65,8 +65,10 @@ include_directories(${CMAKE_BINARY_DIR}/src/core)
# FIXME: this should be in src/core/CMakeLists.txt but actually doesn't work # FIXME: this should be in src/core/CMakeLists.txt but actually doesn't work
## Add CMakeLists from subdirectories: ## Add CMakeLists from subdirectories:
add_subdirectory(tools)
add_subdirectory(src) add_subdirectory(src)
#### Backend-related build system stuff #### Backend-related build system stuff
include(bochs) include(bochs)
include(gem5) include(gem5)

View File

@ -3,6 +3,8 @@ set(SRCS
CommandLine.hpp CommandLine.hpp
ElfReader.cc ElfReader.cc
ElfReader.hpp ElfReader.hpp
Database.hpp
Database.cc
Demangler.hpp Demangler.hpp
Demangler.cc Demangler.cc
Disassembler.hpp Disassembler.hpp

View File

@ -42,6 +42,11 @@ namespace fail {
*/ */
void collect_args(argument_count &, argument_value &); 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 * Add a option to the command line interface of the fail-client
* *

143
src/core/util/Database.cc Normal file
View File

@ -0,0 +1,143 @@
#include <sstream>
#include <stdlib.h>
#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);
}

View File

@ -0,0 +1,32 @@
#ifndef __UTIL_DATABASE_H__
#define __UTIL_DATABASE_H__
#include <mysql/mysql.h>
#include <iostream>
#include <string>
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

9
tools/CMakeLists.txt Normal file
View File

@ -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)

View File

@ -0,0 +1,75 @@
#include <iostream>
#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;
}

View File

@ -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

View File

@ -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)

View File

@ -0,0 +1,112 @@
#include <iostream>
#include <set>
#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<address_t> 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;
}

View File

@ -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

View File

@ -0,0 +1,124 @@
#include <sstream>
#include <iostream>
#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;
}

View File

@ -0,0 +1,36 @@
#ifndef __IMPORTER_H__
#define __IMPORTER_H__
#include <mysql/mysql.h>
#include <map>
#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<fail::address_t, instruction_count_t> AddrLastaccessMap;
};
#endif

156
tools/import-trace/main.cc Normal file
View File

@ -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 <fstream>
#include <string>
#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);
}
}