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:
@ -48,6 +48,8 @@ void ElfReader::setup(const char* path) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_filename = std::string(path);
|
||||||
|
|
||||||
// Evaluate headers
|
// Evaluate headers
|
||||||
Elf32_Ehdr ehdr;
|
Elf32_Ehdr ehdr;
|
||||||
Elf32_Shdr sec_hdr;
|
Elf32_Shdr sec_hdr;
|
||||||
|
|||||||
@ -75,7 +75,6 @@ namespace fail {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class ElfReader {
|
class ElfReader {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef ElfSymbol entry_t;
|
typedef ElfSymbol entry_t;
|
||||||
typedef std::vector<entry_t> container_t;
|
typedef std::vector<entry_t> container_t;
|
||||||
@ -153,9 +152,11 @@ namespace fail {
|
|||||||
container_t::const_iterator sec_begin() { return m_sectiontable.begin(); }
|
container_t::const_iterator sec_begin() { return m_sectiontable.begin(); }
|
||||||
container_t::const_iterator sec_end() { return m_sectiontable.end(); }
|
container_t::const_iterator sec_end() { return m_sectiontable.end(); }
|
||||||
|
|
||||||
|
const std::string & getFilename() { return m_filename; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Logger m_log;
|
Logger m_log;
|
||||||
|
std::string m_filename;
|
||||||
|
|
||||||
void setup(const char*);
|
void setup(const char*);
|
||||||
int process_symboltable(int sect_num, FILE* fp);
|
int process_symboltable(int sect_num, FILE* fp);
|
||||||
|
|||||||
@ -3,6 +3,32 @@ set(SRCS
|
|||||||
MemoryImporter.cc
|
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})
|
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)
|
install(TARGETS import-trace RUNTIME DESTINATION bin)
|
||||||
|
|||||||
@ -78,7 +78,8 @@ public:
|
|||||||
const Trace_Event &ev) = 0;
|
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_memorymap(fail::MemoryMap *mm) { m_mm = mm; }
|
||||||
void set_faultspace_rightmargin(char accesstype) { m_faultspace_rightmargin = accesstype; }
|
void set_faultspace_rightmargin(char accesstype) { m_faultspace_rightmargin = accesstype; }
|
||||||
void set_sanitychecks(bool enabled) { m_sanitychecks = enabled; }
|
void set_sanitychecks(bool enabled) { m_sanitychecks = enabled; }
|
||||||
|
|||||||
80
tools/import-trace/InstructionImporter.cc
Normal file
80
tools/import-trace/InstructionImporter.cc
Normal 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
|
||||||
27
tools/import-trace/InstructionImporter.hpp
Normal file
27
tools/import-trace/InstructionImporter.hpp
Normal 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
|
||||||
@ -1,5 +1,3 @@
|
|||||||
#include "util/optionparser/optionparser.h"
|
|
||||||
#include "util/optionparser/optionparser_ext.hpp"
|
|
||||||
#include "util/CommandLine.hpp"
|
#include "util/CommandLine.hpp"
|
||||||
#include "util/Database.hpp"
|
#include "util/Database.hpp"
|
||||||
#include "util/ElfReader.hpp"
|
#include "util/ElfReader.hpp"
|
||||||
@ -8,9 +6,12 @@
|
|||||||
#include "util/Logger.hpp"
|
#include "util/Logger.hpp"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "MemoryImporter.hpp"
|
#include "MemoryImporter.hpp"
|
||||||
|
|
||||||
|
#ifdef BUILD_LLVM_DISASSEMBLER
|
||||||
|
#include "InstructionImporter.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
using namespace fail;
|
using namespace fail;
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
@ -118,9 +119,14 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
if (cmd[IMPORTER].count() > 0) {
|
if (cmd[IMPORTER].count() > 0) {
|
||||||
std::string imp(cmd[IMPORTER].first()->arg);
|
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;
|
LOG << "Using MemoryImporter" << endl;
|
||||||
importer = new MemoryImporter();
|
importer = new MemoryImporter();
|
||||||
|
#ifdef BUILD_LLVM_DISASSEMBLER
|
||||||
|
} else if (imp == "InstructionImporter" || imp == "code") {
|
||||||
|
LOG << "Using InstructionImporter" << endl;
|
||||||
|
importer = new InstructionImporter();
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
LOG << "Unkown import method: " << imp << endl;
|
LOG << "Unkown import method: " << imp << endl;
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@ -160,7 +166,7 @@ int main(int argc, char *argv[]) {
|
|||||||
if (cmd[ELF_FILE].count() > 0) {
|
if (cmd[ELF_FILE].count() > 0) {
|
||||||
elf_file = new ElfReader(cmd[ELF_FILE].first()->arg);
|
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) {
|
if (cmd[MEMORYMAP].count() > 0) {
|
||||||
memorymap = new MemoryMap();
|
memorymap = new MemoryMap();
|
||||||
|
|||||||
Reference in New Issue
Block a user