diff --git a/include/DwarfInterpret.hpp b/include/DwarfInterpret.hpp index d623d37..33e66cc 100644 --- a/include/DwarfInterpret.hpp +++ b/include/DwarfInterpret.hpp @@ -2,7 +2,13 @@ #include #include +#include +#include +#include +#include +#include +#include #include class DwarfInterpret { @@ -15,7 +21,20 @@ class DwarfInterpret { public: class NotInstanciated: 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 > DwarfRow; // FIXME + + typedef uintptr_t reg_content_t; + + private: + //typedef std::set > DwarfRow; + + + public: DwarfInterpret(DwarfInterpret const&) = delete; void operator=(DwarfInterpret const&) = delete; @@ -24,12 +43,22 @@ class DwarfInterpret { int get_elf_machine() const { return elf_machine; } - // FIXME DEBUG vvv - void dbg_dump_ra(); + reg_content_t interpret_dw_register( + const DwarfRow& row, + const DwarfRegister& reg + ) const; + reg_content_t interpret_dw_register( + const DwarfRow& row, + int reg_id + ) const; private: 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 static std::unique_ptr instance; diff --git a/src/DwarfInterpret.cpp b/src/DwarfInterpret.cpp index ab50cfe..4437bf5 100644 --- a/src/DwarfInterpret.cpp +++ b/src/DwarfInterpret.cpp @@ -15,9 +15,16 @@ #include #include +#include + +#include "register_map.hpp" + using namespace std; using namespace dwarf; + +std::unique_ptr DwarfInterpret::instance(nullptr); + DwarfInterpret::DwarfInterpret(const std::string& elf_path) : root_die(fileno(std::ifstream(elf_path))) { @@ -45,14 +52,58 @@ DwarfInterpret& DwarfInterpret::instanciate(const std::string& elf_path) { return *(DwarfInterpret::instance); } -// BEGIN DEBUG -using core::FrameSection; -typedef FrameSection::register_def register_def; +DwarfInterpret::reg_content_t DwarfInterpret::interpret_dw_register( + const DwarfInterpret::DwarfRow& row, + 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 > 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 std::set >::const_iterator find_column( +static typename std::set >::const_iterator find_column( const std::set >& set, int key) { @@ -69,116 +120,24 @@ typename std::set >::const_iterator find_column( return it; } -register_def get_column(const DwarfRow& row, int column) { - auto it = find_column(row, column); +DwarfInterpret::DwarfRegister DwarfInterpret::get_column( + const DwarfInterpret::DwarfRow& row, + int column + ) const +{ + auto it = find_column(row, column); if(it == row.end()) throw std::out_of_range("No such column"); return it->second; } -struct ColumnQuery { - const DwarfRow& row; - int column; - ColumnQuery(const DwarfRow& row, int column): - row(row), column(column) {} -}; +DwarfInterpret::reg_content_t DwarfInterpret::get_cpu_register( + int reg_id) const +{ + ucontext_t context; + if(getcontext(&context) != 0) + throw FailedGetContext(); -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 fdes; - for(auto fde_it = frame_section.fde_begin(); - fde_it != frame_section.fde_end(); - ++fde_it) - { - fdes.push_back(fde_it); - } - - std::sort(fdes.begin(), fdes.end(), - [&frame_section] - (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; - } + // Let the user deal with reg_id correctness + return context.uc_mcontext.gregs[reg_id]; } diff --git a/src/register_map.hpp b/src/register_map.hpp new file mode 100644 index 0000000..44b4a45 --- /dev/null +++ b/src/register_map.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +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, +};