import-trace: introduce InstructionImporter

The InstructionImporter does disassemble the binary and generate read
traces for every instruction byte executed.

Change-Id: I6b8697c711c009e106ed733c74c6ff8f9bbf8ac5
This commit is contained in:
Christian Dietrich
2013-05-31 15:35:07 +02:00
parent 9843b520c1
commit bedb9c2eb2
7 changed files with 151 additions and 8 deletions

View File

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

View File

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

View File

@ -0,0 +1,80 @@
#ifndef __puma
#include <sstream>
#include <iostream>
#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<ObjectFile>(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

View File

@ -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<llvm::object::Binary> binary;
llvm::OwningPtr<fail::LLVMDisassembler> 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

View File

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