• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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("                                %08" FMT_I64 "X - %08" FMT_I64 "X\n",
216                    (unsigned long long)low, (unsigned long long)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