1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
// 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.
#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());
}
|