From bedb9c2eb2e7abd88fe1d756f8ebe6d1b83ff0f5 Mon Sep 17 00:00:00 2001 From: Christian Dietrich Date: Fri, 31 May 2013 15:35:07 +0200 Subject: [PATCH] import-trace: introduce InstructionImporter The InstructionImporter does disassemble the binary and generate read traces for every instruction byte executed. Change-Id: I6b8697c711c009e106ed733c74c6ff8f9bbf8ac5 --- src/core/util/ElfReader.cc | 2 + src/core/util/ElfReader.hpp | 3 +- tools/import-trace/CMakeLists.txt | 28 +++++++- tools/import-trace/Importer.hpp | 3 +- tools/import-trace/InstructionImporter.cc | 80 ++++++++++++++++++++++ tools/import-trace/InstructionImporter.hpp | 27 ++++++++ tools/import-trace/main.cc | 16 +++-- 7 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 tools/import-trace/InstructionImporter.cc create mode 100644 tools/import-trace/InstructionImporter.hpp diff --git a/src/core/util/ElfReader.cc b/src/core/util/ElfReader.cc index cd5f391c..16ceabe8 100644 --- a/src/core/util/ElfReader.cc +++ b/src/core/util/ElfReader.cc @@ -48,6 +48,8 @@ void ElfReader::setup(const char* path) { return; } + m_filename = std::string(path); + // Evaluate headers Elf32_Ehdr ehdr; Elf32_Shdr sec_hdr; diff --git a/src/core/util/ElfReader.hpp b/src/core/util/ElfReader.hpp index 2d12ec10..8cf12093 100644 --- a/src/core/util/ElfReader.hpp +++ b/src/core/util/ElfReader.hpp @@ -75,7 +75,6 @@ namespace fail { */ class ElfReader { - public: typedef ElfSymbol entry_t; typedef std::vector container_t; @@ -153,9 +152,11 @@ namespace fail { container_t::const_iterator sec_begin() { return m_sectiontable.begin(); } container_t::const_iterator sec_end() { return m_sectiontable.end(); } + const std::string & getFilename() { return m_filename; } private: Logger m_log; + std::string m_filename; void setup(const char*); int process_symboltable(int sect_num, FILE* fp); diff --git a/tools/import-trace/CMakeLists.txt b/tools/import-trace/CMakeLists.txt index 5e5a3260..870a0321 100644 --- a/tools/import-trace/CMakeLists.txt +++ b/tools/import-trace/CMakeLists.txt @@ -3,6 +3,32 @@ set(SRCS MemoryImporter.cc ) +if (BUILD_LLVM_DISASSEMBLER) + set(SRCS ${SRCS} + InstructionImporter.cc + ) + + include(FindLLVM) + + # llvm-config does add -fno-exception to the command line. But this + # breaks some boost libraries. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_CXX_FLAGS} -fexceptions") +endif(BUILD_LLVM_DISASSEMBLER) + + + add_executable(import-trace main.cc ${SRCS}) -target_link_libraries(import-trace ${PROTOBUF_LIBRARY} -lmysqlclient fail-util fail-sal fail-comm) + +target_link_libraries(import-trace + ${PROTOBUF_LIBRARY} + -lmysqlclient + fail-util + fail-comm + fail-sal) + +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 bbdc4203..96f6c336 100644 --- a/tools/import-trace/Importer.hpp +++ b/tools/import-trace/Importer.hpp @@ -78,7 +78,8 @@ public: const Trace_Event &ev) = 0; - void set_elf_file(fail::ElfReader *elf) { m_elf = elf; } + void set_elf(fail::ElfReader *elf) { m_elf = elf; } + void set_memorymap(fail::MemoryMap *mm) { m_mm = mm; } void set_faultspace_rightmargin(char accesstype) { m_faultspace_rightmargin = accesstype; } void set_sanitychecks(bool enabled) { m_sanitychecks = enabled; } diff --git a/tools/import-trace/InstructionImporter.cc b/tools/import-trace/InstructionImporter.cc new file mode 100644 index 00000000..c88034ca --- /dev/null +++ b/tools/import-trace/InstructionImporter.cc @@ -0,0 +1,80 @@ +#ifndef __puma +#include +#include +#include "InstructionImporter.hpp" +#include "util/Logger.hpp" + +using namespace llvm; +using namespace llvm::object; +using namespace fail; + + +static Logger LOG("InstructionImporter"); + +bool InstructionImporter::handle_ip_event(fail::simtime_t curtime, instruction_count_t instr, + const Trace_Event &ev) { + if (!binary) { + /* 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(); + const LLVMDisassembler::Instr &opcode = instr_map.at(ev.ip()); + + address_t from = ev.ip(), to = ev.ip() + opcode.length; + + // 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(data_address)) { + 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 = 'R'; // 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; +} + + +#endif // !__puma diff --git a/tools/import-trace/InstructionImporter.hpp b/tools/import-trace/InstructionImporter.hpp new file mode 100644 index 00000000..a60f5f57 --- /dev/null +++ b/tools/import-trace/InstructionImporter.hpp @@ -0,0 +1,27 @@ +#ifndef __INSTRUCTION_IMPORTER_H__ +#define __INSTRUCTION_IMPORTER_H__ + +#include "Importer.hpp" + +#ifndef __puma +#include "util/llvmdisassembler/LLVMDisassembler.hpp" +#endif + + +class InstructionImporter : public Importer { +#ifndef __puma + llvm::OwningPtr binary; + llvm::OwningPtr disas; +#endif + +public: + 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; + } +}; + +#endif diff --git a/tools/import-trace/main.cc b/tools/import-trace/main.cc index 0c1af3e7..e76c9b7f 100644 --- a/tools/import-trace/main.cc +++ b/tools/import-trace/main.cc @@ -1,5 +1,3 @@ -#include "util/optionparser/optionparser.h" -#include "util/optionparser/optionparser_ext.hpp" #include "util/CommandLine.hpp" #include "util/Database.hpp" #include "util/ElfReader.hpp" @@ -8,9 +6,12 @@ #include "util/Logger.hpp" #include #include - #include "MemoryImporter.hpp" +#ifdef BUILD_LLVM_DISASSEMBLER +#include "InstructionImporter.hpp" +#endif + using namespace fail; using std::cerr; @@ -118,9 +119,14 @@ int main(int argc, char *argv[]) { if (cmd[IMPORTER].count() > 0) { std::string imp(cmd[IMPORTER].first()->arg); - if (imp == "BasicImporter" || imp == "MemoryImporter") { + if (imp == "BasicImporter" || imp == "MemoryImporter" || imp == "memory" || imp == "mem") { LOG << "Using MemoryImporter" << endl; importer = new MemoryImporter(); +#ifdef BUILD_LLVM_DISASSEMBLER + } else if (imp == "InstructionImporter" || imp == "code") { + LOG << "Using InstructionImporter" << endl; + importer = new InstructionImporter(); +#endif } else { LOG << "Unkown import method: " << imp << endl; exit(-1); @@ -160,7 +166,7 @@ int main(int argc, char *argv[]) { if (cmd[ELF_FILE].count() > 0) { elf_file = new ElfReader(cmd[ELF_FILE].first()->arg); } - importer->set_elf_file(elf_file); + importer->set_elf(elf_file); if (cmd[MEMORYMAP].count() > 0) { memorymap = new MemoryMap();