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