gctf2023/pwn/flipper/dist/utils/add-debug/dwarf/die.cc
2023-11-24 13:11:34 -05:00

199 lines
5.2 KiB
C++

#include "internal.hh"
using namespace std;
DWARFPP_BEGIN_NAMESPACE
die::die(const unit *cu)
: cu(cu), abbrev(nullptr)
{
}
const unit &
die::get_unit() const
{
return *cu;
}
section_offset
die::get_section_offset() const
{
return cu->get_section_offset() + offset;
}
void
die::read(section_offset off)
{
cursor cur(cu->data(), off);
offset = off;
abbrev_code acode = cur.uleb128();
if (acode == 0) {
abbrev = nullptr;
next = cur.get_section_offset();
return;
}
abbrev = &cu->get_abbrev(acode);
tag = abbrev->tag;
// XXX We can pre-compute almost all of this work in the
// abbrev_entry.
attrs.clear();
attrs.reserve(abbrev->attributes.size());
for (auto &attr : abbrev->attributes) {
attrs.push_back(cur.get_section_offset());
cur.skip_form(attr.form);
}
next = cur.get_section_offset();
}
bool
die::has(DW_AT attr) const
{
if (!abbrev)
return false;
// XXX Totally lame
for (auto &a : abbrev->attributes)
if (a.name == attr)
return true;
return false;
}
value
die::operator[](DW_AT attr) const
{
// XXX We can pre-compute almost all of this work in the
// abbrev_entry.
if (abbrev) {
int i = 0;
for (auto &a : abbrev->attributes) {
if (a.name == attr)
return value(cu, a.name, a.form, a.type, attrs[i]);
i++;
}
}
throw out_of_range("DIE does not have attribute " + to_string(attr));
}
value
die::resolve(DW_AT attr) const
{
// DWARF4 section 2.13, DWARF4 section 3.3.8
// DWARF4 is unclear about what to do when there's both a
// DW_AT::specification and a DW_AT::abstract_origin.
// Conceptually, though, a concrete inlined instance cannot
// itself complete an external function that wasn't first
// completed by its abstract instance, so we first try to
// resolve abstract_origin, then we resolve specification.
// XXX This traverses the abbrevs at least twice and
// potentially several more times
if (has(attr))
return (*this)[attr];
if (has(DW_AT::abstract_origin)) {
die ao = (*this)[DW_AT::abstract_origin].as_reference();
if (ao.has(attr))
return ao[attr];
if (ao.has(DW_AT::specification)) {
die s = ao[DW_AT::specification].as_reference();
if (s.has(attr))
return s[attr];
}
} else if (has(DW_AT::specification)) {
die s = (*this)[DW_AT::specification].as_reference();
if (s.has(attr))
return s[attr];
}
return value();
}
die::iterator
die::begin() const
{
if (!abbrev || !abbrev->children)
return end();
return iterator(cu, next);
}
die::iterator::iterator(const unit *cu, section_offset off)
: d(cu)
{
d.read(off);
}
die::iterator &
die::iterator::operator++()
{
if (!d.abbrev)
return *this;
if (!d.abbrev->children) {
// The DIE has no children, so its successor follows
// immediately
d.read(d.next);
} else if (d.has(DW_AT::sibling)) {
// They made it easy on us. Follow the sibling
// pointer. XXX Probably worth optimizing
d = d[DW_AT::sibling].as_reference();
} else {
// It's a hard-knock life. We have to iterate through
// the children to find the next DIE.
// XXX Particularly unfortunate if the user is doing a
// DFS, since this will result in N^2 behavior. Maybe
// a small cache of terminator locations in the CU?
iterator sub(d.cu, d.next);
while (sub->abbrev)
++sub;
d.read(sub->next);
}
return *this;
}
const vector<pair<DW_AT, value> >
die::attributes() const
{
vector<pair<DW_AT, value> > res;
if (!abbrev)
return res;
// XXX Quite slow, especially when using this to traverse an
// entire DIE tree since each DIE will produce a new vector
// (whereas other vectors get reused). Might be worth a
// custom iterator.
int i = 0;
for (auto &a : abbrev->attributes) {
res.push_back(make_pair(a.name, value(cu, a.name, a.form, a.type, attrs[i])));
i++;
}
return res;
}
bool
die::operator==(const die &o) const
{
return cu == o.cu && offset == o.offset;
}
bool
die::operator!=(const die &o) const
{
return !(*this == o);
}
DWARFPP_END_NAMESPACE
size_t
std::hash<dwarf::die>::operator()(const dwarf::die &a) const
{
return hash<decltype(a.cu)>()(a.cu) ^
hash<decltype(a.get_unit_offset())>()(a.get_unit_offset());
}