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)] = &section;
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 && &sections_[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