xref: /aosp_15_r20/external/stg/elf_loader.cc (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*-
3*9e3b08aeSAndroid Build Coastguard Worker //
4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2020-2022 Google LLC
5*9e3b08aeSAndroid Build Coastguard Worker //
6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the
8*9e3b08aeSAndroid Build Coastguard Worker // License.  You may obtain a copy of the License at
9*9e3b08aeSAndroid Build Coastguard Worker //
10*9e3b08aeSAndroid Build Coastguard Worker //     https://llvm.org/LICENSE.txt
11*9e3b08aeSAndroid Build Coastguard Worker //
12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License.
17*9e3b08aeSAndroid Build Coastguard Worker //
18*9e3b08aeSAndroid Build Coastguard Worker // Author: Maria Teguiani
19*9e3b08aeSAndroid Build Coastguard Worker // Author: Giuliano Procida
20*9e3b08aeSAndroid Build Coastguard Worker // Author: Aleksei Vetrov
21*9e3b08aeSAndroid Build Coastguard Worker 
22*9e3b08aeSAndroid Build Coastguard Worker #include "elf_loader.h"
23*9e3b08aeSAndroid Build Coastguard Worker 
24*9e3b08aeSAndroid Build Coastguard Worker #include <elf.h>
25*9e3b08aeSAndroid Build Coastguard Worker #include <gelf.h>
26*9e3b08aeSAndroid Build Coastguard Worker #include <libelf.h>
27*9e3b08aeSAndroid Build Coastguard Worker 
28*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef>
29*9e3b08aeSAndroid Build Coastguard Worker #include <cstdint>
30*9e3b08aeSAndroid Build Coastguard Worker #include <cstring>
31*9e3b08aeSAndroid Build Coastguard Worker #include <functional>
32*9e3b08aeSAndroid Build Coastguard Worker #include <limits>
33*9e3b08aeSAndroid Build Coastguard Worker #include <ostream>
34*9e3b08aeSAndroid Build Coastguard Worker #include <string>
35*9e3b08aeSAndroid Build Coastguard Worker #include <string_view>
36*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
37*9e3b08aeSAndroid Build Coastguard Worker 
38*9e3b08aeSAndroid Build Coastguard Worker #include "error.h"
39*9e3b08aeSAndroid Build Coastguard Worker #include "graph.h"
40*9e3b08aeSAndroid Build Coastguard Worker 
41*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
42*9e3b08aeSAndroid Build Coastguard Worker namespace elf {
43*9e3b08aeSAndroid Build Coastguard Worker 
44*9e3b08aeSAndroid Build Coastguard Worker namespace {
45*9e3b08aeSAndroid Build Coastguard Worker 
ParseSymbolType(unsigned char symbol_type)46*9e3b08aeSAndroid Build Coastguard Worker SymbolTableEntry::SymbolType ParseSymbolType(unsigned char symbol_type) {
47*9e3b08aeSAndroid Build Coastguard Worker   switch (symbol_type) {
48*9e3b08aeSAndroid Build Coastguard Worker     case STT_NOTYPE:
49*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::SymbolType::NOTYPE;
50*9e3b08aeSAndroid Build Coastguard Worker     case STT_OBJECT:
51*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::SymbolType::OBJECT;
52*9e3b08aeSAndroid Build Coastguard Worker     case STT_FUNC:
53*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::SymbolType::FUNCTION;
54*9e3b08aeSAndroid Build Coastguard Worker     case STT_SECTION:
55*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::SymbolType::SECTION;
56*9e3b08aeSAndroid Build Coastguard Worker     case STT_FILE:
57*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::SymbolType::FILE;
58*9e3b08aeSAndroid Build Coastguard Worker     case STT_COMMON:
59*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::SymbolType::COMMON;
60*9e3b08aeSAndroid Build Coastguard Worker     case STT_TLS:
61*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::SymbolType::TLS;
62*9e3b08aeSAndroid Build Coastguard Worker     case STT_GNU_IFUNC:
63*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::SymbolType::GNU_IFUNC;
64*9e3b08aeSAndroid Build Coastguard Worker     default:
65*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unknown ELF symbol type: " << symbol_type;
66*9e3b08aeSAndroid Build Coastguard Worker   }
67*9e3b08aeSAndroid Build Coastguard Worker }
68*9e3b08aeSAndroid Build Coastguard Worker 
ParseSymbolBinding(unsigned char binding)69*9e3b08aeSAndroid Build Coastguard Worker SymbolTableEntry::Binding ParseSymbolBinding(unsigned char binding) {
70*9e3b08aeSAndroid Build Coastguard Worker   switch (binding) {
71*9e3b08aeSAndroid Build Coastguard Worker     case STB_LOCAL:
72*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::Binding::LOCAL;
73*9e3b08aeSAndroid Build Coastguard Worker     case STB_GLOBAL:
74*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::Binding::GLOBAL;
75*9e3b08aeSAndroid Build Coastguard Worker     case STB_WEAK:
76*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::Binding::WEAK;
77*9e3b08aeSAndroid Build Coastguard Worker     case STB_GNU_UNIQUE:
78*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::Binding::GNU_UNIQUE;
79*9e3b08aeSAndroid Build Coastguard Worker     default:
80*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unknown ELF symbol binding: " << binding;
81*9e3b08aeSAndroid Build Coastguard Worker   }
82*9e3b08aeSAndroid Build Coastguard Worker }
83*9e3b08aeSAndroid Build Coastguard Worker 
ParseSymbolVisibility(unsigned char visibility)84*9e3b08aeSAndroid Build Coastguard Worker SymbolTableEntry::Visibility ParseSymbolVisibility(unsigned char visibility) {
85*9e3b08aeSAndroid Build Coastguard Worker   switch (visibility) {
86*9e3b08aeSAndroid Build Coastguard Worker     case STV_DEFAULT:
87*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::Visibility::DEFAULT;
88*9e3b08aeSAndroid Build Coastguard Worker     case STV_INTERNAL:
89*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::Visibility::INTERNAL;
90*9e3b08aeSAndroid Build Coastguard Worker     case STV_HIDDEN:
91*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::Visibility::HIDDEN;
92*9e3b08aeSAndroid Build Coastguard Worker     case STV_PROTECTED:
93*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::Visibility::PROTECTED;
94*9e3b08aeSAndroid Build Coastguard Worker     default:
95*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unknown ELF symbol visibility: " << visibility;
96*9e3b08aeSAndroid Build Coastguard Worker   }
97*9e3b08aeSAndroid Build Coastguard Worker }
98*9e3b08aeSAndroid Build Coastguard Worker 
ParseSymbolValueType(Elf64_Section section_index)99*9e3b08aeSAndroid Build Coastguard Worker SymbolTableEntry::ValueType ParseSymbolValueType(Elf64_Section section_index) {
100*9e3b08aeSAndroid Build Coastguard Worker   switch (section_index) {
101*9e3b08aeSAndroid Build Coastguard Worker     case SHN_UNDEF:
102*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::ValueType::UNDEFINED;
103*9e3b08aeSAndroid Build Coastguard Worker     case SHN_ABS:
104*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::ValueType::ABSOLUTE;
105*9e3b08aeSAndroid Build Coastguard Worker     case SHN_COMMON:
106*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::ValueType::COMMON;
107*9e3b08aeSAndroid Build Coastguard Worker     default:
108*9e3b08aeSAndroid Build Coastguard Worker       return SymbolTableEntry::ValueType::RELATIVE_TO_SECTION;
109*9e3b08aeSAndroid Build Coastguard Worker   }
110*9e3b08aeSAndroid Build Coastguard Worker }
111*9e3b08aeSAndroid Build Coastguard Worker 
ElfHeaderTypeToString(unsigned char elf_header_type)112*9e3b08aeSAndroid Build Coastguard Worker std::string ElfHeaderTypeToString(unsigned char elf_header_type) {
113*9e3b08aeSAndroid Build Coastguard Worker   switch (elf_header_type) {
114*9e3b08aeSAndroid Build Coastguard Worker     case ET_NONE:
115*9e3b08aeSAndroid Build Coastguard Worker       return "none";
116*9e3b08aeSAndroid Build Coastguard Worker     case ET_REL:
117*9e3b08aeSAndroid Build Coastguard Worker       return "relocatable";
118*9e3b08aeSAndroid Build Coastguard Worker     case ET_EXEC:
119*9e3b08aeSAndroid Build Coastguard Worker       return "executable";
120*9e3b08aeSAndroid Build Coastguard Worker     case ET_DYN:
121*9e3b08aeSAndroid Build Coastguard Worker       return "shared object";
122*9e3b08aeSAndroid Build Coastguard Worker     case ET_CORE:
123*9e3b08aeSAndroid Build Coastguard Worker       return "coredump";
124*9e3b08aeSAndroid Build Coastguard Worker     default:
125*9e3b08aeSAndroid Build Coastguard Worker       return "unknown (type = " + std::to_string(elf_header_type) + ')';
126*9e3b08aeSAndroid Build Coastguard Worker   }
127*9e3b08aeSAndroid Build Coastguard Worker }
128*9e3b08aeSAndroid Build Coastguard Worker 
ElfSectionTypeToString(Elf64_Word elf_section_type)129*9e3b08aeSAndroid Build Coastguard Worker std::string ElfSectionTypeToString(Elf64_Word elf_section_type) {
130*9e3b08aeSAndroid Build Coastguard Worker   switch (elf_section_type) {
131*9e3b08aeSAndroid Build Coastguard Worker     case SHT_SYMTAB:
132*9e3b08aeSAndroid Build Coastguard Worker       return "symtab";
133*9e3b08aeSAndroid Build Coastguard Worker     case SHT_DYNSYM:
134*9e3b08aeSAndroid Build Coastguard Worker       return "dynsym";
135*9e3b08aeSAndroid Build Coastguard Worker     case SHT_GNU_verdef:
136*9e3b08aeSAndroid Build Coastguard Worker       return "GNU_verdef";
137*9e3b08aeSAndroid Build Coastguard Worker     case SHT_GNU_verneed:
138*9e3b08aeSAndroid Build Coastguard Worker       return "GNU_verneed";
139*9e3b08aeSAndroid Build Coastguard Worker     case SHT_GNU_versym:
140*9e3b08aeSAndroid Build Coastguard Worker       return "GNU_versym";
141*9e3b08aeSAndroid Build Coastguard Worker     default:
142*9e3b08aeSAndroid Build Coastguard Worker       return "unknown (type = " + std::to_string(elf_section_type) + ')';
143*9e3b08aeSAndroid Build Coastguard Worker   }
144*9e3b08aeSAndroid Build Coastguard Worker }
145*9e3b08aeSAndroid Build Coastguard Worker 
GetMachine(Elf * elf)146*9e3b08aeSAndroid Build Coastguard Worker GElf_Half GetMachine(Elf* elf) {
147*9e3b08aeSAndroid Build Coastguard Worker   GElf_Ehdr header;
148*9e3b08aeSAndroid Build Coastguard Worker   Check(gelf_getehdr(elf, &header) != nullptr) << "could not get ELF header";
149*9e3b08aeSAndroid Build Coastguard Worker   return header.e_machine;
150*9e3b08aeSAndroid Build Coastguard Worker }
151*9e3b08aeSAndroid Build Coastguard Worker 
AdjustAddress(GElf_Half machine,SymbolTableEntry & entry)152*9e3b08aeSAndroid Build Coastguard Worker void AdjustAddress(GElf_Half machine, SymbolTableEntry& entry) {
153*9e3b08aeSAndroid Build Coastguard Worker   if (machine == EM_ARM) {
154*9e3b08aeSAndroid Build Coastguard Worker     if (entry.symbol_type == SymbolTableEntry::SymbolType::FUNCTION
155*9e3b08aeSAndroid Build Coastguard Worker         || entry.symbol_type == SymbolTableEntry::SymbolType::GNU_IFUNC) {
156*9e3b08aeSAndroid Build Coastguard Worker       // Clear bit zero of ARM32 addresses as per "ELF for the Arm Architecture"
157*9e3b08aeSAndroid Build Coastguard Worker       // section 5.5.3.  https://static.docs.arm.com/ihi0044/g/aaelf32.pdf
158*9e3b08aeSAndroid Build Coastguard Worker       entry.value &= ~1;
159*9e3b08aeSAndroid Build Coastguard Worker     }
160*9e3b08aeSAndroid Build Coastguard Worker   } else if (machine == EM_AARCH64) {
161*9e3b08aeSAndroid Build Coastguard Worker     // Copy bit 55 over bits 56 to 63 which may be tag information.
162*9e3b08aeSAndroid Build Coastguard Worker     entry.value = entry.value & (1ULL << 55)
163*9e3b08aeSAndroid Build Coastguard Worker                   ? entry.value | (0xffULL << 56)
164*9e3b08aeSAndroid Build Coastguard Worker                   : entry.value & ~(0xffULL << 56);
165*9e3b08aeSAndroid Build Coastguard Worker   }
166*9e3b08aeSAndroid Build Coastguard Worker }
167*9e3b08aeSAndroid Build Coastguard Worker 
GetSectionsIf(Elf * elf,const std::function<bool (const GElf_Shdr &)> & predicate)168*9e3b08aeSAndroid Build Coastguard Worker std::vector<Elf_Scn*> GetSectionsIf(
169*9e3b08aeSAndroid Build Coastguard Worker     Elf* elf, const std::function<bool(const GElf_Shdr&)>& predicate) {
170*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Elf_Scn*> result;
171*9e3b08aeSAndroid Build Coastguard Worker   Elf_Scn* section = nullptr;
172*9e3b08aeSAndroid Build Coastguard Worker   GElf_Shdr header;
173*9e3b08aeSAndroid Build Coastguard Worker   while ((section = elf_nextscn(elf, section)) != nullptr) {
174*9e3b08aeSAndroid Build Coastguard Worker     Check(gelf_getshdr(section, &header) != nullptr)
175*9e3b08aeSAndroid Build Coastguard Worker         << "could not get ELF section header";
176*9e3b08aeSAndroid Build Coastguard Worker     if (predicate(header)) {
177*9e3b08aeSAndroid Build Coastguard Worker       result.push_back(section);
178*9e3b08aeSAndroid Build Coastguard Worker     }
179*9e3b08aeSAndroid Build Coastguard Worker   }
180*9e3b08aeSAndroid Build Coastguard Worker   return result;
181*9e3b08aeSAndroid Build Coastguard Worker }
182*9e3b08aeSAndroid Build Coastguard Worker 
GetSectionsByName(Elf * elf,const std::string & name)183*9e3b08aeSAndroid Build Coastguard Worker std::vector<Elf_Scn*> GetSectionsByName(Elf* elf, const std::string& name) {
184*9e3b08aeSAndroid Build Coastguard Worker   size_t shdr_strtab_index;
185*9e3b08aeSAndroid Build Coastguard Worker   Check(elf_getshdrstrndx(elf, &shdr_strtab_index) == 0)
186*9e3b08aeSAndroid Build Coastguard Worker       << "could not get ELF section header string table index";
187*9e3b08aeSAndroid Build Coastguard Worker   return GetSectionsIf(elf, [&](const GElf_Shdr& header) {
188*9e3b08aeSAndroid Build Coastguard Worker     const auto* section_name =
189*9e3b08aeSAndroid Build Coastguard Worker         elf_strptr(elf, shdr_strtab_index, header.sh_name);
190*9e3b08aeSAndroid Build Coastguard Worker     return section_name != nullptr && section_name == name;
191*9e3b08aeSAndroid Build Coastguard Worker   });
192*9e3b08aeSAndroid Build Coastguard Worker }
193*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetSectionByName(Elf * elf,const std::string & name)194*9e3b08aeSAndroid Build Coastguard Worker Elf_Scn* MaybeGetSectionByName(Elf* elf, const std::string& name) {
195*9e3b08aeSAndroid Build Coastguard Worker   const auto sections = GetSectionsByName(elf, name);
196*9e3b08aeSAndroid Build Coastguard Worker   if (sections.empty()) {
197*9e3b08aeSAndroid Build Coastguard Worker     return nullptr;
198*9e3b08aeSAndroid Build Coastguard Worker   }
199*9e3b08aeSAndroid Build Coastguard Worker   Check(sections.size() == 1)
200*9e3b08aeSAndroid Build Coastguard Worker       << "multiple sections found with name '" << name << "'";
201*9e3b08aeSAndroid Build Coastguard Worker   return sections[0];
202*9e3b08aeSAndroid Build Coastguard Worker }
203*9e3b08aeSAndroid Build Coastguard Worker 
GetSectionByName(Elf * elf,const std::string & name)204*9e3b08aeSAndroid Build Coastguard Worker Elf_Scn* GetSectionByName(Elf* elf, const std::string& name) {
205*9e3b08aeSAndroid Build Coastguard Worker   Elf_Scn* section = MaybeGetSectionByName(elf, name);
206*9e3b08aeSAndroid Build Coastguard Worker   Check(section != nullptr) << "no section found with name '" << name << "'";
207*9e3b08aeSAndroid Build Coastguard Worker   return section;
208*9e3b08aeSAndroid Build Coastguard Worker }
209*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetSectionByType(Elf * elf,Elf64_Word type)210*9e3b08aeSAndroid Build Coastguard Worker Elf_Scn* MaybeGetSectionByType(Elf* elf, Elf64_Word type) {
211*9e3b08aeSAndroid Build Coastguard Worker   auto sections = GetSectionsIf(
212*9e3b08aeSAndroid Build Coastguard Worker       elf, [&](const GElf_Shdr& header) { return header.sh_type == type; });
213*9e3b08aeSAndroid Build Coastguard Worker   if (sections.empty()) {
214*9e3b08aeSAndroid Build Coastguard Worker     return nullptr;
215*9e3b08aeSAndroid Build Coastguard Worker   }
216*9e3b08aeSAndroid Build Coastguard Worker   Check(sections.size() == 1) << "multiple sections found with type " << type;
217*9e3b08aeSAndroid Build Coastguard Worker   return sections[0];
218*9e3b08aeSAndroid Build Coastguard Worker }
219*9e3b08aeSAndroid Build Coastguard Worker 
GetSectionByIndex(Elf * elf,size_t index)220*9e3b08aeSAndroid Build Coastguard Worker Elf_Scn* GetSectionByIndex(Elf* elf, size_t index) {
221*9e3b08aeSAndroid Build Coastguard Worker   Elf_Scn* section = elf_getscn(elf, index);
222*9e3b08aeSAndroid Build Coastguard Worker   Check(section != nullptr) << "no section found with index " << index;
223*9e3b08aeSAndroid Build Coastguard Worker   return section;
224*9e3b08aeSAndroid Build Coastguard Worker }
225*9e3b08aeSAndroid Build Coastguard Worker 
226*9e3b08aeSAndroid Build Coastguard Worker struct SectionInfo {
227*9e3b08aeSAndroid Build Coastguard Worker   GElf_Shdr header;
228*9e3b08aeSAndroid Build Coastguard Worker   Elf_Data* data;
229*9e3b08aeSAndroid Build Coastguard Worker };
230*9e3b08aeSAndroid Build Coastguard Worker 
GetSectionInfo(Elf_Scn * section)231*9e3b08aeSAndroid Build Coastguard Worker SectionInfo GetSectionInfo(Elf_Scn* section) {
232*9e3b08aeSAndroid Build Coastguard Worker   const size_t index = elf_ndxscn(section);
233*9e3b08aeSAndroid Build Coastguard Worker   GElf_Shdr section_header;
234*9e3b08aeSAndroid Build Coastguard Worker   Check(gelf_getshdr(section, &section_header) != nullptr)
235*9e3b08aeSAndroid Build Coastguard Worker       << "failed to read section (index = " << index << ") header";
236*9e3b08aeSAndroid Build Coastguard Worker   Elf_Data* data = elf_getdata(section, nullptr);
237*9e3b08aeSAndroid Build Coastguard Worker   Check(data != nullptr) << "section (index = " << index << ") data is invalid";
238*9e3b08aeSAndroid Build Coastguard Worker   return {section_header, data};
239*9e3b08aeSAndroid Build Coastguard Worker }
240*9e3b08aeSAndroid Build Coastguard Worker 
GetNumberOfEntries(const GElf_Shdr & section_header)241*9e3b08aeSAndroid Build Coastguard Worker size_t GetNumberOfEntries(const GElf_Shdr& section_header) {
242*9e3b08aeSAndroid Build Coastguard Worker   Check(section_header.sh_entsize != 0)
243*9e3b08aeSAndroid Build Coastguard Worker       << "zero table entity size is unexpected for section "
244*9e3b08aeSAndroid Build Coastguard Worker       << ElfSectionTypeToString(section_header.sh_type);
245*9e3b08aeSAndroid Build Coastguard Worker   return section_header.sh_size / section_header.sh_entsize;
246*9e3b08aeSAndroid Build Coastguard Worker }
247*9e3b08aeSAndroid Build Coastguard Worker 
GetRawData(Elf_Scn * section,const char * name)248*9e3b08aeSAndroid Build Coastguard Worker std::string_view GetRawData(Elf_Scn* section, const char* name) {
249*9e3b08aeSAndroid Build Coastguard Worker   Elf_Data* data = elf_rawdata(section, nullptr);
250*9e3b08aeSAndroid Build Coastguard Worker   Check(data != nullptr) << "elf_rawdata failed on section " << name;
251*9e3b08aeSAndroid Build Coastguard Worker   return {static_cast<char*>(data->d_buf), data->d_size};
252*9e3b08aeSAndroid Build Coastguard Worker }
253*9e3b08aeSAndroid Build Coastguard Worker 
GetString(Elf * elf,uint32_t section,size_t offset)254*9e3b08aeSAndroid Build Coastguard Worker std::string_view GetString(Elf* elf, uint32_t section, size_t offset) {
255*9e3b08aeSAndroid Build Coastguard Worker   const auto name = elf_strptr(elf, section, offset);
256*9e3b08aeSAndroid Build Coastguard Worker 
257*9e3b08aeSAndroid Build Coastguard Worker   Check(name != nullptr) << "string was not found (section: " << section
258*9e3b08aeSAndroid Build Coastguard Worker                          << ", offset: " << offset << ")";
259*9e3b08aeSAndroid Build Coastguard Worker   return name;
260*9e3b08aeSAndroid Build Coastguard Worker }
261*9e3b08aeSAndroid Build Coastguard Worker 
GetSymbolTableSection(Elf * elf,bool is_linux_kernel_binary)262*9e3b08aeSAndroid Build Coastguard Worker Elf_Scn* GetSymbolTableSection(Elf* elf, bool is_linux_kernel_binary) {
263*9e3b08aeSAndroid Build Coastguard Worker   GElf_Ehdr elf_header;
264*9e3b08aeSAndroid Build Coastguard Worker   Check(gelf_getehdr(elf, &elf_header) != nullptr)
265*9e3b08aeSAndroid Build Coastguard Worker       << "could not get ELF header";
266*9e3b08aeSAndroid Build Coastguard Worker 
267*9e3b08aeSAndroid Build Coastguard Worker   Elf_Scn* symtab = MaybeGetSectionByType(elf, SHT_SYMTAB);
268*9e3b08aeSAndroid Build Coastguard Worker   Elf_Scn* dynsym = MaybeGetSectionByType(elf, SHT_DYNSYM);
269*9e3b08aeSAndroid Build Coastguard Worker   if (symtab != nullptr && dynsym != nullptr) {
270*9e3b08aeSAndroid Build Coastguard Worker     // Relocatable ELF binaries, Linux kernel and modules have their
271*9e3b08aeSAndroid Build Coastguard Worker     // exported symbols in .symtab, all other ELF types have their
272*9e3b08aeSAndroid Build Coastguard Worker     // exported symbols in .dynsym.
273*9e3b08aeSAndroid Build Coastguard Worker     if (elf_header.e_type == ET_REL || is_linux_kernel_binary) {
274*9e3b08aeSAndroid Build Coastguard Worker       return symtab;
275*9e3b08aeSAndroid Build Coastguard Worker     }
276*9e3b08aeSAndroid Build Coastguard Worker     if (elf_header.e_type == ET_DYN || elf_header.e_type == ET_EXEC) {
277*9e3b08aeSAndroid Build Coastguard Worker       return dynsym;
278*9e3b08aeSAndroid Build Coastguard Worker     }
279*9e3b08aeSAndroid Build Coastguard Worker     Die() << "unsupported ELF type: '"
280*9e3b08aeSAndroid Build Coastguard Worker           << ElfHeaderTypeToString(elf_header.e_type) << "'";
281*9e3b08aeSAndroid Build Coastguard Worker   } else if (symtab != nullptr) {
282*9e3b08aeSAndroid Build Coastguard Worker     return symtab;
283*9e3b08aeSAndroid Build Coastguard Worker   } else if (dynsym != nullptr) {
284*9e3b08aeSAndroid Build Coastguard Worker     return dynsym;
285*9e3b08aeSAndroid Build Coastguard Worker   } else {
286*9e3b08aeSAndroid Build Coastguard Worker     Die() << "no ELF symbol table found";
287*9e3b08aeSAndroid Build Coastguard Worker   }
288*9e3b08aeSAndroid Build Coastguard Worker }
289*9e3b08aeSAndroid Build Coastguard Worker 
290*9e3b08aeSAndroid Build Coastguard Worker 
291*9e3b08aeSAndroid Build Coastguard Worker constexpr std::string_view kCFISuffix = ".cfi";
292*9e3b08aeSAndroid Build Coastguard Worker 
IsCFISymbolName(std::string_view name)293*9e3b08aeSAndroid Build Coastguard Worker bool IsCFISymbolName(std::string_view name) {
294*9e3b08aeSAndroid Build Coastguard Worker   return name.ends_with(kCFISuffix);
295*9e3b08aeSAndroid Build Coastguard Worker }
296*9e3b08aeSAndroid Build Coastguard Worker 
297*9e3b08aeSAndroid Build Coastguard Worker }  // namespace
298*9e3b08aeSAndroid Build Coastguard Worker 
UnwrapCFISymbolName(std::string_view cfi_name)299*9e3b08aeSAndroid Build Coastguard Worker std::string_view UnwrapCFISymbolName(std::string_view cfi_name) {
300*9e3b08aeSAndroid Build Coastguard Worker   Check(IsCFISymbolName(cfi_name))
301*9e3b08aeSAndroid Build Coastguard Worker       << "CFI symbol " << cfi_name << " doesn't end with " << kCFISuffix;
302*9e3b08aeSAndroid Build Coastguard Worker   return cfi_name.substr(0, cfi_name.size() - kCFISuffix.size());
303*9e3b08aeSAndroid Build Coastguard Worker }
304*9e3b08aeSAndroid Build Coastguard Worker 
305*9e3b08aeSAndroid Build Coastguard Worker namespace {
306*9e3b08aeSAndroid Build Coastguard Worker 
GetSymbols(Elf * elf,Elf_Scn * symbol_table_section,bool cfi)307*9e3b08aeSAndroid Build Coastguard Worker std::vector<SymbolTableEntry> GetSymbols(
308*9e3b08aeSAndroid Build Coastguard Worker     Elf* elf, Elf_Scn* symbol_table_section, bool cfi) {
309*9e3b08aeSAndroid Build Coastguard Worker   const auto machine = GetMachine(elf);
310*9e3b08aeSAndroid Build Coastguard Worker   const auto [symbol_table_header, symbol_table_data] =
311*9e3b08aeSAndroid Build Coastguard Worker       GetSectionInfo(symbol_table_section);
312*9e3b08aeSAndroid Build Coastguard Worker   const size_t number_of_symbols = GetNumberOfEntries(symbol_table_header);
313*9e3b08aeSAndroid Build Coastguard Worker 
314*9e3b08aeSAndroid Build Coastguard Worker   std::vector<SymbolTableEntry> result;
315*9e3b08aeSAndroid Build Coastguard Worker   result.reserve(number_of_symbols);
316*9e3b08aeSAndroid Build Coastguard Worker 
317*9e3b08aeSAndroid Build Coastguard Worker   // GElf uses int for indexes in symbol table, prevent int overflow.
318*9e3b08aeSAndroid Build Coastguard Worker   Check(number_of_symbols <= std::numeric_limits<int>::max())
319*9e3b08aeSAndroid Build Coastguard Worker       << "number of symbols exceeds INT_MAX";
320*9e3b08aeSAndroid Build Coastguard Worker   for (size_t i = 0; i < number_of_symbols; ++i) {
321*9e3b08aeSAndroid Build Coastguard Worker     GElf_Sym symbol;
322*9e3b08aeSAndroid Build Coastguard Worker     Check(gelf_getsym(symbol_table_data, static_cast<int>(i), &symbol) !=
323*9e3b08aeSAndroid Build Coastguard Worker           nullptr)
324*9e3b08aeSAndroid Build Coastguard Worker         << "symbol (i = " << i << ") was not found";
325*9e3b08aeSAndroid Build Coastguard Worker 
326*9e3b08aeSAndroid Build Coastguard Worker     const auto name =
327*9e3b08aeSAndroid Build Coastguard Worker         GetString(elf, symbol_table_header.sh_link, symbol.st_name);
328*9e3b08aeSAndroid Build Coastguard Worker     if (cfi != IsCFISymbolName(name)) {
329*9e3b08aeSAndroid Build Coastguard Worker       continue;
330*9e3b08aeSAndroid Build Coastguard Worker     }
331*9e3b08aeSAndroid Build Coastguard Worker     SymbolTableEntry entry{
332*9e3b08aeSAndroid Build Coastguard Worker         .name = name,
333*9e3b08aeSAndroid Build Coastguard Worker         .value = symbol.st_value,
334*9e3b08aeSAndroid Build Coastguard Worker         .size = symbol.st_size,
335*9e3b08aeSAndroid Build Coastguard Worker         .symbol_type = ParseSymbolType(GELF_ST_TYPE(symbol.st_info)),
336*9e3b08aeSAndroid Build Coastguard Worker         .binding = ParseSymbolBinding(GELF_ST_BIND(symbol.st_info)),
337*9e3b08aeSAndroid Build Coastguard Worker         .visibility =
338*9e3b08aeSAndroid Build Coastguard Worker             ParseSymbolVisibility(GELF_ST_VISIBILITY(symbol.st_other)),
339*9e3b08aeSAndroid Build Coastguard Worker         .section_index = symbol.st_shndx,
340*9e3b08aeSAndroid Build Coastguard Worker         .value_type = ParseSymbolValueType(symbol.st_shndx),
341*9e3b08aeSAndroid Build Coastguard Worker     };
342*9e3b08aeSAndroid Build Coastguard Worker     AdjustAddress(machine, entry);
343*9e3b08aeSAndroid Build Coastguard Worker     result.push_back(entry);
344*9e3b08aeSAndroid Build Coastguard Worker   }
345*9e3b08aeSAndroid Build Coastguard Worker 
346*9e3b08aeSAndroid Build Coastguard Worker   return result;
347*9e3b08aeSAndroid Build Coastguard Worker }
348*9e3b08aeSAndroid Build Coastguard Worker 
IsLinuxKernelBinary(Elf * elf)349*9e3b08aeSAndroid Build Coastguard Worker bool IsLinuxKernelBinary(Elf* elf) {
350*9e3b08aeSAndroid Build Coastguard Worker   // The Linux kernel itself has many specific sections that are sufficient to
351*9e3b08aeSAndroid Build Coastguard Worker   // classify a binary as kernel binary if present, `__ksymtab_strings` is one
352*9e3b08aeSAndroid Build Coastguard Worker   // of them. It is present if a kernel binary (vmlinux or a module) exports
353*9e3b08aeSAndroid Build Coastguard Worker   // symbols via the EXPORT_SYMBOL_* macros and it contains symbol names and
354*9e3b08aeSAndroid Build Coastguard Worker   // namespaces which form part of the ABI.
355*9e3b08aeSAndroid Build Coastguard Worker   //
356*9e3b08aeSAndroid Build Coastguard Worker   // Kernel modules might not present a `__ksymtab_strings` section if they do
357*9e3b08aeSAndroid Build Coastguard Worker   // not export symbols themselves via the ksymtab. Yet they can be identified
358*9e3b08aeSAndroid Build Coastguard Worker   // by the presence of the `.modinfo` section. Since that is somewhat a generic
359*9e3b08aeSAndroid Build Coastguard Worker   // name, also check for the presence of `.gnu.linkonce.this_module` to get
360*9e3b08aeSAndroid Build Coastguard Worker   // solid signal as both of those sections are present in kernel modules.
361*9e3b08aeSAndroid Build Coastguard Worker   return MaybeGetSectionByName(elf, "__ksymtab_strings") != nullptr ||
362*9e3b08aeSAndroid Build Coastguard Worker          (MaybeGetSectionByName(elf, ".modinfo") != nullptr &&
363*9e3b08aeSAndroid Build Coastguard Worker           MaybeGetSectionByName(elf, ".gnu.linkonce.this_module") != nullptr);
364*9e3b08aeSAndroid Build Coastguard Worker }
365*9e3b08aeSAndroid Build Coastguard Worker 
IsRelocatable(Elf * elf)366*9e3b08aeSAndroid Build Coastguard Worker bool IsRelocatable(Elf* elf) {
367*9e3b08aeSAndroid Build Coastguard Worker   GElf_Ehdr elf_header;
368*9e3b08aeSAndroid Build Coastguard Worker   Check(gelf_getehdr(elf, &elf_header) != nullptr)
369*9e3b08aeSAndroid Build Coastguard Worker       << "could not get ELF header";
370*9e3b08aeSAndroid Build Coastguard Worker 
371*9e3b08aeSAndroid Build Coastguard Worker   return elf_header.e_type == ET_REL;
372*9e3b08aeSAndroid Build Coastguard Worker }
373*9e3b08aeSAndroid Build Coastguard Worker 
IsLittleEndianBinary(Elf * elf)374*9e3b08aeSAndroid Build Coastguard Worker bool IsLittleEndianBinary(Elf* elf) {
375*9e3b08aeSAndroid Build Coastguard Worker   GElf_Ehdr elf_header;
376*9e3b08aeSAndroid Build Coastguard Worker   Check(gelf_getehdr(elf, &elf_header) != nullptr)
377*9e3b08aeSAndroid Build Coastguard Worker       << "could not get ELF header";
378*9e3b08aeSAndroid Build Coastguard Worker 
379*9e3b08aeSAndroid Build Coastguard Worker   switch (auto endianness = elf_header.e_ident[EI_DATA]) {
380*9e3b08aeSAndroid Build Coastguard Worker     case ELFDATA2LSB:
381*9e3b08aeSAndroid Build Coastguard Worker       return true;
382*9e3b08aeSAndroid Build Coastguard Worker     case ELFDATA2MSB:
383*9e3b08aeSAndroid Build Coastguard Worker       return false;
384*9e3b08aeSAndroid Build Coastguard Worker     default:
385*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unsupported ELF endianness: " << endianness;
386*9e3b08aeSAndroid Build Coastguard Worker   }
387*9e3b08aeSAndroid Build Coastguard Worker }
388*9e3b08aeSAndroid Build Coastguard Worker 
389*9e3b08aeSAndroid Build Coastguard Worker }  // namespace
390*9e3b08aeSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,SymbolTableEntry::SymbolType type)391*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, SymbolTableEntry::SymbolType type) {
392*9e3b08aeSAndroid Build Coastguard Worker   using SymbolType = SymbolTableEntry::SymbolType;
393*9e3b08aeSAndroid Build Coastguard Worker   switch (type) {
394*9e3b08aeSAndroid Build Coastguard Worker     case SymbolType::NOTYPE:
395*9e3b08aeSAndroid Build Coastguard Worker       return os << "notype";
396*9e3b08aeSAndroid Build Coastguard Worker     case SymbolType::OBJECT:
397*9e3b08aeSAndroid Build Coastguard Worker       return os << "object";
398*9e3b08aeSAndroid Build Coastguard Worker     case SymbolType::FUNCTION:
399*9e3b08aeSAndroid Build Coastguard Worker       return os << "function";
400*9e3b08aeSAndroid Build Coastguard Worker     case SymbolType::SECTION:
401*9e3b08aeSAndroid Build Coastguard Worker       return os << "section";
402*9e3b08aeSAndroid Build Coastguard Worker     case SymbolType::FILE:
403*9e3b08aeSAndroid Build Coastguard Worker       return os << "file";
404*9e3b08aeSAndroid Build Coastguard Worker     case SymbolType::COMMON:
405*9e3b08aeSAndroid Build Coastguard Worker       return os << "common";
406*9e3b08aeSAndroid Build Coastguard Worker     case SymbolType::TLS:
407*9e3b08aeSAndroid Build Coastguard Worker       return os << "TLS";
408*9e3b08aeSAndroid Build Coastguard Worker     case SymbolType::GNU_IFUNC:
409*9e3b08aeSAndroid Build Coastguard Worker       return os << "indirect (ifunc) function";
410*9e3b08aeSAndroid Build Coastguard Worker   }
411*9e3b08aeSAndroid Build Coastguard Worker }
412*9e3b08aeSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const SymbolTableEntry::ValueType type)413*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os,
414*9e3b08aeSAndroid Build Coastguard Worker                          const SymbolTableEntry::ValueType type) {
415*9e3b08aeSAndroid Build Coastguard Worker   using ValueType = SymbolTableEntry::ValueType;
416*9e3b08aeSAndroid Build Coastguard Worker   switch (type) {
417*9e3b08aeSAndroid Build Coastguard Worker     case ValueType::UNDEFINED:
418*9e3b08aeSAndroid Build Coastguard Worker       return os << "undefined";
419*9e3b08aeSAndroid Build Coastguard Worker     case ValueType::ABSOLUTE:
420*9e3b08aeSAndroid Build Coastguard Worker       return os << "absolute";
421*9e3b08aeSAndroid Build Coastguard Worker     case ValueType::COMMON:
422*9e3b08aeSAndroid Build Coastguard Worker       return os << "common";
423*9e3b08aeSAndroid Build Coastguard Worker     case ValueType::RELATIVE_TO_SECTION:
424*9e3b08aeSAndroid Build Coastguard Worker       return os << "relative";
425*9e3b08aeSAndroid Build Coastguard Worker   }
426*9e3b08aeSAndroid Build Coastguard Worker }
427*9e3b08aeSAndroid Build Coastguard Worker 
ElfLoader(Elf & elf)428*9e3b08aeSAndroid Build Coastguard Worker ElfLoader::ElfLoader(Elf& elf)
429*9e3b08aeSAndroid Build Coastguard Worker     : elf_(&elf) {
430*9e3b08aeSAndroid Build Coastguard Worker   InitializeElfInformation();
431*9e3b08aeSAndroid Build Coastguard Worker }
432*9e3b08aeSAndroid Build Coastguard Worker 
InitializeElfInformation()433*9e3b08aeSAndroid Build Coastguard Worker void ElfLoader::InitializeElfInformation() {
434*9e3b08aeSAndroid Build Coastguard Worker   is_linux_kernel_binary_ = elf::IsLinuxKernelBinary(elf_);
435*9e3b08aeSAndroid Build Coastguard Worker   is_relocatable_ = elf::IsRelocatable(elf_);
436*9e3b08aeSAndroid Build Coastguard Worker   is_little_endian_binary_ = elf::IsLittleEndianBinary(elf_);
437*9e3b08aeSAndroid Build Coastguard Worker }
438*9e3b08aeSAndroid Build Coastguard Worker 
GetSectionRawData(const char * name) const439*9e3b08aeSAndroid Build Coastguard Worker std::string_view ElfLoader::GetSectionRawData(const char* name) const {
440*9e3b08aeSAndroid Build Coastguard Worker   return GetRawData(GetSectionByName(elf_, name), name);
441*9e3b08aeSAndroid Build Coastguard Worker }
442*9e3b08aeSAndroid Build Coastguard Worker 
GetElfSymbols() const443*9e3b08aeSAndroid Build Coastguard Worker std::vector<SymbolTableEntry> ElfLoader::GetElfSymbols() const {
444*9e3b08aeSAndroid Build Coastguard Worker   Elf_Scn* symbol_table_section =
445*9e3b08aeSAndroid Build Coastguard Worker       GetSymbolTableSection(elf_, is_linux_kernel_binary_);
446*9e3b08aeSAndroid Build Coastguard Worker   Check(symbol_table_section != nullptr)
447*9e3b08aeSAndroid Build Coastguard Worker       << "failed to find symbol table section";
448*9e3b08aeSAndroid Build Coastguard Worker 
449*9e3b08aeSAndroid Build Coastguard Worker   return GetSymbols(elf_, symbol_table_section, /* cfi = */ false);
450*9e3b08aeSAndroid Build Coastguard Worker }
451*9e3b08aeSAndroid Build Coastguard Worker 
GetCFISymbols() const452*9e3b08aeSAndroid Build Coastguard Worker std::vector<SymbolTableEntry> ElfLoader::GetCFISymbols() const {
453*9e3b08aeSAndroid Build Coastguard Worker   // CFI symbols may be only in .symtab
454*9e3b08aeSAndroid Build Coastguard Worker   Elf_Scn* symbol_table_section = MaybeGetSectionByType(elf_, SHT_SYMTAB);
455*9e3b08aeSAndroid Build Coastguard Worker   if (symbol_table_section == nullptr) {
456*9e3b08aeSAndroid Build Coastguard Worker     // It is possible for ET_DYN and ET_EXEC ELF binaries to not have .symtab,
457*9e3b08aeSAndroid Build Coastguard Worker     // because it was trimmed away. We can't determine whether there were CFI
458*9e3b08aeSAndroid Build Coastguard Worker     // symbols in the first place, so the best we can do is returning an empty
459*9e3b08aeSAndroid Build Coastguard Worker     // list.
460*9e3b08aeSAndroid Build Coastguard Worker     return {};
461*9e3b08aeSAndroid Build Coastguard Worker   }
462*9e3b08aeSAndroid Build Coastguard Worker   return GetSymbols(elf_, symbol_table_section, /* cfi = */ true);
463*9e3b08aeSAndroid Build Coastguard Worker }
464*9e3b08aeSAndroid Build Coastguard Worker 
GetElfSymbolCRC(const SymbolTableEntry & symbol) const465*9e3b08aeSAndroid Build Coastguard Worker ElfSymbol::CRC ElfLoader::GetElfSymbolCRC(
466*9e3b08aeSAndroid Build Coastguard Worker     const SymbolTableEntry& symbol) const {
467*9e3b08aeSAndroid Build Coastguard Worker   Check(is_little_endian_binary_)
468*9e3b08aeSAndroid Build Coastguard Worker       << "CRC is not supported in big-endian binaries";
469*9e3b08aeSAndroid Build Coastguard Worker   const auto address = GetAbsoluteAddress(symbol);
470*9e3b08aeSAndroid Build Coastguard Worker   if (symbol.value_type == SymbolTableEntry::ValueType::ABSOLUTE) {
471*9e3b08aeSAndroid Build Coastguard Worker     return ElfSymbol::CRC{static_cast<uint32_t>(address)};
472*9e3b08aeSAndroid Build Coastguard Worker   }
473*9e3b08aeSAndroid Build Coastguard Worker   Check(symbol.value_type == SymbolTableEntry::ValueType::RELATIVE_TO_SECTION)
474*9e3b08aeSAndroid Build Coastguard Worker       << "CRC symbol is expected to be absolute or relative to a section";
475*9e3b08aeSAndroid Build Coastguard Worker 
476*9e3b08aeSAndroid Build Coastguard Worker   const auto section = GetSectionByIndex(elf_, symbol.section_index);
477*9e3b08aeSAndroid Build Coastguard Worker   const auto [header, data] = GetSectionInfo(section);
478*9e3b08aeSAndroid Build Coastguard Worker   Check(data->d_buf != nullptr) << "Section has no data buffer";
479*9e3b08aeSAndroid Build Coastguard Worker 
480*9e3b08aeSAndroid Build Coastguard Worker   Check(address >= header.sh_addr)
481*9e3b08aeSAndroid Build Coastguard Worker       << "CRC symbol address is below CRC section start";
482*9e3b08aeSAndroid Build Coastguard Worker 
483*9e3b08aeSAndroid Build Coastguard Worker   const size_t offset = address - header.sh_addr;
484*9e3b08aeSAndroid Build Coastguard Worker   const size_t offset_end = offset + sizeof(uint32_t);
485*9e3b08aeSAndroid Build Coastguard Worker   Check(offset_end <= data->d_size && offset_end <= header.sh_size)
486*9e3b08aeSAndroid Build Coastguard Worker       << "CRC symbol address is above CRC section end";
487*9e3b08aeSAndroid Build Coastguard Worker 
488*9e3b08aeSAndroid Build Coastguard Worker   return ElfSymbol::CRC{*reinterpret_cast<uint32_t*>(
489*9e3b08aeSAndroid Build Coastguard Worker       reinterpret_cast<char*>(data->d_buf) + offset)};
490*9e3b08aeSAndroid Build Coastguard Worker }
491*9e3b08aeSAndroid Build Coastguard Worker 
GetElfSymbolNamespace(const SymbolTableEntry & symbol) const492*9e3b08aeSAndroid Build Coastguard Worker std::string_view ElfLoader::GetElfSymbolNamespace(
493*9e3b08aeSAndroid Build Coastguard Worker     const SymbolTableEntry& symbol) const {
494*9e3b08aeSAndroid Build Coastguard Worker   Check(symbol.value_type == SymbolTableEntry::ValueType::RELATIVE_TO_SECTION)
495*9e3b08aeSAndroid Build Coastguard Worker       << "Namespace symbol is expected to be relative to a section";
496*9e3b08aeSAndroid Build Coastguard Worker 
497*9e3b08aeSAndroid Build Coastguard Worker   const auto section = GetSectionByIndex(elf_, symbol.section_index);
498*9e3b08aeSAndroid Build Coastguard Worker   const auto [header, data] = GetSectionInfo(section);
499*9e3b08aeSAndroid Build Coastguard Worker   Check(data->d_buf != nullptr) << "Section has no data buffer";
500*9e3b08aeSAndroid Build Coastguard Worker 
501*9e3b08aeSAndroid Build Coastguard Worker   const auto address = GetAbsoluteAddress(symbol);
502*9e3b08aeSAndroid Build Coastguard Worker   Check(address >= header.sh_addr)
503*9e3b08aeSAndroid Build Coastguard Worker       << "Namespace symbol address is below namespace section start";
504*9e3b08aeSAndroid Build Coastguard Worker 
505*9e3b08aeSAndroid Build Coastguard Worker   const size_t offset = address - header.sh_addr;
506*9e3b08aeSAndroid Build Coastguard Worker   Check(offset < data->d_size && offset < header.sh_size)
507*9e3b08aeSAndroid Build Coastguard Worker       << "Namespace symbol address is above namespace section end";
508*9e3b08aeSAndroid Build Coastguard Worker 
509*9e3b08aeSAndroid Build Coastguard Worker   const char* begin = reinterpret_cast<const char*>(data->d_buf) + offset;
510*9e3b08aeSAndroid Build Coastguard Worker   // TODO: replace strnlen with something in a standard library
511*9e3b08aeSAndroid Build Coastguard Worker   const size_t length = strnlen(begin, data->d_size - offset);
512*9e3b08aeSAndroid Build Coastguard Worker   Check(offset + length < data->d_size)
513*9e3b08aeSAndroid Build Coastguard Worker       << "Namespace string should be null-terminated";
514*9e3b08aeSAndroid Build Coastguard Worker 
515*9e3b08aeSAndroid Build Coastguard Worker   return {begin, length};
516*9e3b08aeSAndroid Build Coastguard Worker }
517*9e3b08aeSAndroid Build Coastguard Worker 
GetAbsoluteAddress(const SymbolTableEntry & symbol) const518*9e3b08aeSAndroid Build Coastguard Worker size_t ElfLoader::GetAbsoluteAddress(const SymbolTableEntry& symbol) const {
519*9e3b08aeSAndroid Build Coastguard Worker   if (symbol.value_type == SymbolTableEntry::ValueType::ABSOLUTE) {
520*9e3b08aeSAndroid Build Coastguard Worker     return symbol.value;
521*9e3b08aeSAndroid Build Coastguard Worker   }
522*9e3b08aeSAndroid Build Coastguard Worker   Check(symbol.value_type == SymbolTableEntry::ValueType::RELATIVE_TO_SECTION)
523*9e3b08aeSAndroid Build Coastguard Worker       << "Only absolute and relative to sections symbols are supported";
524*9e3b08aeSAndroid Build Coastguard Worker   // In relocatable files, st_value holds a section offset for a defined symbol.
525*9e3b08aeSAndroid Build Coastguard Worker   if (is_relocatable_) {
526*9e3b08aeSAndroid Build Coastguard Worker     const auto section = GetSectionByIndex(elf_, symbol.section_index);
527*9e3b08aeSAndroid Build Coastguard Worker     GElf_Shdr header;
528*9e3b08aeSAndroid Build Coastguard Worker     Check(gelf_getshdr(section, &header) != nullptr)
529*9e3b08aeSAndroid Build Coastguard Worker         << "failed to get symbol section header";
530*9e3b08aeSAndroid Build Coastguard Worker     Check(symbol.value + symbol.size <= header.sh_size)
531*9e3b08aeSAndroid Build Coastguard Worker         << "Symbol should be inside the section";
532*9e3b08aeSAndroid Build Coastguard Worker     return symbol.value + header.sh_addr;
533*9e3b08aeSAndroid Build Coastguard Worker   }
534*9e3b08aeSAndroid Build Coastguard Worker   // In executable and shared object files, st_value holds a virtual address.
535*9e3b08aeSAndroid Build Coastguard Worker   return symbol.value;
536*9e3b08aeSAndroid Build Coastguard Worker }
537*9e3b08aeSAndroid Build Coastguard Worker 
IsLinuxKernelBinary() const538*9e3b08aeSAndroid Build Coastguard Worker bool ElfLoader::IsLinuxKernelBinary() const {
539*9e3b08aeSAndroid Build Coastguard Worker   return is_linux_kernel_binary_;
540*9e3b08aeSAndroid Build Coastguard Worker }
541*9e3b08aeSAndroid Build Coastguard Worker 
IsLittleEndianBinary() const542*9e3b08aeSAndroid Build Coastguard Worker bool ElfLoader::IsLittleEndianBinary() const {
543*9e3b08aeSAndroid Build Coastguard Worker   return is_little_endian_binary_;
544*9e3b08aeSAndroid Build Coastguard Worker }
545*9e3b08aeSAndroid Build Coastguard Worker 
546*9e3b08aeSAndroid Build Coastguard Worker }  // namespace elf
547*9e3b08aeSAndroid Build Coastguard Worker }  // namespace stg
548