1 //===- ELFObjHandler.cpp --------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===-----------------------------------------------------------------------===/ 8 9 #include "llvm/InterfaceStub/ELFObjHandler.h" 10 #include "llvm/InterfaceStub/IFSStub.h" 11 #include "llvm/MC/StringTableBuilder.h" 12 #include "llvm/Object/Binary.h" 13 #include "llvm/Object/ELFObjectFile.h" 14 #include "llvm/Object/ELFTypes.h" 15 #include "llvm/Support/Errc.h" 16 #include "llvm/Support/Error.h" 17 #include "llvm/Support/FileOutputBuffer.h" 18 #include "llvm/Support/MathExtras.h" 19 #include "llvm/Support/MemoryBuffer.h" 20 #include <optional> 21 22 using llvm::object::ELFObjectFile; 23 24 using namespace llvm; 25 using namespace llvm::object; 26 using namespace llvm::ELF; 27 28 namespace llvm { 29 namespace ifs { 30 31 // Simple struct to hold relevant .dynamic entries. 32 struct DynamicEntries { 33 uint64_t StrTabAddr = 0; 34 uint64_t StrSize = 0; 35 std::optional<uint64_t> SONameOffset; 36 std::vector<uint64_t> NeededLibNames; 37 // Symbol table: 38 uint64_t DynSymAddr = 0; 39 // Hash tables: 40 std::optional<uint64_t> ElfHash; 41 std::optional<uint64_t> GnuHash; 42 }; 43 44 /// This initializes an ELF file header with information specific to a binary 45 /// dynamic shared object. 46 /// Offsets, indexes, links, etc. for section and program headers are just 47 /// zero-initialized as they will be updated elsewhere. 48 /// 49 /// @param ElfHeader Target ELFT::Ehdr to populate. 50 /// @param Machine Target architecture (e_machine from ELF specifications). 51 template <class ELFT> 52 static void initELFHeader(typename ELFT::Ehdr &ElfHeader, uint16_t Machine) { 53 memset(&ElfHeader, 0, sizeof(ElfHeader)); 54 // ELF identification. 55 ElfHeader.e_ident[EI_MAG0] = ElfMagic[EI_MAG0]; 56 ElfHeader.e_ident[EI_MAG1] = ElfMagic[EI_MAG1]; 57 ElfHeader.e_ident[EI_MAG2] = ElfMagic[EI_MAG2]; 58 ElfHeader.e_ident[EI_MAG3] = ElfMagic[EI_MAG3]; 59 ElfHeader.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; 60 bool IsLittleEndian = ELFT::TargetEndianness == llvm::endianness::little; 61 ElfHeader.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; 62 ElfHeader.e_ident[EI_VERSION] = EV_CURRENT; 63 ElfHeader.e_ident[EI_OSABI] = ELFOSABI_NONE; 64 65 // Remainder of ELF header. 66 ElfHeader.e_type = ET_DYN; 67 ElfHeader.e_machine = Machine; 68 ElfHeader.e_version = EV_CURRENT; 69 ElfHeader.e_ehsize = sizeof(typename ELFT::Ehdr); 70 ElfHeader.e_phentsize = sizeof(typename ELFT::Phdr); 71 ElfHeader.e_shentsize = sizeof(typename ELFT::Shdr); 72 } 73 74 namespace { 75 template <class ELFT> struct OutputSection { 76 using Elf_Shdr = typename ELFT::Shdr; 77 std::string Name; 78 Elf_Shdr Shdr; 79 uint64_t Addr; 80 uint64_t Offset; 81 uint64_t Size; 82 uint64_t Align; 83 uint32_t Index; 84 bool NoBits = true; 85 }; 86 87 template <class T, class ELFT> 88 struct ContentSection : public OutputSection<ELFT> { 89 T Content; 90 ContentSection() { this->NoBits = false; } 91 }; 92 93 // This class just wraps StringTableBuilder for the purpose of adding a 94 // default constructor. 95 class ELFStringTableBuilder : public StringTableBuilder { 96 public: 97 ELFStringTableBuilder() : StringTableBuilder(StringTableBuilder::ELF) {} 98 }; 99 100 template <class ELFT> class ELFSymbolTableBuilder { 101 public: 102 using Elf_Sym = typename ELFT::Sym; 103 104 ELFSymbolTableBuilder() { Symbols.push_back({}); } 105 106 void add(size_t StNameOffset, uint64_t StSize, uint8_t StBind, uint8_t StType, 107 uint8_t StOther, uint16_t StShndx) { 108 Elf_Sym S{}; 109 S.st_name = StNameOffset; 110 S.st_size = StSize; 111 S.st_info = (StBind << 4) | (StType & 0xf); 112 S.st_other = StOther; 113 S.st_shndx = StShndx; 114 Symbols.push_back(S); 115 } 116 117 size_t getSize() const { return Symbols.size() * sizeof(Elf_Sym); } 118 119 void write(uint8_t *Buf) const { 120 memcpy(Buf, Symbols.data(), sizeof(Elf_Sym) * Symbols.size()); 121 } 122 123 private: 124 llvm::SmallVector<Elf_Sym, 8> Symbols; 125 }; 126 127 template <class ELFT> class ELFDynamicTableBuilder { 128 public: 129 using Elf_Dyn = typename ELFT::Dyn; 130 131 size_t addAddr(uint64_t Tag, uint64_t Addr) { 132 Elf_Dyn Entry; 133 Entry.d_tag = Tag; 134 Entry.d_un.d_ptr = Addr; 135 Entries.push_back(Entry); 136 return Entries.size() - 1; 137 } 138 139 void modifyAddr(size_t Index, uint64_t Addr) { 140 Entries[Index].d_un.d_ptr = Addr; 141 } 142 143 size_t addValue(uint64_t Tag, uint64_t Value) { 144 Elf_Dyn Entry; 145 Entry.d_tag = Tag; 146 Entry.d_un.d_val = Value; 147 Entries.push_back(Entry); 148 return Entries.size() - 1; 149 } 150 151 void modifyValue(size_t Index, uint64_t Value) { 152 Entries[Index].d_un.d_val = Value; 153 } 154 155 size_t getSize() const { 156 // Add DT_NULL entry at the end. 157 return (Entries.size() + 1) * sizeof(Elf_Dyn); 158 } 159 160 void write(uint8_t *Buf) const { 161 memcpy(Buf, Entries.data(), sizeof(Elf_Dyn) * Entries.size()); 162 // Add DT_NULL entry at the end. 163 memset(Buf + sizeof(Elf_Dyn) * Entries.size(), 0, sizeof(Elf_Dyn)); 164 } 165 166 private: 167 llvm::SmallVector<Elf_Dyn, 8> Entries; 168 }; 169 170 template <class ELFT> class ELFStubBuilder { 171 public: 172 using Elf_Ehdr = typename ELFT::Ehdr; 173 using Elf_Shdr = typename ELFT::Shdr; 174 using Elf_Phdr = typename ELFT::Phdr; 175 using Elf_Sym = typename ELFT::Sym; 176 using Elf_Addr = typename ELFT::Addr; 177 using Elf_Dyn = typename ELFT::Dyn; 178 179 ELFStubBuilder(const ELFStubBuilder &) = delete; 180 ELFStubBuilder(ELFStubBuilder &&) = default; 181 182 explicit ELFStubBuilder(const IFSStub &Stub) { 183 DynSym.Name = ".dynsym"; 184 DynSym.Align = sizeof(Elf_Addr); 185 DynStr.Name = ".dynstr"; 186 DynStr.Align = 1; 187 DynTab.Name = ".dynamic"; 188 DynTab.Align = sizeof(Elf_Addr); 189 ShStrTab.Name = ".shstrtab"; 190 ShStrTab.Align = 1; 191 192 // Populate string tables. 193 for (const IFSSymbol &Sym : Stub.Symbols) 194 DynStr.Content.add(Sym.Name); 195 for (const std::string &Lib : Stub.NeededLibs) 196 DynStr.Content.add(Lib); 197 if (Stub.SoName) 198 DynStr.Content.add(*Stub.SoName); 199 200 std::vector<OutputSection<ELFT> *> Sections = {&DynSym, &DynStr, &DynTab, 201 &ShStrTab}; 202 const OutputSection<ELFT> *LastSection = Sections.back(); 203 // Now set the Index and put sections names into ".shstrtab". 204 uint64_t Index = 1; 205 for (OutputSection<ELFT> *Sec : Sections) { 206 Sec->Index = Index++; 207 ShStrTab.Content.add(Sec->Name); 208 } 209 ShStrTab.Content.finalize(); 210 ShStrTab.Size = ShStrTab.Content.getSize(); 211 DynStr.Content.finalize(); 212 DynStr.Size = DynStr.Content.getSize(); 213 214 // Populate dynamic symbol table. 215 for (const IFSSymbol &Sym : Stub.Symbols) { 216 uint8_t Bind = Sym.Weak ? STB_WEAK : STB_GLOBAL; 217 // For non-undefined symbols, value of the shndx is not relevant at link 218 // time as long as it is not SHN_UNDEF. Set shndx to 1, which 219 // points to ".dynsym". 220 uint16_t Shndx = Sym.Undefined ? SHN_UNDEF : 1; 221 uint64_t Size = Sym.Size.value_or(0); 222 DynSym.Content.add(DynStr.Content.getOffset(Sym.Name), Size, Bind, 223 convertIFSSymbolTypeToELF(Sym.Type), 0, Shndx); 224 } 225 DynSym.Size = DynSym.Content.getSize(); 226 227 // Poplulate dynamic table. 228 size_t DynSymIndex = DynTab.Content.addAddr(DT_SYMTAB, 0); 229 size_t DynStrIndex = DynTab.Content.addAddr(DT_STRTAB, 0); 230 DynTab.Content.addValue(DT_STRSZ, DynSym.Size); 231 for (const std::string &Lib : Stub.NeededLibs) 232 DynTab.Content.addValue(DT_NEEDED, DynStr.Content.getOffset(Lib)); 233 if (Stub.SoName) 234 DynTab.Content.addValue(DT_SONAME, 235 DynStr.Content.getOffset(*Stub.SoName)); 236 DynTab.Size = DynTab.Content.getSize(); 237 // Calculate sections' addresses and offsets. 238 uint64_t CurrentOffset = sizeof(Elf_Ehdr); 239 for (OutputSection<ELFT> *Sec : Sections) { 240 Sec->Offset = alignTo(CurrentOffset, Sec->Align); 241 Sec->Addr = Sec->Offset; 242 CurrentOffset = Sec->Offset + Sec->Size; 243 } 244 // Fill Addr back to dynamic table. 245 DynTab.Content.modifyAddr(DynSymIndex, DynSym.Addr); 246 DynTab.Content.modifyAddr(DynStrIndex, DynStr.Addr); 247 // Write section headers of string tables. 248 fillSymTabShdr(DynSym, SHT_DYNSYM); 249 fillStrTabShdr(DynStr, SHF_ALLOC); 250 fillDynTabShdr(DynTab); 251 fillStrTabShdr(ShStrTab); 252 253 // Finish initializing the ELF header. 254 initELFHeader<ELFT>(ElfHeader, static_cast<uint16_t>(*Stub.Target.Arch)); 255 ElfHeader.e_shstrndx = ShStrTab.Index; 256 ElfHeader.e_shnum = LastSection->Index + 1; 257 ElfHeader.e_shoff = 258 alignTo(LastSection->Offset + LastSection->Size, sizeof(Elf_Addr)); 259 } 260 261 size_t getSize() const { 262 return ElfHeader.e_shoff + ElfHeader.e_shnum * sizeof(Elf_Shdr); 263 } 264 265 void write(uint8_t *Data) const { 266 write(Data, ElfHeader); 267 DynSym.Content.write(Data + DynSym.Shdr.sh_offset); 268 DynStr.Content.write(Data + DynStr.Shdr.sh_offset); 269 DynTab.Content.write(Data + DynTab.Shdr.sh_offset); 270 ShStrTab.Content.write(Data + ShStrTab.Shdr.sh_offset); 271 writeShdr(Data, DynSym); 272 writeShdr(Data, DynStr); 273 writeShdr(Data, DynTab); 274 writeShdr(Data, ShStrTab); 275 } 276 277 private: 278 Elf_Ehdr ElfHeader; 279 ContentSection<ELFStringTableBuilder, ELFT> DynStr; 280 ContentSection<ELFStringTableBuilder, ELFT> ShStrTab; 281 ContentSection<ELFSymbolTableBuilder<ELFT>, ELFT> DynSym; 282 ContentSection<ELFDynamicTableBuilder<ELFT>, ELFT> DynTab; 283 284 template <class T> static void write(uint8_t *Data, const T &Value) { 285 *reinterpret_cast<T *>(Data) = Value; 286 } 287 288 void fillStrTabShdr(ContentSection<ELFStringTableBuilder, ELFT> &StrTab, 289 uint32_t ShFlags = 0) const { 290 StrTab.Shdr.sh_type = SHT_STRTAB; 291 StrTab.Shdr.sh_flags = ShFlags; 292 StrTab.Shdr.sh_addr = StrTab.Addr; 293 StrTab.Shdr.sh_offset = StrTab.Offset; 294 StrTab.Shdr.sh_info = 0; 295 StrTab.Shdr.sh_size = StrTab.Size; 296 StrTab.Shdr.sh_name = ShStrTab.Content.getOffset(StrTab.Name); 297 StrTab.Shdr.sh_addralign = StrTab.Align; 298 StrTab.Shdr.sh_entsize = 0; 299 StrTab.Shdr.sh_link = 0; 300 } 301 void fillSymTabShdr(ContentSection<ELFSymbolTableBuilder<ELFT>, ELFT> &SymTab, 302 uint32_t ShType) const { 303 SymTab.Shdr.sh_type = ShType; 304 SymTab.Shdr.sh_flags = SHF_ALLOC; 305 SymTab.Shdr.sh_addr = SymTab.Addr; 306 SymTab.Shdr.sh_offset = SymTab.Offset; 307 // Only non-local symbols are included in the tbe file, so .dynsym only 308 // contains 1 local symbol (the undefined symbol at index 0). The sh_info 309 // should always be 1. 310 SymTab.Shdr.sh_info = 1; 311 SymTab.Shdr.sh_size = SymTab.Size; 312 SymTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(SymTab.Name); 313 SymTab.Shdr.sh_addralign = SymTab.Align; 314 SymTab.Shdr.sh_entsize = sizeof(Elf_Sym); 315 SymTab.Shdr.sh_link = this->DynStr.Index; 316 } 317 void fillDynTabShdr( 318 ContentSection<ELFDynamicTableBuilder<ELFT>, ELFT> &DynTab) const { 319 DynTab.Shdr.sh_type = SHT_DYNAMIC; 320 DynTab.Shdr.sh_flags = SHF_ALLOC; 321 DynTab.Shdr.sh_addr = DynTab.Addr; 322 DynTab.Shdr.sh_offset = DynTab.Offset; 323 DynTab.Shdr.sh_info = 0; 324 DynTab.Shdr.sh_size = DynTab.Size; 325 DynTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(DynTab.Name); 326 DynTab.Shdr.sh_addralign = DynTab.Align; 327 DynTab.Shdr.sh_entsize = sizeof(Elf_Dyn); 328 DynTab.Shdr.sh_link = this->DynStr.Index; 329 } 330 uint64_t shdrOffset(const OutputSection<ELFT> &Sec) const { 331 return ElfHeader.e_shoff + Sec.Index * sizeof(Elf_Shdr); 332 } 333 334 void writeShdr(uint8_t *Data, const OutputSection<ELFT> &Sec) const { 335 write(Data + shdrOffset(Sec), Sec.Shdr); 336 } 337 }; 338 339 /// This function takes an error, and appends a string of text to the end of 340 /// that error. Since "appending" to an Error isn't supported behavior of an 341 /// Error, this function technically creates a new error with the combined 342 /// message and consumes the old error. 343 /// 344 /// @param Err Source error. 345 /// @param After Text to append at the end of Err's error message. 346 Error appendToError(Error Err, StringRef After) { 347 std::string Message; 348 raw_string_ostream Stream(Message); 349 Stream << Err; 350 Stream << " " << After; 351 consumeError(std::move(Err)); 352 return createError(Stream.str()); 353 } 354 355 template <class ELFT> class DynSym { 356 using Elf_Shdr_Range = typename ELFT::ShdrRange; 357 using Elf_Shdr = typename ELFT::Shdr; 358 359 public: 360 static Expected<DynSym> create(const ELFFile<ELFT> &ElfFile, 361 const DynamicEntries &DynEnt) { 362 Expected<Elf_Shdr_Range> Shdrs = ElfFile.sections(); 363 if (!Shdrs) 364 return Shdrs.takeError(); 365 return DynSym(ElfFile, DynEnt, *Shdrs); 366 } 367 368 Expected<const uint8_t *> getDynSym() { 369 if (DynSymHdr) 370 return ElfFile.base() + DynSymHdr->sh_offset; 371 return getDynamicData(DynEnt.DynSymAddr, "dynamic symbol table"); 372 } 373 374 Expected<StringRef> getDynStr() { 375 if (DynSymHdr) 376 return ElfFile.getStringTableForSymtab(*DynSymHdr, Shdrs); 377 Expected<const uint8_t *> DataOrErr = getDynamicData( 378 DynEnt.StrTabAddr, "dynamic string table", DynEnt.StrSize); 379 if (!DataOrErr) 380 return DataOrErr.takeError(); 381 return StringRef(reinterpret_cast<const char *>(*DataOrErr), 382 DynEnt.StrSize); 383 } 384 385 private: 386 DynSym(const ELFFile<ELFT> &ElfFile, const DynamicEntries &DynEnt, 387 Elf_Shdr_Range Shdrs) 388 : ElfFile(ElfFile), DynEnt(DynEnt), Shdrs(Shdrs), 389 DynSymHdr(findDynSymHdr()) {} 390 391 const Elf_Shdr *findDynSymHdr() { 392 for (const Elf_Shdr &Sec : Shdrs) 393 if (Sec.sh_type == SHT_DYNSYM) { 394 // If multiple .dynsym are present, use the first one. 395 // This behavior aligns with llvm::object::ELFFile::getDynSymtabSize() 396 return &Sec; 397 } 398 return nullptr; 399 } 400 401 Expected<const uint8_t *> getDynamicData(uint64_t EntAddr, StringRef Name, 402 uint64_t Size = 0) { 403 Expected<const uint8_t *> SecPtr = ElfFile.toMappedAddr(EntAddr); 404 if (!SecPtr) 405 return appendToError( 406 SecPtr.takeError(), 407 ("when locating " + Name + " section contents").str()); 408 Expected<const uint8_t *> SecEndPtr = ElfFile.toMappedAddr(EntAddr + Size); 409 if (!SecEndPtr) 410 return appendToError( 411 SecEndPtr.takeError(), 412 ("when locating " + Name + " section contents").str()); 413 return *SecPtr; 414 } 415 416 const ELFFile<ELFT> &ElfFile; 417 const DynamicEntries &DynEnt; 418 Elf_Shdr_Range Shdrs; 419 const Elf_Shdr *DynSymHdr; 420 }; 421 } // end anonymous namespace 422 423 /// This function behaves similarly to StringRef::substr(), but attempts to 424 /// terminate the returned StringRef at the first null terminator. If no null 425 /// terminator is found, an error is returned. 426 /// 427 /// @param Str Source string to create a substring from. 428 /// @param Offset The start index of the desired substring. 429 static Expected<StringRef> terminatedSubstr(StringRef Str, size_t Offset) { 430 size_t StrEnd = Str.find('\0', Offset); 431 if (StrEnd == StringLiteral::npos) { 432 return createError( 433 "String overran bounds of string table (no null terminator)"); 434 } 435 436 size_t StrLen = StrEnd - Offset; 437 return Str.substr(Offset, StrLen); 438 } 439 440 /// This function populates a DynamicEntries struct using an ELFT::DynRange. 441 /// After populating the struct, the members are validated with 442 /// some basic correctness checks. 443 /// 444 /// @param Dyn Target DynamicEntries struct to populate. 445 /// @param DynTable Source dynamic table. 446 template <class ELFT> 447 static Error populateDynamic(DynamicEntries &Dyn, 448 typename ELFT::DynRange DynTable) { 449 if (DynTable.empty()) 450 return createError("No .dynamic section found"); 451 452 // Search .dynamic for relevant entries. 453 bool FoundDynStr = false; 454 bool FoundDynStrSz = false; 455 bool FoundDynSym = false; 456 for (auto &Entry : DynTable) { 457 switch (Entry.d_tag) { 458 case DT_SONAME: 459 Dyn.SONameOffset = Entry.d_un.d_val; 460 break; 461 case DT_STRTAB: 462 Dyn.StrTabAddr = Entry.d_un.d_ptr; 463 FoundDynStr = true; 464 break; 465 case DT_STRSZ: 466 Dyn.StrSize = Entry.d_un.d_val; 467 FoundDynStrSz = true; 468 break; 469 case DT_NEEDED: 470 Dyn.NeededLibNames.push_back(Entry.d_un.d_val); 471 break; 472 case DT_SYMTAB: 473 Dyn.DynSymAddr = Entry.d_un.d_ptr; 474 FoundDynSym = true; 475 break; 476 case DT_HASH: 477 Dyn.ElfHash = Entry.d_un.d_ptr; 478 break; 479 case DT_GNU_HASH: 480 Dyn.GnuHash = Entry.d_un.d_ptr; 481 } 482 } 483 484 if (!FoundDynStr) { 485 return createError( 486 "Couldn't locate dynamic string table (no DT_STRTAB entry)"); 487 } 488 if (!FoundDynStrSz) { 489 return createError( 490 "Couldn't determine dynamic string table size (no DT_STRSZ entry)"); 491 } 492 if (!FoundDynSym) { 493 return createError( 494 "Couldn't locate dynamic symbol table (no DT_SYMTAB entry)"); 495 } 496 if (Dyn.SONameOffset && *Dyn.SONameOffset >= Dyn.StrSize) { 497 return createStringError(object_error::parse_failed, 498 "DT_SONAME string offset (0x%016" PRIx64 499 ") outside of dynamic string table", 500 *Dyn.SONameOffset); 501 } 502 for (uint64_t Offset : Dyn.NeededLibNames) { 503 if (Offset >= Dyn.StrSize) { 504 return createStringError(object_error::parse_failed, 505 "DT_NEEDED string offset (0x%016" PRIx64 506 ") outside of dynamic string table", 507 Offset); 508 } 509 } 510 511 return Error::success(); 512 } 513 514 /// This function creates an IFSSymbol and populates all members using 515 /// information from a binary ELFT::Sym. 516 /// 517 /// @param SymName The desired name of the IFSSymbol. 518 /// @param RawSym ELFT::Sym to extract symbol information from. 519 template <class ELFT> 520 static IFSSymbol createELFSym(StringRef SymName, 521 const typename ELFT::Sym &RawSym) { 522 IFSSymbol TargetSym{std::string(SymName)}; 523 uint8_t Binding = RawSym.getBinding(); 524 if (Binding == STB_WEAK) 525 TargetSym.Weak = true; 526 else 527 TargetSym.Weak = false; 528 529 TargetSym.Undefined = RawSym.isUndefined(); 530 TargetSym.Type = convertELFSymbolTypeToIFS(RawSym.st_info); 531 532 if (TargetSym.Type == IFSSymbolType::Func) { 533 TargetSym.Size = 0; 534 } else { 535 TargetSym.Size = RawSym.st_size; 536 } 537 return TargetSym; 538 } 539 540 /// This function populates an IFSStub with symbols using information read 541 /// from an ELF binary. 542 /// 543 /// @param TargetStub IFSStub to add symbols to. 544 /// @param DynSym Range of dynamic symbols to add to TargetStub. 545 /// @param DynStr StringRef to the dynamic string table. 546 template <class ELFT> 547 static Error populateSymbols(IFSStub &TargetStub, 548 const typename ELFT::SymRange DynSym, 549 StringRef DynStr) { 550 // Skips the first symbol since it's the NULL symbol. 551 for (auto RawSym : DynSym.drop_front(1)) { 552 // If a symbol does not have global or weak binding, ignore it. 553 uint8_t Binding = RawSym.getBinding(); 554 if (!(Binding == STB_GLOBAL || Binding == STB_WEAK)) 555 continue; 556 // If a symbol doesn't have default or protected visibility, ignore it. 557 uint8_t Visibility = RawSym.getVisibility(); 558 if (!(Visibility == STV_DEFAULT || Visibility == STV_PROTECTED)) 559 continue; 560 // Create an IFSSymbol and populate it with information from the symbol 561 // table entry. 562 Expected<StringRef> SymName = terminatedSubstr(DynStr, RawSym.st_name); 563 if (!SymName) 564 return SymName.takeError(); 565 IFSSymbol Sym = createELFSym<ELFT>(*SymName, RawSym); 566 TargetStub.Symbols.push_back(std::move(Sym)); 567 // TODO: Populate symbol warning. 568 } 569 return Error::success(); 570 } 571 572 /// Returns a new IFSStub with all members populated from an ELFObjectFile. 573 /// @param ElfObj Source ELFObjectFile. 574 template <class ELFT> 575 static Expected<std::unique_ptr<IFSStub>> 576 buildStub(const ELFObjectFile<ELFT> &ElfObj) { 577 using Elf_Dyn_Range = typename ELFT::DynRange; 578 using Elf_Sym_Range = typename ELFT::SymRange; 579 using Elf_Sym = typename ELFT::Sym; 580 std::unique_ptr<IFSStub> DestStub = std::make_unique<IFSStub>(); 581 const ELFFile<ELFT> &ElfFile = ElfObj.getELFFile(); 582 // Fetch .dynamic table. 583 Expected<Elf_Dyn_Range> DynTable = ElfFile.dynamicEntries(); 584 if (!DynTable) { 585 return DynTable.takeError(); 586 } 587 588 // Collect relevant .dynamic entries. 589 DynamicEntries DynEnt; 590 if (Error Err = populateDynamic<ELFT>(DynEnt, *DynTable)) 591 return std::move(Err); 592 Expected<DynSym<ELFT>> EDynSym = DynSym<ELFT>::create(ElfFile, DynEnt); 593 if (!EDynSym) 594 return EDynSym.takeError(); 595 596 Expected<StringRef> EDynStr = EDynSym->getDynStr(); 597 if (!EDynStr) 598 return EDynStr.takeError(); 599 600 StringRef DynStr = *EDynStr; 601 602 // Populate Arch from ELF header. 603 DestStub->Target.Arch = static_cast<IFSArch>(ElfFile.getHeader().e_machine); 604 DestStub->Target.BitWidth = 605 convertELFBitWidthToIFS(ElfFile.getHeader().e_ident[EI_CLASS]); 606 DestStub->Target.Endianness = 607 convertELFEndiannessToIFS(ElfFile.getHeader().e_ident[EI_DATA]); 608 DestStub->Target.ObjectFormat = "ELF"; 609 610 // Populate SoName from .dynamic entries and dynamic string table. 611 if (DynEnt.SONameOffset) { 612 Expected<StringRef> NameOrErr = 613 terminatedSubstr(DynStr, *DynEnt.SONameOffset); 614 if (!NameOrErr) { 615 return appendToError(NameOrErr.takeError(), "when reading DT_SONAME"); 616 } 617 DestStub->SoName = std::string(*NameOrErr); 618 } 619 620 // Populate NeededLibs from .dynamic entries and dynamic string table. 621 for (uint64_t NeededStrOffset : DynEnt.NeededLibNames) { 622 Expected<StringRef> LibNameOrErr = 623 terminatedSubstr(DynStr, NeededStrOffset); 624 if (!LibNameOrErr) { 625 return appendToError(LibNameOrErr.takeError(), "when reading DT_NEEDED"); 626 } 627 DestStub->NeededLibs.push_back(std::string(*LibNameOrErr)); 628 } 629 630 // Populate Symbols from .dynsym table and dynamic string table. 631 Expected<uint64_t> SymCount = ElfFile.getDynSymtabSize(); 632 if (!SymCount) 633 return SymCount.takeError(); 634 if (*SymCount > 0) { 635 // Get pointer to in-memory location of .dynsym section. 636 Expected<const uint8_t *> DynSymPtr = EDynSym->getDynSym(); 637 if (!DynSymPtr) 638 return appendToError(DynSymPtr.takeError(), 639 "when locating .dynsym section contents"); 640 Elf_Sym_Range DynSyms = ArrayRef<Elf_Sym>( 641 reinterpret_cast<const Elf_Sym *>(*DynSymPtr), *SymCount); 642 Error SymReadError = populateSymbols<ELFT>(*DestStub, DynSyms, DynStr); 643 if (SymReadError) 644 return appendToError(std::move(SymReadError), 645 "when reading dynamic symbols"); 646 } 647 648 return std::move(DestStub); 649 } 650 651 /// This function opens a file for writing and then writes a binary ELF stub to 652 /// the file. 653 /// 654 /// @param FilePath File path for writing the ELF binary. 655 /// @param Stub Source InterFace Stub to generate a binary ELF stub from. 656 template <class ELFT> 657 static Error writeELFBinaryToFile(StringRef FilePath, const IFSStub &Stub, 658 bool WriteIfChanged) { 659 ELFStubBuilder<ELFT> Builder{Stub}; 660 // Write Stub to memory first. 661 std::vector<uint8_t> Buf(Builder.getSize()); 662 Builder.write(Buf.data()); 663 664 if (WriteIfChanged) { 665 if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError = 666 MemoryBuffer::getFile(FilePath)) { 667 // Compare Stub output with existing Stub file. 668 // If Stub file unchanged, abort updating. 669 if ((*BufOrError)->getBufferSize() == Builder.getSize() && 670 !memcmp((*BufOrError)->getBufferStart(), Buf.data(), 671 Builder.getSize())) 672 return Error::success(); 673 } 674 } 675 676 Expected<std::unique_ptr<FileOutputBuffer>> BufOrError = 677 FileOutputBuffer::create(FilePath, Builder.getSize()); 678 if (!BufOrError) 679 return createStringError(errc::invalid_argument, 680 toString(BufOrError.takeError()) + 681 " when trying to open `" + FilePath + 682 "` for writing"); 683 684 // Write binary to file. 685 std::unique_ptr<FileOutputBuffer> FileBuf = std::move(*BufOrError); 686 memcpy(FileBuf->getBufferStart(), Buf.data(), Buf.size()); 687 688 return FileBuf->commit(); 689 } 690 691 Expected<std::unique_ptr<IFSStub>> readELFFile(MemoryBufferRef Buf) { 692 Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buf); 693 if (!BinOrErr) { 694 return BinOrErr.takeError(); 695 } 696 697 Binary *Bin = BinOrErr->get(); 698 if (auto Obj = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) { 699 return buildStub(*Obj); 700 } else if (auto Obj = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) { 701 return buildStub(*Obj); 702 } else if (auto Obj = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) { 703 return buildStub(*Obj); 704 } else if (auto Obj = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) { 705 return buildStub(*Obj); 706 } 707 return createStringError(errc::not_supported, "unsupported binary format"); 708 } 709 710 // This function wraps the ELFT writeELFBinaryToFile() so writeBinaryStub() 711 // can be called without having to use ELFType templates directly. 712 Error writeBinaryStub(StringRef FilePath, const IFSStub &Stub, 713 bool WriteIfChanged) { 714 assert(Stub.Target.Arch); 715 assert(Stub.Target.BitWidth); 716 assert(Stub.Target.Endianness); 717 if (Stub.Target.BitWidth == IFSBitWidthType::IFS32) { 718 if (Stub.Target.Endianness == IFSEndiannessType::Little) { 719 return writeELFBinaryToFile<ELF32LE>(FilePath, Stub, WriteIfChanged); 720 } else { 721 return writeELFBinaryToFile<ELF32BE>(FilePath, Stub, WriteIfChanged); 722 } 723 } else { 724 if (Stub.Target.Endianness == IFSEndiannessType::Little) { 725 return writeELFBinaryToFile<ELF64LE>(FilePath, Stub, WriteIfChanged); 726 } else { 727 return writeELFBinaryToFile<ELF64BE>(FilePath, Stub, WriteIfChanged); 728 } 729 } 730 llvm_unreachable("invalid binary output target"); 731 } 732 733 } // end namespace ifs 734 } // end namespace llvm 735