169 lines
5.8 KiB
C++
169 lines
5.8 KiB
C++
#pragma once
|
|
|
|
#include <string>
|
|
#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 "MemoryMap.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-ish class holding a Dwarf interpret.
|
|
*
|
|
* There is an instance of this class per object path from the #MemoryMap.
|
|
* This class' interface helps making it a seamless integration, by
|
|
* allowing to call a method for a program counter in any object path, and
|
|
* internally passing the call to the appropriate instance.
|
|
*/
|
|
|
|
public: // Types, sub-classes, …
|
|
class WhatException: public std::exception {
|
|
/** Base exception for other exceptions, not supposed to be thrown
|
|
* by itself */
|
|
|
|
std::string what_str;
|
|
|
|
public:
|
|
/// Initialize the exception with an explanatory text chunk
|
|
explicit WhatException(const std::string& what)
|
|
: what_str(what) {}
|
|
|
|
/// Leave the explanatory text empty
|
|
WhatException(): what_str("") {}
|
|
|
|
/// Get the explanatory text for this exception
|
|
const char* what() const noexcept {
|
|
return what_str.c_str();
|
|
}
|
|
};
|
|
|
|
|
|
/** Thrown when trying to create an instance with an invalid ELF file:
|
|
* this can mean that the file did not exist, was a special path (eg.
|
|
* [heap]) or that it cannot be read. */
|
|
class OF_WHAT_EXCEPTION(InvalidElf);
|
|
|
|
/** Thrown when trying to create an instance with an ELF file that
|
|
* contains no debug information */
|
|
class OF_WHAT_EXCEPTION(NoDebugData);
|
|
|
|
/** Thrown when trying to access a program counter that is not mapped
|
|
* to an ELF file */
|
|
class OF_WHAT_EXCEPTION(NoElfForPC);
|
|
|
|
/** Thrown when trying to get the value of a Dwarf register (column)
|
|
* that is not defined or has, somehow, no value at this PC. */
|
|
class OF_WHAT_EXCEPTION(ValuelessRegister);
|
|
|
|
/// Thrown when accessing unimplemented parts of this library
|
|
class OF_WHAT_EXCEPTION(NotImplemented);
|
|
|
|
/// Thrown when somehow, getcontext (read CPU registers) fails
|
|
class OF_WHAT_EXCEPTION(FailedGetContext);
|
|
|
|
/// Thrown when a Dwarf element is not found for a given PC
|
|
class OF_WHAT_EXCEPTION(NotFound);
|
|
|
|
|
|
/// A Dwarf register
|
|
typedef dwarf::core::FrameSection::register_def DwarfRegister;
|
|
|
|
/// A Dwarf row of registers (for a given PC)
|
|
typedef std::set<std::pair<int, DwarfRegister> > DwarfRow;
|
|
|
|
/// The value type of a register's contents
|
|
typedef uintptr_t reg_content_t;
|
|
|
|
public: // methods
|
|
DwarfInterpret(DwarfInterpret const&) = delete;
|
|
void operator=(DwarfInterpret const&) = delete;
|
|
|
|
/** Acquire the anonymous instance of DwarfInterpret, which works on
|
|
* the empty memory range. Acts as a handle: passes every call to some
|
|
* other instance */
|
|
static DwarfInterpret& acquire();
|
|
|
|
/** Acquire the relevant instance of #DwarfInterpret for the given
|
|
* program counter. Instanciate it if needed. */
|
|
static DwarfInterpret& acquire(uintptr_t pc);
|
|
|
|
/** Get the Dwarf registers row at the given PC.
|
|
*
|
|
* \throws NotFound if for some reason, the Dwarf row cannot be
|
|
* accessed at this PC. */
|
|
const DwarfRow& dwarf_row_at(uintptr_t pc) const;
|
|
|
|
/** Retrieves the value pointed to by the given Dwarf register
|
|
*
|
|
* \throws ValuelessRegister */
|
|
reg_content_t interpret_dw_register(
|
|
const DwarfRow& row,
|
|
const DwarfRegister& reg
|
|
) const;
|
|
|
|
/** Retrieves the value pointed to by the given Dwarf register
|
|
*
|
|
* \throws ValuelessRegister */
|
|
reg_content_t interpret_dw_register(
|
|
const DwarfRow& row,
|
|
int reg_id
|
|
) const;
|
|
|
|
/** Get the return address at a given program counter, assuming the
|
|
* correct registers are stored */
|
|
uintptr_t get_return_address(uintptr_t cur_pc) const;
|
|
|
|
/** Get the return address of the current program point */
|
|
uintptr_t get_self_return_address() const;
|
|
|
|
/// Get the current program counter
|
|
static uintptr_t get_current_pc();
|
|
|
|
private:
|
|
DwarfInterpret(const MemoryMap::MapEntry& memory_object);
|
|
|
|
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;
|
|
|
|
uintptr_t get_caller_pc() const;
|
|
|
|
/** Get the #DwarfInterpret instance responsible for the given PC, or
|
|
* nullptr if the current instance is responsible. */
|
|
DwarfInterpret* get_responsible_instance(uintptr_t pc) const;
|
|
|
|
|
|
private: // members
|
|
static MemoryMap memory_map;
|
|
|
|
// This map maps a `memory_map` memory region index to some instance of
|
|
// a DwarfInterpret. The special index -1 is mapped to the anonymous
|
|
// instance.
|
|
static std::map<int, std::unique_ptr<DwarfInterpret> > instances;
|
|
|
|
MemoryMap::MapEntry map_entry;
|
|
|
|
std::unique_ptr<dwarf::core::root_die> root_die;
|
|
|
|
uintptr_t pc_offset;
|
|
|
|
friend class std::unique_ptr<DwarfInterpret>;
|
|
};
|