#pragma once
#include "SharedObjectInfo.h"
#include <libdwarf.h>
#include <dwarf.h>
#include <memory>
#include <unordered_map>
#include <list>
#include <functional>
#include <panda/exception.h>
#include <panda/optional.h>
namespace panda { namespace backtrace {
namespace dwarf {
const constexpr std::size_t max_inline = 10;
struct HighLow {
Dwarf_Addr high;
Dwarf_Addr low;
};
enum class Scan { found, not_found, dead_end };
struct DieHolder;
struct LookupResult;
struct DieRC;
using DieSP = panda::iptr<DieRC>;
struct CU;
using CUSP = panda::iptr<CU>;
using DieCollection = std::list<DieSP>;
struct FunctionDetails {
panda::string name;
DieSP name_die = nullptr;
std::uint64_t line_no = 0;
panda::string source;
std::uint32_t mask = 0;
};
struct DieRC: panda::Refcnt {
Dwarf_Die die;
Dwarf_Debug debug;
DieSP parent;
DieCollection context;
struct FQN {
string full_name;
DieSP source_die;
};
DieRC(Dwarf_Die die_, Dwarf_Debug debug_, DieSP parent_);
~DieRC();
panda::optional<HighLow> get_addr() noexcept;
Scan contains(std::uint64_t offset) noexcept;
DieSP resolve_ref(DieSP source, Dwarf_Half attribute) noexcept;
DieSP discover(DieSP target) noexcept;
DieSP discover(Dwarf_Off target_offset, DieSP node) noexcept;
FQN gather_fqn() noexcept;
DieSP refine_location(std::uint64_t offset) noexcept;
FunctionDetails refine_fn(LookupResult& lr) noexcept;
void refine_fn_ao(DieSP abstract_origin, FunctionDetails& details) noexcept;
void refine_fn_name(DieSP it, FunctionDetails& details) noexcept;
void refine_fn_line(DieSP die, std::uint64_t offset, FunctionDetails& details) noexcept;
void refine_fn_line_fallback(DieSP it, FunctionDetails& details) noexcept;
void refine_fn_source(DieSP it, FunctionDetails& details, CU& cu) noexcept;
void refine_fn_spec(DieSP specification, FunctionDetails& details) noexcept;
};
struct LookupResult {
LookupResult(CU& root_) noexcept: root{CUSP{&root_}} {}
LookupResult(const LookupResult&) = delete;
LookupResult(LookupResult&&);
bool is_complete() noexcept;
bool get_frames(std::uint64_t ip, const SharedObjectInfo& so, StackFrames& frames) noexcept;
CUSP root;
DieSP cu;
DieSP subprogram;
std::uint64_t offset{0};
};
struct CU: panda::Refcnt {
Dwarf_Debug debug;
int number;
Dwarf_Unsigned header_length = 0;
Dwarf_Unsigned abbrev_offset = 0;
Dwarf_Half address_size = 0;
Dwarf_Half version_stamp = 0;
Dwarf_Half offset_size = 0;
Dwarf_Half extension_size = 0;
Dwarf_Unsigned typeoffset = 0;
Dwarf_Half header_type = DW_UT_compile;
Dwarf_Sig8 signature;
Dwarf_Off cu_offset = 0;
DieSP cu_die;
char **sources = nullptr;
Dwarf_Signed sources_count = 0;
CU(Dwarf_Debug debug, int number_);
~CU();
LookupResult resolve(std::uint64_t offset) noexcept;
void resolve(std::uint64_t offset, DieSP& root, LookupResult& lr) noexcept;
string get_source(size_t index) noexcept;
};
}
struct DwarfInfo;
struct DwarfInfo {
using file_guard_t = std::unique_ptr<FILE, std::function<void(FILE*)>>;
SharedObjectInfo so_info;
Dwarf_Ptr err_arg = nullptr;
Dwarf_Debug debug = nullptr;
std::list<dwarf::CUSP> CUs;
file_guard_t guard;
DwarfInfo(const SharedObjectInfo& info_):so_info{info_}{}
~DwarfInfo();
bool load(file_guard_t&& guard) noexcept;
bool resolve(std::uint64_t ip, StackFrames& frames) noexcept;
};
using DwarfInfoMap = std::map<panda::string, std::unique_ptr<DwarfInfo>>;
struct DwarfBackend: BacktraceBackend {
const Backtrace& raw_traces;
DwarfInfoMap info_map;
DwarfBackend(const Backtrace& raw_traces_) noexcept;
bool produce_frame(StackFrames& frames, size_t i);
};
}}