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