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::Phdr ALIGNED(1) Elf_Phdr; 40 typedef typename ElfTypes::Shdr ALIGNED(1) Elf_Shdr; 41 typedef typename ElfTypes::Sym ALIGNED(1) Elf_Sym; 42 typedef typename ElfTypes::Addr ALIGNED(1) Elf_Addr; 43 44 // Call Frame Information. 45 struct CFI { 46 uint32_t length; // Length excluding the size of this field. 47 int32_t cie_pointer; // Offset in the section or -1 for CIE. 48 dataCFI49 const uint8_t* data() const { return reinterpret_cast<const uint8_t*>(this); } sizeCFI50 size_t size() const { return sizeof(uint32_t) + length; } 51 } PACKED(1); 52 53 // Common Information Entry. 54 struct CIE : public CFI { 55 } PACKED(1); 56 57 // Frame Description Entry. 58 struct FDE : public CFI { 59 Elf_Addr sym_addr; 60 Elf_Addr sym_size; 61 } PACKED(1); 62 ElfDebugReader(ArrayRef<const uint8_t> file)63 explicit ElfDebugReader(ArrayRef<const uint8_t> file) : file_(file) { 64 header_ = Read<Elf_Ehdr>(/*offset=*/ 0); 65 CHECK_EQ(header_->e_ident[0], ELFMAG0); 66 CHECK_EQ(header_->e_ident[1], ELFMAG1); 67 CHECK_EQ(header_->e_ident[2], ELFMAG2); 68 CHECK_EQ(header_->e_ident[3], ELFMAG3); 69 CHECK_EQ(header_->e_ident[4], sizeof(Elf_Addr) / sizeof(uint32_t)); 70 CHECK_EQ(header_->e_ehsize, sizeof(Elf_Ehdr)); 71 72 // Find all ELF sections. 73 CHECK_EQ(header_->e_shentsize, sizeof(Elf_Shdr)); 74 sections_ = Read<Elf_Shdr>(header_->e_shoff, header_->e_shnum); 75 for (const Elf_Shdr& section : sections_) { 76 const char* name = Read<char>(sections_[header_->e_shstrndx].sh_offset + section.sh_name); 77 section_map_[std::string_view(name)] = §ion; 78 } 79 80 // Decompressed embedded debug symbols, if any. 81 const Elf_Shdr* gnu_debugdata = section_map_[".gnu_debugdata"]; 82 if (gnu_debugdata != nullptr) { 83 auto compressed = Read<uint8_t>(gnu_debugdata->sh_offset, gnu_debugdata->sh_size); 84 XzDecompress(compressed, &decompressed_gnu_debugdata_); 85 gnu_debugdata_reader_.reset(new ElfDebugReader(decompressed_gnu_debugdata_)); 86 } 87 } 88 ElfDebugReader(const std::vector<uint8_t> & file)89 explicit ElfDebugReader(const std::vector<uint8_t>& file) 90 : ElfDebugReader(ArrayRef<const uint8_t>(file)) { 91 } 92 93 // Check that ELF signature is present at the start of the files, 94 // and that the ELF bitness matches the ElfTypes template arguments. IsValidElfHeader(const std::vector<uint8_t> & data)95 static bool IsValidElfHeader(const std::vector<uint8_t>& data) { 96 static constexpr bool kIs64Bit = sizeof(Elf_Addr) == sizeof(uint64_t); 97 static constexpr char kMagic[] = { 0x7f, 'E', 'L', 'F', kIs64Bit ? 2 : 1 }; 98 return data.size() >= sizeof(kMagic) && memcmp(data.data(), kMagic, sizeof(kMagic)) == 0; 99 } 100 GetHeader()101 const Elf_Ehdr* GetHeader() { return header_; } 102 GetSections()103 ArrayRef<Elf_Shdr> GetSections() { return sections_; } 104 GetSection(const char * name)105 const Elf_Shdr* GetSection(const char* name) { return section_map_[name]; } 106 107 // Find the base address where the ELF file wants to be loaded. 108 // This is generally zero (therefore always requiring relocation). GetLoadAddress()109 Elf_Addr GetLoadAddress() { 110 std::optional<Elf_Addr> addr; 111 CHECK_EQ(header_->e_phentsize, sizeof(Elf_Phdr)); 112 for (const Elf_Phdr& phdr : Read<Elf_Phdr>(header_->e_phoff, header_->e_phnum)) { 113 if (phdr.p_type == PT_LOAD) { 114 addr = addr.has_value() ? std::min(addr.value(), phdr.p_vaddr) : phdr.p_vaddr; 115 } 116 } 117 CHECK(addr.has_value()); 118 return addr.value(); 119 } 120 121 template <typename VisitSym> VisitFunctionSymbols(VisitSym visit_sym)122 void VisitFunctionSymbols(VisitSym visit_sym) { 123 const Elf_Shdr* symtab = GetSection(".symtab"); 124 const Elf_Shdr* strtab = GetSection(".strtab"); 125 const Elf_Shdr* text = GetSection(".text"); 126 if (symtab != nullptr && strtab != nullptr) { 127 CHECK_EQ(symtab->sh_entsize, sizeof(Elf_Sym)); 128 size_t count = symtab->sh_size / sizeof(Elf_Sym); 129 for (const Elf_Sym& symbol : Read<Elf_Sym>(symtab->sh_offset, count)) { 130 if (ELF_ST_TYPE(symbol.st_info) == STT_FUNC && §ions_[symbol.st_shndx] == text) { 131 visit_sym(symbol, Read<char>(strtab->sh_offset + symbol.st_name)); 132 } 133 } 134 } 135 if (gnu_debugdata_reader_ != nullptr) { 136 gnu_debugdata_reader_->VisitFunctionSymbols(visit_sym); 137 } 138 } 139 140 template <typename VisitSym> VisitDynamicSymbols(VisitSym visit_sym)141 void VisitDynamicSymbols(VisitSym visit_sym) { 142 const Elf_Shdr* dynsym = GetSection(".dynsym"); 143 const Elf_Shdr* dynstr = GetSection(".dynstr"); 144 if (dynsym != nullptr && dynstr != nullptr) { 145 CHECK_EQ(dynsym->sh_entsize, sizeof(Elf_Sym)); 146 size_t count = dynsym->sh_size / sizeof(Elf_Sym); 147 for (const Elf_Sym& symbol : Read<Elf_Sym>(dynsym->sh_offset, count)) { 148 visit_sym(symbol, Read<char>(dynstr->sh_offset + symbol.st_name)); 149 } 150 } 151 } 152 153 template <typename VisitCIE, typename VisitFDE> VisitDebugFrame(VisitCIE visit_cie,VisitFDE visit_fde)154 void VisitDebugFrame(VisitCIE visit_cie, VisitFDE visit_fde) { 155 const Elf_Shdr* debug_frame = GetSection(".debug_frame"); 156 if (debug_frame != nullptr) { 157 for (size_t offset = 0; offset < debug_frame->sh_size;) { 158 const CFI* entry = Read<CFI>(debug_frame->sh_offset + offset); 159 DCHECK_LE(entry->size(), debug_frame->sh_size - offset); 160 if (entry->cie_pointer == -1) { 161 visit_cie(Read<CIE>(debug_frame->sh_offset + offset)); 162 } else { 163 const FDE* fde = Read<FDE>(debug_frame->sh_offset + offset); 164 visit_fde(fde, Read<CIE>(debug_frame->sh_offset + fde->cie_pointer)); 165 } 166 offset += entry->size(); 167 } 168 } 169 if (gnu_debugdata_reader_ != nullptr) { 170 gnu_debugdata_reader_->VisitDebugFrame(visit_cie, visit_fde); 171 } 172 } 173 174 private: 175 template<typename T> Read(size_t offset)176 const T* Read(size_t offset) { 177 DCHECK_LE(offset + sizeof(T), file_.size()); 178 return reinterpret_cast<const T*>(file_.data() + offset); 179 } 180 181 template<typename T> Read(size_t offset,size_t count)182 ArrayRef<const T> Read(size_t offset, size_t count) { 183 DCHECK_LE(offset + count * sizeof(T), file_.size()); 184 return ArrayRef<const T>(Read<T>(offset), count); 185 } 186 187 ArrayRef<const uint8_t> const file_; 188 const Elf_Ehdr* header_; 189 ArrayRef<const Elf_Shdr> sections_; 190 std::unordered_map<std::string_view, const Elf_Shdr*> section_map_; 191 std::vector<uint8_t> decompressed_gnu_debugdata_; 192 std::unique_ptr<ElfDebugReader> gnu_debugdata_reader_; 193 194 DISALLOW_COPY_AND_ASSIGN(ElfDebugReader); 195 }; 196 197 } // namespace art 198 #endif // ART_LIBELFFILE_ELF_ELF_DEBUG_READER_H_ 199