1 /* Copyright (C) 2007-2010 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12
13 /*
14 * Contains implementations of classes defined for a variety of DWARF objects.
15 */
16
17 #include "stdio.h"
18 #include "dwarf_die.h"
19 #include "dwarf_cu.h"
20 #include "dwarf_utils.h"
21 #include "elf_file.h"
22
~DIEObject()23 DIEObject::~DIEObject() {
24 /* Delete all children of this object. */
25 DIEObject* to_del = last_child();
26 while (to_del != NULL) {
27 DIEObject* next = to_del->prev_sibling();
28 delete to_del;
29 to_del = next;
30 }
31 }
32
elf_file() const33 ElfFile* DIEObject::elf_file() const {
34 return parent_cu()->elf_file();
35 }
36
get_tag() const37 Dwarf_Tag DIEObject::get_tag() const {
38 Dwarf_Tag tag;
39 return advance(NULL, &tag) != NULL ? tag : 0;
40 }
41
get_name() const42 const char* DIEObject::get_name() const {
43 DIEAttrib die_attr;
44 /* Start with the obvious. */
45 if (get_attrib(DW_AT_name, &die_attr)) {
46 return die_attr.value()->str;
47 }
48
49 /* Lets see if there is a reference to the abstract origin, or specification,
50 * and use its name as the name for this DIE. */
51 if (get_attrib(DW_AT_abstract_origin, &die_attr) ||
52 get_attrib(DW_AT_specification, &die_attr)) {
53 DIEObject* org_die_obj =
54 parent_cu()->get_referenced_die_object(die_attr.value()->u32);
55 if (org_die_obj != NULL) {
56 return org_die_obj->get_name();
57 }
58 }
59
60 /* Lets see if there is a reference to the type DIE, and use
61 * its name as the name for this DIE. */
62 if (get_attrib(DW_AT_type, &die_attr)) {
63 DIEObject* org_die_obj =
64 parent_cu()->get_referenced_die_object(die_attr.value()->u32);
65 if (org_die_obj != NULL) {
66 return org_die_obj->get_name();
67 }
68 }
69
70 /* Can't figure the name for this DIE. */
71 return NULL;
72 }
73
get_attrib(Dwarf_At at_id,DIEAttrib * attr) const74 bool DIEObject::get_attrib(Dwarf_At at_id, DIEAttrib* attr) const {
75 const Dwarf_Abbr_AT* at_abbr;
76
77 /* Advance to DIE attributes. */
78 const Elf_Byte* die_attr = advance(&at_abbr, NULL);
79 if (die_attr == NULL) {
80 _set_errno(EINVAL);
81 return false;
82 }
83
84 /* Loop through all DIE attributes, looking for the one that's being
85 * requested. */
86 while (!at_abbr->is_separator()) {
87 at_abbr = at_abbr->process(&attr->at_, &attr->form_);
88 die_attr = parent_cu()->process_attrib(die_attr, attr->form_, &attr->value_);
89 if (at_id == attr->at()) {
90 return true;
91 }
92 }
93
94 _set_errno(EINVAL);
95
96 return false;
97 }
98
get_leaf_for_address(Elf_Xword address)99 DIEObject* DIEObject::get_leaf_for_address(Elf_Xword address) {
100 const bool contains = parent_cu()->is_CU_address_64() ?
101 contains_address<Elf_Xword>(address) :
102 contains_address<Elf_Word>(address);
103 if (!contains && !is_cu_die()) {
104 /* For CU DIEs address range may be zero size, even though its child DIEs
105 * occupie some address space. So, if CU DIE's address range doesn't
106 * contain the given address, we still want to go and check the children.
107 */
108 _set_errno(EINVAL);
109 return NULL;
110 }
111
112 /* This DIE contains given address (or may contain it, if this is a CU DIE).
113 * Lets iterate through child DIEs to find the leaf (last DIE) that contains
114 * this address. */
115 DIEObject* child = last_child();
116 while (child != NULL) {
117 DIEObject* leaf = child->get_leaf_for_address(address);
118 if (leaf != NULL) {
119 return leaf;
120 }
121 child = child->prev_sibling();
122 }
123 /* No child DIE contains this address. This DIE is the leaf. */
124 return contains || !is_cu_die() ? this : NULL;
125 }
126
127 template <typename AddrType>
contains_address(Elf_Xword address)128 bool DIEObject::contains_address(Elf_Xword address) {
129 DIEAttrib die_ranges;
130 /* DIE can contain either list of ranges (f.i. DIEs that represent a routine
131 * that is inlined in multiple places will contain list of address ranges
132 * where that routine is inlined), or a pair "low PC, and high PC" describing
133 * contiguos address space where routine has been placed by compiler. */
134 if (get_attrib(DW_AT_ranges, &die_ranges)) {
135 /* Iterate through this DIE's ranges list, looking for the one that
136 * contains the given address. */
137 AddrType low;
138 AddrType high;
139 Elf_Word range_off = die_ranges.value()->u32;
140 while (elf_file()->get_range(range_off, &low, &high) &&
141 (low != 0 || high != 0)) {
142 if (address >= low && address < high) {
143 return true;
144 }
145 range_off += sizeof(AddrType) * 2;
146 }
147 return false;
148 } else {
149 /* This DIE doesn't have ranges. Lets see if it has low_pc and high_pc
150 * attributes. */
151 DIEAttrib low_pc;
152 DIEAttrib high_pc;
153 if (!get_attrib(DW_AT_low_pc, &low_pc) ||
154 !get_attrib(DW_AT_high_pc, &high_pc) ||
155 address < low_pc.value()->u64 ||
156 address >= high_pc.value()->u64) {
157 return false;
158 }
159 return true;
160 }
161 }
162
find_die_object(const Dwarf_DIE * die_to_find)163 DIEObject* DIEObject::find_die_object(const Dwarf_DIE* die_to_find) {
164 if (die_to_find == die()) {
165 return this;
166 }
167
168 /* First we will iterate through the list of children, since chances to
169 * find requested DIE decrease as we go deeper into DIE tree. */
170 DIEObject* iter = last_child();
171 while (iter != NULL) {
172 if (iter->die() == die_to_find) {
173 return iter;
174 }
175 iter = iter->prev_sibling();
176 };
177
178 /* DIE has not been found among the children. Lets go deeper now. */
179 iter = last_child();
180 while (iter != NULL) {
181 DIEObject* ret = iter->find_die_object(die_to_find);
182 if (ret != NULL) {
183 return ret;
184 }
185 iter = iter->prev_sibling();
186 }
187
188 _set_errno(EINVAL);
189 return NULL;
190 }
191
dump(bool only_this) const192 void DIEObject::dump(bool only_this) const {
193 const Dwarf_Abbr_AT* at_abbr;
194 Dwarf_Tag tag;
195
196 const Elf_Byte* die_attr = advance(&at_abbr, &tag);
197 if (die_attr != NULL) {
198 printf("\n********** DIE[%p(%04X)] %s: %s **********\n",
199 die_, parent_cu()->get_die_reference(die_), dwarf_tag_name(tag),
200 get_name());
201
202 /* Dump this DIE attributes. */
203 while (!at_abbr->is_separator()) {
204 DIEAttrib attr;
205 at_abbr = at_abbr->process(&attr.at_, &attr.form_);
206 die_attr = parent_cu()->process_attrib(die_attr, attr.form(), &attr.value_);
207 dump_attrib(attr.at(), attr.form(), attr.value());
208 if (attr.at() == DW_AT_ranges) {
209 /* Dump all ranges for this DIE. */
210 Elf_Word off = attr.value()->u32;
211 if (parent_cu()->is_CU_address_64()) {
212 Elf_Xword low, high;
213 while (elf_file()->get_range<Elf_Xword>(off, &low, &high) &&
214 (low != 0 || high != 0)) {
215 printf(" %08I64X - %08I64X\n",
216 low, high);
217 off += 16;
218 }
219 } else {
220 Elf_Word low, high;
221 while (elf_file()->get_range<Elf_Word>(off, &low, &high) &&
222 (low != 0 || high != 0)) {
223 printf(" %08X - %08X\n",
224 low, high);
225 off += 8;
226 }
227 }
228 }
229 }
230 }
231
232 if (only_this) {
233 if (parent_die_ != NULL && !parent_die_->is_cu_die()) {
234 printf("\n-----------> CHILD OF:\n");
235 parent_die_->dump(true);
236 }
237 } else {
238 /* Dump this DIE's children. */
239 if (last_child() != NULL) {
240 last_child()->dump(false);
241 }
242
243 /* Dump this DIE's siblings. */
244 if (prev_sibling() != NULL) {
245 prev_sibling()->dump(false);
246 }
247 }
248 }
249
advance(const Dwarf_Abbr_AT ** at_abbr,Dwarf_Tag * tag) const250 const Elf_Byte* DIEObject::advance(const Dwarf_Abbr_AT** at_abbr,
251 Dwarf_Tag* tag) const {
252 Dwarf_AbbrNum abbr_num;
253 Dwarf_Tag die_tag;
254
255 const Elf_Byte* die_attr = die()->process(&abbr_num);
256 const Dwarf_Abbr_DIE* abbr = parent_cu()->get_die_abbr(abbr_num);
257 if (abbr == NULL) {
258 return NULL;
259 }
260
261 const Dwarf_Abbr_AT* attrib_abbr = abbr->process(NULL, &die_tag);
262 if (at_abbr != NULL) {
263 *at_abbr = attrib_abbr;
264 }
265 if (tag != NULL) {
266 *tag = die_tag;
267 }
268 return die_attr;
269 }
270