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