From f47d50b1821779ca4f0b8a64871d6c8e8997772a Mon Sep 17 00:00:00 2001 From: Christian Dietrich Date: Thu, 4 Jul 2013 13:38:32 +0200 Subject: [PATCH] import-trace: introduce RegisterImporter The RegisterImporter disassembles the binary and adds a trace event for each byte read or written from register. The register number (Fail Register Numbers are used) and the offset within the register are encoded within the trace event. Change-Id: I2d2fd720841fedeeff5f28b64f24ec5f6d2ea0c3 --- tools/import-trace/CMakeLists.txt | 2 +- tools/import-trace/Importer.hpp | 6 + tools/import-trace/RegisterImporter.cc | 171 ++++++++++++++++++++++++ tools/import-trace/RegisterImporter.hpp | 49 +++++++ tools/import-trace/main.cc | 4 + 5 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 tools/import-trace/RegisterImporter.cc create mode 100644 tools/import-trace/RegisterImporter.hpp diff --git a/tools/import-trace/CMakeLists.txt b/tools/import-trace/CMakeLists.txt index 870a0321..43db2759 100644 --- a/tools/import-trace/CMakeLists.txt +++ b/tools/import-trace/CMakeLists.txt @@ -6,6 +6,7 @@ set(SRCS if (BUILD_LLVM_DISASSEMBLER) set(SRCS ${SRCS} InstructionImporter.cc + RegisterImporter.cc ) include(FindLLVM) @@ -30,5 +31,4 @@ if (BUILD_LLVM_DISASSEMBLER) target_link_libraries(import-trace fail-llvmdisassembler fail-sal ${LLVM_LIBS} ${LLVM_LDFLAGS}) endif (BUILD_LLVM_DISASSEMBLER) - install(TARGETS import-trace RUNTIME DESTINATION bin) diff --git a/tools/import-trace/Importer.hpp b/tools/import-trace/Importer.hpp index 96f6c336..e7492860 100644 --- a/tools/import-trace/Importer.hpp +++ b/tools/import-trace/Importer.hpp @@ -64,6 +64,12 @@ public: Importer() : m_sanitychecks(false), m_row_count(0), m_time_trace_start(0) {} bool init(const std::string &variant, const std::string &benchmark, fail::Database *db); + /** + * Callback function that can be used to add command line options + * to the cmd interface + */ + virtual bool cb_commandline_init() { return true; } + virtual bool create_database(); virtual bool copy_to_database(fail::ProtoIStream &ps); virtual bool clear_database(); diff --git a/tools/import-trace/RegisterImporter.cc b/tools/import-trace/RegisterImporter.cc new file mode 100644 index 00000000..ae46200d --- /dev/null +++ b/tools/import-trace/RegisterImporter.cc @@ -0,0 +1,171 @@ +#ifndef __puma +#include +#include +#include "RegisterImporter.hpp" +#include "util/Logger.hpp" + +using namespace llvm; +using namespace llvm::object; +using namespace fail; + + +static Logger LOG("RegisterImporter"); + +/** + * Callback function that can be used to add command line options + * to the campaign + */ +bool RegisterImporter::cb_commandline_init() { + CommandLine &cmd = CommandLine::Inst(); + + NO_GP = cmd.addOption("", "no-gp", Arg::None, + "--no-gp\t RegisterImporter: do not inject general purpose registers\n"); + FLAGS = cmd.addOption("", "flags", Arg::None, + "--flags: RegisterImporter: trace flags register\n"); + IP = cmd.addOption("", "ip", Arg::None, + "--ip: RegisterImporter: trace instruction pointer\n"); + + return true; +} + + +bool RegisterImporter::addRegisterTrace(simtime_t curtime, instruction_count_t instr, + const Trace_Event &ev, + const LLVMtoFailTranslator::reginfo_t &info, + char access_type) { + LLVMtoFailTranslator::reginfo_t one_byte_window = info; + one_byte_window.width = 8; + address_t from = one_byte_window.toDataAddress(), to = one_byte_window.toDataAddress() + (info.width) / 8; + + // Iterate over all accessed bytes + for (address_t data_address = from; data_address < to; ++data_address) { + // skip events outside a possibly supplied memory map + if (m_mm && !m_mm->isMatching(ev.ip())) { + continue; + } + margin_info_t left_margin = getOpenEC(data_address); + margin_info_t right_margin; + right_margin.time = curtime; + right_margin.dyninstr = instr; // !< The current instruction + right_margin.ip = ev.ip(); + + // skip zero-sized intervals: these can occur when an instruction + // accesses a memory location more than once (e.g., INC, CMPXCHG) + if (left_margin.dyninstr > right_margin.dyninstr) { + continue; + } + + // we now have an interval-terminating R/W event to the memaddr + // we're currently looking at; the EC is defined by + // data_address, dynamic instruction start/end, the absolute PC at + // the end, and time start/end + access_info_t access; + access.access_type = access_type; // instruction fetch is always a read + access.data_address = data_address; + access.data_width = 1; // exactly one byte + if (!add_trace_event(left_margin, right_margin, access)) { + LOG << "add_trace_event failed" << std::endl; + return false; + } + + // next interval must start at next instruction; the aforementioned + // skipping mechanism wouldn't work otherwise + newOpenEC(data_address, curtime + 1, instr + 1, ev.ip()); + } + return true; +} + + +bool RegisterImporter::handle_ip_event(fail::simtime_t curtime, instruction_count_t instr, + const Trace_Event &ev) { + if (!binary) { + // Parse command line again, for jump-from and jump-to + // operations + CommandLine &cmd = CommandLine::Inst(); + if (!cmd.parse()) { + std::cerr << "Error parsing arguments." << std::endl; + return false; + } + + // Read FROM memory file + if (cmd[NO_GP].count() > 0) { + do_gp = false; + } + if (cmd[FLAGS].count() > 0) { + do_flags = true; + } + if (cmd[IP].count() > 0) { + do_ip = true; + } + + /* Disassemble the binary if necessary */ + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllDisassemblers(); + + if (error_code ec = createBinary(m_elf->getFilename(), binary)) { + LOG << m_elf->getFilename() << "': " << ec.message() << ".\n"; + return false; + } + + ObjectFile *obj = dyn_cast(binary.get()); + + disas.reset(new LLVMDisassembler(obj)); + disas->disassemble(); + LLVMDisassembler::InstrMap &instr_map = disas->getInstrMap(); + LOG << "instructions disassembled: " << instr_map.size() << " Triple: " << disas->GetTriple() << std::endl; + } + + const LLVMDisassembler::InstrMap &instr_map = disas->getInstrMap(); + if (instr_map.find(ev.ip()) == instr_map.end()) { + LOG << "Could not find instruction for IP: " << std::hex << ev.ip() << std::endl; + return false; + } + const LLVMDisassembler::Instr &opcode = instr_map.at(ev.ip()); + //const MCRegisterInfo ®_info = disas->getRegisterInfo(); + + fail::LLVMtoFailTranslator & ltof = disas->getTranslator() ; + + for (std::vector::const_iterator it = opcode.reg_uses.begin(); + it != opcode.reg_uses.end(); ++it) { + const LLVMtoFailTranslator::reginfo_t &info = ltof.getFailRegisterID(*it); + + /* if not tracing flags, but flags register -> ignore it + if not tracing gp, but ! flags -> ignore it*/ + if (info.id == RID_FLAGS && !do_flags) + continue; + else if (!do_gp) + continue; + + if (!addRegisterTrace(curtime, instr, ev, info, 'R')) { + return false; + } + } + + for (std::vector::const_iterator it = opcode.reg_defs.begin(); + it != opcode.reg_defs.end(); ++it) { + const LLVMtoFailTranslator::reginfo_t &info = ltof.getFailRegisterID(*it); + /* if not tracing flags, but flags register -> ignore it + if not tracing gp, but ! flags -> ignore it*/ + if (info.id == RID_FLAGS && !do_flags) + continue; + else if (!do_gp) + continue; + + if (!addRegisterTrace(curtime, instr, ev, info, 'W')) + return false; + } + + const LLVMtoFailTranslator::reginfo_t info_pc(RID_PC); + if (do_ip) { + if (!addRegisterTrace(curtime, instr, ev, info_pc, 'R')) + return false; + if (!addRegisterTrace(curtime, instr, ev, info_pc, 'W')) + return false; + } + + return true; +} + + +#endif // !__puma diff --git a/tools/import-trace/RegisterImporter.hpp b/tools/import-trace/RegisterImporter.hpp new file mode 100644 index 00000000..94c51ead --- /dev/null +++ b/tools/import-trace/RegisterImporter.hpp @@ -0,0 +1,49 @@ +#ifndef __REGISTER_IMPORTER_H__ +#define __REGISTER_IMPORTER_H__ + + +#include "util/CommandLine.hpp" +#include "Importer.hpp" + +#ifndef __puma +#include "util/llvmdisassembler/LLVMDisassembler.hpp" +#endif + + +class RegisterImporter : public Importer { +#ifndef __puma + llvm::OwningPtr binary; + llvm::OwningPtr disas; + + bool addRegisterTrace(fail::simtime_t curtime, instruction_count_t instr, + const Trace_Event &ev, + const fail::LLVMtoFailTranslator::reginfo_t &info, + char access_type); +#endif + + + fail::CommandLine::option_handle NO_GP, FLAGS, IP; + bool do_gp, do_flags, do_ip; + +public: + RegisterImporter() : Importer(), do_gp(true), do_flags(false), do_ip(false) {} + /** + * Callback function that can be used to add command line options + * to the cmd interface + */ + virtual bool cb_commandline_init(); + + virtual bool handle_ip_event(fail::simtime_t curtime, instruction_count_t instr, + const Trace_Event &ev); + virtual bool handle_mem_event(fail::simtime_t curtime, instruction_count_t instr, + const Trace_Event &ev) { + /* ignore on purpose */ + return true; + } + + virtual void open_unused_ec_intervals() { + /* empty, Memory Map has a different meaning in this importer */ + } +}; + +#endif diff --git a/tools/import-trace/main.cc b/tools/import-trace/main.cc index e76c9b7f..0f034326 100644 --- a/tools/import-trace/main.cc +++ b/tools/import-trace/main.cc @@ -10,6 +10,7 @@ #ifdef BUILD_LLVM_DISASSEMBLER #include "InstructionImporter.hpp" +#include "RegisterImporter.hpp" #endif @@ -126,6 +127,9 @@ int main(int argc, char *argv[]) { } else if (imp == "InstructionImporter" || imp == "code") { LOG << "Using InstructionImporter" << endl; importer = new InstructionImporter(); + } else if (imp == "RegisterImporter" || imp == "regs") { + LOG << "Using RegisterImporter" << endl; + importer = new RegisterImporter(); #endif } else { LOG << "Unkown import method: " << imp << endl;