Add ability to evaluate registers' values (UNTESTED)
This commit is contained in:
parent
c4a0a38b34
commit
67aef72302
3 changed files with 124 additions and 113 deletions
|
@ -2,7 +2,13 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <dwarfpp/lib.hpp>
|
||||||
|
#include <dwarfpp/regs.hpp>
|
||||||
|
#include <dwarfpp/frame.hpp>
|
||||||
|
#include <dwarfpp/attr.hpp>
|
||||||
|
#include <dwarfpp/frame.hpp>
|
||||||
#include <dwarfpp/root.hpp>
|
#include <dwarfpp/root.hpp>
|
||||||
|
|
||||||
class DwarfInterpret {
|
class DwarfInterpret {
|
||||||
|
@ -15,7 +21,20 @@ class DwarfInterpret {
|
||||||
public:
|
public:
|
||||||
class NotInstanciated: public std::exception {};
|
class NotInstanciated: public std::exception {};
|
||||||
class AlreadyInstanciated: public std::exception {};
|
class AlreadyInstanciated: public std::exception {};
|
||||||
|
class ValuelessRegister: public std::exception {};
|
||||||
|
class NotImplemented: public std::exception {};
|
||||||
|
class FailedGetContext: public std::exception {};
|
||||||
|
|
||||||
|
typedef dwarf::core::FrameSection::register_def DwarfRegister;
|
||||||
|
typedef std::set<std::pair<int, DwarfRegister> > DwarfRow; // FIXME
|
||||||
|
|
||||||
|
typedef uintptr_t reg_content_t;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//typedef std::set<std::pair<int, DwarfRegister> > DwarfRow;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
DwarfInterpret(DwarfInterpret const&) = delete;
|
DwarfInterpret(DwarfInterpret const&) = delete;
|
||||||
void operator=(DwarfInterpret const&) = delete;
|
void operator=(DwarfInterpret const&) = delete;
|
||||||
|
|
||||||
|
@ -24,12 +43,22 @@ class DwarfInterpret {
|
||||||
|
|
||||||
int get_elf_machine() const { return elf_machine; }
|
int get_elf_machine() const { return elf_machine; }
|
||||||
|
|
||||||
// FIXME DEBUG vvv
|
reg_content_t interpret_dw_register(
|
||||||
void dbg_dump_ra();
|
const DwarfRow& row,
|
||||||
|
const DwarfRegister& reg
|
||||||
|
) const;
|
||||||
|
reg_content_t interpret_dw_register(
|
||||||
|
const DwarfRow& row,
|
||||||
|
int reg_id
|
||||||
|
) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DwarfInterpret(const std::string& elf_path);
|
DwarfInterpret(const std::string& elf_path);
|
||||||
|
|
||||||
|
DwarfRegister get_column(const DwarfRow& row, int column) const;
|
||||||
|
reg_content_t get_cpu_register(int reg_id) const;
|
||||||
|
|
||||||
|
|
||||||
private: // members
|
private: // members
|
||||||
static std::unique_ptr<DwarfInterpret> instance;
|
static std::unique_ptr<DwarfInterpret> instance;
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,16 @@
|
||||||
#include <dwarfpp/root.hpp>
|
#include <dwarfpp/root.hpp>
|
||||||
#include <gelf.h>
|
#include <gelf.h>
|
||||||
|
|
||||||
|
#include <ucontext.h>
|
||||||
|
|
||||||
|
#include "register_map.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dwarf;
|
using namespace dwarf;
|
||||||
|
|
||||||
|
|
||||||
|
std::unique_ptr<DwarfInterpret> DwarfInterpret::instance(nullptr);
|
||||||
|
|
||||||
DwarfInterpret::DwarfInterpret(const std::string& elf_path)
|
DwarfInterpret::DwarfInterpret(const std::string& elf_path)
|
||||||
: root_die(fileno(std::ifstream(elf_path)))
|
: root_die(fileno(std::ifstream(elf_path)))
|
||||||
{
|
{
|
||||||
|
@ -45,14 +52,58 @@ DwarfInterpret& DwarfInterpret::instanciate(const std::string& elf_path) {
|
||||||
return *(DwarfInterpret::instance);
|
return *(DwarfInterpret::instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BEGIN DEBUG
|
DwarfInterpret::reg_content_t DwarfInterpret::interpret_dw_register(
|
||||||
using core::FrameSection;
|
const DwarfInterpret::DwarfRow& row,
|
||||||
typedef FrameSection::register_def register_def;
|
const DwarfInterpret::DwarfRegister& reg
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
switch(reg.k) {
|
||||||
|
case core::FrameSection::register_def::INDETERMINATE:
|
||||||
|
case core::FrameSection::register_def::UNDEFINED:
|
||||||
|
throw ValuelessRegister();
|
||||||
|
|
||||||
typedef std::set<std::pair<int, register_def> > DwarfRow;
|
case core::FrameSection::register_def::REGISTER: {
|
||||||
|
ostringstream exprs;
|
||||||
|
int dwarf_regnum = reg.register_plus_offset_r().first;
|
||||||
|
assert(dwarf_regnum != DW_FRAME_CFA_COL3);
|
||||||
|
int cpu_regnum = REG_DWARF_TO_UCONTEXT[dwarf_regnum];
|
||||||
|
|
||||||
|
reg_content_t* cpu_content =
|
||||||
|
(reg_content_t*) get_cpu_register(cpu_regnum);
|
||||||
|
reg_content_t* addr =
|
||||||
|
cpu_content + reg.register_plus_offset_r().second;
|
||||||
|
|
||||||
|
return *addr;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case core::FrameSection::register_def::SAVED_AT_OFFSET_FROM_CFA: {
|
||||||
|
reg_content_t* cfa_loc =
|
||||||
|
(reg_content_t*) interpret_dw_register(row, DW_FRAME_CFA_COL3);
|
||||||
|
reg_content_t* addr = cfa_loc;
|
||||||
|
return *addr;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case core::FrameSection::register_def::SAVED_AT_EXPR:
|
||||||
|
throw NotImplemented();
|
||||||
|
break;
|
||||||
|
case core::FrameSection::register_def::VAL_IS_OFFSET_FROM_CFA:
|
||||||
|
case core::FrameSection::register_def::VAL_OF_EXPR:
|
||||||
|
default:
|
||||||
|
throw NotImplemented();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DwarfInterpret::reg_content_t DwarfInterpret::interpret_dw_register(
|
||||||
|
const DwarfInterpret::DwarfRow& row,
|
||||||
|
int reg_id
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return interpret_dw_register(row, get_column(row, reg_id));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Key>
|
template<typename Key>
|
||||||
typename std::set<std::pair<int, Key> >::const_iterator find_column(
|
static typename std::set<std::pair<int, Key> >::const_iterator find_column(
|
||||||
const std::set<std::pair<int, Key> >& set,
|
const std::set<std::pair<int, Key> >& set,
|
||||||
int key)
|
int key)
|
||||||
{
|
{
|
||||||
|
@ -69,116 +120,24 @@ typename std::set<std::pair<int, Key> >::const_iterator find_column(
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
register_def get_column(const DwarfRow& row, int column) {
|
DwarfInterpret::DwarfRegister DwarfInterpret::get_column(
|
||||||
auto it = find_column<register_def>(row, column);
|
const DwarfInterpret::DwarfRow& row,
|
||||||
|
int column
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
auto it = find_column<DwarfRegister>(row, column);
|
||||||
if(it == row.end())
|
if(it == row.end())
|
||||||
throw std::out_of_range("No such column");
|
throw std::out_of_range("No such column");
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ColumnQuery {
|
DwarfInterpret::reg_content_t DwarfInterpret::get_cpu_register(
|
||||||
const DwarfRow& row;
|
int reg_id) const
|
||||||
int column;
|
|
||||||
ColumnQuery(const DwarfRow& row, int column):
|
|
||||||
row(row), column(column) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
ostream& operator<<(ostream& os, const register_def& reg) {
|
|
||||||
switch(reg.k) {
|
|
||||||
case FrameSection::register_def::INDETERMINATE:
|
|
||||||
case FrameSection::register_def::UNDEFINED:
|
|
||||||
return os << "u";
|
|
||||||
|
|
||||||
case FrameSection::register_def::REGISTER: {
|
|
||||||
ostringstream exprs;
|
|
||||||
int regnum = reg.register_plus_offset_r().first;
|
|
||||||
string regname;
|
|
||||||
if (regnum == DW_FRAME_CFA_COL3) regname = "X";
|
|
||||||
// DON'T confuse this case with 'c', which means
|
|
||||||
// SAVED_AT_OFFSET_FROM_CFA
|
|
||||||
else
|
|
||||||
regname = dwarf::lib::dwarf_regnames_for_elf_machine(
|
|
||||||
DwarfInterpret::acquire().get_elf_machine())[regnum];
|
|
||||||
exprs << regname << std::showpos << std::dec << setw(0)
|
|
||||||
<< (int) reg.register_plus_offset_r().second;
|
|
||||||
|
|
||||||
return os << exprs.str();
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FrameSection::register_def::SAVED_AT_OFFSET_FROM_CFA: {
|
|
||||||
ostringstream exprs;
|
|
||||||
exprs << "c" << std::showpos << std::dec
|
|
||||||
<< reg.saved_at_offset_from_cfa_r();
|
|
||||||
return os << exprs.str();
|
|
||||||
} break;
|
|
||||||
case FrameSection::register_def::SAVED_AT_EXPR:
|
|
||||||
return os << "exp";
|
|
||||||
break;
|
|
||||||
case FrameSection::register_def::VAL_IS_OFFSET_FROM_CFA:
|
|
||||||
case FrameSection::register_def::VAL_OF_EXPR:
|
|
||||||
default:
|
|
||||||
return os << "BLAH";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ostream& operator<<(ostream& os, const ColumnQuery& query) {
|
|
||||||
try {
|
|
||||||
register_def regdef = get_column(query.row, query.column);
|
|
||||||
return os << regdef;
|
|
||||||
} catch(const std::out_of_range&) {
|
|
||||||
return os << "u";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void extract_ra_of_fde(const core::FrameSection& fs, const core::Fde& fde) {
|
|
||||||
auto decoded = fde.decode();
|
|
||||||
const core::Cie& cie = *(fde.find_cie());
|
|
||||||
|
|
||||||
int ra_col = cie.get_return_address_register_rule();
|
|
||||||
int cfa_col = DW_FRAME_CFA_COL3;
|
|
||||||
|
|
||||||
for(const auto& row: decoded.rows) {
|
|
||||||
cout
|
|
||||||
<< std::hex << std::setfill('0')
|
|
||||||
<< std::setw(2 * cie.get_address_size())
|
|
||||||
<< row.first.lower() << ' '
|
|
||||||
<< setfill(' ')
|
|
||||||
<< setw(8) << ColumnQuery(row.second, cfa_col) << ' '
|
|
||||||
<< setw(6) << ColumnQuery(row.second, ra_col)
|
|
||||||
<< endl
|
|
||||||
<< std::dec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// END DEBUG
|
|
||||||
|
|
||||||
void DwarfInterpret::dbg_dump_ra() {
|
|
||||||
dwarf::core::FrameSection& frame_section =
|
|
||||||
root_die.get_frame_section();
|
|
||||||
std::vector<FrameSection::fde_iterator> fdes;
|
|
||||||
for(auto fde_it = frame_section.fde_begin();
|
|
||||||
fde_it != frame_section.fde_end();
|
|
||||||
++fde_it)
|
|
||||||
{
|
{
|
||||||
fdes.push_back(fde_it);
|
ucontext_t context;
|
||||||
}
|
if(getcontext(&context) != 0)
|
||||||
|
throw FailedGetContext();
|
||||||
|
|
||||||
std::sort(fdes.begin(), fdes.end(),
|
// Let the user deal with reg_id correctness
|
||||||
[&frame_section]
|
return context.uc_mcontext.gregs[reg_id];
|
||||||
(const FrameSection::fde_iterator& f1,
|
|
||||||
const FrameSection::fde_iterator& f2)
|
|
||||||
{
|
|
||||||
assert(f1 != frame_section.end());
|
|
||||||
assert(f2 != frame_section.end());
|
|
||||||
return f1->get_offset() < f2->get_offset();
|
|
||||||
});
|
|
||||||
|
|
||||||
// FDEs are sorted, now we can extract RAs for each of them
|
|
||||||
for(const auto& fde: fdes) {
|
|
||||||
cout << "==== FDE at offset "
|
|
||||||
<< std::hex << fde->get_fde_offset() << std::dec
|
|
||||||
<< " ====" << endl;
|
|
||||||
extract_ra_of_fde(frame_section, *fde);
|
|
||||||
cout << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
23
src/register_map.hpp
Normal file
23
src/register_map.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ucontext.h>
|
||||||
|
|
||||||
|
constexpr int REG_DWARF_TO_UCONTEXT[] = {
|
||||||
|
REG_RAX,
|
||||||
|
REG_RDX,
|
||||||
|
REG_RCX,
|
||||||
|
REG_RBX,
|
||||||
|
REG_RSI,
|
||||||
|
REG_RDI,
|
||||||
|
REG_RBP,
|
||||||
|
REG_RSP,
|
||||||
|
REG_R8,
|
||||||
|
REG_R9,
|
||||||
|
REG_R10,
|
||||||
|
REG_R11,
|
||||||
|
REG_R12,
|
||||||
|
REG_R13,
|
||||||
|
REG_R14,
|
||||||
|
REG_R15,
|
||||||
|
REG_RIP,
|
||||||
|
};
|
Loading…
Reference in a new issue