sled/3party/libelfin/dwarf/internal.hh
tqcq cc7d131d95
Some checks failed
linux-x64-gcc / linux-gcc (Release) (push) Failing after 37s
linux-x64-gcc / linux-gcc (Debug) (push) Failing after 48s
linux-arm-gcc / linux-gcc-armhf (push) Failing after 1m6s
linux-mips64-gcc / linux-gcc-mips64el (Debug) (push) Failing after 1m23s
linux-aarch64-cpu-gcc / linux-gcc-aarch64 (push) Failing after 1m42s
linux-mips64-gcc / linux-gcc-mips64el (Release) (push) Failing after 1m47s
feat add dispatcher
2024-04-07 02:42:12 +00:00

298 lines
7.9 KiB
C++

// Copyright (c) 2013 Austin T. Clements. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
#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
};
enum class byte_order
{
lsb,
msb
};
/**
* Return this system's native byte order.
*/
static inline byte_order
native_order()
{
static const union
{
int i;
char c[sizeof(int)];
} test = {1};
return test.c[0] == 1 ? byte_order::lsb : byte_order::msb;
}
/**
* 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;
const byte_order ord;
unsigned addr_size;
section(section_type type, const void *begin,
section_length length,
byte_order ord, format fmt = format::unknown,
unsigned addr_size = 0)
: type(type), begin((char*)begin), end((char*)begin + length),
fmt(fmt), ord(ord), 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)),
ord, 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));
static_assert(sizeof(T) <= 8, "T too big");
uint64_t val = 0;
const unsigned char *p = (const unsigned char*)pos;
if (sec->ord == byte_order::lsb) {
for (unsigned i = 0; i < sizeof(T); i++)
val |= ((uint64_t)p[i]) << (i * 8);
} else {
for (unsigned i = 0; i < sizeof(T); i++)
val = (val << 8) | (uint64_t)p[i];
}
pos += sizeof(T);
return (T)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_unit_type();
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