util: Added disassembler using objdump tool.

The disassembler disassembles an elf file with
an external objdump tool.
The architecture specific objdump must be configured
via cmake (ARCH_TOOL_PREFIX), e.g. arm-none-eabi- for
arm-none-eabi-objdump.
This commit is contained in:
Martin Hoffmann
2013-03-05 21:14:16 +01:00
parent 010137cf54
commit 1fe1dbb3ed
10 changed files with 2340 additions and 49 deletions

View File

@ -11,4 +11,6 @@
#cmakedefine BUILD_X86
#cmakedefine BUILD_ARM
#define ARCH_TOOL_PREFIX "@ARCH_TOOL_PREFIX@"
#endif // __VARIANT_CONFIG_HPP__

View File

@ -72,10 +72,12 @@ if(BUILD_X86)
set(SRCS ${SRCS}
x86/Architecture.cc
)
set(ARCH_TOOL_PREFIX "" CACHE PATH "Setup prefix for binutils, e.g., arm-none-eabi- or tricore-, ..")
elseif(BUILD_ARM)
set(SRCS ${SRCS}
arm/Architecture.cc
)
set(ARCH_TOOL_PREFIX "arm-none-eabi-" CACHE PATH "Setup prefix for binutils, e.g., arm-none-eabi- or tricore-, ..")
endif(BUILD_X86)
# Don't include these sources if perf-stuff is disabled

View File

