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