Skip to content

Commit 15dfe03

Browse files
committed
[ifs] Allow llvm-ifs to generate text stub from elf stub
ELF stubs generated from llvm-ifs lacks program headers, which prevents llvm-ifs from parsing them properly as program headers are required by llvm's own ELF libraries. This patch adds a few workaround bypass this limitation. Differential Revision: https://reviews.llvm.org/D116769
1 parent a59bb21 commit 15dfe03

File tree

3 files changed

+116
-33
lines changed

3 files changed

+116
-33
lines changed

llvm/lib/InterfaceStub/ELFObjHandler.cpp

Lines changed: 91 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,89 @@ template <class ELFT> class ELFStubBuilder {
335335
write(Data + shdrOffset(Sec), Sec.Shdr);
336336
}
337337
};
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+
};
338421
} // end anonymous namespace
339422

340423
/// This function behaves similarly to StringRef::substr(), but attempts to
@@ -354,22 +437,6 @@ static Expected<StringRef> terminatedSubstr(StringRef Str, size_t Offset) {
354437
return Str.substr(Offset, StrLen);
355438
}
356439

357-
/// This function takes an error, and appends a string of text to the end of
358-
/// that error. Since "appending" to an Error isn't supported behavior of an
359-
/// Error, this function technically creates a new error with the combined
360-
/// message and consumes the old error.
361-
///
362-
/// @param Err Source error.
363-
/// @param After Text to append at the end of Err's error message.
364-
Error appendToError(Error Err, StringRef After) {
365-
std::string Message;
366-
raw_string_ostream Stream(Message);
367-
Stream << Err;
368-
Stream << " " << After;
369-
consumeError(std::move(Err));
370-
return createError(Stream.str());
371-
}
372-
373440
/// This function populates a DynamicEntries struct using an ELFT::DynRange.
374441
/// After populating the struct, the members are validated with
375442
/// some basic correctness checks.
@@ -508,7 +575,6 @@ template <class ELFT>
508575
static Expected<std::unique_ptr<IFSStub>>
509576
buildStub(const ELFObjectFile<ELFT> &ElfObj) {
510577
using Elf_Dyn_Range = typename ELFT::DynRange;
511-
using Elf_Phdr_Range = typename ELFT::PhdrRange;
512578
using Elf_Sym_Range = typename ELFT::SymRange;
513579
using Elf_Sym = typename ELFT::Sym;
514580
std::unique_ptr<IFSStub> DestStub = std::make_unique<IFSStub>();
@@ -519,25 +585,19 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) {
519585
return DynTable.takeError();
520586
}
521587

522-
// Fetch program headers.
523-
Expected<Elf_Phdr_Range> PHdrs = ElfFile.program_headers();
524-
if (!PHdrs) {
525-
return PHdrs.takeError();
526-
}
527-
528588
// Collect relevant .dynamic entries.
529589
DynamicEntries DynEnt;
530590
if (Error Err = populateDynamic<ELFT>(DynEnt, *DynTable))
531591
return std::move(Err);
592+
Expected<DynSym<ELFT>> EDynSym = DynSym<ELFT>::create(ElfFile, DynEnt);
593+
if (!EDynSym)
594+
return EDynSym.takeError();
532595

533-
// Get pointer to in-memory location of .dynstr section.
534-
Expected<const uint8_t *> DynStrPtr = ElfFile.toMappedAddr(DynEnt.StrTabAddr);
535-
if (!DynStrPtr)
536-
return appendToError(DynStrPtr.takeError(),
537-
"when locating .dynstr section contents");
596+
Expected<StringRef> EDynStr = EDynSym->getDynStr();
597+
if (!EDynStr)
598+
return EDynStr.takeError();
538599

539-
StringRef DynStr(reinterpret_cast<const char *>(DynStrPtr.get()),
540-
DynEnt.StrSize);
600+
StringRef DynStr = *EDynStr;
541601

542602
// Populate Arch from ELF header.
543603
DestStub->Target.Arch = static_cast<IFSArch>(ElfFile.getHeader().e_machine);
@@ -573,8 +633,7 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) {
573633
return SymCount.takeError();
574634
if (*SymCount > 0) {
575635
// Get pointer to in-memory location of .dynsym section.
576-
Expected<const uint8_t *> DynSymPtr =
577-
ElfFile.toMappedAddr(DynEnt.DynSymAddr);
636+
Expected<const uint8_t *> DynSymPtr = EDynSym->getDynSym();
578637
if (!DynSymPtr)
579638
return appendToError(DynSymPtr.takeError(),
580639
"when locating .dynsym section contents");

llvm/test/tools/llvm-ifs/binary-read-bad-vaddr.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ ProgramHeaders:
4444
FirstSec: .dynamic
4545
LastSec: .dynamic
4646

47-
# CHECK: virtual address is not in any segment: 0x260 when locating .dynstr section contents
47+
# CHECK: virtual address is not in any segment: 0x260 when locating dynamic string table section contents
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
## Test writing stub ELF from IFS and read stub ELF to regenerate IFS.
2+
3+
# RUN: llvm-ifs --output-elf=%t.elf64l --arch=x86_64 --bitwidth=64 --endianness=little %s
4+
# RUN: llvm-ifs --output-ifs=- --strip-ifs-target %t.elf64l | FileCheck %s
5+
6+
--- !ifs-v1
7+
IfsVersion: 3.0
8+
NeededLibs:
9+
- libc.so.6
10+
Symbols:
11+
- { Name: bar, Type: Object, Size: 42 }
12+
- { Name: baz, Type: TLS, Size: 3 }
13+
- { Name: plus, Type: Func }
14+
...
15+
16+
# CHECK: --- !ifs-v1
17+
# CHECK-NEXT: IfsVersion: 3.0
18+
# CHECK-NEXT: NeededLibs:
19+
# CHECK-NEXT: - libc.so.6
20+
# CHECK-NEXT: Symbols:
21+
# CHECK-NEXT: - { Name: bar, Type: Object, Size: 42 }
22+
# CHECK-NEXT: - { Name: baz, Type: TLS, Size: 3 }
23+
# CHECK-NEXT: - { Name: plus, Type: Func }
24+
# CHECK-NEXT: ...

0 commit comments

Comments
 (0)