Acually retrieve dwarf data

Doesn't work for now: still have to take into account the memory map
offsets.
This commit is contained in:
Théophile Bastian 2018-03-30 13:25:05 +02:00
parent 67aef72302
commit bf8864e7e6
2 changed files with 111 additions and 5 deletions

View file

@ -11,6 +11,13 @@
#include <dwarfpp/frame.hpp> #include <dwarfpp/frame.hpp>
#include <dwarfpp/root.hpp> #include <dwarfpp/root.hpp>
#define OF_WHAT_EXCEPTION(cl_name) \
cl_name: public WhatException { \
public:\
cl_name(const std::string& what): WhatException(what) {} \
cl_name() = default; \
}
class DwarfInterpret { class DwarfInterpret {
/** Singleton class holding a Dwarf interpret. /** Singleton class holding a Dwarf interpret.
* Must be first instanciated with the path to the binary being run, with a * Must be first instanciated with the path to the binary being run, with a
@ -19,11 +26,28 @@ class DwarfInterpret {
*/ */
public: public:
class NotInstanciated: public std::exception {}; class WhatException: public std::exception {
class AlreadyInstanciated: public std::exception {}; /** Base exception for other exceptions, not supposed to be thrown
class ValuelessRegister: public std::exception {}; * by itself */
class NotImplemented: public std::exception {};
class FailedGetContext: public std::exception {}; std::string what_str;
public:
WhatException(const std::string& what): what_str(what) {}
WhatException(): what_str("") {}
const char* what() const noexcept {
return what_str.c_str();
}
};
class OF_WHAT_EXCEPTION(NotInstanciated);
class OF_WHAT_EXCEPTION(AlreadyInstanciated);
class OF_WHAT_EXCEPTION(ValuelessRegister);
class OF_WHAT_EXCEPTION(NotImplemented);
class OF_WHAT_EXCEPTION(FailedGetContext);
class OF_WHAT_EXCEPTION(NotFound);
typedef dwarf::core::FrameSection::register_def DwarfRegister; typedef dwarf::core::FrameSection::register_def DwarfRegister;
typedef std::set<std::pair<int, DwarfRegister> > DwarfRow; // FIXME typedef std::set<std::pair<int, DwarfRegister> > DwarfRow; // FIXME
@ -52,12 +76,25 @@ class DwarfInterpret {
int reg_id int reg_id
) const; ) const;
uintptr_t get_return_address(uintptr_t cur_pc) const;
uintptr_t get_self_return_address() const;
static uintptr_t get_current_pc();
private: private:
DwarfInterpret(const std::string& elf_path); DwarfInterpret(const std::string& elf_path);
DwarfRegister get_column(const DwarfRow& row, int column) const; DwarfRegister get_column(const DwarfRow& row, int column) const;
reg_content_t get_cpu_register(int reg_id) const; reg_content_t get_cpu_register(int reg_id) const;
const dwarf::core::FrameSection::fde_iterator fde_at(
uintptr_t pc) const;
const dwarf::core::FrameSection::cie_iterator cie_at(
uintptr_t pc) const;
const DwarfRow& dwarf_row_at(uintptr_t pc) const;
uintptr_t get_caller_pc() const;
private: // members private: // members
static std::unique_ptr<DwarfInterpret> instance; static std::unique_ptr<DwarfInterpret> instance;

View file

@ -102,6 +102,36 @@ DwarfInterpret::reg_content_t DwarfInterpret::interpret_dw_register(
return interpret_dw_register(row, get_column(row, reg_id)); return interpret_dw_register(row, get_column(row, reg_id));
} }
uintptr_t DwarfInterpret::get_return_address(uintptr_t cur_pc) const {
const core::Cie& cie = *cie_at(cur_pc);
const DwarfRow& row = dwarf_row_at(cur_pc);
return interpret_dw_register(row, cie.get_return_address_register_rule());
}
uintptr_t DwarfInterpret::get_self_return_address() const {
// Aaaaand now we have to get_return_address thrice.
return get_return_address(get_caller_pc());
}
uintptr_t DwarfInterpret::get_current_pc() {
// Assumes the PC is stored in REG_RIP **AND** the PC we want is this
// function's return address
DwarfInterpret& dw = DwarfInterpret::acquire();
reg_content_t pc_here = dw.get_cpu_register(REG_RIP);
fprintf(stderr, "PC=%p <inside>\n", pc_here);
fprintf(stderr, "actual PC=%p <inside>\n", __builtin_return_address(0));
return dw.get_return_address(pc_here);
}
uintptr_t DwarfInterpret::get_caller_pc() const {
// We assume we want the PC of the caller of the calling function. This
// means we have to unwind twice. `get_current_pc` unwinds once.
return get_return_address(DwarfInterpret::get_current_pc());
}
template<typename Key> template<typename Key>
static 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,
@ -141,3 +171,42 @@ DwarfInterpret::reg_content_t DwarfInterpret::get_cpu_register(
// Let the user deal with reg_id correctness // Let the user deal with reg_id correctness
return context.uc_mcontext.gregs[reg_id]; return context.uc_mcontext.gregs[reg_id];
} }
const core::FrameSection::fde_iterator DwarfInterpret::fde_at(
uintptr_t pc
) const
{
const core::FrameSection& fs = root_die.get_frame_section();
const auto& fde_it = fs.find_fde_for_pc(pc);
if(fde_it == fs.fde_end())
throw NotFound(std::string("FDE at pc=") + std::to_string(pc));
return fde_it;
}
const core::FrameSection::cie_iterator DwarfInterpret::cie_at(
uintptr_t pc
) const
{
const core::Fde& fde = *fde_at(pc); // let NotFound escape if it occurs
const auto& cie_it = fde.find_cie();
if(cie_it == root_die.get_frame_section().cie_end()) // Should not happen…?
throw NotFound(std::string("CIE matching FDE at pc=")
+ std::to_string(pc));
return cie_it;
}
const DwarfInterpret::DwarfRow& DwarfInterpret::dwarf_row_at(
uintptr_t pc
) const
{
const core::Fde& fde = *fde_at(pc);
auto decoded = fde.decode();
const auto& row_it = decoded.rows.find(pc);
if(row_it == decoded.rows.end())
throw NotFound(std::string("Dwarf row in this FDE at pc=")
+ std::to_string(pc));
return row_it->second;
}