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 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 33 ElfFile* DIEObject::elf_file() const { 34 return parent_cu()->elf_file(); 35 } 36 37 Dwarf_Tag DIEObject::get_tag() const { 38 Dwarf_Tag tag; 39 return advance(NULL, &tag) != NULL ? tag : 0; 40 } 41 42 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 74 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 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> 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 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 192 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 250 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