[llvm] 15dfe03 - [ifs] Allow llvm-ifs to generate text stub from elf stub
Haowei Wu via llvm-commits
llvm-commits at lists.llvm.org
Sun Feb 13 21:06:04 PST 2022
Author: Haowei Wu
Date: 2022-02-13T21:05:52-08:00
New Revision: 15dfe03022caf38d173bd2d950711968c6c31d60
URL: https://github.com/llvm/llvm-project/commit/15dfe03022caf38d173bd2d950711968c6c31d60
DIFF: https://github.com/llvm/llvm-project/commit/15dfe03022caf38d173bd2d950711968c6c31d60.diff
LOG: [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
Added:
llvm/test/tools/llvm-ifs/ifs-elf-conversion.test
Modified:
llvm/lib/InterfaceStub/ELFObjHandler.cpp
llvm/test/tools/llvm-ifs/binary-read-bad-vaddr.test
Removed:
################################################################################
diff --git a/llvm/lib/InterfaceStub/ELFObjHandler.cpp b/llvm/lib/InterfaceStub/ELFObjHandler.cpp
index d2a13428b02a9..82e33adcea81e 100644
--- a/llvm/lib/InterfaceStub/ELFObjHandler.cpp
+++ b/llvm/lib/InterfaceStub/ELFObjHandler.cpp
@@ -335,6 +335,89 @@ template <class ELFT> class ELFStubBuilder {
write(Data + shdrOffset(Sec), Sec.Shdr);
}
};
+
+/// This function takes an error, and appends a string of text to the end of
+/// that error. Since "appending" to an Error isn't supported behavior of an
+/// Error, this function technically creates a new error with the combined
+/// message and consumes the old error.
+///
+/// @param Err Source error.
+/// @param After Text to append at the end of Err's error message.
+Error appendToError(Error Err, StringRef After) {
+ std::string Message;
+ raw_string_ostream Stream(Message);
+ Stream << Err;
+ Stream << " " << After;
+ consumeError(std::move(Err));
+ return createError(Stream.str());
+}
+
+template <class ELFT> class DynSym {
+ using Elf_Shdr_Range = typename ELFT::ShdrRange;
+ using Elf_Shdr = typename ELFT::Shdr;
+
+public:
+ static Expected<DynSym> create(const ELFFile<ELFT> &ElfFile,
+ const DynamicEntries &DynEnt) {
+ Expected<Elf_Shdr_Range> Shdrs = ElfFile.sections();
+ if (!Shdrs)
+ return Shdrs.takeError();
+ return DynSym(ElfFile, DynEnt, *Shdrs);
+ }
+
+ Expected<const uint8_t *> getDynSym() {
+ if (DynSymHdr)
+ return ElfFile.base() + DynSymHdr->sh_offset;
+ return getDynamicData(DynEnt.DynSymAddr, "dynamic symbol table");
+ }
+
+ Expected<StringRef> getDynStr() {
+ if (DynSymHdr)
+ return ElfFile.getStringTableForSymtab(*DynSymHdr, Shdrs);
+ Expected<const uint8_t *> DataOrErr = getDynamicData(
+ DynEnt.StrTabAddr, "dynamic string table", DynEnt.StrSize);
+ if (!DataOrErr)
+ return DataOrErr.takeError();
+ return StringRef(reinterpret_cast<const char *>(*DataOrErr),
+ DynEnt.StrSize);
+ }
+
+private:
+ DynSym(const ELFFile<ELFT> &ElfFile, const DynamicEntries &DynEnt,
+ Elf_Shdr_Range Shdrs)
+ : ElfFile(ElfFile), DynEnt(DynEnt), Shdrs(Shdrs),
+ DynSymHdr(findDynSymHdr()) {}
+
+ const Elf_Shdr *findDynSymHdr() {
+ for (const Elf_Shdr &Sec : Shdrs)
+ if (Sec.sh_type == SHT_DYNSYM) {
+ // If multiple .dynsym are present, use the first one.
+ // This behavior aligns with llvm::object::ELFFile::getDynSymtabSize()
+ return &Sec;
+ }
+ return nullptr;
+ }
+
+ Expected<const uint8_t *> getDynamicData(uint64_t EntAddr, StringRef Name,
+ uint64_t Size = 0) {
+ Expected<const uint8_t *> SecPtr = ElfFile.toMappedAddr(EntAddr);
+ if (!SecPtr)
+ return appendToError(
+ SecPtr.takeError(),
+ ("when locating " + Name + " section contents").str());
+ Expected<const uint8_t *> SecEndPtr = ElfFile.toMappedAddr(EntAddr + Size);
+ if (!SecEndPtr)
+ return appendToError(
+ SecEndPtr.takeError(),
+ ("when locating " + Name + " section contents").str());
+ return *SecPtr;
+ }
+
+ const ELFFile<ELFT> &ElfFile;
+ const DynamicEntries &DynEnt;
+ Elf_Shdr_Range Shdrs;
+ const Elf_Shdr *DynSymHdr;
+};
} // end anonymous namespace
/// This function behaves similarly to StringRef::substr(), but attempts to
@@ -354,22 +437,6 @@ static Expected<StringRef> terminatedSubstr(StringRef Str, size_t Offset) {
return Str.substr(Offset, StrLen);
}
-/// This function takes an error, and appends a string of text to the end of
-/// that error. Since "appending" to an Error isn't supported behavior of an
-/// Error, this function technically creates a new error with the combined
-/// message and consumes the old error.
-///
-/// @param Err Source error.
-/// @param After Text to append at the end of Err's error message.
-Error appendToError(Error Err, StringRef After) {
- std::string Message;
- raw_string_ostream Stream(Message);
- Stream << Err;
- Stream << " " << After;
- consumeError(std::move(Err));
- return createError(Stream.str());
-}
-
/// This function populates a DynamicEntries struct using an ELFT::DynRange.
/// After populating the struct, the members are validated with
/// some basic correctness checks.
@@ -508,7 +575,6 @@ template <class ELFT>
static Expected<std::unique_ptr<IFSStub>>
buildStub(const ELFObjectFile<ELFT> &ElfObj) {
using Elf_Dyn_Range = typename ELFT::DynRange;
- using Elf_Phdr_Range = typename ELFT::PhdrRange;
using Elf_Sym_Range = typename ELFT::SymRange;
using Elf_Sym = typename ELFT::Sym;
std::unique_ptr<IFSStub> DestStub = std::make_unique<IFSStub>();
@@ -519,25 +585,19 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) {
return DynTable.takeError();
}
- // Fetch program headers.
- Expected<Elf_Phdr_Range> PHdrs = ElfFile.program_headers();
- if (!PHdrs) {
- return PHdrs.takeError();
- }
-
// Collect relevant .dynamic entries.
DynamicEntries DynEnt;
if (Error Err = populateDynamic<ELFT>(DynEnt, *DynTable))
return std::move(Err);
+ Expected<DynSym<ELFT>> EDynSym = DynSym<ELFT>::create(ElfFile, DynEnt);
+ if (!EDynSym)
+ return EDynSym.takeError();
- // Get pointer to in-memory location of .dynstr section.
- Expected<const uint8_t *> DynStrPtr = ElfFile.toMappedAddr(DynEnt.StrTabAddr);
- if (!DynStrPtr)
- return appendToError(DynStrPtr.takeError(),
- "when locating .dynstr section contents");
+ Expected<StringRef> EDynStr = EDynSym->getDynStr();
+ if (!EDynStr)
+ return EDynStr.takeError();
- StringRef DynStr(reinterpret_cast<const char *>(DynStrPtr.get()),
- DynEnt.StrSize);
+ StringRef DynStr = *EDynStr;
// Populate Arch from ELF header.
DestStub->Target.Arch = static_cast<IFSArch>(ElfFile.getHeader().e_machine);
@@ -573,8 +633,7 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) {
return SymCount.takeError();
if (*SymCount > 0) {
// Get pointer to in-memory location of .dynsym section.
- Expected<const uint8_t *> DynSymPtr =
- ElfFile.toMappedAddr(DynEnt.DynSymAddr);
+ Expected<const uint8_t *> DynSymPtr = EDynSym->getDynSym();
if (!DynSymPtr)
return appendToError(DynSymPtr.takeError(),
"when locating .dynsym section contents");
diff --git a/llvm/test/tools/llvm-ifs/binary-read-bad-vaddr.test b/llvm/test/tools/llvm-ifs/binary-read-bad-vaddr.test
index 36547176eb938..e9c0cf0ec0b86 100644
--- a/llvm/test/tools/llvm-ifs/binary-read-bad-vaddr.test
+++ b/llvm/test/tools/llvm-ifs/binary-read-bad-vaddr.test
@@ -44,4 +44,4 @@ ProgramHeaders:
FirstSec: .dynamic
LastSec: .dynamic
-# CHECK: virtual address is not in any segment: 0x260 when locating .dynstr section contents
+# CHECK: virtual address is not in any segment: 0x260 when locating dynamic string table section contents
diff --git a/llvm/test/tools/llvm-ifs/ifs-elf-conversion.test b/llvm/test/tools/llvm-ifs/ifs-elf-conversion.test
new file mode 100644
index 0000000000000..c76415047a22e
--- /dev/null
+++ b/llvm/test/tools/llvm-ifs/ifs-elf-conversion.test
@@ -0,0 +1,24 @@
+## Test writing stub ELF from IFS and read stub ELF to regenerate IFS.
+
+# RUN: llvm-ifs --output-elf=%t.elf64l --arch=x86_64 --bitwidth=64 --endianness=little %s
+# RUN: llvm-ifs --output-ifs=- --strip-ifs-target %t.elf64l | FileCheck %s
+
+--- !ifs-v1
+IfsVersion: 3.0
+NeededLibs:
+ - libc.so.6
+Symbols:
+ - { Name: bar, Type: Object, Size: 42 }
+ - { Name: baz, Type: TLS, Size: 3 }
+ - { Name: plus, Type: Func }
+...
+
+# CHECK: --- !ifs-v1
+# CHECK-NEXT: IfsVersion: 3.0
+# CHECK-NEXT: NeededLibs:
+# CHECK-NEXT: - libc.so.6
+# CHECK-NEXT: Symbols:
+# CHECK-NEXT: - { Name: bar, Type: Object, Size: 42 }
+# CHECK-NEXT: - { Name: baz, Type: TLS, Size: 3 }
+# CHECK-NEXT: - { Name: plus, Type: Func }
+# CHECK-NEXT: ...
More information about the llvm-commits
mailing list