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:
@ -11,4 +11,6 @@
|
|||||||
#cmakedefine BUILD_X86
|
#cmakedefine BUILD_X86
|
||||||
#cmakedefine BUILD_ARM
|
#cmakedefine BUILD_ARM
|
||||||
|
|
||||||
|
#define ARCH_TOOL_PREFIX "@ARCH_TOOL_PREFIX@"
|
||||||
|
|
||||||
#endif // __VARIANT_CONFIG_HPP__
|
#endif // __VARIANT_CONFIG_HPP__
|
||||||
|
|||||||
@ -72,10 +72,12 @@ if(BUILD_X86)
|
|||||||
set(SRCS ${SRCS}
|
set(SRCS ${SRCS}
|
||||||
x86/Architecture.cc
|
x86/Architecture.cc
|
||||||
)
|
)
|
||||||
|
set(ARCH_TOOL_PREFIX "" CACHE PATH "Setup prefix for binutils, e.g., arm-none-eabi- or tricore-, ..")
|
||||||
elseif(BUILD_ARM)
|
elseif(BUILD_ARM)
|
||||||
set(SRCS ${SRCS}
|
set(SRCS ${SRCS}
|
||||||
arm/Architecture.cc
|
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)
|
endif(BUILD_X86)
|
||||||
|
|
||||||
# Don't include these sources if perf-stuff is disabled
|
# Don't include these sources if perf-stuff is disabled
|
||||||
|
|||||||
@ -1,23 +1,25 @@
|
|||||||
set(SRCS
|
set(SRCS
|
||||||
ElfReader.cc
|
ElfReader.cc
|
||||||
ElfReader.hpp
|
ElfReader.hpp
|
||||||
Demangler.hpp
|
Demangler.hpp
|
||||||
Demangler.cc
|
Demangler.cc
|
||||||
elfinfo/elfinfo.cc
|
Disassembler.hpp
|
||||||
elfinfo/elfinfo.h
|
Disassembler.cc
|
||||||
gzstream/gzstream.C
|
elfinfo/elfinfo.cc
|
||||||
gzstream/gzstream.h
|
elfinfo/elfinfo.h
|
||||||
Logger.cc
|
gzstream/gzstream.C
|
||||||
Logger.hpp
|
gzstream/gzstream.h
|
||||||
MemoryMap.hpp
|
Logger.cc
|
||||||
ProtoStream.cc
|
Logger.hpp
|
||||||
ProtoStream.hpp
|
MemoryMap.hpp
|
||||||
SynchronizedCounter.cc
|
ProtoStream.cc
|
||||||
SynchronizedCounter.hpp
|
ProtoStream.hpp
|
||||||
SynchronizedMap.hpp
|
SynchronizedCounter.cc
|
||||||
SynchronizedQueue.hpp
|
SynchronizedCounter.hpp
|
||||||
WallclockTimer.cc
|
SynchronizedMap.hpp
|
||||||
WallclockTimer.hpp
|
SynchronizedQueue.hpp
|
||||||
|
WallclockTimer.cc
|
||||||
|
WallclockTimer.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# required by ProtoStream.cc:
|
# required by ProtoStream.cc:
|
||||||
@ -26,7 +28,7 @@ include_directories(${PROTOBUF_INCLUDE_DIRS})
|
|||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
# required by Synchronized*.cc:
|
# 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})
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
link_directories(${Boost_LIBRARY_DIRS})
|
link_directories(${Boost_LIBRARY_DIRS})
|
||||||
|
|
||||||
@ -38,4 +40,4 @@ if(${LIB_IBERTY} STREQUAL LIB_IBERTY-NOTFOUND)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(fail-util ${SRCS})
|
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} )
|
||||||
|
|||||||
100
src/core/util/Disassembler.cc
Normal file
100
src/core/util/Disassembler.cc
Normal 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
|
||||||
|
|
||||||
68
src/core/util/Disassembler.hpp
Normal file
68
src/core/util/Disassembler.hpp
Normal 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
2100
src/core/util/pstream.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "campaign.hpp"
|
#include "campaign.hpp"
|
||||||
#include "kesoref.pb.h"
|
#include "kesoref.pb.h"
|
||||||
|
#include "util/Disassembler.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace fail;
|
using namespace fail;
|
||||||
@ -79,6 +80,7 @@ void handleMemoryAccessEvent(KesoRefExperimentData& param, const fail::MemAccess
|
|||||||
|
|
||||||
bool KESOrefs::run()
|
bool KESOrefs::run()
|
||||||
{
|
{
|
||||||
|
m_dis.init();
|
||||||
//******* Boot, and store state *******//
|
//******* Boot, and store state *******//
|
||||||
m_log << "STARTING EXPERIMENT" << endl;
|
m_log << "STARTING EXPERIMENT" << endl;
|
||||||
#if SAFESTATE // define SS (SafeState) when building: make -DSS
|
#if SAFESTATE // define SS (SafeState) when building: make -DSS
|
||||||
|
|||||||
@ -14,6 +14,7 @@ class KESOrefs : public fail::ExperimentFlow {
|
|||||||
fail::Logger m_log;
|
fail::Logger m_log;
|
||||||
fail::MemoryManager& m_mm;
|
fail::MemoryManager& m_mm;
|
||||||
fail::ElfReader m_elf;
|
fail::ElfReader m_elf;
|
||||||
|
fail::Disassembler m_dis;
|
||||||
|
|
||||||
void printEIP();
|
void printEIP();
|
||||||
void setupExitBPs(const std::string&);
|
void setupExitBPs(const std::string&);
|
||||||
|
|||||||
@ -15,13 +15,14 @@
|
|||||||
#include "sal/Listener.hpp"
|
#include "sal/Listener.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace fail;
|
using namespace fail;
|
||||||
|
|
||||||
|
|
||||||
bool VEZSExperiment::run()
|
bool VEZSExperiment::run()
|
||||||
{
|
{
|
||||||
|
MemoryManager& mm = simulator.getMemoryManager();
|
||||||
|
|
||||||
|
//m_elf.printDemangled();
|
||||||
m_log << "STARTING EXPERIMENT" << endl;
|
m_log << "STARTING EXPERIMENT" << endl;
|
||||||
m_log << "Instruction Pointer: 0x" << hex << simulator.getCPU(0).getInstructionPointer() << endl;
|
m_log << "Instruction Pointer: 0x" << hex << simulator.getCPU(0).getInstructionPointer() << endl;
|
||||||
// Test register access
|
// Test register access
|
||||||
@ -30,34 +31,30 @@ bool VEZSExperiment::run()
|
|||||||
|
|
||||||
reg = simulator.getCPU(0).getRegister(RI_R2);
|
reg = simulator.getCPU(0).getRegister(RI_R2);
|
||||||
m_log << "Register R2: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
|
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
|
// Test Listeners
|
||||||
address_t address = 0xee;
|
address_t address = m_elf.getSymbol("incfoo").getAddress();
|
||||||
BPSingleListener bp(address);
|
address &= ~1; // Cortex M3 Thumb Mode has the first bit set..
|
||||||
simulator.addListener(&bp);
|
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);
|
BPRangeListener rbp(0xef, 0xff);
|
||||||
simulator.addListener(&rbp);
|
simulator.addListener(&rbp);
|
||||||
|
|
||||||
@ -77,6 +74,19 @@ bool VEZSExperiment::run()
|
|||||||
// resume backend.
|
// resume backend.
|
||||||
// simulator.resume();
|
// 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.
|
// Explicitly terminate, or the simulator will continue to run.
|
||||||
simulator.terminate();
|
simulator.terminate();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,14 +5,18 @@
|
|||||||
#include "efw/JobClient.hpp"
|
#include "efw/JobClient.hpp"
|
||||||
#include "util/Logger.hpp"
|
#include "util/Logger.hpp"
|
||||||
|
|
||||||
|
#include "util/Disassembler.hpp"
|
||||||
|
#include "util/ElfReader.hpp"
|
||||||
|
|
||||||
class VEZSExperiment : public fail::ExperimentFlow {
|
class VEZSExperiment : public fail::ExperimentFlow {
|
||||||
|
|
||||||
fail::JobClient m_jc;
|
fail::JobClient m_jc;
|
||||||
fail::Logger m_log;
|
fail::Logger m_log;
|
||||||
|
fail::ElfReader m_elf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VEZSExperiment() : m_log("VEZS-example", false) {};
|
VEZSExperiment() : m_log("VEZS-example", false) {};
|
||||||
bool run();
|
bool run();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __CHECKSUM_OOSTUBS_EXPERIMENT_HPP__
|
#endif // __CHECKSUM_OOSTUBS_EXPERIMENT_HPP__
|
||||||
|
|||||||
Reference in New Issue
Block a user