@ -1,23 +1,25 @@
set(SRCS
ElfReader.cc
ElfReader.hpp
Demangler.hpp
Demangler.cc
elfinfo/elfinfo.cc
elfinfo/elfinfo.h
gzstream/gzstream.C
gzstream/gzstream.h
Logger.cc
Logger.hpp
MemoryMap.hpp
ProtoStream.cc
ProtoStream.hpp
SynchronizedCounter.cc
SynchronizedCounter.hpp
SynchronizedMap.hpp
SynchronizedQueue.hpp
WallclockTimer.cc
WallclockTimer.hpp
ElfReader.cc
ElfReader.hpp
Demangler.hpp
Demangler.cc
Disassembler.hpp
Disassembler.cc
elfinfo/elfinfo.cc
elfinfo/elfinfo.h
gzstream/gzstream.C
gzstream/gzstream.h
Logger.cc
Logger.hpp
MemoryMap.hpp
ProtoStream.cc
ProtoStream.hpp
SynchronizedCounter.cc
SynchronizedCounter.hpp
SynchronizedMap.hpp
SynchronizedQueue.hpp
WallclockTimer.cc
WallclockTimer.hpp
)
# required by ProtoStream.cc:
@ -26,7 +28,7 @@ include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# required by Synchronized*.cc:
find_package(Boost 1.42 COMPONENTS thread REQUIRED)
find_package(Boost 1.42 COMPONENTS thread regex REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
@ -38,4 +40,4 @@ if(${LIB_IBERTY} STREQUAL LIB_IBERTY-NOTFOUND)
endif()
add_library(fail-util ${SRCS})
target_link_libraries(fail-util ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${LIB_IBERTY})
target_link_libraries(fail-util ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${LIB_IBERTY} )

View File

@ -0,0 +1,100 @@
#include "Disassembler.hpp"
#include <cstdlib>
#include "pstream.h"
#include <sstream>
#include <iostream>
#include <vector>
#include <utility>
#ifndef __puma
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#endif
namespace fail {
const std::string DISASSEMBLER::FAILED = "[Disassembler] Disassemble failed.";
Disassembler::Disassembler() : m_log("Fail*Disassembler", false){ }
int Disassembler::init() {
// try to open elf file from environment variable
char * elfpath = getenv("FAIL_ELF_PATH");
if(elfpath == NULL){
m_log << "FAIL_ELF_PATH not set :(" << std::endl;
return 0;
}else{
return init(elfpath);
}
}
int Disassembler::init(const char* path){
// Disassemble ELF
#ifndef __puma
std::string command = std::string(ARCH_TOOL_PREFIX) + std::string("objdump -d ") + std::string(path);
m_log << "Executing: " << command << std::endl;
redi::ipstream objdump( command );
std::string str;
while(std::getline(objdump, str)){
evaluate(str);
}
objdump.close();
if(objdump.rdbuf()->exited()){
int ex = objdump.rdbuf()->status();
if(ex != 0){
m_code.clear();
m_log << "Could not disassemble!" << std::endl;
return 0;
}
}
m_log << "disassembled " << m_code.size() << " lines." << std::endl;
#endif
return m_code.size();
}
std::ostream& operator <<(std::ostream & os, const fail::Instruction & i) {
os << i.opcode << "\t" << i.instruction << "\t" << i.comment;
return os;
}
void Disassembler::evaluate(const std::string& line){
#ifndef __puma
// Only read in real code lines:
// Code lines start with a leading whitespace! (hopefully in each objdump implementation!)
if(line.size() > 0 && isspace(line[0])){
// a line looks like: 800156c:\tdd14 \tble.n 8001598 <_ZN2hw3hal7T32Term8PutBlockEPci+0x30>
boost::regex expr("\\s+([A-Fa-f0-9]+):((?:\\s+[A-Fa-f0-9]+)+)\\s+(.+?)(;.*)?$");
boost::smatch res;
if(boost::regex_search(line, res, expr)){
std::string address = res[1];
std::stringstream ss;
ss << std::hex << address;
address_t addr = 0;
ss >> addr;
std::string opcode = res[2];
boost::trim(opcode);
std::string instruction = res[3];
boost::trim(instruction);
std::string comment = res[4];
boost::trim(comment);
m_code.insert(std::make_pair(addr, Instruction(opcode, instruction, comment)));
}
}
#endif
}
static Instruction g_InstructionNotFound;
const Instruction& Disassembler::disassemble(address_t address){
InstructionMap_t::const_iterator it = m_code.find(address);
if(it == m_code.end()){
return g_InstructionNotFound;
}else{
return it->second;
}
}
} // end of namespace

View File

@ -0,0 +1,68 @@
#ifndef __DISASSEMBLER_HPP
#define __DISASSEMBLER_HPP
#include <string>
#include "Logger.hpp"
#include "sal/SALConfig.hpp"
#include <map>
#include <ostream>
namespace fail {
//! Inform about failed disassembly
struct DISASSEMBLER {
static const std::string FAILED;
};
/**
* @class Instruction
* @brief An Instruction represents an disassembled opcode
*/
struct Instruction {
std::string opcode; // TODO convert to integer, size?
std::string instruction; //!< The disassembled instruction
std::string comment; //!< Comment (rest of line after ; )
Instruction(std::string opcode = "", const std::string& instr = DISASSEMBLER::FAILED, const std::string& comment = "")
: opcode(opcode), instruction(instr), comment(comment) { };
};
//<! This allows to print an Instruction via Logger or cout
std::ostream& operator <<(std::ostream & os, const fail::Instruction & i);
class Disassembler {
public:
/**
* Constructor.
*/
Disassembler();
/**
* Get disassembler instruction
* @param address The instruction address
* @return The according disassembled instruction if found, else DISASSEMBLER:FAILED
*/
const Instruction& disassemble(address_t address);
/**
* Evaluate new ELF file
* @param elfpath Path to ELF file.
* @return Number of disassembled lines.
*/
int init(const char* elfpath);
/**
* Evaluate new ELF file from env variable $FAIL_ELF_PATH
* @return Number of disassembled lines.
* @note The path is guessed from a FAIL_ELF_PATH environment variable
*/
int init(void);
private:
Logger m_log;
typedef std::map<address_t, Instruction> InstructionMap_t;
InstructionMap_t m_code;
void evaluate(const std::string &);
};
} // end of namespace
#endif // DISASSEMBLER_HPP

2100
src/core/util/pstream.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
#include "campaign.hpp"
#include "kesoref.pb.h"
#include "util/Disassembler.hpp"
using namespace std;
using namespace fail;
@ -79,6 +80,7 @@ void handleMemoryAccessEvent(KesoRefExperimentData& param, const fail::MemAccess
bool KESOrefs::run()
{
m_dis.init();
//******* Boot, and store state *******//
m_log << "STARTING EXPERIMENT" << endl;
#if SAFESTATE // define SS (SafeState) when building: make -DSS

View File

@ -14,6 +14,7 @@ class KESOrefs : public fail::ExperimentFlow {
fail::Logger m_log;
fail::MemoryManager& m_mm;
fail::ElfReader m_elf;
fail::Disassembler m_dis;
void printEIP();
void setupExitBPs(const std::string&);

View File

@ -15,13 +15,14 @@
#include "sal/Listener.hpp"
#include <string>
using namespace std;
using namespace fail;
bool VEZSExperiment::run()
{
MemoryManager& mm = simulator.getMemoryManager();
//m_elf.printDemangled();
m_log << "STARTING EXPERIMENT" << endl;
m_log << "Instruction Pointer: 0x" << hex << simulator.getCPU(0).getInstructionPointer() << endl;
// Test register access
@ -30,34 +31,30 @@ bool VEZSExperiment::run()
reg = simulator.getCPU(0).getRegister(RI_R2);
m_log << "Register R2: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
simulator.getCPU(0).setRegisterContent(reg, 0x23);
reg = simulator.getCPU(0).getRegister(RI_R3);
m_log << "Register R3: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
simulator.terminate();
// STOP HERE
// Test Memory access
address_t targetaddress = 0x12345678;
MemoryManager& mm = simulator.getMemoryManager();
mm.setByte(targetaddress, 0x42);
mm.getByte(targetaddress);
uint8_t tb[] = {0xab, 0xbb, 0xcc, 0xdd};
mm.setBytes(targetaddress, 4, tb);
*((uint32_t*)(tb)) = 0; // clear array.
// read back bytes
mm.getBytes(targetaddress, 4, tb);
// Test Listeners
address_t address = 0xee;
BPSingleListener bp(address);
simulator.addListener(&bp);
address_t address = m_elf.getSymbol("incfoo").getAddress();
address &= ~1; // Cortex M3 Thumb Mode has the first bit set..
m_log << "incfoo() @ 0x" << std::hex << address << std::endl;
address_t pfoo = m_elf.getSymbol("foo").getAddress();
//BPSingleListener bp(address);
BPRangeListener bp(address-32, address + 32);
MemWriteListener l_foo( pfoo );
simulator.addListener(&l_foo);
reg = simulator.getCPU(0).getRegister(RI_R4);
unsigned foo = 23;
for(int i = 0; i < 15; i++){
simulator.addListenerAndResume(&bp);
if(i == 0) mm.setBytes(pfoo, 4, (void*)&foo);
m_log << " Breakpoint hit! @ 0x" << std::hex << simulator.getCPU(0).getInstructionPointer() << std::endl;
m_log << " Register R3: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
mm.getBytes(pfoo, 4, (void*)&foo);
m_log << " foo @ 0x"<< std::hex << pfoo << " = " << foo << std::endl;
}
/*
BPRangeListener rbp(0xef, 0xff);
simulator.addListener(&rbp);
@ -77,6 +74,19 @@ bool VEZSExperiment::run()
// resume backend.
// simulator.resume();
// Test Memory access
address_t targetaddress = 0x12345678;
MemoryManager& mm = simulator.getMemoryManager();
mm.setByte(targetaddress, 0x42);
mm.getByte(targetaddress);
uint8_t tb[] = {0xab, 0xbb, 0xcc, 0xdd};
mm.setBytes(targetaddress, 4, tb);
*((uint32_t*)(tb)) = 0; // clear array.
// read back bytes
mm.getBytes(targetaddress, 4, tb);
*/
// Explicitly terminate, or the simulator will continue to run.
simulator.terminate();
}

View File

@ -5,14 +5,18 @@
#include "efw/JobClient.hpp"
#include "util/Logger.hpp"
#include "util/Disassembler.hpp"
#include "util/ElfReader.hpp"
class VEZSExperiment : public fail::ExperimentFlow {
fail::JobClient m_jc;
fail::Logger m_log;
fail::ElfReader m_elf;
public:
VEZSExperiment() : m_log("VEZS-example", false) {};
bool run();
VEZSExperiment() : m_log("VEZS-example", false) {};
bool run();
};
#endif // __CHECKSUM_OOSTUBS_EXPERIMENT_HPP__