Home | History | Annotate | Download | only in elff
      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 
     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 
     35 ElfFile* DIEObject::elf_file() const {
     36   return parent_cu()->elf_file();
     37 }
     38 
     39 Dwarf_Tag DIEObject::get_tag() const {
     40   Dwarf_Tag tag;
     41   return advance(NULL, &tag) != NULL ? tag : 0;
     42 }
     43 
     44 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 
     76 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 
    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>
    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 
    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 
    194 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 
    252 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