gctf2023/pwn/flipper/dist/utils/add-debug/dwarf/internal.hh

261 lines
6.8 KiB
C++
Raw Normal View History

2023-11-24 18:11:34 +00:00
#ifndef _DWARFPP_INTERNAL_HH_
#define _DWARFPP_INTERNAL_HH_
#include "dwarf++.hh"
#include "../elf/to_hex.hh"
#include <stdexcept>
#include <type_traits>
#include <unordered_map>
#include <vector>
DWARFPP_BEGIN_NAMESPACE
enum class format
{
unknown,
dwarf32,
dwarf64
};
/**
* A single DWARF section or a slice of a section. This also tracks
* dynamic information necessary to decode values in this section.
*/
struct section
{
section_type type;
const char *begin, *end;
const format fmt;
unsigned addr_size;
section(section_type type, const void *begin,
section_length length, format fmt = format::unknown,
unsigned addr_size = 0)
: type(type), begin((char*)begin), end((char*)begin + length),
fmt(fmt), addr_size(addr_size) { }
section(const section &o) = default;
std::shared_ptr<section> slice(section_offset start, section_length len,
format fmt = format::unknown,
unsigned addr_size = 0)
{
if (fmt == format::unknown)
fmt = this->fmt;
if (addr_size == 0)
addr_size = this->addr_size;
return std::make_shared<section>(
type, begin+start,
std::min(len, (section_length)(end-begin)),
fmt, addr_size);
}
size_t size() const
{
return end - begin;
}
};
/**
* A cursor pointing into a DWARF section. Provides deserialization
* operations and bounds checking.
*/
struct cursor
{
// XXX There's probably a lot of overhead to maintaining the
// shared pointer to the section from this. Perhaps the rule
// should be that all objects keep the dwarf::impl alive
// (directly or indirectly) and that keeps the loader alive,
// so a cursor just needs a regular section*.
std::shared_ptr<section> sec;
const char *pos;
cursor()
: pos(nullptr) { }
cursor(const std::shared_ptr<section> sec, section_offset offset = 0)
: sec(sec), pos(sec->begin + offset) { }
/**
* Read a subsection. The cursor must be at an initial
* length. After, the cursor will point just past the end of
* the subsection. The returned section has the appropriate
* DWARF format and begins at the current location of the
* cursor (so this is usually followed by a
* skip_initial_length).
*/
std::shared_ptr<section> subsection();
std::int64_t sleb128();
section_offset offset();
void string(std::string &out);
const char *cstr(size_t *size_out = nullptr);
void
ensure(section_offset bytes)
{
if ((section_offset)(sec->end - pos) < bytes || pos >= sec->end)
underflow();
}
template<typename T>
T fixed()
{
ensure(sizeof(T));
T val = *(T*)pos;
pos += sizeof(T);
return val;
}
std::uint64_t uleb128()
{
// Appendix C
// XXX Pre-compute all two byte ULEB's
std::uint64_t result = 0;
int shift = 0;
while (pos < sec->end) {
uint8_t byte = *(uint8_t*)(pos++);
result |= (uint64_t)(byte & 0x7f) << shift;
if ((byte & 0x80) == 0)
return result;
shift += 7;
}
underflow();
return 0;
}
taddr address()
{
switch (sec->addr_size) {
case 1:
return fixed<uint8_t>();
case 2:
return fixed<uint16_t>();
case 4:
return fixed<uint32_t>();
case 8:
return fixed<uint64_t>();
default:
throw std::runtime_error("address size " + std::to_string(sec->addr_size) + " not supported");
}
}
void skip_initial_length();
void skip_form(DW_FORM form);
cursor &operator+=(section_offset offset)
{
pos += offset;
return *this;
}
cursor operator+(section_offset offset) const
{
return cursor(sec, pos + offset);
}
bool operator<(const cursor &o) const
{
return pos < o.pos;
}
bool end() const
{
return pos >= sec->end;
}
bool valid() const
{
return !!pos;
}
section_offset get_section_offset() const
{
return pos - sec->begin;
}
private:
cursor(const std::shared_ptr<section> sec, const char *pos)
: sec(sec), pos(pos) { }
void underflow();
};
/**
* An attribute specification in an abbrev.
*/
struct attribute_spec
{
DW_AT name;
DW_FORM form;
// Computed information
value::type type;
attribute_spec(DW_AT name, DW_FORM form);
};
typedef std::uint64_t abbrev_code;
/**
* An entry in .debug_abbrev.
*/
struct abbrev_entry
{
abbrev_code code;
DW_TAG tag;
bool children;
std::vector<attribute_spec> attributes;
abbrev_entry() : code(0) { }
bool read(cursor *cur);
};
/**
* A section header in .debug_pubnames or .debug_pubtypes.
*/
struct name_unit
{
uhalf version;
section_offset debug_info_offset;
section_length debug_info_length;
// Cursor to the first name_entry in this unit. This cursor's
// section is limited to this unit.
cursor entries;
void read(cursor *cur)
{
// Section 7.19
std::shared_ptr<section> subsec = cur->subsection();
cursor sub(subsec);
sub.skip_initial_length();
version = sub.fixed<uhalf>();
if (version != 2)
throw format_error("unknown name unit version " + std::to_string(version));
debug_info_offset = sub.offset();
debug_info_length = sub.offset();
entries = sub;
}
};
/**
* An entry in a .debug_pubnames or .debug_pubtypes unit.
*/
struct name_entry
{
section_offset offset;
std::string name;
void read(cursor *cur)
{
offset = cur->offset();
cur->string(name);
}
};
DWARFPP_END_NAMESPACE
#endif