Home | History | Annotate | Download | only in elf
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ART_LIBELFFILE_ELF_ELF_DEBUG_READER_H_
     18 #define ART_LIBELFFILE_ELF_ELF_DEBUG_READER_H_
     19 
     20 #include "base/array_ref.h"
     21 #include "dwarf/headers.h"
     22 #include "elf/elf_utils.h"
     23 #include "xz_utils.h"
     24 
     25 #include <map>
     26 #include <string_view>
     27 
     28 namespace art {
     29 
     30 // Trivial ELF file reader.
     31 //
     32 // It is the bare minimum needed to read mini-debug-info symbols for unwinding.
     33 // We use it to merge JIT mini-debug-infos together or to prune them after GC.
     34 template <typename ElfTypes>
     35 class ElfDebugReader {
     36  public:
     37   // Note that the input buffer might be misaligned.
     38   typedef typename ElfTypes::Ehdr ALIGNED(1) Elf_Ehdr;
     39   typedef typename ElfTypes::Shdr ALIGNED(1) Elf_Shdr;
     40   typedef typename ElfTypes::Sym ALIGNED(1) Elf_Sym;
     41   typedef typename ElfTypes::Addr ALIGNED(1) Elf_Addr;
     42 
     43   // Call Frame Information.
     44   struct CFI {
     45     uint32_t length;  // Length excluding the size of this field.
     46     int32_t cie_pointer;  // Offset in the section or -1 for CIE.
     47 
     48     const uint8_t* data() const { return reinterpret_cast<const uint8_t*>(this); }
     49     size_t size() const { return sizeof(uint32_t) + length; }
     50   } PACKED(1);
     51 
     52   // Common Information Entry.
     53   struct CIE : public CFI {
     54   } PACKED(1);
     55 
     56   // Frame Description Entry.
     57   struct FDE : public CFI {
     58     Elf_Addr sym_addr;
     59     Elf_Addr sym_size;
     60   } PACKED(1);
     61 
     62   explicit ElfDebugReader(ArrayRef<const uint8_t> file) : file_(file) {
     63     header_ = Read<Elf_Ehdr>(/*offset=*/ 0);
     64     CHECK_EQ(header_->e_ident[0], ELFMAG0);
     65     CHECK_EQ(header_->e_ident[1], ELFMAG1);
     66     CHECK_EQ(header_->e_ident[2], ELFMAG2);
     67     CHECK_EQ(header_->e_ident[3], ELFMAG3);
     68     CHECK_EQ(header_->e_ehsize, sizeof(Elf_Ehdr));
     69     CHECK_EQ(header_->e_shentsize, sizeof(Elf_Shdr));
     70 
     71     // Find all ELF sections.
     72     sections_ = Read<Elf_Shdr>(header_->e_shoff, header_->e_shnum);
     73     for (const Elf_Shdr& section : sections_) {
     74       const char* name = Read<char>(sections_[header_->e_shstrndx].sh_offset + section.sh_name);
     75       section_map_[std::string_view(name)] = &section;
     76     }
     77 
     78     // Decompressed embedded debug symbols, if any.
     79     const Elf_Shdr* gnu_debugdata = section_map_[".gnu_debugdata"];
     80     if (gnu_debugdata != nullptr) {
     81       auto compressed = Read<uint8_t>(gnu_debugdata->sh_offset, gnu_debugdata->sh_size);
     82       XzDecompress(compressed, &decompressed_gnu_debugdata_);
     83       gnu_debugdata_reader_.reset(new ElfDebugReader(decompressed_gnu_debugdata_));
     84     }
     85   }
     86 
     87   explicit ElfDebugReader(std::vector<uint8_t>& file)
     88       : ElfDebugReader(ArrayRef<const uint8_t>(file)) {
     89   }
     90 
     91   const Elf_Ehdr* GetHeader() { return header_; }
     92 
     93   ArrayRef<Elf_Shdr> GetSections() { return sections_; }
     94 
     95   const Elf_Shdr* GetSection(const char* name) { return section_map_[name]; }
     96 
     97   template <typename VisitSym>
     98   void VisitFunctionSymbols(VisitSym visit_sym) {
     99     const Elf_Shdr* symtab = GetSection(".symtab");
    100     const Elf_Shdr* strtab = GetSection(".strtab");
    101     const Elf_Shdr* text = GetSection(".text");
    102     if (symtab != nullptr && strtab != nullptr) {
    103       CHECK_EQ(symtab->sh_entsize, sizeof(Elf_Sym));
    104       size_t count = symtab->sh_size / sizeof(Elf_Sym);
    105       for (const Elf_Sym& symbol : Read<Elf_Sym>(symtab->sh_offset, count)) {
    106         if (ELF_ST_TYPE(symbol.st_info) == STT_FUNC && &sections_[symbol.st_shndx] == text) {
    107           visit_sym(symbol, Read<char>(strtab->sh_offset + symbol.st_name));
    108         }
    109       }
    110     }
    111     if (gnu_debugdata_reader_ != nullptr) {
    112       gnu_debugdata_reader_->VisitFunctionSymbols(visit_sym);
    113     }
    114   }
    115 
    116   template <typename VisitSym>
    117   void VisitDynamicSymbols(VisitSym visit_sym) {
    118     const Elf_Shdr* dynsym = GetSection(".dynsym");
    119     const Elf_Shdr* dynstr = GetSection(".dynstr");
    120     if (dynsym != nullptr && dynstr != nullptr) {
    121       CHECK_EQ(dynsym->sh_entsize, sizeof(Elf_Sym));
    122       size_t count = dynsym->sh_size / sizeof(Elf_Sym);
    123       for (const Elf_Sym& symbol : Read<Elf_Sym>(dynsym->sh_offset, count)) {
    124         visit_sym(symbol, Read<char>(dynstr->sh_offset + symbol.st_name));
    125       }
    126     }
    127   }
    128 
    129   template <typename VisitCIE, typename VisitFDE>
    130   void VisitDebugFrame(VisitCIE visit_cie, VisitFDE visit_fde) {
    131     const Elf_Shdr* debug_frame = GetSection(".debug_frame");
    132     if (debug_frame != nullptr) {
    133       for (size_t offset = 0; offset < debug_frame->sh_size;) {
    134         const CFI* entry = Read<CFI>(debug_frame->sh_offset + offset);
    135         DCHECK_LE(entry->size(), debug_frame->sh_size - offset);
    136         if (entry->cie_pointer == -1) {
    137           visit_cie(Read<CIE>(debug_frame->sh_offset + offset));
    138         } else {
    139           const FDE* fde = Read<FDE>(debug_frame->sh_offset + offset);
    140           visit_fde(fde, Read<CIE>(debug_frame->sh_offset + fde->cie_pointer));
    141         }
    142         offset += entry->size();
    143       }
    144     }
    145     if (gnu_debugdata_reader_ != nullptr) {
    146       gnu_debugdata_reader_->VisitDebugFrame(visit_cie, visit_fde);
    147     }
    148   }
    149 
    150  private:
    151   template<typename T>
    152   const T* Read(size_t offset) {
    153     DCHECK_LE(offset + sizeof(T), file_.size());
    154     return reinterpret_cast<const T*>(file_.data() + offset);
    155   }
    156 
    157   template<typename T>
    158   ArrayRef<const T> Read(size_t offset, size_t count) {
    159     DCHECK_LE(offset + count * sizeof(T), file_.size());
    160     return ArrayRef<const T>(Read<T>(offset), count);
    161   }
    162 
    163   ArrayRef<const uint8_t> const file_;
    164   const Elf_Ehdr* header_;
    165   ArrayRef<const Elf_Shdr> sections_;
    166   std::unordered_map<std::string_view, const Elf_Shdr*> section_map_;
    167   std::vector<uint8_t> decompressed_gnu_debugdata_;
    168   std::unique_ptr<ElfDebugReader> gnu_debugdata_reader_;
    169 
    170   DISALLOW_COPY_AND_ASSIGN(ElfDebugReader);
    171 };
    172 
    173 }  // namespace art
    174 #endif  // ART_LIBELFFILE_ELF_ELF_DEBUG_READER_H_
    175