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:
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
|
||||
|
||||
Reference in New Issue
Block a user