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