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 #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("                                %08I64X - %08I64X\n",
    216                    low, 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