xref: /llvm-project/offload/plugins-nextgen/common/src/Utils/ELF.cpp (revision bdf727065b581c45b68a81090272f497f1ce5485)
1330d8983SJohannes Doerfert //===-- Utils/ELF.cpp - Common ELF functionality --------------------------===//
2330d8983SJohannes Doerfert //
3330d8983SJohannes Doerfert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4330d8983SJohannes Doerfert // See https://llvm.org/LICENSE.txt for license information.
5330d8983SJohannes Doerfert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6330d8983SJohannes Doerfert //
7330d8983SJohannes Doerfert //===----------------------------------------------------------------------===//
8330d8983SJohannes Doerfert //
9330d8983SJohannes Doerfert // Common ELF functionality for target plugins.
10330d8983SJohannes Doerfert //
11330d8983SJohannes Doerfert //===----------------------------------------------------------------------===//
12330d8983SJohannes Doerfert 
13330d8983SJohannes Doerfert #include "Utils/ELF.h"
14330d8983SJohannes Doerfert 
15330d8983SJohannes Doerfert #include "llvm/BinaryFormat/Magic.h"
16330d8983SJohannes Doerfert #include "llvm/Object/Binary.h"
17330d8983SJohannes Doerfert #include "llvm/Object/ELFObjectFile.h"
18330d8983SJohannes Doerfert #include "llvm/Object/ELFTypes.h"
19330d8983SJohannes Doerfert #include "llvm/Object/ObjectFile.h"
20330d8983SJohannes Doerfert #include "llvm/Support/MemoryBuffer.h"
21330d8983SJohannes Doerfert 
22330d8983SJohannes Doerfert using namespace llvm;
23330d8983SJohannes Doerfert using namespace llvm::ELF;
24330d8983SJohannes Doerfert using namespace llvm::object;
25330d8983SJohannes Doerfert 
26330d8983SJohannes Doerfert bool utils::elf::isELF(StringRef Buffer) {
27330d8983SJohannes Doerfert   switch (identify_magic(Buffer)) {
28330d8983SJohannes Doerfert   case file_magic::elf:
29330d8983SJohannes Doerfert   case file_magic::elf_relocatable:
30330d8983SJohannes Doerfert   case file_magic::elf_executable:
31330d8983SJohannes Doerfert   case file_magic::elf_shared_object:
32330d8983SJohannes Doerfert   case file_magic::elf_core:
33330d8983SJohannes Doerfert     return true;
34330d8983SJohannes Doerfert   default:
35330d8983SJohannes Doerfert     return false;
36330d8983SJohannes Doerfert   }
37330d8983SJohannes Doerfert }
38330d8983SJohannes Doerfert 
39e3938f4dSJoseph Huber uint16_t utils::elf::getTargetMachine() {
40e3938f4dSJoseph Huber #if defined(__x86_64__)
41e3938f4dSJoseph Huber   return EM_X86_64;
42e3938f4dSJoseph Huber #elif defined(__s390x__)
43e3938f4dSJoseph Huber   return EM_S390;
44e3938f4dSJoseph Huber #elif defined(__aarch64__)
45e3938f4dSJoseph Huber   return EM_AARCH64;
46e3938f4dSJoseph Huber #elif defined(__powerpc64__)
47e3938f4dSJoseph Huber   return EM_PPC64;
48b6bd7477Saurel32 #elif defined(__riscv)
49b6bd7477Saurel32   return EM_RISCV;
50*bdf72706Swanglei #elif defined(__loongarch__)
51*bdf72706Swanglei   return EM_LOONGARCH;
52e3938f4dSJoseph Huber #else
53e3938f4dSJoseph Huber #warning "Unknown ELF compilation target architecture"
54e3938f4dSJoseph Huber   return EM_NONE;
55e3938f4dSJoseph Huber #endif
56e3938f4dSJoseph Huber }
57e3938f4dSJoseph Huber 
58330d8983SJohannes Doerfert template <class ELFT>
59330d8983SJohannes Doerfert static Expected<bool>
60330d8983SJohannes Doerfert checkMachineImpl(const object::ELFObjectFile<ELFT> &ELFObj, uint16_t EMachine) {
61330d8983SJohannes Doerfert   const auto Header = ELFObj.getELFFile().getHeader();
62330d8983SJohannes Doerfert   if (Header.e_type != ET_EXEC && Header.e_type != ET_DYN)
63330d8983SJohannes Doerfert     return createError("Only executable ELF files are supported");
64330d8983SJohannes Doerfert 
65330d8983SJohannes Doerfert   if (Header.e_machine == EM_AMDGPU) {
66330d8983SJohannes Doerfert     if (Header.e_ident[EI_OSABI] != ELFOSABI_AMDGPU_HSA)
67330d8983SJohannes Doerfert       return createError("Invalid AMD OS/ABI, must be AMDGPU_HSA");
68330d8983SJohannes Doerfert     if (Header.e_ident[EI_ABIVERSION] != ELFABIVERSION_AMDGPU_HSA_V4 &&
69eb49788bSShilei Tian         Header.e_ident[EI_ABIVERSION] != ELFABIVERSION_AMDGPU_HSA_V5 &&
70eb49788bSShilei Tian         Header.e_ident[EI_ABIVERSION] != ELFABIVERSION_AMDGPU_HSA_V6)
71eb49788bSShilei Tian       return createError("Invalid AMD ABI version, must be version 4 or above");
72330d8983SJohannes Doerfert     if ((Header.e_flags & EF_AMDGPU_MACH) < EF_AMDGPU_MACH_AMDGCN_GFX700 ||
73f2bceb23Shidekisaito         (Header.e_flags & EF_AMDGPU_MACH) >
74f2bceb23Shidekisaito             EF_AMDGPU_MACH_AMDGCN_GFX9_4_GENERIC)
75330d8983SJohannes Doerfert       return createError("Unsupported AMDGPU architecture");
76330d8983SJohannes Doerfert   } else if (Header.e_machine == EM_CUDA) {
77330d8983SJohannes Doerfert     if (~Header.e_flags & EF_CUDA_64BIT_ADDRESS)
78330d8983SJohannes Doerfert       return createError("Invalid CUDA addressing mode");
79330d8983SJohannes Doerfert     if ((Header.e_flags & EF_CUDA_SM) < EF_CUDA_SM35 ||
80330d8983SJohannes Doerfert         (Header.e_flags & EF_CUDA_SM) > EF_CUDA_SM90)
81330d8983SJohannes Doerfert       return createError("Unsupported NVPTX architecture");
82330d8983SJohannes Doerfert   }
83330d8983SJohannes Doerfert 
84330d8983SJohannes Doerfert   return Header.e_machine == EMachine;
85330d8983SJohannes Doerfert }
86330d8983SJohannes Doerfert 
87330d8983SJohannes Doerfert Expected<bool> utils::elf::checkMachine(StringRef Object, uint16_t EMachine) {
88330d8983SJohannes Doerfert   assert(isELF(Object) && "Input is not an ELF!");
89330d8983SJohannes Doerfert 
90330d8983SJohannes Doerfert   Expected<std::unique_ptr<ObjectFile>> ElfOrErr =
91330d8983SJohannes Doerfert       ObjectFile::createELFObjectFile(
92330d8983SJohannes Doerfert           MemoryBufferRef(Object, /*Identifier=*/""),
93330d8983SJohannes Doerfert           /*InitContent=*/false);
94330d8983SJohannes Doerfert   if (!ElfOrErr)
95330d8983SJohannes Doerfert     return ElfOrErr.takeError();
96330d8983SJohannes Doerfert 
97330d8983SJohannes Doerfert   if (const ELF64LEObjectFile *ELFObj =
98330d8983SJohannes Doerfert           dyn_cast<ELF64LEObjectFile>(&**ElfOrErr))
99330d8983SJohannes Doerfert     return checkMachineImpl(*ELFObj, EMachine);
100330d8983SJohannes Doerfert   if (const ELF64BEObjectFile *ELFObj =
101330d8983SJohannes Doerfert           dyn_cast<ELF64BEObjectFile>(&**ElfOrErr))
102330d8983SJohannes Doerfert     return checkMachineImpl(*ELFObj, EMachine);
103330d8983SJohannes Doerfert   return createError("Only 64-bit ELF files are supported");
104330d8983SJohannes Doerfert }
105330d8983SJohannes Doerfert 
106330d8983SJohannes Doerfert template <class ELFT>
107330d8983SJohannes Doerfert static Expected<const typename ELFT::Sym *>
108330d8983SJohannes Doerfert getSymbolFromGnuHashTable(StringRef Name, const typename ELFT::GnuHash &HashTab,
109330d8983SJohannes Doerfert                           ArrayRef<typename ELFT::Sym> SymTab,
110330d8983SJohannes Doerfert                           StringRef StrTab) {
111330d8983SJohannes Doerfert   const uint32_t NameHash = hashGnu(Name);
112330d8983SJohannes Doerfert   const typename ELFT::Word NBucket = HashTab.nbuckets;
113330d8983SJohannes Doerfert   const typename ELFT::Word SymOffset = HashTab.symndx;
114330d8983SJohannes Doerfert   ArrayRef<typename ELFT::Off> Filter = HashTab.filter();
115330d8983SJohannes Doerfert   ArrayRef<typename ELFT::Word> Bucket = HashTab.buckets();
116330d8983SJohannes Doerfert   ArrayRef<typename ELFT::Word> Chain = HashTab.values(SymTab.size());
117330d8983SJohannes Doerfert 
118330d8983SJohannes Doerfert   // Check the bloom filter and exit early if the symbol is not present.
119330d8983SJohannes Doerfert   uint64_t ElfClassBits = ELFT::Is64Bits ? 64 : 32;
120330d8983SJohannes Doerfert   typename ELFT::Off Word =
121330d8983SJohannes Doerfert       Filter[(NameHash / ElfClassBits) % HashTab.maskwords];
122330d8983SJohannes Doerfert   uint64_t Mask = (0x1ull << (NameHash % ElfClassBits)) |
123330d8983SJohannes Doerfert                   (0x1ull << ((NameHash >> HashTab.shift2) % ElfClassBits));
124330d8983SJohannes Doerfert   if ((Word & Mask) != Mask)
125330d8983SJohannes Doerfert     return nullptr;
126330d8983SJohannes Doerfert 
127330d8983SJohannes Doerfert   // The symbol may or may not be present, check the hash values.
128330d8983SJohannes Doerfert   for (typename ELFT::Word I = Bucket[NameHash % NBucket];
129330d8983SJohannes Doerfert        I >= SymOffset && I < SymTab.size(); I = I + 1) {
130330d8983SJohannes Doerfert     const uint32_t ChainHash = Chain[I - SymOffset];
131330d8983SJohannes Doerfert 
132330d8983SJohannes Doerfert     if ((NameHash | 0x1) != (ChainHash | 0x1))
133330d8983SJohannes Doerfert       continue;
134330d8983SJohannes Doerfert 
135330d8983SJohannes Doerfert     if (SymTab[I].st_name >= StrTab.size())
136330d8983SJohannes Doerfert       return createError("symbol [index " + Twine(I) +
137330d8983SJohannes Doerfert                          "] has invalid st_name: " + Twine(SymTab[I].st_name));
138330d8983SJohannes Doerfert     if (StrTab.drop_front(SymTab[I].st_name).data() == Name)
139330d8983SJohannes Doerfert       return &SymTab[I];
140330d8983SJohannes Doerfert 
141330d8983SJohannes Doerfert     if (ChainHash & 0x1)
142330d8983SJohannes Doerfert       return nullptr;
143330d8983SJohannes Doerfert   }
144330d8983SJohannes Doerfert   return nullptr;
145330d8983SJohannes Doerfert }
146330d8983SJohannes Doerfert 
147330d8983SJohannes Doerfert template <class ELFT>
148330d8983SJohannes Doerfert static Expected<const typename ELFT::Sym *>
149330d8983SJohannes Doerfert getSymbolFromSysVHashTable(StringRef Name, const typename ELFT::Hash &HashTab,
150330d8983SJohannes Doerfert                            ArrayRef<typename ELFT::Sym> SymTab,
151330d8983SJohannes Doerfert                            StringRef StrTab) {
152330d8983SJohannes Doerfert   const uint32_t Hash = hashSysV(Name);
153330d8983SJohannes Doerfert   const typename ELFT::Word NBucket = HashTab.nbucket;
154330d8983SJohannes Doerfert   ArrayRef<typename ELFT::Word> Bucket = HashTab.buckets();
155330d8983SJohannes Doerfert   ArrayRef<typename ELFT::Word> Chain = HashTab.chains();
156330d8983SJohannes Doerfert   for (typename ELFT::Word I = Bucket[Hash % NBucket]; I != ELF::STN_UNDEF;
157330d8983SJohannes Doerfert        I = Chain[I]) {
158330d8983SJohannes Doerfert     if (I >= SymTab.size())
159330d8983SJohannes Doerfert       return createError(
160330d8983SJohannes Doerfert           "symbol [index " + Twine(I) +
161330d8983SJohannes Doerfert           "] is greater than the number of symbols: " + Twine(SymTab.size()));
162330d8983SJohannes Doerfert     if (SymTab[I].st_name >= StrTab.size())
163330d8983SJohannes Doerfert       return createError("symbol [index " + Twine(I) +
164330d8983SJohannes Doerfert                          "] has invalid st_name: " + Twine(SymTab[I].st_name));
165330d8983SJohannes Doerfert 
166330d8983SJohannes Doerfert     if (StrTab.drop_front(SymTab[I].st_name).data() == Name)
167330d8983SJohannes Doerfert       return &SymTab[I];
168330d8983SJohannes Doerfert   }
169330d8983SJohannes Doerfert   return nullptr;
170330d8983SJohannes Doerfert }
171330d8983SJohannes Doerfert 
172330d8983SJohannes Doerfert template <class ELFT>
173330d8983SJohannes Doerfert static Expected<std::optional<ELFSymbolRef>>
174330d8983SJohannes Doerfert getHashTableSymbol(const ELFObjectFile<ELFT> &ELFObj,
175330d8983SJohannes Doerfert                    const typename ELFT::Shdr &Sec, StringRef Name) {
176330d8983SJohannes Doerfert   const ELFFile<ELFT> &Elf = ELFObj.getELFFile();
177330d8983SJohannes Doerfert   if (Sec.sh_type != ELF::SHT_HASH && Sec.sh_type != ELF::SHT_GNU_HASH)
178330d8983SJohannes Doerfert     return createError(
179330d8983SJohannes Doerfert         "invalid sh_type for hash table, expected SHT_HASH or SHT_GNU_HASH");
180330d8983SJohannes Doerfert   Expected<typename ELFT::ShdrRange> SectionsOrError = Elf.sections();
181330d8983SJohannes Doerfert   if (!SectionsOrError)
182330d8983SJohannes Doerfert     return SectionsOrError.takeError();
183330d8983SJohannes Doerfert 
184330d8983SJohannes Doerfert   auto SymTabOrErr = getSection<ELFT>(*SectionsOrError, Sec.sh_link);
185330d8983SJohannes Doerfert   if (!SymTabOrErr)
186330d8983SJohannes Doerfert     return SymTabOrErr.takeError();
187330d8983SJohannes Doerfert 
188330d8983SJohannes Doerfert   auto StrTabOrErr =
189330d8983SJohannes Doerfert       Elf.getStringTableForSymtab(**SymTabOrErr, *SectionsOrError);
190330d8983SJohannes Doerfert   if (!StrTabOrErr)
191330d8983SJohannes Doerfert     return StrTabOrErr.takeError();
192330d8983SJohannes Doerfert   StringRef StrTab = *StrTabOrErr;
193330d8983SJohannes Doerfert 
194330d8983SJohannes Doerfert   auto SymsOrErr = Elf.symbols(*SymTabOrErr);
195330d8983SJohannes Doerfert   if (!SymsOrErr)
196330d8983SJohannes Doerfert     return SymsOrErr.takeError();
197330d8983SJohannes Doerfert   ArrayRef<typename ELFT::Sym> SymTab = *SymsOrErr;
198330d8983SJohannes Doerfert 
199330d8983SJohannes Doerfert   // If this is a GNU hash table we verify its size and search the symbol
200330d8983SJohannes Doerfert   // table using the GNU hash table format.
201330d8983SJohannes Doerfert   if (Sec.sh_type == ELF::SHT_GNU_HASH) {
202330d8983SJohannes Doerfert     const typename ELFT::GnuHash *HashTab =
203330d8983SJohannes Doerfert         reinterpret_cast<const typename ELFT::GnuHash *>(Elf.base() +
204330d8983SJohannes Doerfert                                                          Sec.sh_offset);
205330d8983SJohannes Doerfert     if (Sec.sh_offset + Sec.sh_size >= Elf.getBufSize())
206330d8983SJohannes Doerfert       return createError("section has invalid sh_offset: " +
207330d8983SJohannes Doerfert                          Twine(Sec.sh_offset));
208330d8983SJohannes Doerfert     if (Sec.sh_size < sizeof(typename ELFT::GnuHash) ||
209330d8983SJohannes Doerfert         Sec.sh_size <
210330d8983SJohannes Doerfert             sizeof(typename ELFT::GnuHash) +
211330d8983SJohannes Doerfert                 sizeof(typename ELFT::Word) * HashTab->maskwords +
212330d8983SJohannes Doerfert                 sizeof(typename ELFT::Word) * HashTab->nbuckets +
213330d8983SJohannes Doerfert                 sizeof(typename ELFT::Word) * (SymTab.size() - HashTab->symndx))
214330d8983SJohannes Doerfert       return createError("section has invalid sh_size: " + Twine(Sec.sh_size));
215330d8983SJohannes Doerfert     auto Sym = getSymbolFromGnuHashTable<ELFT>(Name, *HashTab, SymTab, StrTab);
216330d8983SJohannes Doerfert     if (!Sym)
217330d8983SJohannes Doerfert       return Sym.takeError();
218330d8983SJohannes Doerfert     if (!*Sym)
219330d8983SJohannes Doerfert       return std::nullopt;
220330d8983SJohannes Doerfert     return ELFObj.toSymbolRef(*SymTabOrErr, *Sym - &SymTab[0]);
221330d8983SJohannes Doerfert   }
222330d8983SJohannes Doerfert 
223330d8983SJohannes Doerfert   // If this is a Sys-V hash table we verify its size and search the symbol
224330d8983SJohannes Doerfert   // table using the Sys-V hash table format.
225330d8983SJohannes Doerfert   if (Sec.sh_type == ELF::SHT_HASH) {
226330d8983SJohannes Doerfert     const typename ELFT::Hash *HashTab =
227330d8983SJohannes Doerfert         reinterpret_cast<const typename ELFT::Hash *>(Elf.base() +
228330d8983SJohannes Doerfert                                                       Sec.sh_offset);
229330d8983SJohannes Doerfert     if (Sec.sh_offset + Sec.sh_size >= Elf.getBufSize())
230330d8983SJohannes Doerfert       return createError("section has invalid sh_offset: " +
231330d8983SJohannes Doerfert                          Twine(Sec.sh_offset));
232330d8983SJohannes Doerfert     if (Sec.sh_size < sizeof(typename ELFT::Hash) ||
233330d8983SJohannes Doerfert         Sec.sh_size < sizeof(typename ELFT::Hash) +
234330d8983SJohannes Doerfert                           sizeof(typename ELFT::Word) * HashTab->nbucket +
235330d8983SJohannes Doerfert                           sizeof(typename ELFT::Word) * HashTab->nchain)
236330d8983SJohannes Doerfert       return createError("section has invalid sh_size: " + Twine(Sec.sh_size));
237330d8983SJohannes Doerfert 
238330d8983SJohannes Doerfert     auto Sym = getSymbolFromSysVHashTable<ELFT>(Name, *HashTab, SymTab, StrTab);
239330d8983SJohannes Doerfert     if (!Sym)
240330d8983SJohannes Doerfert       return Sym.takeError();
241330d8983SJohannes Doerfert     if (!*Sym)
242330d8983SJohannes Doerfert       return std::nullopt;
243330d8983SJohannes Doerfert     return ELFObj.toSymbolRef(*SymTabOrErr, *Sym - &SymTab[0]);
244330d8983SJohannes Doerfert   }
245330d8983SJohannes Doerfert 
246330d8983SJohannes Doerfert   return std::nullopt;
247330d8983SJohannes Doerfert }
248330d8983SJohannes Doerfert 
249330d8983SJohannes Doerfert template <class ELFT>
250330d8983SJohannes Doerfert static Expected<std::optional<ELFSymbolRef>>
251330d8983SJohannes Doerfert getSymTableSymbol(const ELFObjectFile<ELFT> &ELFObj,
252330d8983SJohannes Doerfert                   const typename ELFT::Shdr &Sec, StringRef Name) {
253330d8983SJohannes Doerfert   const ELFFile<ELFT> &Elf = ELFObj.getELFFile();
254330d8983SJohannes Doerfert   if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM)
255330d8983SJohannes Doerfert     return createError(
256330d8983SJohannes Doerfert         "invalid sh_type for hash table, expected SHT_SYMTAB or SHT_DYNSYM");
257330d8983SJohannes Doerfert   Expected<typename ELFT::ShdrRange> SectionsOrError = Elf.sections();
258330d8983SJohannes Doerfert   if (!SectionsOrError)
259330d8983SJohannes Doerfert     return SectionsOrError.takeError();
260330d8983SJohannes Doerfert 
261330d8983SJohannes Doerfert   auto StrTabOrErr = Elf.getStringTableForSymtab(Sec, *SectionsOrError);
262330d8983SJohannes Doerfert   if (!StrTabOrErr)
263330d8983SJohannes Doerfert     return StrTabOrErr.takeError();
264330d8983SJohannes Doerfert   StringRef StrTab = *StrTabOrErr;
265330d8983SJohannes Doerfert 
266330d8983SJohannes Doerfert   auto SymsOrErr = Elf.symbols(&Sec);
267330d8983SJohannes Doerfert   if (!SymsOrErr)
268330d8983SJohannes Doerfert     return SymsOrErr.takeError();
269330d8983SJohannes Doerfert   ArrayRef<typename ELFT::Sym> SymTab = *SymsOrErr;
270330d8983SJohannes Doerfert 
271330d8983SJohannes Doerfert   for (const typename ELFT::Sym &Sym : SymTab)
272330d8983SJohannes Doerfert     if (StrTab.drop_front(Sym.st_name).data() == Name)
273330d8983SJohannes Doerfert       return ELFObj.toSymbolRef(&Sec, &Sym - &SymTab[0]);
274330d8983SJohannes Doerfert 
275330d8983SJohannes Doerfert   return std::nullopt;
276330d8983SJohannes Doerfert }
277330d8983SJohannes Doerfert 
278330d8983SJohannes Doerfert template <class ELFT>
279330d8983SJohannes Doerfert static Expected<std::optional<ELFSymbolRef>>
280330d8983SJohannes Doerfert getSymbolImpl(const ELFObjectFile<ELFT> &ELFObj, StringRef Name) {
281330d8983SJohannes Doerfert   // First try to look up the symbol via the hash table.
282330d8983SJohannes Doerfert   for (ELFSectionRef Sec : ELFObj.sections()) {
283330d8983SJohannes Doerfert     if (Sec.getType() != SHT_HASH && Sec.getType() != SHT_GNU_HASH)
284330d8983SJohannes Doerfert       continue;
285330d8983SJohannes Doerfert 
286330d8983SJohannes Doerfert     auto HashTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex());
287330d8983SJohannes Doerfert     if (!HashTabOrErr)
288330d8983SJohannes Doerfert       return HashTabOrErr.takeError();
289330d8983SJohannes Doerfert     return getHashTableSymbol<ELFT>(ELFObj, **HashTabOrErr, Name);
290330d8983SJohannes Doerfert   }
291330d8983SJohannes Doerfert 
292330d8983SJohannes Doerfert   // If this is an executable file check the entire standard symbol table.
293330d8983SJohannes Doerfert   for (ELFSectionRef Sec : ELFObj.sections()) {
294330d8983SJohannes Doerfert     if (Sec.getType() != SHT_SYMTAB)
295330d8983SJohannes Doerfert       continue;
296330d8983SJohannes Doerfert 
297330d8983SJohannes Doerfert     auto SymTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex());
298330d8983SJohannes Doerfert     if (!SymTabOrErr)
299330d8983SJohannes Doerfert       return SymTabOrErr.takeError();
300330d8983SJohannes Doerfert     return getSymTableSymbol<ELFT>(ELFObj, **SymTabOrErr, Name);
301330d8983SJohannes Doerfert   }
302330d8983SJohannes Doerfert 
303330d8983SJohannes Doerfert   return std::nullopt;
304330d8983SJohannes Doerfert }
305330d8983SJohannes Doerfert 
306330d8983SJohannes Doerfert Expected<std::optional<ELFSymbolRef>>
307330d8983SJohannes Doerfert utils::elf::getSymbol(const ObjectFile &Obj, StringRef Name) {
308330d8983SJohannes Doerfert   if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(&Obj))
309330d8983SJohannes Doerfert     return getSymbolImpl(*ELFObj, Name);
310330d8983SJohannes Doerfert   if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(&Obj))
311330d8983SJohannes Doerfert     return getSymbolImpl(*ELFObj, Name);
312330d8983SJohannes Doerfert   return createError("Only 64-bit ELF files are supported");
313330d8983SJohannes Doerfert }
314330d8983SJohannes Doerfert 
315330d8983SJohannes Doerfert template <class ELFT>
316330d8983SJohannes Doerfert static Expected<const void *>
317330d8983SJohannes Doerfert getSymbolAddressImpl(const ELFObjectFile<ELFT> &ELFObj,
318330d8983SJohannes Doerfert                      const ELFSymbolRef &SymRef) {
319330d8983SJohannes Doerfert   const ELFFile<ELFT> &ELFFile = ELFObj.getELFFile();
320330d8983SJohannes Doerfert 
321330d8983SJohannes Doerfert   auto SymOrErr = ELFObj.getSymbol(SymRef.getRawDataRefImpl());
322330d8983SJohannes Doerfert   if (!SymOrErr)
323330d8983SJohannes Doerfert     return SymOrErr.takeError();
324330d8983SJohannes Doerfert   const auto &Symbol = **SymOrErr;
325330d8983SJohannes Doerfert 
326330d8983SJohannes Doerfert   auto SecOrErr = ELFFile.getSection(Symbol.st_shndx);
327330d8983SJohannes Doerfert   if (!SecOrErr)
328330d8983SJohannes Doerfert     return SecOrErr.takeError();
329330d8983SJohannes Doerfert   const auto &Section = *SecOrErr;
330330d8983SJohannes Doerfert 
331330d8983SJohannes Doerfert   // A section with SHT_NOBITS occupies no space in the file and has no
332330d8983SJohannes Doerfert   // offset.
333330d8983SJohannes Doerfert   if (Section->sh_type == ELF::SHT_NOBITS)
334330d8983SJohannes Doerfert     return createError(
335330d8983SJohannes Doerfert         "invalid sh_type for symbol lookup, cannot be SHT_NOBITS");
336330d8983SJohannes Doerfert 
337330d8983SJohannes Doerfert   uint64_t Offset = Section->sh_offset - Section->sh_addr + Symbol.st_value;
338330d8983SJohannes Doerfert   if (Offset > ELFFile.getBufSize())
339330d8983SJohannes Doerfert     return createError("invalid offset [" + Twine(Offset) +
340330d8983SJohannes Doerfert                        "] into ELF file of size [" +
341330d8983SJohannes Doerfert                        Twine(ELFFile.getBufSize()) + "]");
342330d8983SJohannes Doerfert 
343330d8983SJohannes Doerfert   return ELFFile.base() + Offset;
344330d8983SJohannes Doerfert }
345330d8983SJohannes Doerfert 
346330d8983SJohannes Doerfert Expected<const void *>
347330d8983SJohannes Doerfert utils::elf::getSymbolAddress(const ELFSymbolRef &SymRef) {
348330d8983SJohannes Doerfert   const ObjectFile *Obj = SymRef.getObject();
349330d8983SJohannes Doerfert   if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
350330d8983SJohannes Doerfert     return getSymbolAddressImpl(*ELFObj, SymRef);
351330d8983SJohannes Doerfert   if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
352330d8983SJohannes Doerfert     return getSymbolAddressImpl(*ELFObj, SymRef);
353330d8983SJohannes Doerfert   return createError("Only 64-bit ELF files are supported");
354330d8983SJohannes Doerfert }
355