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 implementation of ElfFile classes that encapsulate an ELF file.
     15  */
     16 
     17 #include "string.h"
     18 #include "elf_file.h"
     19 #include "elf_alloc.h"
     20 #include "dwarf_cu.h"
     21 #include "dwarf_utils.h"
     22 
     23 #include <fcntl.h>
     24 #ifndef O_BINARY
     25 #define O_BINARY 0
     26 #endif
     27 
     28 /* Tags to parse when collecting info about routines. */
     29 static const Dwarf_Tag parse_rt_tags[] = {
     30   DW_TAG_compile_unit,
     31   DW_TAG_partial_unit,
     32   DW_TAG_inlined_subroutine,
     33   DW_TAG_subprogram,
     34   0
     35 };
     36 static const DwarfParseContext parse_rt_context = { parse_rt_tags };
     37 
     38 //=============================================================================
     39 // Base ElfFile implementation
     40 //=============================================================================
     41 
     42 ElfFile::ElfFile()
     43     : fixed_base_address_(0),
     44       elf_handle_((MapFile*)-1),
     45       elf_file_path_(NULL),
     46       allocator_(NULL),
     47       sec_table_(NULL),
     48       sec_count_(0),
     49       sec_entry_size_(0),
     50       last_cu_(NULL),
     51       cu_count_(0),
     52       is_exec_(0) {
     53 }
     54 
     55 ElfFile::~ElfFile() {
     56   DwarfCU* cu_to_del = last_cu_;
     57   while (cu_to_del != NULL) {
     58     DwarfCU* next_cu_to_del = cu_to_del->prev_cu_;
     59     delete cu_to_del;
     60     cu_to_del = next_cu_to_del;
     61   }
     62 
     63   if (mapfile_is_valid(elf_handle_)) {
     64     mapfile_close(elf_handle_);
     65   }
     66 
     67   if (elf_file_path_ != NULL) {
     68     delete[] elf_file_path_;
     69   }
     70 
     71   if (sec_table_ != NULL) {
     72     delete[] reinterpret_cast<Elf_Byte*>(sec_table_);
     73   }
     74 
     75   /* Must be deleted last! */
     76   if (allocator_ != NULL) {
     77     delete allocator_;
     78   }
     79 }
     80 
     81 ElfFile* ElfFile::Create(const char* path) {
     82   ElfFile* ret = NULL;
     83   /* Allocate enough space on the stack to fit the largest ELF file header. */
     84   Elf64_FHdr header;
     85   const Elf_CommonHdr* elf_hdr = &header.common;
     86 
     87   assert(path != NULL && *path != '\0');
     88   if (path == NULL || *path == '\0') {
     89     _set_errno(EINVAL);
     90     return NULL;
     91   }
     92 
     93   /*
     94    * Open ELF file, and read its header (the largest one possible).
     95    */
     96   MapFile* file_handle = mapfile_open(path, O_RDONLY | O_BINARY, 0);
     97   if (!mapfile_is_valid(file_handle)) {
     98     return NULL;
     99   }
    100   const ssize_t read_bytes = mapfile_read(file_handle, &header, sizeof(header));
    101   mapfile_close(file_handle);
    102   assert(read_bytes != -1 && read_bytes == sizeof(header));
    103   if (read_bytes == -1 || read_bytes != sizeof(header)) {
    104     if (read_bytes != -1) {
    105       _set_errno(EINVAL);
    106     }
    107     return NULL;
    108   }
    109 
    110   /* Lets see if this is an ELF file at all. */
    111   if (memcmp(elf_hdr->e_ident, ELFMAG, SELFMAG) != 0) {
    112     /* File is not an ELF file. */
    113     _set_errno(ENOEXEC);
    114     return NULL;
    115   }
    116 
    117   /* Lets check ELF's "bitness". */
    118   assert(elf_hdr->ei_info.ei_class == ELFCLASS32 ||
    119          elf_hdr->ei_info.ei_class == ELFCLASS64);
    120   if (elf_hdr->ei_info.ei_class != ELFCLASS32 &&
    121       elf_hdr->ei_info.ei_class != ELFCLASS64) {
    122     /* Neither 32, or 64-bit ELF file. Something wrong here. */
    123     _set_errno(EBADF);
    124     return NULL;
    125   }
    126 
    127   /* Lets instantiate appropriate ElfFileImpl object for this ELF. */
    128   if (elf_hdr->ei_info.ei_class == ELFCLASS32) {
    129     ret = new ElfFileImpl<Elf32_Addr, Elf32_Off>;
    130   } else {
    131     ret = new ElfFileImpl<Elf64_Addr, Elf64_Off>;
    132   }
    133   assert(ret != NULL);
    134   if (ret != NULL) {
    135     if (!ret->initialize(elf_hdr, path)) {
    136       delete ret;
    137       ret = NULL;
    138     }
    139   } else {
    140     _set_errno(ENOMEM);
    141   }
    142 
    143   return ret;
    144 }
    145 
    146 bool ElfFile::initialize(const Elf_CommonHdr* elf_hdr, const char* path) {
    147   /* Must be created first! */
    148   allocator_ = new ElfAllocator();
    149   assert(allocator_ != NULL);
    150   if (allocator_ == NULL) {
    151     _set_errno(ENOMEM);
    152     return false;
    153   }
    154 
    155   /* Copy file path. */
    156   size_t path_len = strlen(path) + 1;
    157   elf_file_path_ = new char[path_len];
    158   assert(elf_file_path_ != NULL);
    159   if (elf_file_path_ == NULL) {
    160     _set_errno(ENOMEM);
    161     return false;
    162   }
    163   memcpy(elf_file_path_, path, path_len);
    164 
    165   /* Cache some basic ELF properties. */
    166   is_ELF_64_ = elf_hdr->ei_info.ei_class == ELFCLASS64;
    167   is_elf_big_endian_ = elf_hdr->ei_info.ei_data == ELFDATA2MSB;
    168   same_endianness_ = is_elf_little_endian() == is_little_endian_cpu();
    169   is_exec_ = elf_hdr->e_type == 2;
    170 
    171   /* Reopen file for further reads and mappings. */
    172   elf_handle_ = mapfile_open(elf_file_path_, O_RDONLY | O_BINARY, 0);
    173   return mapfile_is_valid(elf_handle_);
    174 }
    175 
    176 bool ElfFile::get_pc_address_info(Elf_Xword address,
    177                                   Elf_AddressInfo* address_info) {
    178   assert(address_info != NULL);
    179   if (address_info == NULL) {
    180     _set_errno(EINVAL);
    181     return false;
    182   }
    183 
    184   /* Collect routine information for all CUs in this file. */
    185   if (parse_compilation_units(&parse_rt_context) == -1) {
    186     return false;
    187   }
    188 
    189   /* Iterate through the collected CUs looking for the one that
    190    * contains the given address. */
    191   address_info->inline_stack = NULL;
    192   DwarfCU* cu = last_cu();
    193   while (cu != NULL) {
    194     /* Find a leaf DIE object in the current CU that contains the address. */
    195     Dwarf_AddressInfo info;
    196     info.die_obj = cu->get_leaf_die_for_address(address);
    197     if (info.die_obj != NULL) {
    198       /* Convert the address to a location inside source file. */
    199       if (cu->get_pc_address_file_info(address, &info)) {
    200           /* Copy location information to the returning structure. */
    201           address_info->file_name = info.file_name;
    202           address_info->dir_name = info.dir_name;
    203           address_info->line_number = info.line_number;
    204       } else {
    205           address_info->file_name = NULL;
    206           address_info->dir_name = NULL;
    207           address_info->line_number = 0;
    208       }
    209 
    210       /* Lets see if the DIE represents a routine (rather than
    211        * a lexical block, for instance). */
    212       Dwarf_Tag tag = info.die_obj->get_tag();
    213       while (!dwarf_tag_is_routine(tag)) {
    214         /* This is not a routine DIE. Lets loop trhough the parents of that
    215          * DIE looking for the first routine DIE. */
    216         info.die_obj = info.die_obj->parent_die();
    217         if (info.die_obj == NULL) {
    218           /* Reached compilation unit DIE. Can't go any further. */
    219           address_info->routine_name = "<unknown>";
    220           return true;
    221         }
    222         tag = info.die_obj->get_tag();
    223       }
    224 
    225       /* Save name of the routine that contains the address. */
    226       address_info->routine_name = info.die_obj->get_name();
    227       if (address_info->routine_name == NULL) {
    228         /* In some cases (minimum debugging info in the file) routine
    229          * name may be not avaible. We, however, are obliged by API
    230          * considerations to return something in this field. */
    231           address_info->routine_name = "<unknown>";
    232       }
    233 
    234       /* Lets see if address belongs to an inlined routine. */
    235       if (tag != DW_TAG_inlined_subroutine) {
    236         address_info->inline_stack = NULL;
    237         return true;
    238       }
    239 
    240       /*
    241        * Address belongs to an inlined routine. Create inline stack.
    242        */
    243 
    244       /* Allocate inline stack array big enough to fit all parent entries. */
    245       address_info->inline_stack =
    246         new Elf_InlineInfo[info.die_obj->get_level() + 1];
    247       assert(address_info->inline_stack != NULL);
    248       if (address_info->inline_stack == NULL) {
    249         _set_errno(ENOMEM);
    250         return false;
    251       }
    252       memset(address_info->inline_stack, 0,
    253              sizeof(Elf_InlineInfo) * (info.die_obj->get_level() + 1));
    254 
    255       /* Reverse DIEs filling in inline stack entries for inline
    256        * routine tags. */
    257       int inl_index = 0;
    258       do {
    259         /* Save source file information. */
    260         DIEAttrib file_desc;
    261         if (info.die_obj->get_attrib(DW_AT_call_file, &file_desc)) {
    262           const Dwarf_STMTL_FileDesc* desc =
    263               cu->get_stmt_file_info(file_desc.value()->u32);
    264           if (desc != NULL) {
    265             address_info->inline_stack[inl_index].inlined_in_file =
    266                 desc->file_name;
    267             address_info->inline_stack[inl_index].inlined_in_file_dir =
    268                 cu->get_stmt_dir_name(desc->get_dir_index());
    269           }
    270         }
    271         if (address_info->inline_stack[inl_index].inlined_in_file == NULL) {
    272           address_info->inline_stack[inl_index].inlined_in_file = "<unknown>";
    273           address_info->inline_stack[inl_index].inlined_in_file_dir = NULL;
    274         }
    275 
    276         /* Save source line information. */
    277         if (info.die_obj->get_attrib(DW_AT_call_line, &file_desc)) {
    278           address_info->inline_stack[inl_index].inlined_at_line = file_desc.value()->u32;
    279         }
    280 
    281         /* Advance DIE to the parent routine, and save its name. */
    282         info.die_obj = info.die_obj->parent_die();
    283         assert(info.die_obj != NULL);
    284         if (info.die_obj != NULL) {
    285           tag = info.die_obj->get_tag();
    286           while (!dwarf_tag_is_routine(tag)) {
    287             info.die_obj = info.die_obj->parent_die();
    288             if (info.die_obj == NULL) {
    289               break;
    290             }
    291             tag = info.die_obj->get_tag();
    292           }
    293           if (info.die_obj != NULL) {
    294             address_info->inline_stack[inl_index].routine_name =
    295                 info.die_obj->get_name();
    296           }
    297         }
    298         if (address_info->inline_stack[inl_index].routine_name == NULL) {
    299           address_info->inline_stack[inl_index].routine_name = "<unknown>";
    300         }
    301 
    302         /* Continue with the parent DIE. */
    303         inl_index++;
    304       } while (info.die_obj != NULL && tag == DW_TAG_inlined_subroutine);
    305 
    306       return true;
    307     }
    308     cu = cu->prev_cu();
    309   }
    310 
    311   return false;
    312 }
    313 
    314 void ElfFile::free_pc_address_info(Elf_AddressInfo* address_info) const {
    315   assert(address_info != NULL);
    316   if (address_info != NULL && address_info->inline_stack != NULL) {
    317     delete address_info->inline_stack;
    318     address_info->inline_stack = NULL;
    319   }
    320 }
    321 
    322 //=============================================================================
    323 // ElfFileImpl
    324 //=============================================================================
    325 
    326 template <typename Elf_Addr, typename Elf_Off>
    327 bool ElfFileImpl<Elf_Addr, Elf_Off>::initialize(const Elf_CommonHdr* elf_hdr,
    328                                                 const char* path) {
    329   /* Must be called first! */
    330   if (!ElfFile::initialize(elf_hdr, path)) {
    331     return false;
    332   }
    333 
    334   /* Cache some header data, so later we can discard the header. */
    335   const Elf_FHdr<Elf_Addr, Elf_Off>* header =
    336       reinterpret_cast<const Elf_FHdr<Elf_Addr, Elf_Off>*>(elf_hdr);
    337   sec_count_ = pull_val(header->e_shnum);
    338   sec_entry_size_ = pull_val(header->e_shentsize);
    339   fixed_base_address_ = pull_val(header->e_entry) & ~0xFFF;
    340 
    341   /* Cache section table (must have one!) */
    342   const Elf_Off sec_table_off = pull_val(header->e_shoff);
    343   assert(sec_table_off != 0 && sec_count_ != 0);
    344   if (sec_table_off == 0 || sec_count_ == 0) {
    345     _set_errno(EBADF);
    346     return false;
    347   }
    348   const size_t sec_table_size = sec_count_ * sec_entry_size_;
    349   sec_table_ = new Elf_Byte[sec_table_size];
    350   assert(sec_table_ != NULL);
    351   if (sec_table_ == NULL) {
    352     _set_errno(ENOMEM);
    353     return false;
    354   }
    355   if (mapfile_read_at(elf_handle_, sec_table_off, sec_table_,
    356                       sec_table_size) < 0) {
    357       return false;
    358   }
    359 
    360   /* Map ELF's string section (must have one!). */
    361   const Elf_Half str_sec_index = pull_val(header->e_shstrndx);
    362   assert(str_sec_index != SHN_UNDEF);
    363   if (str_sec_index == SHN_UNDEF) {
    364     _set_errno(EBADF);
    365     return false;
    366   }
    367   const Elf_SHdr<Elf_Addr, Elf_Off>* str_sec =
    368       reinterpret_cast<const Elf_SHdr<Elf_Addr, Elf_Off>*>
    369           (get_section_by_index(str_sec_index));
    370   assert(str_sec != NULL);
    371   if (str_sec == NULL) {
    372     _set_errno(EBADF);
    373     return false;
    374   }
    375   if (!string_section_.map(elf_handle_, pull_val(str_sec->sh_offset),
    376                            pull_val(str_sec->sh_size))) {
    377     return false;
    378   }
    379 
    380   /* Lets determine DWARF format. According to the docs, DWARF is 64 bit, if
    381    * first 4 bytes in the compilation unit header are set to 0xFFFFFFFF.
    382    * .debug_info section of the ELF file begins with the first CU header. */
    383   if (!map_section_by_name(".debug_info", &debug_info_)) {
    384     _set_errno(EBADF);
    385     return false;
    386   }
    387 
    388   /* Note that we don't care about endianness here, since 0xFFFFFFFF is an
    389    * endianness-independent value, so we don't have to pull_val here. */
    390   is_DWARF_64_ =
    391     *reinterpret_cast<const Elf_Word*>(debug_info_.data()) == 0xFFFFFFFF;
    392 
    393   return true;
    394 }
    395 
    396 template <typename Elf_Addr, typename Elf_Off>
    397 int ElfFileImpl<Elf_Addr, Elf_Off>::parse_compilation_units(
    398     const DwarfParseContext* parse_context) {
    399   /* Lets see if we already parsed the file. */
    400   if (last_cu() != NULL) {
    401     return cu_count_;
    402   }
    403 
    404   /* Cache sections required for this parsing. */
    405   if (!map_section_by_name(".debug_abbrev", &debug_abbrev_) ||
    406       !map_section_by_name(".debug_ranges", &debug_ranges_) ||
    407       !map_section_by_name(".debug_line", &debug_line_) ||
    408       !map_section_by_name(".debug_str", &debug_str_)) {
    409     _set_errno(EBADF);
    410     return false;
    411   }
    412 
    413   /* .debug_info section opens with the first CU header. */
    414   const void* next_cu = debug_info_.data();
    415 
    416   /* Iterate through CUs until we reached the end of .debug_info section, or
    417    * advanced to a CU with zero size, indicating the end of CU list for this
    418    * file. */
    419   while (is_valid_cu(next_cu)) {
    420     /* Instatiate CU, depending on DWARF "bitness". */
    421     DwarfCU* cu = DwarfCU::create_instance(this, next_cu);
    422     if (cu == NULL) {
    423       _set_errno(ENOMEM);
    424       return -1;
    425     }
    426 
    427     if (cu->parse(parse_context, &next_cu)) {
    428       cu->set_prev_cu(last_cu_);
    429       last_cu_ = cu;
    430       cu_count_++;
    431     } else {
    432       delete cu;
    433       return -1;
    434     }
    435   };
    436 
    437   return cu_count_;
    438 }
    439 
    440 template <typename Elf_Addr, typename Elf_Off>
    441 bool ElfFileImpl<Elf_Addr, Elf_Off>::get_section_info_by_name(const char* name,
    442                                                               Elf_Off* offset,
    443                                                               Elf_Word* size) {
    444   const Elf_SHdr<Elf_Addr, Elf_Off>* cur_section =
    445       reinterpret_cast<const Elf_SHdr<Elf_Addr, Elf_Off>*>(sec_table_);
    446 
    447   for (Elf_Half sec = 0; sec < sec_count_; sec++) {
    448     const char* sec_name = get_str_sec_str(pull_val(cur_section->sh_name));
    449     if (sec_name != NULL && strcmp(name, sec_name) == 0) {
    450       *offset = pull_val(cur_section->sh_offset);
    451       *size = pull_val(cur_section->sh_size);
    452       return true;
    453     }
    454     cur_section = reinterpret_cast<const Elf_SHdr<Elf_Addr, Elf_Off>*>
    455                                   (INC_CPTR(cur_section, sec_entry_size_));
    456   }
    457   _set_errno(EINVAL);
    458   return false;
    459 }
    460 
    461 template <typename Elf_Addr, typename Elf_Off>
    462 bool ElfFileImpl<Elf_Addr, Elf_Off>::map_section_by_name(
    463     const char* name,
    464     ElfMappedSection* section) {
    465   if (section->is_mapped()) {
    466     return true;
    467   }
    468 
    469   Elf_Off offset;
    470   Elf_Word size;
    471   if (!get_section_info_by_name(name, &offset, &size)) {
    472     return false;
    473   }
    474 
    475   return section->map(elf_handle_, offset, size);
    476 }
    477