Acually retrieve dwarf data
Doesn't work for now: still have to take into account the memory map offsets.
This commit is contained in:
parent
67aef72302
commit
bf8864e7e6
2 changed files with 111 additions and 5 deletions
|
@ -11,6 +11,13 @@
|
|||
#include <dwarfpp/frame.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 {
|
||||
/** Singleton class holding a Dwarf interpret.
|
||||
* Must be first instanciated with the path to the binary being run, with a
|
||||
|
@ -19,11 +26,28 @@ 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 {};
|
||||
class WhatException: public std::exception {
|
||||
/** Base exception for other exceptions, not supposed to be thrown
|
||||
* by itself */
|
||||
|
||||
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 std::set<std::pair<int, DwarfRegister> > DwarfRow; // FIXME
|
||||
|
@ -52,12 +76,25 @@ class DwarfInterpret {
|
|||
int reg_id
|
||||
) 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:
|
||||
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;
|
||||
|
||||
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
|
||||
static std::unique_ptr<DwarfInterpret> instance;
|
||||
|
|
|
@ -102,6 +102,36 @@ DwarfInterpret::reg_content_t DwarfInterpret::interpret_dw_register(
|
|||
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>
|
||||
static typename std::set<std::pair<int, Key> >::const_iterator find_column(
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue