[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