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